Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/bootloader/main.c
3693 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 "gfx/logos.h"
26
#include "gfx/tui.h"
27
#include "hos/hos.h"
28
#include "hos/secmon_exo.h"
29
#include "l4t/l4t.h"
30
#include <ianos/ianos.h>
31
#include <libs/compr/blz.h>
32
#include <libs/fatfs/ff.h>
33
#include "storage/emummc.h"
34
35
#include "frontend/fe_tools.h"
36
#include "frontend/fe_info.h"
37
38
hekate_config h_cfg;
39
boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;
40
const volatile ipl_ver_meta_t __attribute__((section ("._ipl_version"))) ipl_ver = {
41
.magic = BL_MAGIC,
42
.version = (BL_VER_MJ + '0') | ((BL_VER_MN + '0') << 8) | ((BL_VER_HF + '0') << 16) | ((BL_VER_RL) << 24),
43
.rcfg.rsvd_flags = 0,
44
.rcfg.bclk_t210 = BPMP_CLK_LOWER_BOOST,
45
.rcfg.bclk_t210b01 = BPMP_CLK_DEFAULT_BOOST
46
};
47
48
volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR;
49
50
static void _check_power_off_from_hos()
51
{
52
// Power off on alarm wakeup from HOS shutdown. For modchips/dongles.
53
u8 hos_wakeup = i2c_recv_byte(I2C_5, MAX77620_I2C_ADDR, MAX77620_REG_IRQTOP);
54
55
// Clear RTC interrupts.
56
(void)i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_RTCINT_REG);
57
58
// Stop the alarm, in case we injected and powered off too fast.
59
max77620_rtc_stop_alarm();
60
61
// Handle RTC wake up.
62
if (hos_wakeup & MAX77620_IRQ_TOP_RTC_MASK)
63
{
64
if (h_cfg.autohosoff == 1)
65
{
66
render_static_bootlogo();
67
68
if (display_get_decoded_panel_id() != PANEL_SAM_AMS699VC01)
69
{
70
// Slow fading for LCD panels.
71
display_backlight_brightness(10, 5000);
72
display_backlight_brightness(100, 25000);
73
msleep(600);
74
display_backlight_brightness(0, 20000);
75
}
76
else
77
{
78
// Blink 3 times for OLED panel.
79
for (u32 i = 0; i < 3; i++)
80
{
81
msleep(150);
82
display_backlight_brightness(100, 0);
83
msleep(150);
84
display_backlight_brightness(0, 0);
85
}
86
}
87
}
88
power_set_state(POWER_OFF_RESET);
89
}
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 VERSION_RCFG_OFF 0x120
96
#define PATCHED_RELOC_STACK 0x40007000
97
#define PATCHED_RELOC_ENTRY 0x40010000
98
#define EXT_PAYLOAD_ADDR 0xC0000000
99
#define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))
100
101
static void _reloc_append(u32 payload_dst, u32 payload_src, u32 payload_size)
102
{
103
memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ);
104
105
volatile reloc_meta_t *relocator = (reloc_meta_t *)(payload_src + RELOC_META_OFF);
106
107
relocator->start = payload_dst - ALIGN(PATCHED_RELOC_SZ, 0x10);
108
relocator->stack = PATCHED_RELOC_STACK;
109
relocator->end = payload_dst + payload_size;
110
relocator->ep = payload_dst;
111
}
112
113
bool is_ipl_updated(void *buf, u32 size, const char *path, bool force)
114
{
115
ipl_ver_meta_t *update_ft = (ipl_ver_meta_t *)(buf + PATCHED_RELOC_SZ + sizeof(boot_cfg_t));
116
117
bool magic_valid = update_ft->magic == ipl_ver.magic;
118
bool force_update = force && !magic_valid;
119
bool is_valid_old = magic_valid && (byte_swap_32(update_ft->version) < byte_swap_32(ipl_ver.version));
120
121
// Check if newer version.
122
if (!force && magic_valid)
123
{
124
// Copy reserved config.
125
if (size && !is_valid_old && memcmp((u8 *)(IPL_LOAD_ADDR + VERSION_RCFG_OFF), (u8 *)(buf + VERSION_RCFG_OFF), sizeof(rsvd_cfg_t)))
126
{
127
memcpy((u8 *)(buf + VERSION_RCFG_OFF), (u8 *)(IPL_LOAD_ADDR + VERSION_RCFG_OFF), sizeof(rsvd_cfg_t));
128
sd_save_to_file(buf, size, path);
129
}
130
131
if (byte_swap_32(update_ft->version) > byte_swap_32(ipl_ver.version))
132
return false;
133
}
134
135
// Update if old or broken.
136
if (force_update || is_valid_old)
137
{
138
boot_cfg_t tmp_cfg;
139
reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF);
140
141
// Reset boot storage configuration.
142
memcpy(&tmp_cfg, (u8 *)(reloc->start + PATCHED_RELOC_SZ), sizeof(boot_cfg_t));
143
memset((u8 *)(reloc->start + PATCHED_RELOC_SZ), 0, sizeof(boot_cfg_t));
144
145
sd_save_to_file((u8 *)reloc->start, reloc->end - reloc->start, path);
146
147
// Restore boot storage configuration.
148
memcpy((u8 *)(reloc->start + PATCHED_RELOC_SZ), &tmp_cfg, sizeof(boot_cfg_t));
149
}
150
151
return true;
152
}
153
154
static void _launch_payload(char *path, bool update, bool clear_screen)
155
{
156
if (clear_screen)
157
gfx_clear_grey(0x1B);
158
gfx_con_setpos(0, 0);
159
160
// Read payload.
161
u32 size = 0;
162
void *buf = sd_file_read(path, &size);
163
if (!buf)
164
{
165
gfx_con.mute = false;
166
EPRINTFARGS("Payload file is missing!\n(%s)", path);
167
168
goto out;
169
}
170
171
if (update && is_ipl_updated(buf, size, path, false))
172
goto out;
173
174
// Check if it safely fits IRAM.
175
if (size > 0x30000)
176
{
177
gfx_con.mute = false;
178
EPRINTF("Payload is too big!");
179
180
goto out;
181
}
182
183
sd_end();
184
185
// Copy the payload to our chosen address.
186
memcpy((void *)RCM_PAYLOAD_ADDR, buf, size);
187
188
// Append relocator or set config.
189
void (*payload_ptr)();
190
if (!update)
191
{
192
_reloc_append(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10));
193
194
payload_ptr = (void *)EXT_PAYLOAD_ADDR;
195
}
196
else
197
{
198
memcpy((u8 *)(RCM_PAYLOAD_ADDR + PATCHED_RELOC_SZ), &b_cfg, sizeof(boot_cfg_t)); // Transfer boot cfg.
199
200
// Set updated flag to skip check on launch.
201
EMC(EMC_SCRATCH0) |= EMC_HEKA_UPD;
202
203
payload_ptr = (void *)RCM_PAYLOAD_ADDR;
204
}
205
206
hw_deinit(false);
207
208
// Launch our payload.
209
(*payload_ptr)();
210
211
out:
212
free(buf);
213
if (!update)
214
{
215
gfx_con.mute = false;
216
EPRINTF("Failed to launch payload!");
217
}
218
}
219
220
static void _launch_payloads()
221
{
222
u8 max_entries = 61;
223
ment_t *ments = NULL;
224
char *file_sec = NULL;
225
char *dir = NULL;
226
dirlist_t *filelist = NULL;
227
228
gfx_clear_grey(0x1B);
229
gfx_con_setpos(0, 0);
230
231
if (sd_mount())
232
goto failed_sd_mount;
233
234
ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3));
235
236
dir = (char *)malloc(256);
237
memcpy(dir, "bootloader/payloads", 20);
238
239
filelist = dirlist(dir, NULL, 0);
240
241
u32 i = 0;
242
243
if (filelist)
244
{
245
// Build configuration menu.
246
ments[0].type = MENT_BACK;
247
ments[0].caption = "Back";
248
249
ments[1].type = MENT_CHGLINE;
250
251
while (true)
252
{
253
if (i > max_entries || !filelist->name[i])
254
break;
255
ments[i + 2].type = INI_CHOICE;
256
ments[i + 2].caption = filelist->name[i];
257
ments[i + 2].data = filelist->name[i];
258
259
i++;
260
}
261
}
262
263
if (i > 0)
264
{
265
memset(&ments[i + 2], 0, sizeof(ment_t));
266
menu_t menu = { ments, "Choose a payload", 0, 0 };
267
268
file_sec = (char *)tui_do_menu(&menu);
269
270
if (!file_sec)
271
{
272
free(ments);
273
free(dir);
274
free(filelist);
275
sd_end();
276
277
return;
278
}
279
}
280
else
281
EPRINTF("No payloads found.");
282
283
if (file_sec)
284
{
285
memcpy(dir + strlen(dir), "/", 2);
286
memcpy(dir + strlen(dir), file_sec, strlen(file_sec) + 1);
287
288
_launch_payload(dir, false, true);
289
}
290
291
failed_sd_mount:
292
free(dir);
293
free(ments);
294
free(filelist);
295
sd_end();
296
297
btn_wait();
298
}
299
300
static void _launch_ini_list()
301
{
302
u8 max_entries = 61;
303
char *special_path = NULL;
304
char *emummc_path = NULL;
305
ment_t *ments = NULL;
306
ini_sec_t *cfg_sec = NULL;
307
308
LIST_INIT(ini_list_sections);
309
310
gfx_clear_grey(0x1B);
311
gfx_con_setpos(0, 0);
312
313
if (sd_mount())
314
goto parse_failed;
315
316
// Check that ini files exist and parse them.
317
if (ini_parse(&ini_list_sections, "bootloader/ini", true))
318
{
319
EPRINTF("No .ini files in bootloader/ini!");
320
goto parse_failed;
321
}
322
323
// Build configuration menu.
324
ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3));
325
ments[0].type = MENT_BACK;
326
ments[0].caption = "Back";
327
328
ments[1].type = MENT_CHGLINE;
329
330
u32 sec_idx = 2;
331
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_list_sections, link)
332
{
333
if (ini_sec->type == INI_COMMENT ||
334
ini_sec->type == INI_NEWLINE ||
335
!strcmp(ini_sec->name, "config"))
336
continue;
337
338
ments[sec_idx].type = ini_sec->type;
339
ments[sec_idx].caption = ini_sec->name;
340
ments[sec_idx].data = ini_sec;
341
342
if (ini_sec->type == MENT_CAPTION)
343
ments[sec_idx].color = ini_sec->color;
344
sec_idx++;
345
346
if ((sec_idx - 1) > max_entries)
347
break;
348
}
349
350
if (sec_idx > 2)
351
{
352
memset(&ments[sec_idx], 0, sizeof(ment_t));
353
menu_t menu = {
354
ments, "Launch ini entries", 0, 0
355
};
356
357
cfg_sec = (ini_sec_t *)tui_do_menu(&menu);
358
359
special_path = ini_check_special_section(cfg_sec);
360
361
if (cfg_sec && !special_path)
362
{
363
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link)
364
{
365
if (!strcmp("emummc_force_disable", kv->key))
366
h_cfg.emummc_force_disable = atoi(kv->val);
367
else if (!strcmp("emupath", kv->key))
368
emummc_path = kv->val;
369
}
370
371
if (emummc_path && !emummc_set_path(emummc_path))
372
{
373
EPRINTF("emupath is wrong!");
374
goto wrong_emupath;
375
}
376
}
377
378
if (!cfg_sec)
379
{
380
free(ments);
381
382
return;
383
}
384
}
385
else
386
EPRINTF("No extra configs found.");
387
388
parse_failed:
389
if (!cfg_sec)
390
goto out;
391
392
if (special_path)
393
{
394
// Try to launch Payload or L4T.
395
if (special_path != (char *)-1)
396
_launch_payload(special_path, false, true);
397
else
398
{
399
u32 entry_idx = 0;
400
for (u32 i = 0; i < sec_idx; i++)
401
{
402
if (ments[i].data == cfg_sec)
403
{
404
entry_idx = i;
405
break;
406
}
407
}
408
launch_l4t(cfg_sec, entry_idx, 1, h_cfg.t210b01);
409
}
410
}
411
else
412
{
413
hos_launch(cfg_sec);
414
415
wrong_emupath:
416
if (emummc_path)
417
{
418
sd_mount();
419
emummc_load_cfg(); // Reload emuMMC config in case of emupath.
420
}
421
}
422
423
out:
424
free(ments);
425
426
btn_wait();
427
}
428
429
static void _launch_config()
430
{
431
u8 max_entries = 61;
432
char *special_path = NULL;
433
char *emummc_path = NULL;
434
435
ment_t *ments = NULL;
436
ini_sec_t *cfg_sec = NULL;
437
438
LIST_INIT(ini_sections);
439
440
gfx_clear_grey(0x1B);
441
gfx_con_setpos(0, 0);
442
443
if (sd_mount())
444
goto parse_failed;
445
446
// Load emuMMC configuration.
447
emummc_load_cfg();
448
449
// Parse main configuration.
450
ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false);
451
452
// Build configuration menu.
453
ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 6));
454
ments[0].type = MENT_BACK;
455
ments[0].caption = "Back";
456
457
ments[1].type = MENT_CHGLINE;
458
459
ments[2].type = MENT_HANDLER;
460
ments[2].caption = "Payloads...";
461
ments[2].handler = _launch_payloads;
462
463
ments[3].type = MENT_HANDLER;
464
ments[3].caption = "More configs...";
465
ments[3].handler = _launch_ini_list;
466
467
ments[4].type = MENT_CHGLINE;
468
469
u32 sec_idx = 5;
470
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
471
{
472
if (ini_sec->type == INI_COMMENT ||
473
ini_sec->type == INI_NEWLINE ||
474
!strcmp(ini_sec->name, "config"))
475
continue;
476
477
ments[sec_idx].type = ini_sec->type;
478
ments[sec_idx].caption = ini_sec->name;
479
ments[sec_idx].data = ini_sec;
480
481
if (ini_sec->type == MENT_CAPTION)
482
ments[sec_idx].color = ini_sec->color;
483
sec_idx++;
484
485
if ((sec_idx - 4) > max_entries)
486
break;
487
}
488
489
if (sec_idx < 6)
490
{
491
ments[sec_idx].type = MENT_CAPTION;
492
ments[sec_idx].caption = "No main configs found...";
493
ments[sec_idx].color = TXT_CLR_WARNING;
494
sec_idx++;
495
}
496
497
memset(&ments[sec_idx], 0, sizeof(ment_t));
498
menu_t menu = {
499
ments, "Launch configurations", 0, 0
500
};
501
502
cfg_sec = (ini_sec_t *)tui_do_menu(&menu);
503
504
special_path = ini_check_special_section(cfg_sec);
505
506
if (cfg_sec && !special_path)
507
{
508
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link)
509
{
510
if (!strcmp("emummc_force_disable", kv->key))
511
h_cfg.emummc_force_disable = atoi(kv->val);
512
if (!strcmp("emupath", kv->key))
513
emummc_path = kv->val;
514
}
515
516
if (emummc_path && !emummc_set_path(emummc_path))
517
{
518
EPRINTF("emupath is wrong!");
519
goto wrong_emupath;
520
}
521
}
522
523
if (!cfg_sec)
524
{
525
free(ments);
526
sd_end();
527
return;
528
}
529
530
parse_failed:
531
if (!cfg_sec)
532
{
533
gfx_printf("\nPress any key...\n");
534
goto out;
535
}
536
537
if (special_path)
538
{
539
// Try to launch Payload or L4T.
540
if (special_path != (char *)-1)
541
_launch_payload(special_path, false, true);
542
else
543
{
544
u32 entry_idx = 0;
545
for (u32 i = 0; i < sec_idx; i++)
546
{
547
if (ments[i].data == cfg_sec)
548
{
549
entry_idx = i;
550
break;
551
}
552
}
553
launch_l4t(cfg_sec, entry_idx, 0, h_cfg.t210b01);
554
}
555
}
556
else
557
{
558
hos_launch(cfg_sec);
559
560
wrong_emupath:
561
if (emummc_path)
562
{
563
sd_mount();
564
emummc_load_cfg(); // Reload emuMMC config in case of emupath.
565
}
566
}
567
568
out:
569
sd_end();
570
571
free(ments);
572
573
h_cfg.emummc_force_disable = false;
574
575
btn_wait();
576
}
577
578
#define NYX_VER_OFF 0x9C
579
580
static void _nyx_load_run()
581
{
582
u8 *nyx = sd_file_read("bootloader/sys/nyx.bin", NULL);
583
if (!nyx)
584
return;
585
586
sd_end();
587
588
render_static_bootlogo();
589
display_backlight_brightness(h_cfg.backlight, 1000);
590
591
// Check if Nyx version is old.
592
u32 expected_nyx_ver = ((NYX_VER_MJ + '0') << 24) | ((NYX_VER_MN + '0') << 16) | ((NYX_VER_HF + '0') << 8);
593
u32 nyx_ver = byte_swap_32(*(u32 *)(nyx + NYX_VER_OFF)) & 0xFFFFFF00;
594
if (nyx_ver < expected_nyx_ver)
595
{
596
h_cfg.errors |= ERR_SYSOLD_NYX;
597
598
gfx_con_setpos(0, 0);
599
WPRINTF("Old Nyx GUI found! There will be dragons!\n");
600
WPRINTF("\nUpdate bootloader folder!\n\n");
601
WPRINTF("Press any key...");
602
603
msleep(1000);
604
btn_wait();
605
}
606
607
// Set hekate errors.
608
nyx_str->info.errors = h_cfg.errors;
609
610
// Set Nyx mode.
611
nyx_str->cfg = 0;
612
if (b_cfg.extra_cfg & EXTRA_CFG_NYX_UMS)
613
{
614
b_cfg.extra_cfg &= ~(EXTRA_CFG_NYX_UMS);
615
616
nyx_str->cfg |= NYX_CFG_UMS;
617
nyx_str->cfg |= b_cfg.ums << 24;
618
}
619
620
// Set hekate version used to boot Nyx.
621
nyx_str->version = ipl_ver.version - 0x303030; // Convert ASCII to numbers.
622
623
// Set [new] info validation magic.
624
nyx_str->info.magic = NYX_NEW_INFO;
625
nyx_str->info_ex.magic = NYX_NEW_INFO;
626
627
// Set [new] reserved flags.
628
nyx_str->info_ex.rsvd_flags = ipl_ver.rcfg.rsvd_flags;
629
630
// Set [new] SD card initialization and error info.
631
nyx_str->info.sd_init = sd_get_mode();
632
u16 *sd_errors = sd_get_error_count();
633
for (u32 i = 0; i < 3; i++)
634
nyx_str->info.sd_errors[i] = sd_errors[i];
635
636
// Set Display ID info.
637
nyx_str->info.panel_id = display_get_verbose_panel_id();
638
639
reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF);
640
memcpy((u8 *)nyx_str->hekate, (u8 *)reloc->start, reloc->end - reloc->start);
641
642
// Do one last training.
643
minerva_periodic_training();
644
645
bpmp_mmu_disable();
646
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
647
648
// Some cards (Sandisk U1), do not like a fast power cycle.
649
sdmmc_storage_init_wait_sd();
650
651
void (*nyx_ptr)() = (void *)nyx;
652
(*nyx_ptr)();
653
}
654
655
void launch_nyx()
656
{
657
sd_mount();
658
_nyx_load_run();
659
}
660
661
static ini_sec_t *_get_ini_sec_from_id(ini_sec_t *ini_sec, char **bootlogoCustomEntry, char **emummc_path)
662
{
663
ini_sec_t *cfg_sec = NULL;
664
665
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
666
{
667
if (!strcmp("id", kv->key))
668
{
669
if (b_cfg.id[0] && kv->val[0] && !strcmp(b_cfg.id, kv->val))
670
cfg_sec = ini_sec;
671
else
672
break;
673
}
674
if (!strcmp("emupath", kv->key))
675
*emummc_path = kv->val;
676
else if (!strcmp("logopath", kv->key))
677
*bootlogoCustomEntry = kv->val;
678
else if (!strcmp("emummc_force_disable", kv->key))
679
h_cfg.emummc_force_disable = atoi(kv->val);
680
}
681
if (!cfg_sec)
682
{
683
*emummc_path = NULL;
684
*bootlogoCustomEntry = NULL;
685
h_cfg.emummc_force_disable = false;
686
}
687
688
return cfg_sec;
689
}
690
691
static void _bootloader_corruption_protect()
692
{
693
FILINFO fno;
694
if (!f_stat("bootloader", &fno))
695
{
696
if (!h_cfg.bootprotect && (fno.fattrib & AM_ARC))
697
f_chmod("bootloader", 0, AM_ARC);
698
else if (h_cfg.bootprotect && !(fno.fattrib & AM_ARC))
699
f_chmod("bootloader", AM_ARC, AM_ARC);
700
}
701
}
702
703
static void _check_for_updated_bootloader()
704
{
705
// Check if already chainloaded update and clear flag. Otherwise check for updates.
706
if (EMC(EMC_SCRATCH0) & EMC_HEKA_UPD)
707
EMC(EMC_SCRATCH0) &= ~EMC_HEKA_UPD;
708
else
709
{
710
// Check if update.bin exists and is newer and launch it. Otherwise create it.
711
if (!f_stat("bootloader/update.bin", NULL))
712
_launch_payload("bootloader/update.bin", true, false);
713
else
714
{
715
u8 *buf = zalloc(0x200);
716
is_ipl_updated(buf, 0, "bootloader/update.bin", true);
717
free(buf);
718
}
719
}
720
}
721
722
static void _auto_launch()
723
{
724
struct _bmp_data
725
{
726
u32 size;
727
u32 size_x;
728
u32 size_y;
729
u32 offset;
730
u32 pos_x;
731
u32 pos_y;
732
};
733
734
u32 boot_wait = h_cfg.bootwait;
735
u32 boot_entry_id = 0;
736
ini_sec_t *cfg_sec = NULL;
737
char *emummc_path = NULL;
738
char *bootlogoCustomEntry = NULL;
739
bool config_entry_found = false;
740
741
bool boot_from_id = (b_cfg.boot_cfg & BOOT_CFG_FROM_ID) && (b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN);
742
if (boot_from_id)
743
b_cfg.id[7] = 0;
744
745
if (!(b_cfg.boot_cfg & BOOT_CFG_FROM_LAUNCH))
746
gfx_con.mute = true;
747
748
LIST_INIT(ini_sections);
749
LIST_INIT(ini_list_sections);
750
751
// Load emuMMC configuration.
752
emummc_load_cfg();
753
754
// Parse hekate main configuration.
755
if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
756
goto out; // Can't load hekate_ipl.ini.
757
758
// Load configuration.
759
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
760
{
761
// Skip other ini entries for autoboot.
762
if (ini_sec->type == INI_CHOICE)
763
{
764
if (!config_entry_found && !strcmp(ini_sec->name, "config"))
765
{
766
config_entry_found = true;
767
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
768
{
769
if (!strcmp("autoboot", kv->key))
770
h_cfg.autoboot = atoi(kv->val);
771
else if (!strcmp("autoboot_list", kv->key))
772
h_cfg.autoboot_list = atoi(kv->val);
773
else if (!strcmp("bootwait", kv->key))
774
boot_wait = atoi(kv->val);
775
else if (!strcmp("backlight", kv->key))
776
h_cfg.backlight = atoi(kv->val);
777
else if (!strcmp("noticker", kv->key))
778
h_cfg.noticker = atoi(kv->val);
779
else if (!strcmp("autohosoff", kv->key))
780
h_cfg.autohosoff = atoi(kv->val);
781
else if (!strcmp("autonogc", kv->key))
782
h_cfg.autonogc = atoi(kv->val);
783
else if (!strcmp("updater2p", kv->key))
784
h_cfg.updater2p = atoi(kv->val);
785
else if (!strcmp("bootprotect", kv->key))
786
h_cfg.bootprotect = atoi(kv->val);
787
}
788
boot_entry_id++;
789
790
// Override autoboot.
791
if (b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN)
792
{
793
h_cfg.autoboot = b_cfg.autoboot;
794
h_cfg.autoboot_list = b_cfg.autoboot_list;
795
}
796
797
// Apply bootloader protection against corruption.
798
_bootloader_corruption_protect();
799
800
// If ini list, exit here.
801
if (!boot_from_id && h_cfg.autoboot_list)
802
break;
803
804
continue;
805
}
806
807
if (boot_from_id)
808
cfg_sec = _get_ini_sec_from_id(ini_sec, &bootlogoCustomEntry, &emummc_path);
809
else if (h_cfg.autoboot == boot_entry_id && config_entry_found)
810
{
811
cfg_sec = ini_sec;
812
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link)
813
{
814
if (!strcmp("logopath", kv->key))
815
bootlogoCustomEntry = kv->val;
816
else if (!strcmp("emupath", kv->key))
817
emummc_path = kv->val;
818
else if (!strcmp("emummc_force_disable", kv->key))
819
h_cfg.emummc_force_disable = atoi(kv->val);
820
else if (!strcmp("bootwait", kv->key))
821
boot_wait = atoi(kv->val);
822
}
823
}
824
if (cfg_sec)
825
break;
826
boot_entry_id++;
827
}
828
}
829
830
if (h_cfg.autohosoff && !(b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN))
831
_check_power_off_from_hos();
832
833
if (h_cfg.autoboot_list || (boot_from_id && !cfg_sec))
834
{
835
if (boot_from_id && cfg_sec)
836
goto skip_list;
837
838
cfg_sec = NULL;
839
boot_entry_id = 1;
840
bootlogoCustomEntry = NULL;
841
842
if (ini_parse(&ini_list_sections, "bootloader/ini", true))
843
goto skip_list;
844
845
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec_list, &ini_list_sections, link)
846
{
847
if (ini_sec_list->type != INI_CHOICE)
848
continue;
849
850
if (!strcmp(ini_sec_list->name, "config"))
851
continue;
852
853
if (boot_from_id)
854
cfg_sec = _get_ini_sec_from_id(ini_sec_list, &bootlogoCustomEntry, &emummc_path);
855
else if (h_cfg.autoboot == boot_entry_id)
856
{
857
h_cfg.emummc_force_disable = false;
858
cfg_sec = ini_sec_list;
859
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link)
860
{
861
if (!strcmp("logopath", kv->key))
862
bootlogoCustomEntry = kv->val;
863
else if (!strcmp("emupath", kv->key))
864
emummc_path = kv->val;
865
else if (!strcmp("emummc_force_disable", kv->key))
866
h_cfg.emummc_force_disable = atoi(kv->val);
867
else if (!strcmp("bootwait", kv->key))
868
boot_wait = atoi(kv->val);
869
}
870
}
871
if (cfg_sec)
872
break;
873
boot_entry_id++;
874
}
875
}
876
877
skip_list:
878
if (!cfg_sec)
879
goto out; // No configurations or auto boot is disabled.
880
881
// Check if entry is payload or l4t special case.
882
char *special_path = ini_check_special_section(cfg_sec);
883
884
if ((!(b_cfg.boot_cfg & BOOT_CFG_FROM_LAUNCH) && boot_wait) || // Conditional for HOS/Payload.
885
(special_path && special_path == (char *)-1)) // Always show for L4T.
886
{
887
u32 fsize;
888
u8 *logo_buf = NULL;
889
u8 *bitmap = NULL;
890
struct _bmp_data bmpData;
891
bool bootlogoFound = false;
892
893
// Check if user set custom logo path at the boot entry.
894
if (bootlogoCustomEntry)
895
bitmap = (u8 *)sd_file_read(bootlogoCustomEntry, &fsize);
896
897
// Custom entry bootlogo not found, trying default custom one.
898
if (!bitmap)
899
bitmap = (u8 *)sd_file_read("bootloader/bootlogo.bmp", &fsize);
900
901
if (bitmap)
902
{
903
// Get values manually to avoid unaligned access.
904
bmpData.size = bitmap[2] | bitmap[3] << 8 |
905
bitmap[4] << 16 | bitmap[5] << 24;
906
bmpData.offset = bitmap[10] | bitmap[11] << 8 |
907
bitmap[12] << 16 | bitmap[13] << 24;
908
bmpData.size_x = bitmap[18] | bitmap[19] << 8 |
909
bitmap[20] << 16 | bitmap[21] << 24;
910
bmpData.size_y = bitmap[22] | bitmap[23] << 8 |
911
bitmap[24] << 16 | bitmap[25] << 24;
912
// Sanity check.
913
if (bitmap[0] == 'B' &&
914
bitmap[1] == 'M' &&
915
bitmap[28] == 32 && // Only 32 bit BMPs allowed.
916
bmpData.size_x <= 720 &&
917
bmpData.size_y <= 1280)
918
{
919
if (bmpData.size <= fsize && ((bmpData.size - bmpData.offset) < SZ_4M))
920
{
921
// Avoid unaligned access from BM 2-byte MAGIC and remove header.
922
logo_buf = (u8 *)malloc(SZ_4M);
923
memcpy(logo_buf, bitmap + bmpData.offset, bmpData.size - bmpData.offset);
924
free(bitmap);
925
// Center logo if res < 720x1280.
926
bmpData.pos_x = (720 - bmpData.size_x) >> 1;
927
bmpData.pos_y = (1280 - bmpData.size_y) >> 1;
928
// Get background color from 1st pixel.
929
if (bmpData.size_x < 720 || bmpData.size_y < 1280)
930
gfx_clear_color(*(u32 *)logo_buf);
931
932
bootlogoFound = true;
933
}
934
}
935
else
936
free(bitmap);
937
}
938
939
// Clamp value to default if it exceeds 20s to protect against corruption.
940
if (boot_wait > 20)
941
boot_wait = 3;
942
943
// Render boot logo.
944
if (bootlogoFound)
945
{
946
gfx_render_bmp_argb((u32 *)logo_buf, bmpData.size_x, bmpData.size_y,
947
bmpData.pos_x, bmpData.pos_y);
948
free(logo_buf);
949
950
// Do animated waiting before booting. If VOL- is pressed go into bootloader menu.
951
if (render_ticker(boot_wait, h_cfg.backlight, h_cfg.noticker))
952
goto out;
953
}
954
else
955
{
956
// Do animated waiting before booting. If VOL- is pressed go into bootloader menu.
957
if (render_ticker_logo(boot_wait, h_cfg.backlight))
958
goto out;
959
}
960
}
961
962
if (b_cfg.boot_cfg & BOOT_CFG_FROM_LAUNCH)
963
display_backlight_brightness(h_cfg.backlight, 0);
964
else if (btn_read_vol() == BTN_VOL_DOWN) // 0s bootwait VOL- check.
965
goto out;
966
967
if (special_path)
968
{
969
// Try to launch Payload or L4T.
970
if (special_path != (char *)-1)
971
_launch_payload(special_path, false, false);
972
else
973
launch_l4t(cfg_sec, h_cfg.autoboot, h_cfg.autoboot_list, h_cfg.t210b01);
974
goto error;
975
}
976
else
977
{
978
if (b_cfg.boot_cfg & BOOT_CFG_TO_EMUMMC)
979
emummc_set_path(b_cfg.emummc_path);
980
else if (emummc_path && !emummc_set_path(emummc_path))
981
{
982
gfx_con.mute = false;
983
EPRINTF("emupath is wrong!");
984
goto wrong_emupath;
985
}
986
987
hos_launch(cfg_sec);
988
989
wrong_emupath:
990
if (emummc_path || b_cfg.boot_cfg & BOOT_CFG_TO_EMUMMC)
991
{
992
sd_mount();
993
emummc_load_cfg(); // Reload emuMMC config in case of emupath.
994
}
995
996
error:
997
gfx_con.mute = false;
998
gfx_printf("\nPress any key...\n");
999
display_backlight_brightness(h_cfg.backlight, 1000);
1000
msleep(500);
1001
btn_wait();
1002
}
1003
1004
out:
1005
gfx_con.mute = false;
1006
1007
// Clear boot reasons from binary.
1008
if (b_cfg.boot_cfg & (BOOT_CFG_FROM_ID | BOOT_CFG_TO_EMUMMC))
1009
memset(b_cfg.xt_str, 0, sizeof(b_cfg.xt_str));
1010
h_cfg.emummc_force_disable = false;
1011
1012
// L4T: Clear custom boot mode flags from PMC_SCRATCH0.
1013
PMC(APBDEV_PMC_SCRATCH0) &= ~PMC_SCRATCH0_MODE_CUSTOM_ALL;
1014
1015
_nyx_load_run();
1016
}
1017
1018
#define EXCP_EN_ADDR 0x4003FF1C
1019
#define EXCP_MAGIC 0x30505645 // "EVP0".
1020
#define EXCP_TYPE_ADDR 0x4003FF18
1021
#define EXCP_TYPE_RESET 0x545352 // "RST".
1022
#define EXCP_TYPE_UNDEF 0x464455 // "UDF".
1023
#define EXCP_TYPE_PABRT 0x54424150 // "PABT".
1024
#define EXCP_TYPE_DABRT 0x54424144 // "DABT".
1025
#define EXCP_TYPE_WDT 0x544457 // "WDT".
1026
#define EXCP_LR_ADDR 0x4003FF14
1027
1028
#define PSTORE_LOG_OFFSET 0x180000
1029
#define PSTORE_RAM_SIG 0x43474244 // "DBGC".
1030
1031
typedef struct _pstore_buf {
1032
u32 sig;
1033
u32 start;
1034
u32 size;
1035
} pstore_buf_t;
1036
1037
static void _show_errors()
1038
{
1039
u32 *excp_lr = (u32 *)EXCP_LR_ADDR;
1040
u32 *excp_type = (u32 *)EXCP_TYPE_ADDR;
1041
u32 *excp_enabled = (u32 *)EXCP_EN_ADDR;
1042
1043
u32 panic_status = hw_rst_status & 0xFFFFF;
1044
1045
// Check for exception error.
1046
if (*excp_enabled == EXCP_MAGIC)
1047
h_cfg.errors |= ERR_EXCEPTION;
1048
1049
// Check for L4T kernel panic.
1050
if (PMC(APBDEV_PMC_SCRATCH37) == PMC_SCRATCH37_KERNEL_PANIC_MAGIC)
1051
{
1052
// Set error and clear flag.
1053
h_cfg.errors |= ERR_L4T_KERNEL;
1054
PMC(APBDEV_PMC_SCRATCH37) = 0;
1055
}
1056
1057
// Check for watchdog panic.
1058
if (hw_rst_reason == PMC_RST_STATUS_WATCHDOG && panic_status &&
1059
panic_status <= 0xFF && panic_status != 0x20 && panic_status != 0x21)
1060
{
1061
h_cfg.errors |= ERR_PANIC_CODE;
1062
}
1063
1064
// Check if we had a panic while in CFW.
1065
secmon_exo_check_panic();
1066
1067
// Handle errors.
1068
if (h_cfg.errors)
1069
{
1070
gfx_clear_grey(0x1B);
1071
gfx_con_setpos(0, 0);
1072
display_backlight_brightness(150, 1000);
1073
1074
if (h_cfg.errors & ERR_SD_BOOT_EN)
1075
{
1076
WPRINTF("Failed to init or mount SD!\n");
1077
1078
// Clear the module bits as to not cram the error screen.
1079
h_cfg.errors &= ~(ERR_LIBSYS_LP0 | ERR_LIBSYS_MTC);
1080
}
1081
1082
if (h_cfg.errors & ERR_LIBSYS_LP0)
1083
WPRINTF("Missing LP0 (sleep) lib!\n");
1084
if (h_cfg.errors & ERR_LIBSYS_MTC)
1085
WPRINTF("Missing Minerva lib!\n");
1086
1087
if (h_cfg.errors & (ERR_LIBSYS_LP0 | ERR_LIBSYS_MTC))
1088
WPRINTF("\nUpdate bootloader folder!\n\n");
1089
1090
if (h_cfg.errors & ERR_EXCEPTION)
1091
{
1092
WPRINTFARGS("hekate exception occurred (LR %08X):\n", *excp_lr);
1093
switch (*excp_type)
1094
{
1095
case EXCP_TYPE_WDT:
1096
WPRINTF("Hang detected in LP0/Minerva!");
1097
break;
1098
case EXCP_TYPE_RESET:
1099
WPRINTF("RESET");
1100
break;
1101
case EXCP_TYPE_UNDEF:
1102
WPRINTF("UNDEF");
1103
break;
1104
case EXCP_TYPE_PABRT:
1105
WPRINTF("PABRT");
1106
break;
1107
case EXCP_TYPE_DABRT:
1108
WPRINTF("DABRT");
1109
break;
1110
}
1111
gfx_puts("\n");
1112
1113
// Clear the exception.
1114
*excp_enabled = 0;
1115
*excp_type = 0;
1116
}
1117
1118
if (h_cfg.errors & ERR_L4T_KERNEL)
1119
{
1120
WPRINTF("L4T Kernel panic occurred!\n");
1121
if (!(h_cfg.errors & ERR_SD_BOOT_EN))
1122
{
1123
if (!sd_save_to_file((void *)PSTORE_ADDR, PSTORE_SZ, "L4T_panic.bin"))
1124
WPRINTF("PSTORE saved to L4T_panic.bin");
1125
pstore_buf_t *buf = (pstore_buf_t *)(PSTORE_ADDR + PSTORE_LOG_OFFSET);
1126
if (buf->sig == PSTORE_RAM_SIG && buf->size && buf->size < 0x80000)
1127
{
1128
u32 log_offset = PSTORE_ADDR + PSTORE_LOG_OFFSET + sizeof(pstore_buf_t);
1129
if (!sd_save_to_file((void *)log_offset, buf->size, "L4T_panic.txt"))
1130
WPRINTF("Log saved to L4T_panic.txt");
1131
}
1132
}
1133
gfx_puts("\n");
1134
}
1135
1136
if (h_cfg.errors & ERR_PANIC_CODE)
1137
{
1138
u32 r = (hw_rst_status >> 20) & 0xF;
1139
u32 g = (hw_rst_status >> 24) & 0xF;
1140
u32 b = (hw_rst_status >> 28) & 0xF;
1141
r = (r << 16) | (r << 20);
1142
g = (g << 8) | (g << 12);
1143
b = (b << 0) | (b << 4);
1144
u32 color = r | g | b;
1145
1146
WPRINTF("HOS panic occurred!\n");
1147
gfx_printf("Color: %k####%k, Code: %02X\n\n", color, TXT_CLR_DEFAULT, panic_status);
1148
}
1149
1150
WPRINTF("Press any key...");
1151
1152
msleep(1000); // Guard against injection VOL+.
1153
btn_wait();
1154
msleep(500); // Guard against force menu VOL-.
1155
}
1156
}
1157
1158
static void _check_low_battery()
1159
{
1160
if (h_cfg.devmode)
1161
goto out;
1162
1163
int enough_battery;
1164
int batt_volt = 0;
1165
int charge_status = 0;
1166
1167
// Enable charger in case it's disabled.
1168
bq24193_enable_charger();
1169
1170
bq24193_get_property(BQ24193_ChargeStatus, &charge_status);
1171
max17050_get_property(MAX17050_AvgVCELL, &batt_volt);
1172
1173
enough_battery = charge_status ? 3300 : 3100;
1174
1175
// If battery voltage is enough, exit.
1176
if (batt_volt > enough_battery || !batt_volt)
1177
goto out;
1178
1179
// Prepare battery icon resources.
1180
u8 *battery_res = malloc(ALIGN(BATTERY_EMPTY_SIZE, SZ_4K));
1181
blz_uncompress_srcdest(battery_icons_blz, BATTERY_EMPTY_BLZ_SIZE, battery_res, BATTERY_EMPTY_SIZE);
1182
1183
u8 *battery_icon = malloc(0x95A); // 21x38x3
1184
u8 *charging_icon = malloc(0x2F4); // 21x12x3
1185
u8 *no_charging_icon = zalloc(0x2F4);
1186
1187
memcpy(charging_icon, battery_res, 0x2F4);
1188
memcpy(battery_icon, battery_res + 0x2F4, 0x95A);
1189
1190
u32 battery_icon_y_pos = 1280 - 16 - BATTERY_EMPTY_BATT_HEIGHT;
1191
u32 charging_icon_y_pos = 1280 - 16 - BATTERY_EMPTY_BATT_HEIGHT - 12 - BATTERY_EMPTY_CHRG_HEIGHT;
1192
free(battery_res);
1193
1194
charge_status = !charge_status;
1195
1196
u32 timer = 0;
1197
bool screen_on = false;
1198
while (true)
1199
{
1200
bpmp_msleep(250);
1201
1202
// Refresh battery stats.
1203
int current_charge_status = 0;
1204
bq24193_get_property(BQ24193_ChargeStatus, &current_charge_status);
1205
max17050_get_property(MAX17050_AvgVCELL, &batt_volt);
1206
enough_battery = current_charge_status ? 3300 : 3100;
1207
1208
// If battery voltage is enough, exit.
1209
if (batt_volt > enough_battery)
1210
break;
1211
1212
// Refresh charging icon.
1213
if (screen_on && (charge_status != current_charge_status))
1214
{
1215
if (current_charge_status)
1216
gfx_set_rect_rgb(charging_icon, BATTERY_EMPTY_WIDTH, BATTERY_EMPTY_CHRG_HEIGHT, 16, charging_icon_y_pos);
1217
else
1218
gfx_set_rect_rgb(no_charging_icon, BATTERY_EMPTY_WIDTH, BATTERY_EMPTY_CHRG_HEIGHT, 16, charging_icon_y_pos);
1219
}
1220
1221
// Check if it's time to turn off display.
1222
if (screen_on && timer < get_tmr_ms())
1223
{
1224
// If battery is not charging, power off.
1225
if (!current_charge_status)
1226
{
1227
max77620_low_battery_monitor_config(true);
1228
1229
// Handle full hw deinit and power off.
1230
power_set_state(POWER_OFF_RESET);
1231
}
1232
1233
// If charging, just disable display.
1234
display_end();
1235
screen_on = false;
1236
}
1237
1238
// Check if charging status changed or Power button was pressed and enable display.
1239
if ((charge_status != current_charge_status) || (btn_wait_timeout_single(0, BTN_POWER) & BTN_POWER))
1240
{
1241
if (!screen_on)
1242
{
1243
display_init();
1244
u32 *fb = display_init_window_a_pitch();
1245
gfx_init_ctxt(fb, 720, 1280, 720);
1246
1247
gfx_set_rect_rgb(battery_icon, BATTERY_EMPTY_WIDTH, BATTERY_EMPTY_BATT_HEIGHT, 16, battery_icon_y_pos);
1248
if (current_charge_status)
1249
gfx_set_rect_rgb(charging_icon, BATTERY_EMPTY_WIDTH, BATTERY_EMPTY_CHRG_HEIGHT, 16, charging_icon_y_pos);
1250
else
1251
gfx_set_rect_rgb(no_charging_icon, BATTERY_EMPTY_WIDTH, BATTERY_EMPTY_CHRG_HEIGHT, 16, charging_icon_y_pos);
1252
1253
display_backlight_pwm_init();
1254
display_backlight_brightness(100, 1000);
1255
1256
screen_on = true;
1257
}
1258
1259
timer = get_tmr_ms() + 15000;
1260
}
1261
1262
// Check if forcefully continuing.
1263
if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))
1264
break;
1265
1266
charge_status = current_charge_status;
1267
}
1268
1269
if (screen_on)
1270
display_end();
1271
1272
free(battery_icon);
1273
free(charging_icon);
1274
free(no_charging_icon);
1275
1276
out:
1277
// Re enable Low Battery Monitor shutdown.
1278
max77620_low_battery_monitor_config(true);
1279
}
1280
1281
static void _r2c_get_config_t210b01()
1282
{
1283
rtc_reboot_reason_t rr;
1284
if (!max77620_rtc_get_reboot_reason(&rr))
1285
return;
1286
1287
// Check if reason is actually set.
1288
if (rr.dec.reason != REBOOT_REASON_NOP)
1289
{
1290
// Clear boot storage.
1291
memset(&b_cfg, 0, sizeof(boot_cfg_t));
1292
1293
// Enable boot storage.
1294
b_cfg.boot_cfg |= BOOT_CFG_AUTOBOOT_EN;
1295
}
1296
1297
switch (rr.dec.reason)
1298
{
1299
case REBOOT_REASON_NOP:
1300
break;
1301
case REBOOT_REASON_REC:
1302
PMC(APBDEV_PMC_SCRATCH0) |= PMC_SCRATCH0_MODE_RECOVERY;
1303
case REBOOT_REASON_SELF:
1304
b_cfg.autoboot = rr.dec.autoboot_idx;
1305
b_cfg.autoboot_list = rr.dec.autoboot_list;
1306
break;
1307
case REBOOT_REASON_MENU:
1308
break;
1309
case REBOOT_REASON_UMS:
1310
b_cfg.extra_cfg |= EXTRA_CFG_NYX_UMS;
1311
b_cfg.ums = rr.dec.ums_idx;
1312
break;
1313
case REBOOT_REASON_PANIC:
1314
PMC(APBDEV_PMC_SCRATCH37) = PMC_SCRATCH37_KERNEL_PANIC_MAGIC;
1315
break;
1316
}
1317
}
1318
1319
static void _ipl_reload()
1320
{
1321
hw_deinit(false);
1322
1323
// Reload hekate.
1324
void (*ipl_ptr)() = (void *)IPL_LOAD_ADDR;
1325
(*ipl_ptr)();
1326
}
1327
1328
static void _about()
1329
{
1330
static const char credits[] =
1331
"\nhekate (c) 2018, naehrwert, st4rk\n\n"
1332
" (c) 2018-2026, CTCaer\n\n"
1333
" ___________________________________________\n\n"
1334
"Thanks to: %kderrek, nedwill, plutoo,\n"
1335
" shuffle2, smea, thexyz, yellows8%k\n"
1336
" ___________________________________________\n\n"
1337
"Greetings to: fincs, hexkyz, SciresM,\n"
1338
" Shiny Quagsire, WinterMute\n"
1339
" ___________________________________________\n\n"
1340
"Open source and free packages used:\n\n"
1341
" - FatFs R0.13c\n"
1342
" (c) 2006-2018, ChaN\n"
1343
" (c) 2018-2022, CTCaer\n\n"
1344
" - bcl-1.2.0\n"
1345
" (c) 2003-2006, Marcus Geelnard\n\n"
1346
" - blz\n"
1347
" (c) 2018, SciresM\n\n"
1348
" - elfload\n"
1349
" (c) 2014, Owen Shepherd\n"
1350
" (c) 2018, M4xw\n"
1351
" ___________________________________________\n\n";
1352
static const char octopus[] =
1353
" %k___\n"
1354
" .-' `'.\n"
1355
" / \\\n"
1356
" | ;\n"
1357
" | | ___.--,\n"
1358
" _.._ |0) = (0) | _.---'`__.-( (_.\n"
1359
" __.--'`_.. '.__.\\ '--. \\_.-' ,.--'` `\"\"`\n"
1360
" ( ,.--'` ',__ /./; ;, '.__.'` __\n"
1361
" _`) ) .---.__.' / | |\\ \\__..--\"\" \"\"\"--.,_\n"
1362
" `---' .'.''-._.-'`_./ /\\ '. \\ _.--''````'''--._`-.__.'\n"
1363
" | | .' _.-' | | \\ \\ '. `----`\n"
1364
" \\ \\/ .' \\ \\ '. '-._)\n"
1365
" \\/ / \\ \\ `=.__`'-.\n"
1366
" / /\\ `) ) / / `\"\".`\\\n"
1367
" , _.-'.'\\ \\ / / ( ( / /\n"
1368
" `--'` ) ) .-'.' '.'. | (\n"
1369
" (/` ( (` ) ) '-; %k[switchbrew]%k\n"
1370
" ` '-; (-'%k";
1371
1372
gfx_clear_grey(0x1B);
1373
gfx_con_setpos(0, 0);
1374
1375
gfx_printf(credits, TXT_CLR_CYAN_L, TXT_CLR_DEFAULT);
1376
gfx_con.fntsz = 8;
1377
gfx_printf(octopus, TXT_CLR_CYAN_L, TXT_CLR_TURQUOISE, TXT_CLR_CYAN_L, TXT_CLR_DEFAULT);
1378
1379
btn_wait();
1380
}
1381
1382
ment_t ment_cinfo[] = {
1383
MDEF_BACK(),
1384
MDEF_CHGLINE(),
1385
MDEF_CAPTION("---- SoC Info ----", TXT_CLR_CYAN_L),
1386
MDEF_HANDLER("Fuses", print_fuseinfo),
1387
MDEF_CHGLINE(),
1388
MDEF_CAPTION("-- Storage Info --", TXT_CLR_CYAN_L),
1389
MDEF_HANDLER("eMMC", print_mmc_info),
1390
MDEF_HANDLER("SD Card", print_sdcard_info),
1391
MDEF_CHGLINE(),
1392
MDEF_CAPTION("------ Misc ------", TXT_CLR_CYAN_L),
1393
MDEF_HANDLER("Battery", print_battery_info),
1394
MDEF_END()
1395
};
1396
1397
menu_t menu_cinfo = { ment_cinfo, "Console Info", 0, 0 };
1398
1399
ment_t ment_tools[] = {
1400
MDEF_BACK(),
1401
MDEF_CHGLINE(),
1402
MDEF_CAPTION("-------- Other -------", TXT_CLR_WARNING),
1403
MDEF_HANDLER("AutoRCM", menu_autorcm),
1404
MDEF_END()
1405
};
1406
1407
menu_t menu_tools = { ment_tools, "Tools", 0, 0 };
1408
1409
power_state_t STATE_POWER_OFF = POWER_OFF_RESET;
1410
power_state_t STATE_REBOOT_RCM = REBOOT_RCM;
1411
power_state_t STATE_REBOOT_BYPASS_FUSES = REBOOT_BYPASS_FUSES;
1412
1413
ment_t ment_top[] = {
1414
MDEF_HANDLER("Launch", _launch_config),
1415
MDEF_CAPTION("---------------", TXT_CLR_GREY_DM),
1416
MDEF_MENU("Tools", &menu_tools),
1417
MDEF_MENU("Console info", &menu_cinfo),
1418
MDEF_CAPTION("---------------", TXT_CLR_GREY_DM),
1419
MDEF_HANDLER("Reload", _ipl_reload),
1420
MDEF_HANDLER("Load Nyx", launch_nyx),
1421
MDEF_HANDLER_EX("Reboot (OFW)", &STATE_REBOOT_BYPASS_FUSES, power_set_state_ex),
1422
MDEF_HANDLER_EX("Reboot (RCM)", &STATE_REBOOT_RCM, power_set_state_ex),
1423
MDEF_HANDLER_EX("Power off", &STATE_POWER_OFF, power_set_state_ex),
1424
MDEF_CAPTION("---------------", TXT_CLR_GREY_DM),
1425
MDEF_HANDLER("About", _about),
1426
MDEF_END()
1427
};
1428
1429
menu_t menu_top = { ment_top, "hekate v6.5.2", 0, 0 };
1430
1431
extern void pivot_stack(u32 stack_top);
1432
1433
void ipl_main()
1434
{
1435
// Override DRAM ID if needed.
1436
if (ipl_ver.rcfg.rsvd_flags & RSVD_FLAG_DRAM_8GB)
1437
fuse_force_8gb_dramid();
1438
1439
// Do initial HW configuration. This is compatible with consecutive reruns without a reset.
1440
hw_init();
1441
1442
// Pivot the stack under IPL. (Only max 4KB is needed).
1443
pivot_stack(IPL_LOAD_ADDR);
1444
1445
// Place heap at a place outside of L4T/HOS configuration and binaries.
1446
heap_init((void *)IPL_HEAP_START);
1447
1448
#ifdef DEBUG_UART_PORT
1449
uart_send(DEBUG_UART_PORT, (u8 *)"hekate: Hello!\n", 15);
1450
uart_wait_xfer(DEBUG_UART_PORT, UART_TX_IDLE);
1451
#endif
1452
1453
// Set bootloader's default configuration.
1454
set_default_configuration();
1455
1456
// Check if battery is enough.
1457
_check_low_battery();
1458
1459
// Prep RTC regs for read. Needed for T210B01 R2C.
1460
max77620_rtc_prep_read();
1461
1462
// Initialize display.
1463
display_init();
1464
1465
// Overclock BPMP.
1466
bpmp_clk_rate_set(h_cfg.t210b01 ? ipl_ver.rcfg.bclk_t210b01 : ipl_ver.rcfg.bclk_t210);
1467
1468
// Mount SD Card.
1469
if (sd_mount())
1470
h_cfg.errors |= ERR_SD_BOOT_EN;
1471
1472
// Check if watchdog was fired previously.
1473
if (watchdog_fired())
1474
goto skip_lp0_minerva_config;
1475
1476
// Enable watchdog protection to avoid SD corruption based hanging in LP0/Minerva config.
1477
watchdog_start(5000000 / 2, TIMER_FIQENABL_EN); // 5 seconds.
1478
1479
// Save sdram lp0 config.
1480
void *sdram_params = h_cfg.t210b01 ? sdram_get_params_t210b01() : sdram_get_params_patched();
1481
if (!ianos_static_module("bootloader/sys/libsys_lp0.bso", sdram_params))
1482
h_cfg.errors |= ERR_LIBSYS_LP0;
1483
1484
// Train DRAM and switch to max frequency.
1485
if (minerva_init((minerva_str_t *)&nyx_str->minerva))
1486
h_cfg.errors |= ERR_LIBSYS_MTC;
1487
1488
// Disable watchdog protection.
1489
watchdog_end();
1490
1491
skip_lp0_minerva_config:
1492
// Initialize display window, backlight and gfx console.
1493
u32 *fb = display_init_window_a_pitch();
1494
gfx_init_ctxt(fb, 720, 1280, 720);
1495
gfx_con_init();
1496
1497
// Initialize backlight PWM.
1498
display_backlight_pwm_init();
1499
//display_backlight_brightness(h_cfg.backlight, 1000);
1500
1501
// Show exceptions, HOS errors, library errors and L4T kernel panics.
1502
_show_errors();
1503
1504
// Get R2C config from RTC.
1505
if (h_cfg.t210b01)
1506
_r2c_get_config_t210b01();
1507
1508
// Load saved configuration and auto boot if enabled.
1509
if (!(h_cfg.errors & ERR_SD_BOOT_EN))
1510
{
1511
_check_for_updated_bootloader();
1512
_auto_launch();
1513
}
1514
1515
// Failed to launch Nyx, unmount SD Card.
1516
sd_end();
1517
1518
// Set ram to a freq that doesn't need periodic training.
1519
minerva_change_freq(FREQ_800);
1520
1521
while (true)
1522
tui_do_menu(&menu_top);
1523
1524
// Halt BPMP if we managed to get out of execution.
1525
while (true)
1526
bpmp_halt();
1527
}
1528
1529