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