Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/nyx/nyx_gui/nyx.c
1476 views
1
/*
2
* Copyright (c) 2018 naehrwert
3
*
4
* Copyright (c) 2018-2023 CTCaer
5
*
6
* This program is free software; you can redistribute it and/or modify it
7
* under the terms and conditions of the GNU General Public License,
8
* version 2, as published by the Free Software Foundation.
9
*
10
* This program is distributed in the hope it will be useful, but WITHOUT
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13
* more details.
14
*
15
* You should have received a copy of the GNU General Public License
16
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
*/
18
19
#include <string.h>
20
#include <stdlib.h>
21
22
#include <bdk.h>
23
24
#include "config.h"
25
#include "hos/hos.h"
26
#include <ianos/ianos.h>
27
#include <libs/compr/blz.h>
28
#include <libs/fatfs/ff.h>
29
30
#include "frontend/fe_emmc_tools.h"
31
#include "frontend/gui.h"
32
33
nyx_config n_cfg;
34
hekate_config h_cfg;
35
36
const volatile ipl_ver_meta_t __attribute__((section ("._ipl_version"))) ipl_ver = {
37
.magic = NYX_MAGIC,
38
.version = (NYX_VER_MJ + '0') | ((NYX_VER_MN + '0') << 8) | ((NYX_VER_HF + '0') << 16) | ((NYX_VER_RL) << 24),
39
.rsvd0 = 0,
40
.rsvd1 = 0
41
};
42
43
volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR;
44
volatile boot_cfg_t *b_cfg;
45
46
char *emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage)
47
{
48
static char emmc_sn[9] = {0};
49
50
// Check if eMMC S/N storage has valid data and skip parsing in that case.
51
if (emmc_sn[0] && strcmp(emmc_sn, "00000000"))
52
goto create_dir;
53
54
// Get actual eMMC S/N.
55
if (!storage)
56
{
57
if (!emmc_initialize(false))
58
strcpy(emmc_sn, "00000000");
59
else
60
{
61
itoa(emmc_storage.cid.serial, emmc_sn, 16);
62
emmc_end();
63
}
64
}
65
else
66
itoa(storage->cid.serial, emmc_sn, 16);
67
68
create_dir:
69
// Check if only eMMC S/N was requested.
70
if (!path)
71
return emmc_sn;
72
73
// Create main folder.
74
strcpy(path, "backup");
75
f_mkdir(path);
76
77
// Create eMMC S/N folder.
78
strcat(path, "/");
79
strcat(path, emmc_sn);
80
f_mkdir(path);
81
82
// Create sub folder if defined. Dir slash must be included.
83
strcat(path, sub_dir); // Can be a null-terminator.
84
if (strlen(sub_dir))
85
f_mkdir(path);
86
87
// Add filename.
88
strcat(path, "/");
89
strcat(path, filename); // Can be a null-terminator.
90
91
return emmc_sn;
92
}
93
94
// This is a safe and unused DRAM region for our payloads.
95
#define RELOC_META_OFF 0x7C
96
#define PATCHED_RELOC_SZ 0x94
97
#define PATCHED_RELOC_STACK 0x40007000
98
#define PATCHED_RELOC_ENTRY 0x40010000
99
#define EXT_PAYLOAD_ADDR 0xC0000000
100
#define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))
101
#define COREBOOT_END_ADDR 0xD0000000
102
#define CBFS_DRAM_EN_ADDR 0x4003E000
103
#define CBFS_DRAM_MAGIC 0x4452414D // "DRAM"
104
105
static void *coreboot_addr;
106
107
void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
108
{
109
memcpy((u8 *)payload_src, (u8 *)nyx_str->hekate, PATCHED_RELOC_SZ);
110
111
volatile reloc_meta_t *relocator = (reloc_meta_t *)(payload_src + RELOC_META_OFF);
112
113
relocator->start = payload_dst - ALIGN(PATCHED_RELOC_SZ, 0x10);
114
relocator->stack = PATCHED_RELOC_STACK;
115
relocator->end = payload_dst + payload_size;
116
relocator->ep = payload_dst;
117
118
if (payload_size == 0x7000)
119
{
120
memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), coreboot_addr, 0x7000); // Bootblock.
121
*(vu32 *)CBFS_DRAM_EN_ADDR = CBFS_DRAM_MAGIC;
122
}
123
}
124
125
lv_res_t launch_payload(lv_obj_t *list)
126
{
127
const char *filename = lv_list_get_btn_text(list);
128
129
if (!filename || !filename[0])
130
goto out;
131
132
char path[128];
133
134
strcpy(path,"bootloader/payloads/");
135
strcat(path, filename);
136
137
if (!sd_mount())
138
goto out;
139
140
FIL fp;
141
if (f_open(&fp, path, FA_READ))
142
{
143
EPRINTFARGS("Payload file is missing!\n(%s)", path);
144
145
goto out;
146
}
147
148
// Read and copy the payload to our chosen address
149
void *buf;
150
u32 size = f_size(&fp);
151
152
if (size < 0x30000)
153
buf = (void *)RCM_PAYLOAD_ADDR;
154
else
155
{
156
coreboot_addr = (void *)(COREBOOT_END_ADDR - size);
157
buf = coreboot_addr;
158
if (h_cfg.t210b01)
159
{
160
f_close(&fp);
161
162
EPRINTF("Coreboot not allowed on Mariko!");
163
164
goto out;
165
}
166
}
167
168
if (f_read(&fp, buf, size, NULL))
169
{
170
f_close(&fp);
171
172
goto out;
173
}
174
175
f_close(&fp);
176
177
sd_end();
178
179
if (size < 0x30000)
180
{
181
reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10));
182
hw_deinit(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32))));
183
}
184
else
185
{
186
reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, 0x7000);
187
hw_deinit(true, 0);
188
}
189
190
void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR;
191
192
// Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms.
193
sdmmc_storage_init_wait_sd();
194
195
// Launch our payload.
196
(*ext_payload_ptr)();
197
198
out:
199
sd_unmount();
200
201
return LV_RES_OK;
202
}
203
204
static void _load_saved_configuration()
205
{
206
LIST_INIT(ini_sections);
207
LIST_INIT(ini_nyx_sections);
208
209
if (!ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
210
{
211
create_config_entry();
212
goto skip_main_cfg_parse;
213
}
214
215
// Load hekate configuration.
216
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
217
{
218
// Only parse config section.
219
if (ini_sec->type == INI_CHOICE && !strcmp(ini_sec->name, "config"))
220
{
221
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
222
{
223
if (!strcmp("autoboot", kv->key))
224
h_cfg.autoboot = atoi(kv->val);
225
else if (!strcmp("autoboot_list", kv->key))
226
h_cfg.autoboot_list = atoi(kv->val);
227
else if (!strcmp("bootwait", kv->key))
228
h_cfg.bootwait = atoi(kv->val);
229
else if (!strcmp("backlight", kv->key))
230
{
231
h_cfg.backlight = atoi(kv->val);
232
if (h_cfg.backlight <= 20)
233
h_cfg.backlight = 30;
234
}
235
else if (!strcmp("noticker", kv->key))
236
h_cfg.noticker = atoi(kv->val);
237
else if (!strcmp("autohosoff", kv->key))
238
h_cfg.autohosoff = atoi(kv->val);
239
else if (!strcmp("autonogc", kv->key))
240
h_cfg.autonogc = atoi(kv->val);
241
else if (!strcmp("updater2p", kv->key))
242
h_cfg.updater2p = atoi(kv->val);
243
else if (!strcmp("bootprotect", kv->key))
244
h_cfg.bootprotect = atoi(kv->val);
245
}
246
247
break;
248
}
249
}
250
251
ini_free(&ini_sections);
252
253
skip_main_cfg_parse:
254
if (!ini_parse(&ini_nyx_sections, "bootloader/nyx.ini", false))
255
return;
256
257
// Load Nyx configuration.
258
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_nyx_sections, link)
259
{
260
// Only parse config section.
261
if (ini_sec->type == INI_CHOICE && !strcmp(ini_sec->name, "config"))
262
{
263
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
264
{
265
if (!strcmp("themebg", kv->key))
266
n_cfg.theme_bg = strtol(kv->val, NULL, 16);
267
else if (!strcmp("themecolor", kv->key))
268
n_cfg.theme_color = atoi(kv->val);
269
else if (!strcmp("entries5col", kv->key))
270
n_cfg.entries_5_col = atoi(kv->val) == 1;
271
else if (!strcmp("timeoff", kv->key))
272
{
273
n_cfg.timeoff = strtol(kv->val, NULL, 16);
274
if (n_cfg.timeoff != 1)
275
max77620_rtc_set_epoch_offset((int)n_cfg.timeoff);
276
}
277
else if (!strcmp("homescreen", kv->key))
278
n_cfg.home_screen = atoi(kv->val);
279
else if (!strcmp("verification", kv->key))
280
n_cfg.verification = atoi(kv->val);
281
else if (!strcmp("umsemmcrw", kv->key))
282
n_cfg.ums_emmc_rw = atoi(kv->val) == 1;
283
else if (!strcmp("jcdisable", kv->key))
284
n_cfg.jc_disable = atoi(kv->val) == 1;
285
else if (!strcmp("jcforceright", kv->key))
286
n_cfg.jc_force_right = atoi(kv->val) == 1;
287
else if (!strcmp("bpmpclock", kv->key))
288
n_cfg.bpmp_clock = atoi(kv->val);
289
}
290
291
break;
292
}
293
}
294
295
ini_free(&ini_nyx_sections);
296
}
297
298
static int nyx_load_resources()
299
{
300
FIL fp;
301
int res;
302
303
res = f_open(&fp, "bootloader/sys/res.pak", FA_READ);
304
if (res)
305
return res;
306
307
res = f_read(&fp, (void *)NYX_RES_ADDR, f_size(&fp), NULL);
308
f_close(&fp);
309
310
return res;
311
}
312
313
static void nyx_load_bg_icons()
314
{
315
// If no custom switch icon exists, load normal.
316
if (!f_stat("bootloader/res/icon_switch_custom.bmp", NULL))
317
icon_switch = bmp_to_lvimg_obj("bootloader/res/icon_switch_custom.bmp");
318
else
319
icon_switch = bmp_to_lvimg_obj("bootloader/res/icon_switch.bmp");
320
321
// If no custom payload icon exists, load normal.
322
if (!f_stat("bootloader/res/icon_payload_custom.bmp", NULL))
323
icon_payload = bmp_to_lvimg_obj("bootloader/res/icon_payload_custom.bmp");
324
else
325
icon_payload = bmp_to_lvimg_obj("bootloader/res/icon_payload.bmp");
326
327
// Load background resource if any.
328
hekate_bg = bmp_to_lvimg_obj("bootloader/res/background.bmp");
329
}
330
331
#define EXCP_EN_ADDR 0x4003FFFC
332
#define EXCP_MAGIC 0x30505645 // EVP0
333
#define EXCP_TYPE_ADDR 0x4003FFF8
334
#define EXCP_TYPE_RESET 0x545352 // RST
335
#define EXCP_TYPE_UNDEF 0x464455 // UDF
336
#define EXCP_TYPE_PABRT 0x54424150 // PABT
337
#define EXCP_TYPE_DABRT 0x54424144 // DABT
338
#define EXCP_LR_ADDR 0x4003FFF4
339
340
enum {
341
SD_NO_ERROR = 0,
342
SD_MOUNT_ERROR = 1,
343
SD_FILE_ERROR = 2
344
};
345
346
static void _show_errors(int sd_error)
347
{
348
u32 *excp_enabled = (u32 *)EXCP_EN_ADDR;
349
u32 *excp_type = (u32 *)EXCP_TYPE_ADDR;
350
u32 *excp_lr = (u32 *)EXCP_LR_ADDR;
351
352
if (*excp_enabled == EXCP_MAGIC || sd_error)
353
{
354
gfx_clear_grey(0);
355
gfx_con_setpos(0, 0, 0);
356
display_backlight_brightness(150, 1000);
357
display_init_window_d_console();
358
display_window_d_console_enable();
359
}
360
361
switch (sd_error)
362
{
363
case SD_MOUNT_ERROR:
364
WPRINTF("Failed to init or mount SD!\n");
365
goto error_occured;
366
case SD_FILE_ERROR:
367
WPRINTF("Failed to load GUI resources!\nres.pak not found or corrupted.\n");
368
goto error_occured;
369
case SD_NO_ERROR:
370
default:
371
break;
372
}
373
374
if (*excp_enabled == EXCP_MAGIC)
375
{
376
WPRINTFARGS("Nyx exception occurred (LR %08X):\n", *excp_lr);
377
switch (*excp_type)
378
{
379
case EXCP_TYPE_RESET:
380
WPRINTF("RESET");
381
break;
382
case EXCP_TYPE_UNDEF:
383
WPRINTF("UNDEF");
384
break;
385
case EXCP_TYPE_PABRT:
386
WPRINTF("PABRT");
387
break;
388
case EXCP_TYPE_DABRT:
389
WPRINTF("DABRT");
390
break;
391
}
392
gfx_puts("\n");
393
394
// Clear the exception.
395
*excp_lr = 0;
396
*excp_type = 0;
397
*excp_enabled = 0;
398
399
error_occured:
400
WPRINTF("Press any key to reload Nyx...");
401
402
msleep(1000);
403
btn_wait();
404
405
reload_nyx(NULL, true);
406
}
407
}
408
409
void nyx_init_load_res()
410
{
411
bpmp_mmu_enable();
412
bpmp_clk_rate_get();
413
414
// Set a modest clock for init. It will be restored later if possible.
415
bpmp_clk_rate_set(BPMP_CLK_LOWER_BOOST);
416
417
// Set bootloader's default configuration.
418
set_default_configuration();
419
set_nyx_default_configuration();
420
421
// Reset new info if magic not correct.
422
if (nyx_str->info.magic != NYX_NEW_INFO)
423
{
424
nyx_str->info.sd_init = 0;
425
for (u32 i = 0; i < 3; i++)
426
nyx_str->info.sd_errors[i] = 0;
427
}
428
429
// Clear info magic.
430
nyx_str->info.magic = 0;
431
432
// Set display id from previous initialization.
433
display_set_decoded_panel_id(nyx_str->info.disp_id);
434
435
// Initialize gfx console.
436
gfx_init_ctxt((u32 *)LOG_FB_ADDRESS, 1280, 656, 656);
437
gfx_con_init();
438
439
// Show exception errors if any.
440
_show_errors(SD_NO_ERROR);
441
442
// Try 2 times to mount SD card.
443
if (!sd_mount())
444
{
445
// Restore speed to SDR104.
446
sd_end();
447
448
// Retry.
449
if (!sd_mount())
450
_show_errors(SD_MOUNT_ERROR); // Fatal.
451
}
452
453
// Train DRAM and switch to max frequency.
454
minerva_init();
455
456
// Load hekate/Nyx configuration.
457
_load_saved_configuration();
458
459
// Load Nyx resources.
460
if (nyx_load_resources())
461
{
462
// Try again.
463
if (nyx_load_resources())
464
_show_errors(SD_FILE_ERROR); // Fatal since resources are mandatory.
465
}
466
467
// Initialize nyx cfg to lower clock on first boot.
468
// In case of lower binned SoC, this can help with hangs.
469
if (!n_cfg.bpmp_clock)
470
{
471
// Set lower clock and save it.
472
n_cfg.bpmp_clock = 2;
473
create_nyx_config_entry(false);
474
475
// Start at max clock and test it.
476
n_cfg.bpmp_clock = 0;
477
}
478
479
// Set selected clock.
480
switch (n_cfg.bpmp_clock)
481
{
482
case 0:
483
case 1:
484
bpmp_clk_rate_set(BPMP_CLK_DEFAULT_BOOST);
485
break;
486
case 2:
487
bpmp_clk_rate_set(BPMP_CLK_LOWER_BOOST);
488
break;
489
case 3:
490
default:
491
bpmp_clk_rate_set(BPMP_CLK_LOWEST_BOOST);
492
break;
493
}
494
495
// Load default launch icons and background if it exists.
496
nyx_load_bg_icons();
497
498
// Unmount FAT partition.
499
sd_unmount();
500
}
501
502
void ipl_main()
503
{
504
// Set heap address.
505
heap_init((void *)IPL_HEAP_START);
506
507
b_cfg = (boot_cfg_t *)(nyx_str->hekate + 0x94);
508
509
#ifdef DEBUG_UART_PORT
510
// Enable the selected uart debug port.
511
#if (DEBUG_UART_PORT == UART_B)
512
gpio_config(GPIO_PORT_G, GPIO_PIN_0, GPIO_MODE_SPIO);
513
#elif (DEBUG_UART_PORT == UART_C)
514
gpio_config(GPIO_PORT_D, GPIO_PIN_1, GPIO_MODE_SPIO);
515
#endif
516
pinmux_config_uart(DEBUG_UART_PORT);
517
clock_enable_uart(DEBUG_UART_PORT);
518
uart_init(DEBUG_UART_PORT, DEBUG_UART_BAUDRATE, UART_AO_TX_AO_RX);
519
uart_invert(DEBUG_UART_PORT, DEBUG_UART_INVERT, UART_INVERT_TXD);
520
521
uart_send(DEBUG_UART_PORT, (u8 *)"hekate-NYX: Hello!\r\n", 20);
522
uart_wait_xfer(DEBUG_UART_PORT, UART_TX_IDLE);
523
#endif
524
525
// Initialize the rest of hw and load Nyx resources.
526
nyx_init_load_res();
527
528
// Initialize Nyx GUI and show it.
529
nyx_load_and_run();
530
531
// Halt BPMP if we managed to get out of execution.
532
while (true)
533
bpmp_halt();
534
}
535
536