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