hekate/nyx: improve cyclomatic complexity

This commit is contained in:
CTCaer 2022-01-29 01:23:40 +02:00
parent 2f1d1572f7
commit aee5861f65
9 changed files with 1733 additions and 1701 deletions

View file

@ -192,87 +192,87 @@ int launch_payload(char *path, bool update, bool clear_screen)
gfx_clear_grey(0x1B); gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0); gfx_con_setpos(0, 0);
if (sd_mount()) if (!sd_mount())
goto out;
FIL fp;
if (f_open(&fp, path, FA_READ))
{ {
FIL fp; gfx_con.mute = false;
if (f_open(&fp, path, FA_READ)) EPRINTFARGS("Payload file is missing!\n(%s)", path);
{
gfx_con.mute = false;
EPRINTFARGS("Payload file is missing!\n(%s)", path);
goto out; goto out;
} }
// Read and copy the payload to our chosen address // Read and copy the payload to our chosen address
void *buf; void *buf;
u32 size = f_size(&fp); u32 size = f_size(&fp);
if (size < 0x30000) if (size < 0x30000)
buf = (void *)RCM_PAYLOAD_ADDR; buf = (void *)RCM_PAYLOAD_ADDR;
else else
{ {
coreboot_addr = (void *)(COREBOOT_END_ADDR - size); coreboot_addr = (void *)(COREBOOT_END_ADDR - size);
buf = coreboot_addr; buf = coreboot_addr;
if (h_cfg.t210b01) if (h_cfg.t210b01)
{
f_close(&fp);
gfx_con.mute = false;
EPRINTF("Coreboot not allowed on Mariko!");
goto out;
}
}
if (f_read(&fp, buf, size, NULL))
{ {
f_close(&fp); f_close(&fp);
gfx_con.mute = false;
EPRINTF("Coreboot not allowed on Mariko!");
goto out; goto out;
} }
}
if (f_read(&fp, buf, size, NULL))
{
f_close(&fp); f_close(&fp);
if (update && is_ipl_updated(buf, path, false)) goto out;
goto out; }
sd_end(); f_close(&fp);
if (size < 0x30000) if (update && is_ipl_updated(buf, path, false))
{ goto out;
if (update)
memcpy((u8 *)(RCM_PAYLOAD_ADDR + PATCHED_RELOC_SZ), &b_cfg, sizeof(boot_cfg_t)); // Transfer boot cfg.
else
reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10));
hw_reinit_workaround(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32)))); sd_end();
}
if (size < 0x30000)
{
if (update)
memcpy((u8 *)(RCM_PAYLOAD_ADDR + PATCHED_RELOC_SZ), &b_cfg, sizeof(boot_cfg_t)); // Transfer boot cfg.
else else
{ reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10));
reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, 0x7000);
// Get coreboot seamless display magic. hw_reinit_workaround(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32))));
u32 magic = 0; }
char *magic_ptr = buf + COREBOOT_VER_OFF; else
memcpy(&magic, magic_ptr + strlen(magic_ptr) - 4, 4); {
hw_reinit_workaround(true, magic); reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, 0x7000);
}
// Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms. // Get coreboot seamless display magic.
sdmmc_storage_init_wait_sd(); u32 magic = 0;
char *magic_ptr = buf + COREBOOT_VER_OFF;
memcpy(&magic, magic_ptr + strlen(magic_ptr) - 4, 4);
hw_reinit_workaround(true, magic);
}
void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR; // Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms.
void (*update_ptr)() = (void *)RCM_PAYLOAD_ADDR; sdmmc_storage_init_wait_sd();
// Launch our payload. void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR;
if (!update) void (*update_ptr)() = (void *)RCM_PAYLOAD_ADDR;
(*ext_payload_ptr)();
else // Launch our payload.
{ if (!update)
// Set updated flag to skip check on launch. (*ext_payload_ptr)();
EMC(EMC_SCRATCH0) |= EMC_HEKA_UPD; else
(*update_ptr)(); {
} // Set updated flag to skip check on launch.
EMC(EMC_SCRATCH0) |= EMC_HEKA_UPD;
(*update_ptr)();
} }
out: out:
@ -282,25 +282,6 @@ out:
return 1; return 1;
} }
void auto_launch_update()
{
// Check if already chainloaded update and clear flag. Otherwise check for updates.
if (EMC(EMC_SCRATCH0) & EMC_HEKA_UPD)
EMC(EMC_SCRATCH0) &= ~EMC_HEKA_UPD;
else
{
// Check if update.bin exists and is newer and launch it. Otherwise create it.
if (!f_stat("bootloader/update.bin", NULL))
launch_payload("bootloader/update.bin", true, false);
else
{
u8 *buf = calloc(0x200, 1);
is_ipl_updated(buf, "bootloader/update.bin", true);
free(buf);
}
}
}
void launch_tools() void launch_tools()
{ {
u8 max_entries = 61; u8 max_entries = 61;
@ -313,63 +294,60 @@ void launch_tools()
gfx_clear_grey(0x1B); gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0); gfx_con_setpos(0, 0);
if (sd_mount()) if (!sd_mount())
{ {
dir = (char *)malloc(256);
memcpy(dir, "bootloader/payloads", 20);
filelist = dirlist(dir, NULL, false, false);
u32 i = 0;
if (filelist)
{
// Build configuration menu.
ments[0].type = MENT_BACK;
ments[0].caption = "Back";
ments[1].type = MENT_CHGLINE;
while (true)
{
if (i > max_entries || !filelist[i * 256])
break;
ments[i + 2].type = INI_CHOICE;
ments[i + 2].caption = &filelist[i * 256];
ments[i + 2].data = &filelist[i * 256];
i++;
}
}
if (i > 0)
{
memset(&ments[i + 2], 0, sizeof(ment_t));
menu_t menu = { ments, "Choose a file to launch", 0, 0 };
file_sec = (char *)tui_do_menu(&menu);
if (!file_sec)
{
free(ments);
free(dir);
free(filelist);
sd_end();
return;
}
}
else
EPRINTF("No payloads or modules found.");
free(ments); free(ments);
free(filelist); goto failed_sd_mount;
}
dir = (char *)malloc(256);
memcpy(dir, "bootloader/payloads", 20);
filelist = dirlist(dir, NULL, false, false);
u32 i = 0;
if (filelist)
{
// Build configuration menu.
ments[0].type = MENT_BACK;
ments[0].caption = "Back";
ments[1].type = MENT_CHGLINE;
while (true)
{
if (i > max_entries || !filelist[i * 256])
break;
ments[i + 2].type = INI_CHOICE;
ments[i + 2].caption = &filelist[i * 256];
ments[i + 2].data = &filelist[i * 256];
i++;
}
}
if (i > 0)
{
memset(&ments[i + 2], 0, sizeof(ment_t));
menu_t menu = { ments, "Choose a file to launch", 0, 0 };
file_sec = (char *)tui_do_menu(&menu);
if (!file_sec)
{
free(ments);
free(dir);
free(filelist);
sd_end();
return;
}
} }
else else
{ EPRINTF("No payloads or modules found.");
free(ments);
goto out; free(ments);
} free(filelist);
if (file_sec) if (file_sec)
{ {
@ -380,7 +358,7 @@ void launch_tools()
EPRINTF("Failed to launch payload."); EPRINTF("Failed to launch payload.");
} }
out: failed_sd_mount:
sd_end(); sd_end();
free(dir); free(dir);
@ -399,94 +377,101 @@ void ini_list_launcher()
gfx_clear_grey(0x1B); gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0); gfx_con_setpos(0, 0);
if (sd_mount()) if (!sd_mount())
goto parse_failed;
// Check that ini files exist and parse them.
if (!ini_parse(&ini_list_sections, "bootloader/ini", true))
{ {
if (ini_parse(&ini_list_sections, "bootloader/ini", true)) EPRINTF("Could not find any ini\nin bootloader/ini!");
{ goto parse_failed;
// Build configuration menu.
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3));
ments[0].type = MENT_BACK;
ments[0].caption = "Back";
ments[1].type = MENT_CHGLINE;
u32 i = 2;
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_list_sections, link)
{
if (!strcmp(ini_sec->name, "config") ||
ini_sec->type == INI_COMMENT || ini_sec->type == INI_NEWLINE)
continue;
ments[i].type = ini_sec->type;
ments[i].caption = ini_sec->name;
ments[i].data = ini_sec;
if (ini_sec->type == MENT_CAPTION)
ments[i].color = ini_sec->color;
i++;
if ((i - 1) > max_entries)
break;
}
if (i > 2)
{
memset(&ments[i], 0, sizeof(ment_t));
menu_t menu = {
ments, "Launch ini configurations", 0, 0
};
cfg_sec = (ini_sec_t *)tui_do_menu(&menu);
if (cfg_sec)
{
u32 non_cfg = 1;
for (u32 j = 2; j < i; j++)
{
if (ments[j].type != INI_CHOICE)
non_cfg++;
if (ments[j].data == cfg_sec)
{
b_cfg.boot_cfg = BOOT_CFG_FROM_LAUNCH;
b_cfg.autoboot = j - non_cfg;
b_cfg.autoboot_list = 1;
break;
}
}
}
payload_path = ini_check_payload_section(cfg_sec);
if (cfg_sec)
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link)
{
if (!strcmp("emummc_force_disable", kv->key))
h_cfg.emummc_force_disable = atoi(kv->val);
else if (!strcmp("emupath", kv->key))
emummc_path = kv->val;
}
}
if (emummc_path && !emummc_set_path(emummc_path))
{
EPRINTF("emupath is wrong!");
goto wrong_emupath;
}
if (!cfg_sec)
{
free(ments);
return;
}
}
else
EPRINTF("No extra configs found.");
free(ments);
}
else
EPRINTF("Could not find any ini\nin bootloader/ini!");
} }
// Build configuration menu.
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3));
ments[0].type = MENT_BACK;
ments[0].caption = "Back";
ments[1].type = MENT_CHGLINE;
u32 i = 2;
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_list_sections, link)
{
if (!strcmp(ini_sec->name, "config") ||
ini_sec->type == INI_COMMENT ||
ini_sec->type == INI_NEWLINE)
continue;
ments[i].type = ini_sec->type;
ments[i].caption = ini_sec->name;
ments[i].data = ini_sec;
if (ini_sec->type == MENT_CAPTION)
ments[i].color = ini_sec->color;
i++;
if ((i - 1) > max_entries)
break;
}
if (i > 2)
{
memset(&ments[i], 0, sizeof(ment_t));
menu_t menu = {
ments, "Launch ini configurations", 0, 0
};
cfg_sec = (ini_sec_t *)tui_do_menu(&menu);
if (cfg_sec)
{
u32 non_cfg = 1;
for (u32 j = 2; j < i; j++)
{
if (ments[j].type != INI_CHOICE)
non_cfg++;
if (ments[j].data == cfg_sec)
{
b_cfg.boot_cfg = BOOT_CFG_FROM_LAUNCH;
b_cfg.autoboot = j - non_cfg;
b_cfg.autoboot_list = 1;
break;
}
}
}
payload_path = ini_check_payload_section(cfg_sec);
if (cfg_sec)
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link)
{
if (!strcmp("emummc_force_disable", kv->key))
h_cfg.emummc_force_disable = atoi(kv->val);
else if (!strcmp("emupath", kv->key))
emummc_path = kv->val;
}
}
if (emummc_path && !emummc_set_path(emummc_path))
{
EPRINTF("emupath is wrong!");
goto wrong_emupath;
}
if (!cfg_sec)
{
free(ments);
return;
}
}
else
EPRINTF("No extra configs found.");
free(ments);
parse_failed:
if (!cfg_sec) if (!cfg_sec)
goto out; goto out;
@ -524,108 +509,116 @@ void launch_firmware()
gfx_clear_grey(0x1B); gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0); gfx_con_setpos(0, 0);
if (sd_mount()) if (!sd_mount())
goto parse_failed;
// Load emuMMC configuration.
emummc_load_cfg();
// Check that main configuration exists and parse it.
if (!ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
{ {
// Load emuMMC configuration. EPRINTF("Could not open 'bootloader/hekate_ipl.ini'!");
emummc_load_cfg(); goto parse_failed;
if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
{
// Build configuration menu.
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 6));
ments[0].type = MENT_BACK;
ments[0].caption = "Back";
ments[1].type = MENT_CHGLINE;
ments[2].type = MENT_HANDLER;
ments[2].caption = "Payloads...";
ments[2].handler = launch_tools;
ments[3].type = MENT_HANDLER;
ments[3].caption = "More configs...";
ments[3].handler = ini_list_launcher;
ments[4].type = MENT_CHGLINE;
u32 i = 5;
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
{
if (!strcmp(ini_sec->name, "config") ||
ini_sec->type == INI_COMMENT || ini_sec->type == INI_NEWLINE)
continue;
ments[i].type = ini_sec->type;
ments[i].caption = ini_sec->name;
ments[i].data = ini_sec;
if (ini_sec->type == MENT_CAPTION)
ments[i].color = ini_sec->color;
i++;
if ((i - 4) > max_entries)
break;
}
if (i < 6)
{
ments[i].type = MENT_CAPTION;
ments[i].caption = "No main configs found...";
ments[i].color = 0xFFFFDD00;
i++;
}
memset(&ments[i], 0, sizeof(ment_t));
menu_t menu = {
ments, "Launch configurations", 0, 0
};
cfg_sec = (ini_sec_t *)tui_do_menu(&menu);
if (cfg_sec)
{
u8 non_cfg = 4;
for (u32 j = 5; j < i; j++)
{
if (ments[j].type != INI_CHOICE)
non_cfg++;
if (ments[j].data == cfg_sec)
{
b_cfg.boot_cfg = BOOT_CFG_FROM_LAUNCH;
b_cfg.autoboot = j - non_cfg;
b_cfg.autoboot_list = 0;
break;
}
}
}
payload_path = ini_check_payload_section(cfg_sec);
if (cfg_sec)
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link)
{
if (!strcmp("emummc_force_disable", kv->key))
h_cfg.emummc_force_disable = atoi(kv->val);
if (!strcmp("emupath", kv->key))
emummc_path = kv->val;
}
}
if (emummc_path && !emummc_set_path(emummc_path))
{
EPRINTF("emupath is wrong!");
goto wrong_emupath;
}
if (!cfg_sec)
{
free(ments);
sd_end();
return;
}
free(ments);
}
else
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!");
} }
// Build configuration menu.
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 6));
ments[0].type = MENT_BACK;
ments[0].caption = "Back";
ments[1].type = MENT_CHGLINE;
ments[2].type = MENT_HANDLER;
ments[2].caption = "Payloads...";
ments[2].handler = launch_tools;
ments[3].type = MENT_HANDLER;
ments[3].caption = "More configs...";
ments[3].handler = ini_list_launcher;
ments[4].type = MENT_CHGLINE;
u32 i = 5;
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
{
if (!strcmp(ini_sec->name, "config") ||
ini_sec->type == INI_COMMENT ||
ini_sec->type == INI_NEWLINE)
continue;
ments[i].type = ini_sec->type;
ments[i].caption = ini_sec->name;
ments[i].data = ini_sec;
if (ini_sec->type == MENT_CAPTION)
ments[i].color = ini_sec->color;
i++;
if ((i - 4) > max_entries)
break;
}
if (i < 6)
{
ments[i].type = MENT_CAPTION;
ments[i].caption = "No main configs found...";
ments[i].color = 0xFFFFDD00;
i++;
}
memset(&ments[i], 0, sizeof(ment_t));
menu_t menu = {
ments, "Launch configurations", 0, 0
};
cfg_sec = (ini_sec_t *)tui_do_menu(&menu);
if (cfg_sec)
{
u8 non_cfg = 4;
for (u32 j = 5; j < i; j++)
{
if (ments[j].type != INI_CHOICE)
non_cfg++;
if (ments[j].data == cfg_sec)
{
b_cfg.boot_cfg = BOOT_CFG_FROM_LAUNCH;
b_cfg.autoboot = j - non_cfg;
b_cfg.autoboot_list = 0;
break;
}
}
}
payload_path = ini_check_payload_section(cfg_sec);
if (cfg_sec)
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link)
{
if (!strcmp("emummc_force_disable", kv->key))
h_cfg.emummc_force_disable = atoi(kv->val);
if (!strcmp("emupath", kv->key))
emummc_path = kv->val;
}
}
if (emummc_path && !emummc_set_path(emummc_path))
{
EPRINTF("emupath is wrong!");
goto wrong_emupath;
}
if (!cfg_sec)
{
free(ments);
sd_end();
return;
}
free(ments);
parse_failed:
if (!cfg_sec) if (!cfg_sec)
{ {
gfx_printf("\nPress any key...\n"); gfx_printf("\nPress any key...\n");
@ -769,6 +762,25 @@ static void _bootloader_corruption_protect()
} }
} }
void auto_launch_update()
{
// Check if already chainloaded update and clear flag. Otherwise check for updates.
if (EMC(EMC_SCRATCH0) & EMC_HEKA_UPD)
EMC(EMC_SCRATCH0) &= ~EMC_HEKA_UPD;
else
{
// Check if update.bin exists and is newer and launch it. Otherwise create it.
if (!f_stat("bootloader/update.bin", NULL))
launch_payload("bootloader/update.bin", true, false);
else
{
u8 *buf = calloc(0x200, 1);
is_ipl_updated(buf, "bootloader/update.bin", true);
free(buf);
}
}
}
static void _auto_launch_firmware() static void _auto_launch_firmware()
{ {
struct _bmp_data struct _bmp_data
@ -784,6 +796,8 @@ static void _auto_launch_firmware()
char *emummc_path = NULL; char *emummc_path = NULL;
char *bootlogoCustomEntry = NULL; char *bootlogoCustomEntry = NULL;
ini_sec_t *cfg_sec = NULL; ini_sec_t *cfg_sec = NULL;
u32 boot_entry_id = 0;
bool config_entry_found = false;
auto_launch_update(); auto_launch_update();
@ -803,142 +817,137 @@ static void _auto_launch_firmware()
if (f_stat("bootloader/hekate_ipl.ini", NULL)) if (f_stat("bootloader/hekate_ipl.ini", NULL))
create_config_entry(); create_config_entry();
if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) // Parse hekate main configuration.
{ if (!ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
u32 configEntry = 0;
u32 boot_entry_id = 0;
// Load configuration.
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
{
// Skip other ini entries for autoboot.
if (ini_sec->type == INI_CHOICE)
{
if (!strcmp(ini_sec->name, "config"))
{
configEntry = 1;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
if (!strcmp("autoboot", kv->key))
h_cfg.autoboot = atoi(kv->val);
else if (!strcmp("autoboot_list", kv->key))
h_cfg.autoboot_list = atoi(kv->val);
else if (!strcmp("bootwait", kv->key))
{
h_cfg.bootwait = atoi(kv->val);
/*
* Clamp value to default if it exceeds 20s to protect against corruption.
* Allow up to 20s though for use in cases where user needs lots of time.
* For example dock-only use and r2p with enough time to reach dock and cancel it.
*/
if (h_cfg.bootwait > 20)
h_cfg.bootwait = 3;
}
else if (!strcmp("backlight", kv->key))
h_cfg.backlight = atoi(kv->val);
else if (!strcmp("autohosoff", kv->key))
h_cfg.autohosoff = atoi(kv->val);
else if (!strcmp("autonogc", kv->key))
h_cfg.autonogc = atoi(kv->val);
else if (!strcmp("updater2p", kv->key))
h_cfg.updater2p = atoi(kv->val);
else if (!strcmp("bootprotect", kv->key))
h_cfg.bootprotect = atoi(kv->val);
}
boot_entry_id++;
// Override autoboot.
if (b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN)
{
h_cfg.autoboot = b_cfg.autoboot;
h_cfg.autoboot_list = b_cfg.autoboot_list;
}
// Apply bootloader protection against corruption.
_bootloader_corruption_protect();
continue;
}
if (boot_from_id)
cfg_sec = get_ini_sec_from_id(ini_sec, &bootlogoCustomEntry, &emummc_path);
else if (h_cfg.autoboot == boot_entry_id && configEntry)
{
cfg_sec = ini_sec;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link)
{
if (!strcmp("logopath", kv->key))
bootlogoCustomEntry = kv->val;
else if (!strcmp("emummc_force_disable", kv->key))
h_cfg.emummc_force_disable = atoi(kv->val);
else if (!strcmp("emupath", kv->key))
emummc_path = kv->val;
}
}
if (cfg_sec)
break;
boot_entry_id++;
}
}
if (h_cfg.autohosoff && !(b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN))
check_power_off_from_hos();
if (h_cfg.autoboot_list || (boot_from_id && !cfg_sec))
{
if (boot_from_id && cfg_sec)
goto skip_list;
cfg_sec = NULL;
boot_entry_id = 1;
bootlogoCustomEntry = NULL;
if (ini_parse(&ini_list_sections, "bootloader/ini", true))
{
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec_list, &ini_list_sections, link)
{
if (ini_sec_list->type == INI_CHOICE)
{
if (!strcmp(ini_sec_list->name, "config"))
continue;
if (boot_from_id)
cfg_sec = get_ini_sec_from_id(ini_sec_list, &bootlogoCustomEntry, &emummc_path);
else if (h_cfg.autoboot == boot_entry_id)
{
h_cfg.emummc_force_disable = false;
cfg_sec = ini_sec_list;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link)
{
if (!strcmp("logopath", kv->key))
bootlogoCustomEntry = kv->val;
else if (!strcmp("emummc_force_disable", kv->key))
h_cfg.emummc_force_disable = atoi(kv->val);
else if (!strcmp("emupath", kv->key))
emummc_path = kv->val;
}
}
if (cfg_sec)
break;
boot_entry_id++;
}
}
}
}
skip_list:
// Add missing configuration entry.
if (!configEntry)
create_config_entry();
if (!cfg_sec)
goto out; // No configurations or auto boot is disabled.
}
else
goto out; // Can't load hekate_ipl.ini. goto out; // Can't load hekate_ipl.ini.
// Load configuration.
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
{
// Skip other ini entries for autoboot.
if (ini_sec->type == INI_CHOICE)
{
if (!config_entry_found && !strcmp(ini_sec->name, "config"))
{
config_entry_found = true;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
if (!strcmp("autoboot", kv->key))
h_cfg.autoboot = atoi(kv->val);
else if (!strcmp("autoboot_list", kv->key))
h_cfg.autoboot_list = atoi(kv->val);
else if (!strcmp("bootwait", kv->key))
{
h_cfg.bootwait = atoi(kv->val);
/*
* Clamp value to default if it exceeds 20s to protect against corruption.
* Allow up to 20s though for use in cases where user needs lots of time.
* For example dock-only use and r2p with enough time to reach dock and cancel it.
*/
if (h_cfg.bootwait > 20)
h_cfg.bootwait = 3;
}
else if (!strcmp("backlight", kv->key))
h_cfg.backlight = atoi(kv->val);
else if (!strcmp("autohosoff", kv->key))
h_cfg.autohosoff = atoi(kv->val);
else if (!strcmp("autonogc", kv->key))
h_cfg.autonogc = atoi(kv->val);
else if (!strcmp("updater2p", kv->key))
h_cfg.updater2p = atoi(kv->val);
else if (!strcmp("bootprotect", kv->key))
h_cfg.bootprotect = atoi(kv->val);
}
boot_entry_id++;
// Override autoboot.
if (b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN)
{
h_cfg.autoboot = b_cfg.autoboot;
h_cfg.autoboot_list = b_cfg.autoboot_list;
}
// Apply bootloader protection against corruption.
_bootloader_corruption_protect();
continue;
}
if (boot_from_id)
cfg_sec = get_ini_sec_from_id(ini_sec, &bootlogoCustomEntry, &emummc_path);
else if (h_cfg.autoboot == boot_entry_id && config_entry_found)
{
cfg_sec = ini_sec;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link)
{
if (!strcmp("logopath", kv->key))
bootlogoCustomEntry = kv->val;
else if (!strcmp("emummc_force_disable", kv->key))
h_cfg.emummc_force_disable = atoi(kv->val);
else if (!strcmp("emupath", kv->key))
emummc_path = kv->val;
}
}
if (cfg_sec)
break;
boot_entry_id++;
}
}
if (h_cfg.autohosoff && !(b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN))
check_power_off_from_hos();
if (h_cfg.autoboot_list || (boot_from_id && !cfg_sec))
{
if (boot_from_id && cfg_sec)
goto skip_list;
cfg_sec = NULL;
boot_entry_id = 1;
bootlogoCustomEntry = NULL;
if (!ini_parse(&ini_list_sections, "bootloader/ini", true))
goto skip_list;
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec_list, &ini_list_sections, link)
{
if (ini_sec_list->type != INI_CHOICE)
continue;
if (!strcmp(ini_sec_list->name, "config"))
continue;
if (boot_from_id)
cfg_sec = get_ini_sec_from_id(ini_sec_list, &bootlogoCustomEntry, &emummc_path);
else if (h_cfg.autoboot == boot_entry_id)
{
h_cfg.emummc_force_disable = false;
cfg_sec = ini_sec_list;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link)
{
if (!strcmp("logopath", kv->key))
bootlogoCustomEntry = kv->val;
else if (!strcmp("emummc_force_disable", kv->key))
h_cfg.emummc_force_disable = atoi(kv->val);
else if (!strcmp("emupath", kv->key))
emummc_path = kv->val;
}
}
if (cfg_sec)
break;
boot_entry_id++;
}
}
skip_list:
// Add missing configuration entry.
if (!config_entry_found)
create_config_entry();
if (!cfg_sec)
goto out; // No configurations or auto boot is disabled.
u8 *bitmap = NULL; u8 *bitmap = NULL;
struct _bmp_data bmpData; struct _bmp_data bmpData;
bool bootlogoFound = false; bool bootlogoFound = false;

View file

@ -950,124 +950,125 @@ static int _restore_emmc_part(emmc_tool_gui_t *gui, char *sd_path, int active_pa
bool use_multipart = false; bool use_multipart = false;
bool check_4MB_aligned = true; bool check_4MB_aligned = true;
if (allow_multi_part) if (!allow_multi_part)
goto multipart_not_allowed;
// Check to see if there is a combined file and if so then use that.
if (f_stat(outFilename, &fno))
{ {
// Check to see if there is a combined file and if so then use that. // If not, check if there are partial files and the total size matches.
if (f_stat(outFilename, &fno)) s_printf(gui->txt_buf, "\nNo single file, checking for part files...\n");
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
outFilename[sdPathLen++] = '.';
_update_filename(outFilename, sdPathLen, numSplitParts);
s_printf(gui->txt_buf, "#96FF00 Filepath:#\n%s\n#96FF00 Filename:# #FF8000 %s#",
gui->base_path, outFilename + strlen(gui->base_path));
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
// Stat total size of the part files.
while ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors)
{ {
// If not, check if there are partial files and the total size matches.
s_printf(gui->txt_buf, "\nNo single file, checking for part files...\n");
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
outFilename[sdPathLen++] = '.';
_update_filename(outFilename, sdPathLen, numSplitParts); _update_filename(outFilename, sdPathLen, numSplitParts);
s_printf(gui->txt_buf, "#96FF00 Filepath:#\n%s\n#96FF00 Filename:# #FF8000 %s#", s_printf(gui->txt_buf, "%s#", outFilename + strlen(gui->base_path));
gui->base_path, outFilename + strlen(gui->base_path)); lv_label_cut_text(gui->label_info,
strlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path)) - 1,
strlen(outFilename + strlen(gui->base_path)) + 1);
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf); lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
// Stat total size of the part files. if ((u32)((u64)totalCheckFileSize >> (u64)9) > totalSectors)
while ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors)
{ {
_update_filename(outFilename, sdPathLen, numSplitParts); s_printf(gui->txt_buf, "#FF8000 Size of SD Card split backup exceeds#\n#FF8000 eMMC's selected part size!#\n#FFDD00 Aborting...#");
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
s_printf(gui->txt_buf, "%s#", outFilename + strlen(gui->base_path));
lv_label_cut_text(gui->label_info,
strlen(lv_label_get_text(gui->label_info)) - strlen(outFilename + strlen(gui->base_path)) - 1,
strlen(outFilename + strlen(gui->base_path)) + 1);
lv_label_ins_text(gui->label_info, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true); manual_system_maintenance(true);
if ((u32)((u64)totalCheckFileSize >> (u64)9) > totalSectors) return 0;
}
else if (f_stat(outFilename, &fno))
{
if (!gui->raw_emummc)
{ {
s_printf(gui->txt_buf, "#FF8000 Size of SD Card split backup exceeds#\n#FF8000 eMMC's selected part size!#\n#FFDD00 Aborting...#"); s_printf(gui->txt_buf, "#FFDD00 Error (%d) file not found#\n#FFDD00 %s.#\n\n", res, outFilename);
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true); manual_system_maintenance(true);
return 0; // Attempt a smaller restore.
} if (numSplitParts)
else if (f_stat(outFilename, &fno)) break;
{
if (!gui->raw_emummc)
{
s_printf(gui->txt_buf, "#FFDD00 Error (%d) file not found#\n#FFDD00 %s.#\n\n", res, outFilename);
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
// Attempt a smaller restore.
if (numSplitParts)
break;
}
else
{
// Set new total sectors and lba end sector for percentage calculations.
totalSectors = (u32)((u64)totalCheckFileSize >> (u64)9);
lba_end = totalSectors + part->lba_start - 1;
}
// Restore folder is empty.
if (!numSplitParts)
{
s_printf(gui->txt_buf, "#FFDD00 Restore folder is empty.#\n\n");
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
return 0;
}
} }
else else
{ {
totalCheckFileSize += (u64)fno.fsize; // Set new total sectors and lba end sector for percentage calculations.
totalSectors = (u32)((u64)totalCheckFileSize >> (u64)9);
if (check_4MB_aligned && (((u64)fno.fsize) % SZ_4M)) lba_end = totalSectors + part->lba_start - 1;
{
s_printf(gui->txt_buf, "#FFDD00 The split file must be a#\n#FFDD00 multiple of 4 MiB.#\n#FFDD00 Aborting...#", res, outFilename);
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
return 0;
}
check_4MB_aligned = false;
} }
numSplitParts++; // Restore folder is empty.
} if (!numSplitParts)
s_printf(gui->txt_buf, "%X sectors total.\n", (u32)((u64)totalCheckFileSize >> (u64)9));
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
if ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors)
{
lv_obj_t *warn_mbox_bg = create_mbox_text(
"#FF8000 Size of SD Card split backup does not match#\n#FF8000 eMMC's selected part size!#\n\n"
"#FFDD00 The backup might be corrupted,#\n#FFDD00 or missing files!#\n#FFDD00 Aborting is suggested!#\n\n"
"Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort.", false);
manual_system_maintenance(true);
if (!(btn_wait() & BTN_POWER))
{ {
lv_obj_del(warn_mbox_bg); s_printf(gui->txt_buf, "#FFDD00 Restore folder is empty.#\n\n");
s_printf(gui->txt_buf, "#FF0000 Size of SD Card split backup does not match#\n#FF0000 eMMC's selected part size!#\n");
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf); lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true); manual_system_maintenance(true);
return 0; return 0;
} }
lv_obj_del(warn_mbox_bg);
// Set new total sectors and lba end sector for percentage calculations.
totalSectors = (u32)((u64)totalCheckFileSize >> (u64)9);
lba_end = totalSectors + part->lba_start - 1;
} }
use_multipart = true; else
_update_filename(outFilename, sdPathLen, 0); {
totalCheckFileSize += (u64)fno.fsize;
if (check_4MB_aligned && (((u64)fno.fsize) % SZ_4M))
{
s_printf(gui->txt_buf, "#FFDD00 The split file must be a#\n#FFDD00 multiple of 4 MiB.#\n#FFDD00 Aborting...#", res, outFilename);
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
return 0;
}
check_4MB_aligned = false;
}
numSplitParts++;
} }
s_printf(gui->txt_buf, "%X sectors total.\n", (u32)((u64)totalCheckFileSize >> (u64)9));
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
if ((u32)((u64)totalCheckFileSize >> (u64)9) != totalSectors)
{
lv_obj_t *warn_mbox_bg = create_mbox_text(
"#FF8000 Size of SD Card split backup does not match#\n#FF8000 eMMC's selected part size!#\n\n"
"#FFDD00 The backup might be corrupted,#\n#FFDD00 or missing files!#\n#FFDD00 Aborting is suggested!#\n\n"
"Press #FF8000 POWER# to Continue.\nPress #FF8000 VOL# to abort.", false);
manual_system_maintenance(true);
if (!(btn_wait() & BTN_POWER))
{
lv_obj_del(warn_mbox_bg);
s_printf(gui->txt_buf, "#FF0000 Size of SD Card split backup does not match#\n#FF0000 eMMC's selected part size!#\n");
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, gui->txt_buf);
manual_system_maintenance(true);
return 0;
}
lv_obj_del(warn_mbox_bg);
// Set new total sectors and lba end sector for percentage calculations.
totalSectors = (u32)((u64)totalCheckFileSize >> (u64)9);
lba_end = totalSectors + part->lba_start - 1;
}
use_multipart = true;
_update_filename(outFilename, sdPathLen, 0);
} }
multipart_not_allowed:
res = f_open(&fp, outFilename, FA_READ); res = f_open(&fp, outFilename, FA_READ);
if (use_multipart) if (use_multipart)
{ {

View file

@ -42,26 +42,28 @@ void load_emummc_cfg(emummc_cfg_t *emu_info)
// Parse emuMMC configuration. // Parse emuMMC configuration.
LIST_INIT(ini_sections); LIST_INIT(ini_sections);
if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false)) if (!ini_parse(&ini_sections, "emuMMC/emummc.ini", false))
return;
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
{ {
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) if (!strcmp(ini_sec->name, "emummc"))
{ {
if (!strcmp(ini_sec->name, "emummc")) LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{ {
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link) if (!strcmp("enabled", kv->key))
{ emu_info->enabled = atoi(kv->val);
if (!strcmp("enabled", kv->key)) else if (!strcmp("sector", kv->key))
emu_info->enabled = atoi(kv->val); emu_info->sector = strtol(kv->val, NULL, 16);
else if (!strcmp("sector", kv->key)) else if (!strcmp("id", kv->key))
emu_info->sector = strtol(kv->val, NULL, 16); emu_info->id = strtol(kv->val, NULL, 16);
else if (!strcmp("id", kv->key)) else if (!strcmp("path", kv->key))
emu_info->id = strtol(kv->val, NULL, 16); emu_info->path = kv->val;
else if (!strcmp("path", kv->key)) else if (!strcmp("nintendo_path", kv->key))
emu_info->path = kv->val; emu_info->nintendo_path = kv->val;
else if (!strcmp("nintendo_path", kv->key))
emu_info->nintendo_path = kv->val;
}
} }
break;
} }
} }
} }
@ -262,6 +264,7 @@ static int _dump_emummc_file_part(emmc_tool_gui_t *gui, char *sd_path, sdmmc_sto
retryCount = 0; retryCount = 0;
num = MIN(totalSectors, NUM_SECTORS_PER_ITER); num = MIN(totalSectors, NUM_SECTORS_PER_ITER);
while (!sdmmc_storage_read(storage, lba_curr, num, buf)) while (!sdmmc_storage_read(storage, lba_curr, num, buf))
{ {
s_printf(gui->txt_buf, s_printf(gui->txt_buf,
@ -405,6 +408,7 @@ void dump_emummc_file(emmc_tool_gui_t *gui)
memset(&bootPart, 0, sizeof(bootPart)); memset(&bootPart, 0, sizeof(bootPart));
bootPart.lba_start = 0; bootPart.lba_start = 0;
bootPart.lba_end = (BOOT_PART_SIZE / EMMC_BLOCKSIZE) - 1; bootPart.lba_end = (BOOT_PART_SIZE / EMMC_BLOCKSIZE) - 1;
for (i = 0; i < 2; i++) for (i = 0; i < 2; i++)
{ {
strcpy(bootPart.name, "BOOT"); strcpy(bootPart.name, "BOOT");
@ -448,24 +452,23 @@ void dump_emummc_file(emmc_tool_gui_t *gui)
rawPart.lba_start = 0; rawPart.lba_start = 0;
rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1; rawPart.lba_end = RAW_AREA_NUM_SECTORS - 1;
strcpy(rawPart.name, "GPP"); strcpy(rawPart.name, "GPP");
{
s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n",
i, rawPart.name, rawPart.lba_start, rawPart.lba_end);
lv_label_set_text(gui->label_info, txt_buf);
s_printf(txt_buf, "%02d: %s... ", i, rawPart.name);
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
manual_system_maintenance(true);
res = _dump_emummc_file_part(gui, sdPath, &emmc_storage, &rawPart); s_printf(txt_buf, "#00DDFF %02d: %s#\n#00DDFF Range: 0x%08X - 0x%08X#\n\n",
i, rawPart.name, rawPart.lba_start, rawPart.lba_end);
lv_label_set_text(gui->label_info, txt_buf);
s_printf(txt_buf, "%02d: %s... ", i, rawPart.name);
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
manual_system_maintenance(true);
if (!res) res = _dump_emummc_file_part(gui, sdPath, &emmc_storage, &rawPart);
s_printf(txt_buf, "#FFDD00 Failed!#\n");
else
s_printf(txt_buf, "Done!\n");
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf); if (!res)
manual_system_maintenance(true); s_printf(txt_buf, "#FFDD00 Failed!#\n");
} else
s_printf(txt_buf, "Done!\n");
lv_label_ins_text(gui->label_log, LV_LABEL_POS_LAST, txt_buf);
manual_system_maintenance(true);
out_failed: out_failed:
timer = get_tmr_s() - timer; timer = get_tmr_s() - timer;

View file

@ -1608,149 +1608,151 @@ static lv_res_t _create_window_home_launch(lv_obj_t *btn)
u32 curr_btn_idx = 0; // Active buttons. u32 curr_btn_idx = 0; // Active buttons.
LIST_INIT(ini_sections); LIST_INIT(ini_sections);
if (sd_mount()) if (!sd_mount())
goto failed_sd_mount;
// Check if we use custom system icons.
bool icon_sw_custom = !f_stat("bootloader/res/icon_switch_custom.bmp", NULL);
bool icon_pl_custom = !f_stat("bootloader/res/icon_payload_custom.bmp", NULL);
// Choose what to parse.
bool ini_parse_success = false;
if (!more_cfg)
ini_parse_success = ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false);
else
ini_parse_success = ini_parse(&ini_sections, "bootloader/ini", true);
if (combined_cfg && !ini_parse_success)
{ {
// Check if we use custom system icons.
bool icon_sw_custom = !f_stat("bootloader/res/icon_switch_custom.bmp", NULL);
bool icon_pl_custom = !f_stat("bootloader/res/icon_payload_custom.bmp", NULL);
// Choose what to parse.
bool ini_parse_success = false;
if (!more_cfg)
ini_parse_success = ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false);
else
ini_parse_success = ini_parse(&ini_sections, "bootloader/ini", true);
if (combined_cfg && !ini_parse_success)
{
ini_parsing: ini_parsing:
// Reinit list. // Reinit list.
ini_sections.prev = &ini_sections; ini_sections.prev = &ini_sections;
ini_sections.next = &ini_sections; ini_sections.next = &ini_sections;
ini_parse_success = ini_parse(&ini_sections, "bootloader/ini", true); ini_parse_success = ini_parse(&ini_sections, "bootloader/ini", true);
more_cfg = true; more_cfg = true;
}
if (ini_parse_success)
{
// Iterate to all boot entries and load icons.
u32 entry_idx = 1;
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
{
if (!strcmp(ini_sec->name, "config") || (ini_sec->type != INI_CHOICE))
continue;
icon_path = NULL;
bool payload = false;
bool img_colorize = false;
lv_img_dsc_t *bmp = NULL;
lv_obj_t *img = NULL;
// Check for icons.
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
if (!strcmp("icon", kv->key))
icon_path = kv->val;
else if (!strcmp("payload", kv->key))
payload = true;
}
// If icon not found, check res folder for section_name.bmp.
// If not, use defaults.
if (!icon_path)
{
s_printf(tmp_path, "bootloader/res/%s.bmp", ini_sec->name);
bmp = bmp_to_lvimg_obj(tmp_path);
if (!bmp)
{
s_printf(tmp_path, "bootloader/res/%s_hue.bmp", ini_sec->name);
bmp = bmp_to_lvimg_obj(tmp_path);
if (bmp)
img_colorize = true;
}
if (!bmp && payload)
{
bmp = icon_payload;
if (!icon_pl_custom)
img_colorize = true;
}
}
else
{
bmp = bmp_to_lvimg_obj(icon_path);
// Check if colorization is enabled.
if (bmp && strlen(icon_path) > 8 && !memcmp(icon_path + strlen(icon_path) - 8, "_hue", 4))
img_colorize = true;
}
// Enable button.
lv_obj_set_opa_scale(launch_ctxt.btn[curr_btn_idx], LV_OPA_COVER);
// Default to switch logo if no icon found at all.
if (!bmp)
{
bmp = icon_switch;
if (!icon_sw_custom)
img_colorize = true;
}
//Set icon.
if (bmp)
{
img = lv_img_create(launch_ctxt.btn[curr_btn_idx], NULL);
if (img_colorize)
lv_img_set_style(img, &img_style);
lv_img_set_src(img, bmp);
}
// Add button mask/radius and align icon.
lv_obj_t *btn = lv_btn_create(launch_ctxt.btn[curr_btn_idx], NULL);
lv_obj_set_size(btn, 200, 200);
lv_btn_set_style(btn, LV_BTN_STYLE_REL, &btn_home_transp_rel);
lv_btn_set_style(btn, LV_BTN_STYLE_PR, &btn_home_transp_pr);
if (img)
lv_obj_align(img, NULL, LV_ALIGN_CENTER, 0, 0);
// Set autoboot index.
ext = lv_obj_get_ext_attr(btn);
ext->idx = entry_idx;
ext = lv_obj_get_ext_attr(launch_ctxt.btn[curr_btn_idx]); // Redundancy.
ext->idx = entry_idx;
// Set action.
if (!more_cfg)
lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, _launch_action);
else
lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, _launch_more_cfg_action);
// Set button's label text.
lv_label_set_text(launch_ctxt.label[curr_btn_idx], ini_sec->name);
lv_obj_set_opa_scale(launch_ctxt.label[curr_btn_idx], LV_OPA_COVER);
// Set rolling text if name is big.
if (strlen(ini_sec->name) > 22)
lv_label_set_long_mode(launch_ctxt.label[curr_btn_idx], LV_LABEL_LONG_ROLL);
entry_idx++;
curr_btn_idx++;
// Check if we exceed max buttons.
if (curr_btn_idx >= max_entries)
break;
}
}
// Reiterate the loop with more cfgs if combined.
if (combined_cfg && (curr_btn_idx < 8) && !more_cfg)
goto ini_parsing;
} }
if (!ini_parse_success)
goto ini_parse_failed;
// Iterate to all boot entries and load icons.
u32 entry_idx = 1;
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
{
if (!strcmp(ini_sec->name, "config") || (ini_sec->type != INI_CHOICE))
continue;
icon_path = NULL;
bool payload = false;
bool img_colorize = false;
lv_img_dsc_t *bmp = NULL;
lv_obj_t *img = NULL;
// Check for icons.
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
if (!strcmp("icon", kv->key))
icon_path = kv->val;
else if (!strcmp("payload", kv->key))
payload = true;
}
// If icon not found, check res folder for section_name.bmp.
// If not, use defaults.
if (!icon_path)
{
s_printf(tmp_path, "bootloader/res/%s.bmp", ini_sec->name);
bmp = bmp_to_lvimg_obj(tmp_path);
if (!bmp)
{
s_printf(tmp_path, "bootloader/res/%s_hue.bmp", ini_sec->name);
bmp = bmp_to_lvimg_obj(tmp_path);
if (bmp)
img_colorize = true;
}
if (!bmp && payload)
{
bmp = icon_payload;
if (!icon_pl_custom)
img_colorize = true;
}
}
else
{
bmp = bmp_to_lvimg_obj(icon_path);
// Check if colorization is enabled.
if (bmp && strlen(icon_path) > 8 && !memcmp(icon_path + strlen(icon_path) - 8, "_hue", 4))
img_colorize = true;
}
// Enable button.
lv_obj_set_opa_scale(launch_ctxt.btn[curr_btn_idx], LV_OPA_COVER);
// Default to switch logo if no icon found at all.
if (!bmp)
{
bmp = icon_switch;
if (!icon_sw_custom)
img_colorize = true;
}
//Set icon.
if (bmp)
{
img = lv_img_create(launch_ctxt.btn[curr_btn_idx], NULL);
if (img_colorize)
lv_img_set_style(img, &img_style);
lv_img_set_src(img, bmp);
}
// Add button mask/radius and align icon.
lv_obj_t *btn = lv_btn_create(launch_ctxt.btn[curr_btn_idx], NULL);
lv_obj_set_size(btn, 200, 200);
lv_btn_set_style(btn, LV_BTN_STYLE_REL, &btn_home_transp_rel);
lv_btn_set_style(btn, LV_BTN_STYLE_PR, &btn_home_transp_pr);
if (img)
lv_obj_align(img, NULL, LV_ALIGN_CENTER, 0, 0);
// Set autoboot index.
ext = lv_obj_get_ext_attr(btn);
ext->idx = entry_idx;
ext = lv_obj_get_ext_attr(launch_ctxt.btn[curr_btn_idx]); // Redundancy.
ext->idx = entry_idx;
// Set action.
if (!more_cfg)
lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, _launch_action);
else
lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, _launch_more_cfg_action);
// Set button's label text.
lv_label_set_text(launch_ctxt.label[curr_btn_idx], ini_sec->name);
lv_obj_set_opa_scale(launch_ctxt.label[curr_btn_idx], LV_OPA_COVER);
// Set rolling text if name is big.
if (strlen(ini_sec->name) > 22)
lv_label_set_long_mode(launch_ctxt.label[curr_btn_idx], LV_LABEL_LONG_ROLL);
entry_idx++;
curr_btn_idx++;
// Check if we exceed max buttons.
if (curr_btn_idx >= max_entries)
break;
}
ini_parse_failed:
// Reiterate the loop with more cfgs if combined.
if (combined_cfg && (curr_btn_idx < 8) && !more_cfg)
goto ini_parsing;
failed_sd_mount:
if (curr_btn_idx < 1) if (curr_btn_idx < 1)
no_boot_entries = true; no_boot_entries = true;

View file

@ -782,26 +782,27 @@ static lv_res_t _create_mbox_emummc_migrate(lv_obj_t *btn)
for (int i = 1; i < 4; i++) for (int i = 1; i < 4; i++)
{ {
mbr_ctx.sector_start = mbr->partitions[i].start_sct; mbr_ctx.sector_start = mbr->partitions[i].start_sct;
if (mbr_ctx.sector_start)
if (!mbr_ctx.sector_start)
continue;
sdmmc_storage_read(&sd_storage, mbr_ctx.sector_start + 0xC001, 1, efi_part);
if (!memcmp(efi_part, "EFI PART", 8))
{ {
sdmmc_storage_read(&sd_storage, mbr_ctx.sector_start + 0xC001, 1, efi_part); mbr_ctx.sector_start += 0x8000;
emummc = true;
mbr_ctx.part_idx = i;
break;
}
else
{
sdmmc_storage_read(&sd_storage, mbr_ctx.sector_start + 0x4001, 1, efi_part);
if (!memcmp(efi_part, "EFI PART", 8)) if (!memcmp(efi_part, "EFI PART", 8))
{ {
mbr_ctx.sector_start += 0x8000;
emummc = true; emummc = true;
mbr_ctx.part_idx = i; mbr_ctx.part_idx = i;
break; break;
} }
else
{
sdmmc_storage_read(&sd_storage, mbr_ctx.sector_start + 0x4001, 1, efi_part);
if (!memcmp(efi_part, "EFI PART", 8))
{
emummc = true;
mbr_ctx.part_idx = i;
break;
}
}
} }
} }

View file

@ -1329,194 +1329,197 @@ static lv_res_t _create_mbox_benchmark(bool sd_bench)
} }
if (res) if (res)
lv_mbox_set_text(mbox, "#FFDD00 Failed to init Storage!#");
else
{ {
int error = 0; lv_mbox_set_text(mbox, "#FFDD00 Failed to init Storage!#");
u32 iters = 3; goto out;
u32 offset_chunk_start = ALIGN_DOWN(storage->sec_cnt / 3, 0x8000); // Align to 16MB. }
if (storage->sec_cnt < 0xC00000)
iters -= 2; // 4GB card.
for (u32 iter_curr = 0; iter_curr < iters; iter_curr++) int error = 0;
u32 iters = 3;
u32 offset_chunk_start = ALIGN_DOWN(storage->sec_cnt / 3, 0x8000); // Align to 16MB.
if (storage->sec_cnt < 0xC00000)
iters -= 2; // 4GB card.
for (u32 iter_curr = 0; iter_curr < iters; iter_curr++)
{
u32 pct = 0;
u32 prevPct = 200;
u32 timer = 0;
u32 lba_curr = 0;
u32 sector = offset_chunk_start * iter_curr;
u32 sector_num = 0x8000; // 16MB chunks.
u32 data_remaining = 0x200000; // 1GB.
s_printf(txt_buf + strlen(txt_buf), "#C7EA46 %d/3# - Sector Offset #C7EA46 %08X#:\n", iter_curr + 1, sector);
while (data_remaining)
{ {
u32 pct = 0; u32 time_taken = get_tmr_us();
u32 prevPct = 200; error = !sdmmc_storage_read(storage, sector + lba_curr, sector_num, (u8 *)MIXD_BUF_ALIGNED);
u32 timer = 0; time_taken = get_tmr_us() - time_taken;
u32 lba_curr = 0; timer += time_taken;
u32 sector = offset_chunk_start * iter_curr;
u32 sector_num = 0x8000; // 16MB chunks.
u32 data_remaining = 0x200000; // 1GB.
s_printf(txt_buf + strlen(txt_buf), "#C7EA46 %d/3# - Sector Offset #C7EA46 %08X#:\n", iter_curr + 1, sector); manual_system_maintenance(false);
data_remaining -= sector_num;
lba_curr += sector_num;
while (data_remaining) pct = (lba_curr * 100) / 0x200000;
if (pct != prevPct)
{ {
u32 time_taken = get_tmr_us(); lv_bar_set_value(bar, pct);
error = !sdmmc_storage_read(storage, sector + lba_curr, sector_num, (u8 *)MIXD_BUF_ALIGNED); manual_system_maintenance(true);
time_taken = get_tmr_us() - time_taken;
timer += time_taken;
manual_system_maintenance(false); prevPct = pct;
data_remaining -= sector_num;
lba_curr += sector_num;
pct = (lba_curr * 100) / 0x200000; if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))
if (pct != prevPct) error = -1;
{
lv_bar_set_value(bar, pct);
manual_system_maintenance(true);
prevPct = pct;
if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))
error = -1;
}
if (error)
goto error;
}
lv_bar_set_value(bar, 100);
u32 rate_1k = ((u64)1024 * 1000 * 1000 * 1000) / timer;
s_printf(txt_buf + strlen(txt_buf),
" Sequential 16MiB - Rate: #C7EA46 %3d.%02d MiB/s#\n",
rate_1k / 1000, (rate_1k % 1000) / 10);
lv_label_set_text(lbl_status, txt_buf);
lv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0);
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
manual_system_maintenance(true);
pct = 0;
prevPct = 200;
timer = 0;
lba_curr = 0;
sector_num = 8; // 4KB chunks.
data_remaining = 0x100000; // 512MB.
while (data_remaining)
{
u32 time_taken = get_tmr_us();
error = !sdmmc_storage_read(storage, sector + lba_curr, sector_num, (u8 *)MIXD_BUF_ALIGNED);
time_taken = get_tmr_us() - time_taken;
timer += time_taken;
manual_system_maintenance(false);
data_remaining -= sector_num;
lba_curr += sector_num;
pct = (lba_curr * 100) / 0x100000;
if (pct != prevPct)
{
lv_bar_set_value(bar, pct);
manual_system_maintenance(true);
prevPct = pct;
if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))
error = -1;
}
if (error)
goto error;
}
lv_bar_set_value(bar, 100);
rate_1k = ((u64)512 * 1000 * 1000 * 1000) / timer;
u32 iops_1k = ((u64)512 * 1024 * 1000 * 1000 * 1000) / (4096 / 1024) / timer / 1000;
s_printf(txt_buf + strlen(txt_buf),
" Sequential 4KiB - Rate: #C7EA46 %3d.%02d MiB/s#, IOPS: #C7EA46 %4d#\n",
rate_1k / 1000, (rate_1k % 1000) / 10, iops_1k);
lv_label_set_text(lbl_status, txt_buf);
lv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0);
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
manual_system_maintenance(true);
u32 lba_idx = 0;
u32 *random_offsets = malloc(0x20000 * sizeof(u32));
u32 random_numbers[4];
for (u32 i = 0; i < 0x20000; i += 4)
{
// Generate new random numbers.
while (!se_gen_prng128(random_numbers))
;
// Clamp offsets to 512MBrange.
random_offsets[i + 0] = random_numbers[0] % 0x100000;
random_offsets[i + 1] = random_numbers[1] % 0x100000;
random_offsets[i + 2] = random_numbers[2] % 0x100000;
random_offsets[i + 3] = random_numbers[3] % 0x100000;
} }
pct = 0; if (error)
prevPct = 200; goto error;
timer = 0;
data_remaining = 0x100000; // 512MB.
while (data_remaining)
{
u32 time_taken = get_tmr_us();
error = !sdmmc_storage_read(storage, sector + random_offsets[lba_idx], sector_num, (u8 *)MIXD_BUF_ALIGNED);
time_taken = get_tmr_us() - time_taken;
timer += time_taken;
manual_system_maintenance(false);
data_remaining -= sector_num;
lba_idx++;
pct = (lba_idx * 100) / 0x20000;
if (pct != prevPct)
{
lv_bar_set_value(bar, pct);
manual_system_maintenance(true);
prevPct = pct;
if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))
error = -1;
}
if (error)
{
free(random_offsets);
goto error;
}
}
lv_bar_set_value(bar, 100);
// Calculate rate and IOPS for 512MB transfer.
rate_1k = ((u64)512 * 1000 * 1000 * 1000) / timer;
iops_1k = ((u64)512 * 1024 * 1000 * 1000 * 1000) / (4096 / 1024) / timer / 1000;
s_printf(txt_buf + strlen(txt_buf),
" Random 4KiB - Rate: #C7EA46 %3d.%02d MiB/s#, IOPS: #C7EA46 %4d#\n",
rate_1k / 1000, (rate_1k % 1000) / 10, iops_1k);
if (iter_curr == iters - 1)
txt_buf[strlen(txt_buf) - 1] = 0; // Cut off last line change.
lv_label_set_text(lbl_status, txt_buf);
lv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0);
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
manual_system_maintenance(true);
free(random_offsets);
} }
lv_bar_set_value(bar, 100);
u32 rate_1k = ((u64)1024 * 1000 * 1000 * 1000) / timer;
s_printf(txt_buf + strlen(txt_buf),
" Sequential 16MiB - Rate: #C7EA46 %3d.%02d MiB/s#\n",
rate_1k / 1000, (rate_1k % 1000) / 10);
lv_label_set_text(lbl_status, txt_buf);
lv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0);
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
manual_system_maintenance(true);
pct = 0;
prevPct = 200;
timer = 0;
lba_curr = 0;
sector_num = 8; // 4KB chunks.
data_remaining = 0x100000; // 512MB.
while (data_remaining)
{
u32 time_taken = get_tmr_us();
error = !sdmmc_storage_read(storage, sector + lba_curr, sector_num, (u8 *)MIXD_BUF_ALIGNED);
time_taken = get_tmr_us() - time_taken;
timer += time_taken;
manual_system_maintenance(false);
data_remaining -= sector_num;
lba_curr += sector_num;
pct = (lba_curr * 100) / 0x100000;
if (pct != prevPct)
{
lv_bar_set_value(bar, pct);
manual_system_maintenance(true);
prevPct = pct;
if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))
error = -1;
}
if (error)
goto error;
}
lv_bar_set_value(bar, 100);
rate_1k = ((u64)512 * 1000 * 1000 * 1000) / timer;
u32 iops_1k = ((u64)512 * 1024 * 1000 * 1000 * 1000) / (4096 / 1024) / timer / 1000;
s_printf(txt_buf + strlen(txt_buf),
" Sequential 4KiB - Rate: #C7EA46 %3d.%02d MiB/s#, IOPS: #C7EA46 %4d#\n",
rate_1k / 1000, (rate_1k % 1000) / 10, iops_1k);
lv_label_set_text(lbl_status, txt_buf);
lv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0);
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
manual_system_maintenance(true);
u32 lba_idx = 0;
u32 *random_offsets = malloc(0x20000 * sizeof(u32));
u32 random_numbers[4];
for (u32 i = 0; i < 0x20000; i += 4)
{
// Generate new random numbers.
while (!se_gen_prng128(random_numbers))
;
// Clamp offsets to 512MBrange.
random_offsets[i + 0] = random_numbers[0] % 0x100000;
random_offsets[i + 1] = random_numbers[1] % 0x100000;
random_offsets[i + 2] = random_numbers[2] % 0x100000;
random_offsets[i + 3] = random_numbers[3] % 0x100000;
}
pct = 0;
prevPct = 200;
timer = 0;
data_remaining = 0x100000; // 512MB.
while (data_remaining)
{
u32 time_taken = get_tmr_us();
error = !sdmmc_storage_read(storage, sector + random_offsets[lba_idx], sector_num, (u8 *)MIXD_BUF_ALIGNED);
time_taken = get_tmr_us() - time_taken;
timer += time_taken;
manual_system_maintenance(false);
data_remaining -= sector_num;
lba_idx++;
pct = (lba_idx * 100) / 0x20000;
if (pct != prevPct)
{
lv_bar_set_value(bar, pct);
manual_system_maintenance(true);
prevPct = pct;
if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))
error = -1;
}
if (error)
{
free(random_offsets);
goto error;
}
}
lv_bar_set_value(bar, 100);
// Calculate rate and IOPS for 512MB transfer.
rate_1k = ((u64)512 * 1000 * 1000 * 1000) / timer;
iops_1k = ((u64)512 * 1024 * 1000 * 1000 * 1000) / (4096 / 1024) / timer / 1000;
s_printf(txt_buf + strlen(txt_buf),
" Random 4KiB - Rate: #C7EA46 %3d.%02d MiB/s#, IOPS: #C7EA46 %4d#\n",
rate_1k / 1000, (rate_1k % 1000) / 10, iops_1k);
if (iter_curr == iters - 1)
txt_buf[strlen(txt_buf) - 1] = 0; // Cut off last line change.
lv_label_set_text(lbl_status, txt_buf);
lv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0);
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
manual_system_maintenance(true);
free(random_offsets);
}
error: error:
if (error) if (error)
{ {
if (error == -1) if (error == -1)
s_printf(txt_buf + strlen(txt_buf), "\n#FFDD00 Aborted!#"); s_printf(txt_buf + strlen(txt_buf), "\n#FFDD00 Aborted!#");
else
s_printf(txt_buf + strlen(txt_buf), "\n#FFDD00 IO Error occurred!#");
lv_label_set_text(lbl_status, txt_buf);
lv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0);
}
lv_obj_del(bar);
if (sd_bench)
sd_unmount();
else else
sdmmc_storage_end(&emmc_storage); s_printf(txt_buf + strlen(txt_buf), "\n#FFDD00 IO Error occurred!#");
lv_label_set_text(lbl_status, txt_buf);
lv_obj_align(lbl_status, NULL, LV_ALIGN_CENTER, 0, 0);
} }
lv_obj_del(bar);
if (sd_bench)
sd_unmount();
else
sdmmc_storage_end(&emmc_storage);
out:
free(txt_buf); free(txt_buf);
lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); // Important. After set_text. lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); // Important. After set_text.
@ -1559,233 +1562,234 @@ static lv_res_t _create_window_emmc_info_status(lv_obj_t *btn)
{ {
lv_label_set_text(lb_desc, "#FFDD00 Failed to init eMMC!#"); lv_label_set_text(lb_desc, "#FFDD00 Failed to init eMMC!#");
lv_obj_set_width(lb_desc, lv_obj_get_width(desc)); lv_obj_set_width(lb_desc, lv_obj_get_width(desc));
goto out;
} }
else
u32 speed = 0;
char *rsvd_blocks;
char life_a_txt[8];
char life_b_txt[8];
u32 cache = emmc_storage.ext_csd.cache_size;
u32 life_a = emmc_storage.ext_csd.dev_life_est_a;
u32 life_b = emmc_storage.ext_csd.dev_life_est_b;
u16 card_type = emmc_storage.ext_csd.card_type;
char card_type_support[96];
card_type_support[0] = 0;
// Identify manufacturer. Only official eMMCs.
switch (emmc_storage.cid.manfid)
{ {
u32 speed = 0; case 0x11:
char *rsvd_blocks; strcat(txt_buf, "Toshiba ");
char life_a_txt[8]; break;
char life_b_txt[8]; case 0x15:
u32 cache = emmc_storage.ext_csd.cache_size; strcat(txt_buf, "Samsung ");
u32 life_a = emmc_storage.ext_csd.dev_life_est_a; break;
u32 life_b = emmc_storage.ext_csd.dev_life_est_b; case 0x45: // Unofficial.
u16 card_type = emmc_storage.ext_csd.card_type; strcat(txt_buf, "SanDisk ");
char card_type_support[96]; lv_win_add_btn(win, NULL, SYMBOL_FILE_ALT" Device Report", _create_mbox_emmc_sandisk_report);
card_type_support[0] = 0; break;
case 0x90:
// Identify manufacturer. Only official eMMCs. strcat(txt_buf, "SK Hynix ");
switch (emmc_storage.cid.manfid) break;
{
case 0x11:
strcat(txt_buf, "Toshiba ");
break;
case 0x15:
strcat(txt_buf, "Samsung ");
break;
case 0x45: // Unofficial.
strcat(txt_buf, "SanDisk ");
lv_win_add_btn(win, NULL, SYMBOL_FILE_ALT" Device Report", _create_mbox_emmc_sandisk_report);
break;
case 0x90:
strcat(txt_buf, "SK Hynix ");
break;
}
s_printf(txt_buf + strlen(txt_buf), "(%02X)\n%c%c%c%c%c%c\n%d.%d\n%04X\n%02d/%04d\n\n",
emmc_storage.cid.manfid,
emmc_storage.cid.prod_name[0], emmc_storage.cid.prod_name[1], emmc_storage.cid.prod_name[2],
emmc_storage.cid.prod_name[3], emmc_storage.cid.prod_name[4], emmc_storage.cid.prod_name[5],
emmc_storage.cid.prv & 0xF, emmc_storage.cid.prv >> 4,
emmc_storage.cid.serial, emmc_storage.cid.month, emmc_storage.cid.year);
if (card_type & EXT_CSD_CARD_TYPE_HS_26)
{
strcat(card_type_support, "HS26");
speed = (26 << 16) | 26;
}
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
{
strcat(card_type_support, ", HS52");
speed = (52 << 16) | 52;
}
if (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
{
strcat(card_type_support, ", DDR52 1.8V");
speed = (52 << 16) | 104;
}
if (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
{
strcat(card_type_support, ", HS200 1.8V");
speed = (200 << 16) | 200;
}
if (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)
{
strcat(card_type_support, ", HS400 1.8V");
speed = (200 << 16) | 400;
}
strcpy(life_a_txt, "-");
strcpy(life_b_txt, "-");
// Normalize cells life.
if (life_a) // SK Hynix is 0 (undefined).
{
life_a--;
life_a = (10 - life_a) * 10;
s_printf(life_a_txt, "%d%%", life_a);
}
if (life_b) // Toshiba is 0 (undefined).
{
life_b--;
life_b = (10 - life_b) * 10;
s_printf(life_b_txt, "%d%%", life_b);
}
switch (emmc_storage.ext_csd.pre_eol_info)
{
case 1:
rsvd_blocks = "Normal (< 80%)";
break;
case 2:
rsvd_blocks = "Warning (> 80%)";
break;
case 3:
rsvd_blocks = "Critical (> 90%)";
break;
default:
rsvd_blocks = "#FF8000 Unknown#";
break;
}
s_printf(txt_buf + strlen(txt_buf),
"#00DDFF V1.%d (rev 1.%d)#\n%02X\n%d MB/s (%d MHz)\n%d MB/s\n%s\n%d %s\n%d MiB\nA: %s, B: %s\n%s",
emmc_storage.ext_csd.ext_struct, emmc_storage.ext_csd.rev,
emmc_storage.csd.cmdclass, speed & 0xFFFF, (speed >> 16) & 0xFFFF,
emmc_storage.csd.busspeed, card_type_support,
!(cache % 1024) ? (cache / 1024) : cache, !(cache % 1024) ? "MiB" : "KiB",
emmc_storage.ext_csd.max_enh_mult * 512 / 1024,
life_a_txt, life_b_txt, rsvd_blocks);
lv_label_set_static_text(lb_desc,
"#00DDFF CID:#\n"
"Vendor ID:\n"
"Model:\n"
"Prod Rev:\n"
"S/N:\n"
"Month/Year:\n\n"
"#00DDFF Ext CSD:#\n"
"Cmd Classes:\n"
"Max Rate:\n"
"Current Rate:\n"
"Type Support:\n\n"
"Write Cache:\n"
"Enhanced Area:\n"
"Estimated Life:\n"
"Reserved Used:"
);
lv_obj_set_width(lb_desc, lv_obj_get_width(desc));
lv_obj_t *val = lv_cont_create(win, NULL);
lv_obj_set_size(val, LV_HOR_RES / 11 * 3, LV_VER_RES - (LV_DPI * 11 / 7) - 5);
lv_obj_t * lb_val = lv_label_create(val, lb_desc);
lv_label_set_text(lb_val, txt_buf);
lv_obj_set_width(lb_val, lv_obj_get_width(val));
lv_obj_align(val, desc, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
lv_obj_t *desc2 = lv_cont_create(win, NULL);
lv_obj_set_size(desc2, LV_HOR_RES / 2 / 4 * 4, LV_VER_RES - (LV_DPI * 11 / 7) - 5);
lv_obj_t * lb_desc2 = lv_label_create(desc2, lb_desc);
lv_label_set_style(lb_desc2, &monospace_text);
u32 boot_size = emmc_storage.ext_csd.boot_mult << 17;
u32 rpmb_size = emmc_storage.ext_csd.rpmb_mult << 17;
strcpy(txt_buf, "#00DDFF eMMC Physical Partitions:#\n");
s_printf(txt_buf + strlen(txt_buf), "1: #96FF00 BOOT0# Size: %6d KiB (Sect: 0x%08X)\n", boot_size / 1024, boot_size / 512);
s_printf(txt_buf + strlen(txt_buf), "2: #96FF00 BOOT1# Size: %6d KiB (Sect: 0x%08X)\n", boot_size / 1024, boot_size / 512);
s_printf(txt_buf + strlen(txt_buf), "3: #96FF00 RPMB# Size: %6d KiB (Sect: 0x%08X)\n", rpmb_size / 1024, rpmb_size / 512);
s_printf(txt_buf + strlen(txt_buf), "0: #96FF00 GPP# Size: %6d MiB (Sect: 0x%08X)\n", emmc_storage.sec_cnt >> SECTORS_TO_MIB_COEFF, emmc_storage.sec_cnt);
strcat(txt_buf, "\n#00DDFF GPP (eMMC USER) Partition Table:#\n");
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
LIST_INIT(gpt);
emmc_gpt_parse(&gpt);
u32 idx = 0;
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
{
if (idx > 10)
{
strcat(txt_buf, "#FFDD00 Table does not fit on screen!#");
break;
}
if (part->index < 2)
{
s_printf(txt_buf + strlen(txt_buf), "%02d: #96FF00 %s#%s Size: %d MiB (Sect: 0x%X), Start: %06X\n",
part->index, part->name, !part->name[8] ? " " : "",
(part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF,
part->lba_end - part->lba_start + 1, part->lba_start);
}
else
{
s_printf(txt_buf + strlen(txt_buf), "%02d: #96FF00 %s#\n Size: %7d MiB (Sect: 0x%07X), Start: %07X\n",
part->index, part->name, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF,
part->lba_end - part->lba_start + 1, part->lba_start);
}
idx++;
}
if (!idx)
strcat(txt_buf, "#FFDD00 Partition table is empty!#");
emmc_gpt_free(&gpt);
lv_label_set_text(lb_desc2, txt_buf);
lv_obj_set_width(lb_desc2, lv_obj_get_width(desc2));
lv_obj_align(desc2, val, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 6, 0);
u16 *emmc_errors = emmc_get_error_count();
if (emmc_get_mode() < EMMC_MMC_HS400 ||
emmc_errors[EMMC_ERROR_INIT_FAIL] ||
emmc_errors[EMMC_ERROR_RW_FAIL] ||
emmc_errors[EMMC_ERROR_RW_RETRY])
{
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
lv_obj_set_style(dark_bg, &mbox_darken);
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
static const char * mbox_btn_map[] = { "\211", "\222OK", "\211", "" };
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
lv_mbox_set_recolor_text(mbox, true);
s_printf(txt_buf,
"#FF8000 eMMC Issues Check#\n\n"
"#FFDD00 Your eMMC is initialized in slower mode,#\n"
"#FFDD00 or init/read/write errors occurred!#\n"
"#FFDD00 This might mean hardware issues!#\n\n"
"#00DDFF Bus Speed:# %d MB/s\n\n"
"#00DDFF SDMMC4 Errors:#\n"
"Init fails: %d\n"
"Read/Write fails: %d\n"
"Read/Write errors: %d",
emmc_storage.csd.busspeed,
emmc_errors[EMMC_ERROR_INIT_FAIL],
emmc_errors[EMMC_ERROR_RW_FAIL],
emmc_errors[EMMC_ERROR_RW_RETRY]);
lv_mbox_set_text(mbox, txt_buf);
lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_top(mbox, true);
}
} }
s_printf(txt_buf + strlen(txt_buf), "(%02X)\n%c%c%c%c%c%c\n%d.%d\n%04X\n%02d/%04d\n\n",
emmc_storage.cid.manfid,
emmc_storage.cid.prod_name[0], emmc_storage.cid.prod_name[1], emmc_storage.cid.prod_name[2],
emmc_storage.cid.prod_name[3], emmc_storage.cid.prod_name[4], emmc_storage.cid.prod_name[5],
emmc_storage.cid.prv & 0xF, emmc_storage.cid.prv >> 4,
emmc_storage.cid.serial, emmc_storage.cid.month, emmc_storage.cid.year);
if (card_type & EXT_CSD_CARD_TYPE_HS_26)
{
strcat(card_type_support, "HS26");
speed = (26 << 16) | 26;
}
if (card_type & EXT_CSD_CARD_TYPE_HS_52)
{
strcat(card_type_support, ", HS52");
speed = (52 << 16) | 52;
}
if (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
{
strcat(card_type_support, ", DDR52 1.8V");
speed = (52 << 16) | 104;
}
if (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
{
strcat(card_type_support, ", HS200 1.8V");
speed = (200 << 16) | 200;
}
if (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)
{
strcat(card_type_support, ", HS400 1.8V");
speed = (200 << 16) | 400;
}
strcpy(life_a_txt, "-");
strcpy(life_b_txt, "-");
// Normalize cells life.
if (life_a) // SK Hynix is 0 (undefined).
{
life_a--;
life_a = (10 - life_a) * 10;
s_printf(life_a_txt, "%d%%", life_a);
}
if (life_b) // Toshiba is 0 (undefined).
{
life_b--;
life_b = (10 - life_b) * 10;
s_printf(life_b_txt, "%d%%", life_b);
}
switch (emmc_storage.ext_csd.pre_eol_info)
{
case 1:
rsvd_blocks = "Normal (< 80%)";
break;
case 2:
rsvd_blocks = "Warning (> 80%)";
break;
case 3:
rsvd_blocks = "Critical (> 90%)";
break;
default:
rsvd_blocks = "#FF8000 Unknown#";
break;
}
s_printf(txt_buf + strlen(txt_buf),
"#00DDFF V1.%d (rev 1.%d)#\n%02X\n%d MB/s (%d MHz)\n%d MB/s\n%s\n%d %s\n%d MiB\nA: %s, B: %s\n%s",
emmc_storage.ext_csd.ext_struct, emmc_storage.ext_csd.rev,
emmc_storage.csd.cmdclass, speed & 0xFFFF, (speed >> 16) & 0xFFFF,
emmc_storage.csd.busspeed, card_type_support,
!(cache % 1024) ? (cache / 1024) : cache, !(cache % 1024) ? "MiB" : "KiB",
emmc_storage.ext_csd.max_enh_mult * 512 / 1024,
life_a_txt, life_b_txt, rsvd_blocks);
lv_label_set_static_text(lb_desc,
"#00DDFF CID:#\n"
"Vendor ID:\n"
"Model:\n"
"Prod Rev:\n"
"S/N:\n"
"Month/Year:\n\n"
"#00DDFF Ext CSD:#\n"
"Cmd Classes:\n"
"Max Rate:\n"
"Current Rate:\n"
"Type Support:\n\n"
"Write Cache:\n"
"Enhanced Area:\n"
"Estimated Life:\n"
"Reserved Used:"
);
lv_obj_set_width(lb_desc, lv_obj_get_width(desc));
lv_obj_t *val = lv_cont_create(win, NULL);
lv_obj_set_size(val, LV_HOR_RES / 11 * 3, LV_VER_RES - (LV_DPI * 11 / 7) - 5);
lv_obj_t * lb_val = lv_label_create(val, lb_desc);
lv_label_set_text(lb_val, txt_buf);
lv_obj_set_width(lb_val, lv_obj_get_width(val));
lv_obj_align(val, desc, LV_ALIGN_OUT_RIGHT_MID, 0, 0);
lv_obj_t *desc2 = lv_cont_create(win, NULL);
lv_obj_set_size(desc2, LV_HOR_RES / 2 / 4 * 4, LV_VER_RES - (LV_DPI * 11 / 7) - 5);
lv_obj_t * lb_desc2 = lv_label_create(desc2, lb_desc);
lv_label_set_style(lb_desc2, &monospace_text);
u32 boot_size = emmc_storage.ext_csd.boot_mult << 17;
u32 rpmb_size = emmc_storage.ext_csd.rpmb_mult << 17;
strcpy(txt_buf, "#00DDFF eMMC Physical Partitions:#\n");
s_printf(txt_buf + strlen(txt_buf), "1: #96FF00 BOOT0# Size: %6d KiB (Sect: 0x%08X)\n", boot_size / 1024, boot_size / 512);
s_printf(txt_buf + strlen(txt_buf), "2: #96FF00 BOOT1# Size: %6d KiB (Sect: 0x%08X)\n", boot_size / 1024, boot_size / 512);
s_printf(txt_buf + strlen(txt_buf), "3: #96FF00 RPMB# Size: %6d KiB (Sect: 0x%08X)\n", rpmb_size / 1024, rpmb_size / 512);
s_printf(txt_buf + strlen(txt_buf), "0: #96FF00 GPP# Size: %6d MiB (Sect: 0x%08X)\n", emmc_storage.sec_cnt >> SECTORS_TO_MIB_COEFF, emmc_storage.sec_cnt);
strcat(txt_buf, "\n#00DDFF GPP (eMMC USER) Partition Table:#\n");
sdmmc_storage_set_mmc_partition(&emmc_storage, EMMC_GPP);
LIST_INIT(gpt);
emmc_gpt_parse(&gpt);
u32 idx = 0;
LIST_FOREACH_ENTRY(emmc_part_t, part, &gpt, link)
{
if (idx > 10)
{
strcat(txt_buf, "#FFDD00 Table does not fit on screen!#");
break;
}
if (part->index < 2)
{
s_printf(txt_buf + strlen(txt_buf), "%02d: #96FF00 %s#%s Size: %d MiB (Sect: 0x%X), Start: %06X\n",
part->index, part->name, !part->name[8] ? " " : "",
(part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF,
part->lba_end - part->lba_start + 1, part->lba_start);
}
else
{
s_printf(txt_buf + strlen(txt_buf), "%02d: #96FF00 %s#\n Size: %7d MiB (Sect: 0x%07X), Start: %07X\n",
part->index, part->name, (part->lba_end - part->lba_start + 1) >> SECTORS_TO_MIB_COEFF,
part->lba_end - part->lba_start + 1, part->lba_start);
}
idx++;
}
if (!idx)
strcat(txt_buf, "#FFDD00 Partition table is empty!#");
emmc_gpt_free(&gpt);
lv_label_set_text(lb_desc2, txt_buf);
lv_obj_set_width(lb_desc2, lv_obj_get_width(desc2));
lv_obj_align(desc2, val, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 6, 0);
u16 *emmc_errors = emmc_get_error_count();
if (emmc_get_mode() < EMMC_MMC_HS400 ||
emmc_errors[EMMC_ERROR_INIT_FAIL] ||
emmc_errors[EMMC_ERROR_RW_FAIL] ||
emmc_errors[EMMC_ERROR_RW_RETRY])
{
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
lv_obj_set_style(dark_bg, &mbox_darken);
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
static const char * mbox_btn_map[] = { "\211", "\222OK", "\211", "" };
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
lv_mbox_set_recolor_text(mbox, true);
s_printf(txt_buf,
"#FF8000 eMMC Issues Check#\n\n"
"#FFDD00 Your eMMC is initialized in slower mode,#\n"
"#FFDD00 or init/read/write errors occurred!#\n"
"#FFDD00 This might mean hardware issues!#\n\n"
"#00DDFF Bus Speed:# %d MB/s\n\n"
"#00DDFF SDMMC4 Errors:#\n"
"Init fails: %d\n"
"Read/Write fails: %d\n"
"Read/Write errors: %d",
emmc_storage.csd.busspeed,
emmc_errors[EMMC_ERROR_INIT_FAIL],
emmc_errors[EMMC_ERROR_RW_FAIL],
emmc_errors[EMMC_ERROR_RW_RETRY]);
lv_mbox_set_text(mbox, txt_buf);
lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 5);
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_top(mbox, true);
}
out:
sdmmc_storage_end(&emmc_storage); sdmmc_storage_end(&emmc_storage);
free(txt_buf); free(txt_buf);

View file

@ -993,66 +993,67 @@ static lv_res_t _create_mbox_fix_touchscreen(lv_obj_t *btn)
} }
u8 err[2]; u8 err[2];
if (touch_panel_ito_test(err)) if (!touch_panel_ito_test(err))
goto ito_failed;
if (!err[0] && !err[1])
{ {
if (!err[0] && !err[1]) res = touch_execute_autotune();
{ if (res)
res = touch_execute_autotune(); goto out;
if (res) }
goto out; else
} {
else touch_sense_enable();
{
touch_sense_enable();
s_printf(txt_buf, "#FFFF00 ITO Test: "); s_printf(txt_buf, "#FFFF00 ITO Test: ");
switch (err[0]) switch (err[0])
{ {
case ITO_FORCE_OPEN: case ITO_FORCE_OPEN:
strcat(txt_buf, "Force Open"); strcat(txt_buf, "Force Open");
break; break;
case ITO_SENSE_OPEN: case ITO_SENSE_OPEN:
strcat(txt_buf, "Sense Open"); strcat(txt_buf, "Sense Open");
break; break;
case ITO_FORCE_SHRT_GND: case ITO_FORCE_SHRT_GND:
strcat(txt_buf, "Force Short to GND"); strcat(txt_buf, "Force Short to GND");
break; break;
case ITO_SENSE_SHRT_GND: case ITO_SENSE_SHRT_GND:
strcat(txt_buf, "Sense Short to GND"); strcat(txt_buf, "Sense Short to GND");
break; break;
case ITO_FORCE_SHRT_VCM: case ITO_FORCE_SHRT_VCM:
strcat(txt_buf, "Force Short to VDD"); strcat(txt_buf, "Force Short to VDD");
break; break;
case ITO_SENSE_SHRT_VCM: case ITO_SENSE_SHRT_VCM:
strcat(txt_buf, "Sense Short to VDD"); strcat(txt_buf, "Sense Short to VDD");
break; break;
case ITO_FORCE_SHRT_FORCE: case ITO_FORCE_SHRT_FORCE:
strcat(txt_buf, "Force Short to Force"); strcat(txt_buf, "Force Short to Force");
break; break;
case ITO_SENSE_SHRT_SENSE: case ITO_SENSE_SHRT_SENSE:
strcat(txt_buf, "Sense Short to Sense"); strcat(txt_buf, "Sense Short to Sense");
break; break;
case ITO_F2E_SENSE: case ITO_F2E_SENSE:
strcat(txt_buf, "Force Short to Sense"); strcat(txt_buf, "Force Short to Sense");
break; break;
case ITO_FPC_FORCE_OPEN: case ITO_FPC_FORCE_OPEN:
strcat(txt_buf, "FPC Force Open"); strcat(txt_buf, "FPC Force Open");
break; break;
case ITO_FPC_SENSE_OPEN: case ITO_FPC_SENSE_OPEN:
strcat(txt_buf, "FPC Sense Open"); strcat(txt_buf, "FPC Sense Open");
break; break;
default: default:
strcat(txt_buf, "Unknown"); strcat(txt_buf, "Unknown");
break; break;
}
s_printf(txt_buf + strlen(txt_buf), " (%d), Chn: %d#\n\n", err[0], err[1]);
strcat(txt_buf, "#FFFF00 The touchscreen calibration failed!");
lv_mbox_set_text(mbox, txt_buf);
goto out2;
} }
s_printf(txt_buf + strlen(txt_buf), " (%d), Chn: %d#\n\n", err[0], err[1]);
strcat(txt_buf, "#FFFF00 The touchscreen calibration failed!");
lv_mbox_set_text(mbox, txt_buf);
goto out2;
} }
ito_failed:
touch_sense_enable(); touch_sense_enable();
out: out:

View file

@ -540,183 +540,183 @@ static lv_res_t _action_flash_linux_data(lv_obj_t * btns, const char * txt)
bool succeeded = false; bool succeeded = false;
if (btn_idx)
return LV_RES_INV;
// Flash Linux. // Flash Linux.
if (!btn_idx) lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
lv_obj_set_style(dark_bg, &mbox_darken);
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
static const char *mbox_btn_map[] = { "\211", "\222OK", "\211", "" };
static const char *mbox_btn_map2[] = { "\223Delete Installation Files", "\221OK", "" };
lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);
lv_mbox_set_recolor_text(mbox, true);
lv_obj_set_width(mbox, LV_HOR_RES / 10 * 5);
lv_mbox_set_text(mbox, "#FF8000 Linux Flasher#");
lv_obj_t *lbl_status = lv_label_create(mbox, NULL);
lv_label_set_recolor(lbl_status, true);
lv_label_set_text(lbl_status, "#C7EA46 Status:# Flashing Linux...");
// Create container to keep content inside.
lv_obj_t *h1 = lv_cont_create(mbox, NULL);
lv_cont_set_fit(h1, true, true);
lv_cont_set_style(h1, &lv_style_transp_tight);
lv_obj_t *bar = lv_bar_create(h1, NULL);
lv_obj_set_size(bar, LV_DPI * 30 / 10, LV_DPI / 5);
lv_bar_set_range(bar, 0, 100);
lv_bar_set_value(bar, 0);
lv_obj_t *label_pct = lv_label_create(h1, NULL);
lv_label_set_recolor(label_pct, true);
lv_label_set_text(label_pct, " "SYMBOL_DOT" 0%");
lv_label_set_style(label_pct, lv_theme_get_current()->label.prim);
lv_obj_align(label_pct, bar, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 20, 0);
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_top(mbox, true);
sd_mount();
int res = 0;
char *path = malloc(1024);
char *txt_buf = malloc(SZ_4K);
strcpy(path, "switchroot/install/l4t.00");
u32 path_len = strlen(path) - 2;
FIL fp;
res = f_open(&fp, path, FA_READ);
if (res)
{ {
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to open 1st part!");
lv_obj_set_style(dark_bg, &mbox_darken);
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
static const char *mbox_btn_map[] = { "\211", "\222OK", "\211", "" }; goto exit;
static const char *mbox_btn_map2[] = { "\223Delete Installation Files", "\221OK", "" }; }
lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);
lv_mbox_set_recolor_text(mbox, true);
lv_obj_set_width(mbox, LV_HOR_RES / 10 * 5);
lv_mbox_set_text(mbox, "#FF8000 Linux Flasher#"); u64 fileSize = (u64)f_size(&fp);
lv_obj_t *lbl_status = lv_label_create(mbox, NULL); u32 num = 0;
lv_label_set_recolor(lbl_status, true); u32 pct = 0;
lv_label_set_text(lbl_status, "#C7EA46 Status:# Flashing Linux..."); u32 lba_curr = 0;
u32 bytesWritten = 0;
u32 currPartIdx = 0;
u32 prevPct = 200;
int retryCount = 0;
u32 total_size_sct = l4t_flash_ctxt.image_size_sct;
// Create container to keep content inside. u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
lv_obj_t *h1 = lv_cont_create(mbox, NULL); DWORD *clmt = f_expand_cltbl(&fp, SZ_4M, 0);
lv_cont_set_fit(h1, true, true);
lv_cont_set_style(h1, &lv_style_transp_tight);
lv_obj_t *bar = lv_bar_create(h1, NULL); while (total_size_sct > 0)
lv_obj_set_size(bar, LV_DPI * 30 / 10, LV_DPI / 5); {
lv_bar_set_range(bar, 0, 100); // If we have more than one part, check the size for the split parts and make sure that the bytes written is not more than that.
lv_bar_set_value(bar, 0); if (bytesWritten >= fileSize)
lv_obj_t *label_pct = lv_label_create(h1, NULL);
lv_label_set_recolor(label_pct, true);
lv_label_set_text(label_pct, " "SYMBOL_DOT" 0%");
lv_label_set_style(label_pct, lv_theme_get_current()->label.prim);
lv_obj_align(label_pct, bar, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 20, 0);
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_top(mbox, true);
sd_mount();
int res = 0;
char *path = malloc(1024);
char *txt_buf = malloc(SZ_4K);
strcpy(path, "switchroot/install/l4t.00");
u32 path_len = strlen(path) - 2;
FIL fp;
res = f_open(&fp, path, FA_READ);
if (res)
{ {
lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to open 1st part!"); // If we have more bytes written then close the file pointer and increase the part index we are using
f_close(&fp);
free(clmt);
memset(&fp, 0, sizeof(fp));
currPartIdx++;
goto exit; if (currPartIdx < 10)
}
u64 fileSize = (u64)f_size(&fp);
u32 num = 0;
u32 pct = 0;
u32 lba_curr = 0;
u32 bytesWritten = 0;
u32 currPartIdx = 0;
u32 prevPct = 200;
int retryCount = 0;
u32 total_size_sct = l4t_flash_ctxt.image_size_sct;
u8 *buf = (u8 *)MIXD_BUF_ALIGNED;
DWORD *clmt = f_expand_cltbl(&fp, SZ_4M, 0);
while (total_size_sct > 0)
{
// If we have more than one part, check the size for the split parts and make sure that the bytes written is not more than that.
if (bytesWritten >= fileSize)
{ {
// If we have more bytes written then close the file pointer and increase the part index we are using path[path_len] = '0';
f_close(&fp); itoa(currPartIdx, &path[path_len + 1], 10);
free(clmt);
memset(&fp, 0, sizeof(fp));
currPartIdx++;
if (currPartIdx < 10)
{
path[path_len] = '0';
itoa(currPartIdx, &path[path_len + 1], 10);
}
else
itoa(currPartIdx, &path[path_len], 10);
// Try to open the next file part
res = f_open(&fp, path, FA_READ);
if (res)
{
s_printf(txt_buf, "#FFDD00 Error:# Failed to open part %d#", currPartIdx);
lv_label_set_text(lbl_status, txt_buf);
manual_system_maintenance(true);
goto exit;
}
fileSize = (u64)f_size(&fp);
bytesWritten = 0;
clmt = f_expand_cltbl(&fp, SZ_4M, 0);
} }
else
itoa(currPartIdx, &path[path_len], 10);
retryCount = 0; // Try to open the next file part
num = MIN(total_size_sct, 8192); res = f_open(&fp, path, FA_READ);
res = f_read_fast(&fp, buf, num << 9);
manual_system_maintenance(false);
if (res) if (res)
{ {
lv_label_set_text(lbl_status, "#FFDD00 Error:# Reading from SD!"); s_printf(txt_buf, "#FFDD00 Error:# Failed to open part %d#", currPartIdx);
lv_label_set_text(lbl_status, txt_buf);
manual_system_maintenance(true);
goto exit;
}
fileSize = (u64)f_size(&fp);
bytesWritten = 0;
clmt = f_expand_cltbl(&fp, SZ_4M, 0);
}
retryCount = 0;
num = MIN(total_size_sct, 8192);
res = f_read_fast(&fp, buf, num << 9);
manual_system_maintenance(false);
if (res)
{
lv_label_set_text(lbl_status, "#FFDD00 Error:# Reading from SD!");
manual_system_maintenance(true);
f_close(&fp);
free(clmt);
goto exit;
}
res = !sdmmc_storage_write(&sd_storage, lba_curr + l4t_flash_ctxt.offset_sct, num, buf);
manual_system_maintenance(false);
while (res)
{
msleep(150);
manual_system_maintenance(true);
if (retryCount >= 3)
{
lv_label_set_text(lbl_status, "#FFDD00 Error:# Writing to SD!");
manual_system_maintenance(true); manual_system_maintenance(true);
f_close(&fp); f_close(&fp);
free(clmt); free(clmt);
goto exit; goto exit;
} }
res = !sdmmc_storage_write(&sd_storage, lba_curr + l4t_flash_ctxt.offset_sct, num, buf); res = !sdmmc_storage_write(&sd_storage, lba_curr + l4t_flash_ctxt.offset_sct, num, buf);
manual_system_maintenance(false); manual_system_maintenance(false);
while (res)
{
msleep(150);
manual_system_maintenance(true);
if (retryCount >= 3)
{
lv_label_set_text(lbl_status, "#FFDD00 Error:# Writing to SD!");
manual_system_maintenance(true);
f_close(&fp);
free(clmt);
goto exit;
}
res = !sdmmc_storage_write(&sd_storage, lba_curr + l4t_flash_ctxt.offset_sct, num, buf);
manual_system_maintenance(false);
}
pct = (u64)((u64)lba_curr * 100u) / (u64)l4t_flash_ctxt.image_size_sct;
if (pct != prevPct)
{
lv_bar_set_value(bar, pct);
s_printf(txt_buf, " #DDDDDD "SYMBOL_DOT"# %d%%", pct);
lv_label_set_text(label_pct, txt_buf);
manual_system_maintenance(true);
prevPct = pct;
}
lba_curr += num;
total_size_sct -= num;
bytesWritten += num * EMMC_BLOCKSIZE;
} }
lv_bar_set_value(bar, 100); pct = (u64)((u64)lba_curr * 100u) / (u64)l4t_flash_ctxt.image_size_sct;
lv_label_set_text(label_pct, " "SYMBOL_DOT" 100%"); if (pct != prevPct)
manual_system_maintenance(true); {
lv_bar_set_value(bar, pct);
s_printf(txt_buf, " #DDDDDD "SYMBOL_DOT"# %d%%", pct);
lv_label_set_text(label_pct, txt_buf);
manual_system_maintenance(true);
prevPct = pct;
}
// Restore operation ended successfully. lba_curr += num;
f_close(&fp); total_size_sct -= num;
free(clmt); bytesWritten += num * EMMC_BLOCKSIZE;
}
lv_bar_set_value(bar, 100);
lv_label_set_text(label_pct, " "SYMBOL_DOT" 100%");
manual_system_maintenance(true);
succeeded = true; // Restore operation ended successfully.
f_close(&fp);
free(clmt);
succeeded = true;
exit: exit:
free(path); free(path);
free(txt_buf); free(txt_buf);
if (!succeeded) if (!succeeded)
lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action); lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);
else else
lv_mbox_add_btns(mbox, mbox_btn_map2, _action_delete_linux_installer_files); lv_mbox_add_btns(mbox, mbox_btn_map2, _action_delete_linux_installer_files);
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0); lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
sd_unmount(); sd_unmount();
}
return LV_RES_INV; return LV_RES_INV;
} }
@ -856,36 +856,34 @@ static lv_res_t _action_check_flash_linux(lv_obj_t *btn)
itoa(idx, &path[23], 10); itoa(idx, &path[23], 10);
// Check for alignment. // Check for alignment.
if (!f_stat(path, &fno)) if (f_stat(path, &fno))
{
if ((u64)fno.fsize % SZ_4M)
{
// Check if last part.
idx++;
if (idx < 10)
{
path[23] = '0';
itoa(idx, &path[23 + 1], 10);
}
else
itoa(idx, &path[23], 10);
// If not the last part, unaligned size is not permitted.
if (!f_stat(path, NULL)) // NULL: Don't override current part fs info.
{
lv_label_set_text(lbl_status, "#FFDD00 Error:# The image is not aligned to 4 MiB!");
goto error;
}
// Last part. Align size to LBA (512 bytes).
fno.fsize = ALIGN((u64)fno.fsize, 512);
idx--;
}
l4t_flash_ctxt.image_size_sct += (u64)fno.fsize >> 9;
}
else
break; break;
if ((u64)fno.fsize % SZ_4M)
{
// Check if last part.
idx++;
if (idx < 10)
{
path[23] = '0';
itoa(idx, &path[23 + 1], 10);
}
else
itoa(idx, &path[23], 10);
// If not the last part, unaligned size is not permitted.
if (!f_stat(path, NULL)) // NULL: Don't override current part fs info.
{
lv_label_set_text(lbl_status, "#FFDD00 Error:# The image is not aligned to 4 MiB!");
goto error;
}
// Last part. Align size to LBA (512 bytes).
fno.fsize = ALIGN((u64)fno.fsize, 512);
idx--;
}
l4t_flash_ctxt.image_size_sct += (u64)fno.fsize >> 9;
idx++; idx++;
} }
@ -950,236 +948,244 @@ static lv_res_t _action_flash_android_data(lv_obj_t * btns, const char * txt)
// Delete parent mbox. // Delete parent mbox.
mbox_action(btns, txt); mbox_action(btns, txt);
if (btn_idx)
return LV_RES_INV;
// Flash Android components. // Flash Android components.
if (!btn_idx) char path[128];
gpt_t *gpt = calloc(1, sizeof(gpt_t));
char *txt_buf = malloc(SZ_4K);
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
lv_obj_set_style(dark_bg, &mbox_darken);
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
static const char *mbox_btn_map[] = { "\211", "\222OK", "\211", "" };
static const char *mbox_btn_map2[] = { "\222Continue", "\222No", "" };
lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL);
lv_mbox_set_recolor_text(mbox, true);
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);
lv_mbox_set_text(mbox, "#FF8000 Android Flasher#");
lv_obj_t *lbl_status = lv_label_create(mbox, NULL);
lv_label_set_recolor(lbl_status, true);
lv_label_set_text(lbl_status, "#C7EA46 Status:# Searching for files and partitions...");
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_top(mbox, true);
manual_system_maintenance(true);
sd_mount();
// Read main GPT.
sdmmc_storage_read(&sd_storage, 1, sizeof(gpt_t) >> 9, gpt);
bool boot_twrp = false;
if (memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128)
{ {
char path[128]; lv_label_set_text(lbl_status, "#FFDD00 Error:# No Android GPT was found!");
gpt_t *gpt = calloc(1, sizeof(gpt_t)); goto error;
char *txt_buf = malloc(SZ_4K); }
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL); u32 offset_sct = 0;
lv_obj_set_style(dark_bg, &mbox_darken); u32 size_sct = 0;
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
static const char *mbox_btn_map[] = { "\211", "\222OK", "\211", "" }; strcpy(path, "switchroot/install/boot.img");
static const char *mbox_btn_map2[] = { "\222Continue", "\222No", "" }; if (f_stat(path, NULL))
lv_obj_t *mbox = lv_mbox_create(dark_bg, NULL); {
lv_mbox_set_recolor_text(mbox, true); s_printf(txt_buf, "#FF8000 Warning:# Kernel image not found!\n");
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6); goto boot_img_not_found;
}
lv_mbox_set_text(mbox, "#FF8000 Android Flasher#"); for (u32 i = 0; i < gpt->header.num_part_ents; i++)
{
lv_obj_t *lbl_status = lv_label_create(mbox, NULL); if (!memcmp(gpt->entries[i].name, (char[]) { 'L', 0, 'N', 0, 'X', 0 }, 6))
lv_label_set_recolor(lbl_status, true);
lv_label_set_text(lbl_status, "#C7EA46 Status:# Searching for files and partitions...");
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
lv_obj_set_top(mbox, true);
manual_system_maintenance(true);
sd_mount();
// Read main GPT.
sdmmc_storage_read(&sd_storage, 1, sizeof(gpt_t) >> 9, gpt);
bool boot_twrp = false;
if (memcmp(&gpt->header.signature, "EFI PART", 8) || gpt->header.num_part_ents > 128)
{ {
lv_label_set_text(lbl_status, "#FFDD00 Error:# No Android GPT was found!"); offset_sct = gpt->entries[i].lba_start;
goto error; size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;
break;
} }
strcpy(path, "switchroot/install/boot.img"); if (i > 126)
if (!f_stat(path, NULL)) break;
}
if (offset_sct && size_sct)
{
u32 file_size = 0;
u8 *buf = sd_file_read(path, &file_size);
if (file_size % 0x200)
{ {
u32 offset_sct = 0; file_size = ALIGN(file_size, 0x200);
u32 size_sct = 0; u8 *buf_tmp = calloc(file_size, 1);
for (u32 i = 0; i < gpt->header.num_part_ents; i++) memcpy(buf_tmp, buf, file_size);
{ free(buf);
if (!memcmp(gpt->entries[i].name, (char[]) { 'L', 0, 'N', 0, 'X', 0 }, 6)) buf = buf_tmp;
{
offset_sct = gpt->entries[i].lba_start;
size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;
break;
}
if (i > 126)
break;
}
if (offset_sct && size_sct)
{
u32 file_size = 0;
u8 *buf = sd_file_read(path, &file_size);
if (file_size % 0x200)
{
file_size = ALIGN(file_size, 0x200);
u8 *buf_tmp = calloc(file_size, 1);
memcpy(buf_tmp, buf, file_size);
free(buf);
buf = buf_tmp;
}
if ((file_size >> 9) > size_sct)
s_printf(txt_buf, "#FF8000 Warning:# Kernel image too big!\n");
else
{
sdmmc_storage_write(&sd_storage, offset_sct, file_size >> 9, buf);
s_printf(txt_buf, "#C7EA46 Success:# Kernel image flashed!\n");
f_unlink(path);
}
free(buf);
}
else
s_printf(txt_buf, "#FF8000 Warning:# Kernel partition not found!\n");
} }
if ((file_size >> 9) > size_sct)
s_printf(txt_buf, "#FF8000 Warning:# Kernel image too big!\n");
else else
s_printf(txt_buf, "#FF8000 Warning:# Kernel image not found!\n");
lv_label_set_text(lbl_status, txt_buf);
manual_system_maintenance(true);
strcpy(path, "switchroot/install/twrp.img");
if (!f_stat(path, NULL))
{ {
u32 offset_sct = 0; sdmmc_storage_write(&sd_storage, offset_sct, file_size >> 9, buf);
u32 size_sct = 0;
for (u32 i = 0; i < gpt->header.num_part_ents; i++)
{
if (!memcmp(gpt->entries[i].name, (char[]) { 'S', 0, 'O', 0, 'S', 0 }, 6))
{
offset_sct = gpt->entries[i].lba_start;
size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;
break;
}
if (i > 126) s_printf(txt_buf, "#C7EA46 Success:# Kernel image flashed!\n");
break; f_unlink(path);
}
if (offset_sct && size_sct)
{
u32 file_size = 0;
u8 *buf = sd_file_read(path, &file_size);
if (file_size % 0x200)
{
file_size = ALIGN(file_size, 0x200);
u8 *buf_tmp = calloc(file_size, 1);
memcpy(buf_tmp, buf, file_size);
free(buf);
buf = buf_tmp;
}
if ((file_size >> 9) > size_sct)
strcat(txt_buf, "#FF8000 Warning:# TWRP image too big!\n");
else
{
sdmmc_storage_write(&sd_storage, offset_sct, file_size >> 9, buf);
strcat(txt_buf, "#C7EA46 Success:# TWRP image flashed!\n");
f_unlink(path);
}
free(buf);
}
else
strcat(txt_buf, "#FF8000 Warning:# TWRP partition not found!\n");
} }
free(buf);
}
else
s_printf(txt_buf, "#FF8000 Warning:# Kernel partition not found!\n");
boot_img_not_found:
lv_label_set_text(lbl_status, txt_buf);
manual_system_maintenance(true);
strcpy(path, "switchroot/install/twrp.img");
if (f_stat(path, NULL))
{
strcat(txt_buf, "#FF8000 Warning:# TWRP image not found!\n");
goto twrp_not_found;
}
offset_sct = 0;
size_sct = 0;
for (u32 i = 0; i < gpt->header.num_part_ents; i++)
{
if (!memcmp(gpt->entries[i].name, (char[]) { 'S', 0, 'O', 0, 'S', 0 }, 6))
{
offset_sct = gpt->entries[i].lba_start;
size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;
break;
}
if (i > 126)
break;
}
if (offset_sct && size_sct)
{
u32 file_size = 0;
u8 *buf = sd_file_read(path, &file_size);
if (file_size % 0x200)
{
file_size = ALIGN(file_size, 0x200);
u8 *buf_tmp = calloc(file_size, 1);
memcpy(buf_tmp, buf, file_size);
free(buf);
buf = buf_tmp;
}
if ((file_size >> 9) > size_sct)
strcat(txt_buf, "#FF8000 Warning:# TWRP image too big!\n");
else else
strcat(txt_buf, "#FF8000 Warning:# TWRP image not found!\n");
lv_label_set_text(lbl_status, txt_buf);
manual_system_maintenance(true);
strcpy(path, "switchroot/install/tegra210-icosa.dtb");
if (!f_stat(path, NULL))
{ {
u32 offset_sct = 0; sdmmc_storage_write(&sd_storage, offset_sct, file_size >> 9, buf);
u32 size_sct = 0; strcat(txt_buf, "#C7EA46 Success:# TWRP image flashed!\n");
for (u32 i = 0; i < gpt->header.num_part_ents; i++) f_unlink(path);
{
if (!memcmp(gpt->entries[i].name, (char[]) { 'D', 0, 'T', 0, 'B', 0 }, 6))
{
offset_sct = gpt->entries[i].lba_start;
size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;
break;
}
if (i > 126)
break;
}
if (offset_sct && size_sct)
{
u32 file_size = 0;
u8 *buf = sd_file_read(path, &file_size);
if (file_size % 0x200)
{
file_size = ALIGN(file_size, 0x200);
u8 *buf_tmp = calloc(file_size, 1);
memcpy(buf_tmp, buf, file_size);
free(buf);
buf = buf_tmp;
}
if ((file_size >> 9) > size_sct)
strcat(txt_buf, "#FF8000 Warning:# DTB image too big!");
else
{
sdmmc_storage_write(&sd_storage, offset_sct, file_size >> 9, buf);
strcat(txt_buf, "#C7EA46 Success:# DTB image flashed!");
f_unlink(path);
}
free(buf);
}
else
strcat(txt_buf, "#FF8000 Warning:# DTB partition not found!");
} }
free(buf);
}
else
strcat(txt_buf, "#FF8000 Warning:# TWRP partition not found!\n");
twrp_not_found:
lv_label_set_text(lbl_status, txt_buf);
manual_system_maintenance(true);
strcpy(path, "switchroot/install/tegra210-icosa.dtb");
if (f_stat(path, NULL))
{
strcat(txt_buf, "#FF8000 Warning:# DTB image not found!");
goto dtb_not_found;
}
offset_sct = 0;
size_sct = 0;
for (u32 i = 0; i < gpt->header.num_part_ents; i++)
{
if (!memcmp(gpt->entries[i].name, (char[]) { 'D', 0, 'T', 0, 'B', 0 }, 6))
{
offset_sct = gpt->entries[i].lba_start;
size_sct = (gpt->entries[i].lba_end + 1) - gpt->entries[i].lba_start;
break;
}
if (i > 126)
break;
}
if (offset_sct && size_sct)
{
u32 file_size = 0;
u8 *buf = sd_file_read(path, &file_size);
if (file_size % 0x200)
{
file_size = ALIGN(file_size, 0x200);
u8 *buf_tmp = calloc(file_size, 1);
memcpy(buf_tmp, buf, file_size);
free(buf);
buf = buf_tmp;
}
if ((file_size >> 9) > size_sct)
strcat(txt_buf, "#FF8000 Warning:# DTB image too big!");
else else
strcat(txt_buf, "#FF8000 Warning:# DTB image not found!");
lv_label_set_text(lbl_status, txt_buf);
// Check if TWRP is flashed unconditionally.
for (u32 i = 0; i < gpt->header.num_part_ents; i++)
{ {
if (!memcmp(gpt->entries[i].name, (char[]) { 'S', 0, 'O', 0, 'S', 0 }, 6)) sdmmc_storage_write(&sd_storage, offset_sct, file_size >> 9, buf);
{ strcat(txt_buf, "#C7EA46 Success:# DTB image flashed!");
u8 *buf = malloc(512); f_unlink(path);
sdmmc_storage_read(&sd_storage, gpt->entries[i].lba_start, 1, buf);
if (!memcmp(buf, "ANDROID", 7))
boot_twrp = true;
free(buf);
break;
}
if (i > 126)
break;
} }
free(buf);
}
else
strcat(txt_buf, "#FF8000 Warning:# DTB partition not found!");
dtb_not_found:
lv_label_set_text(lbl_status, txt_buf);
// Check if TWRP is flashed unconditionally.
for (u32 i = 0; i < gpt->header.num_part_ents; i++)
{
if (!memcmp(gpt->entries[i].name, (char[]) { 'S', 0, 'O', 0, 'S', 0 }, 6))
{
u8 *buf = malloc(512);
sdmmc_storage_read(&sd_storage, gpt->entries[i].lba_start, 1, buf);
if (!memcmp(buf, "ANDROID", 7))
boot_twrp = true;
free(buf);
break;
}
if (i > 126)
break;
}
error: error:
if (boot_twrp) if (boot_twrp)
{ {
strcat(txt_buf,"\n\nDo you want to reboot into TWRP\nto finish Android installation?"); strcat(txt_buf,"\n\nDo you want to reboot into TWRP\nto finish Android installation?");
lv_label_set_text(lbl_status, txt_buf); lv_label_set_text(lbl_status, txt_buf);
lv_mbox_add_btns(mbox, mbox_btn_map2, _action_reboot_twrp); lv_mbox_add_btns(mbox, mbox_btn_map2, _action_reboot_twrp);
}
else
lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
free(txt_buf);
free(gpt);
sd_unmount();
} }
else
lv_mbox_add_btns(mbox, mbox_btn_map, mbox_action);
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
free(txt_buf);
free(gpt);
sd_unmount();
return LV_RES_INV; return LV_RES_INV;
} }
@ -1409,54 +1415,58 @@ static lv_res_t _create_mbox_start_partitioning(lv_obj_t *btn)
u32 cluster_size = 65536; u32 cluster_size = 65536;
u32 mkfs_error = f_mkfs("sd:", FM_FAT32, cluster_size, buf, SZ_4M); u32 mkfs_error = f_mkfs("sd:", FM_FAT32, cluster_size, buf, SZ_4M);
if (!mkfs_error)
goto mkfs_no_error;
// Retry by halving cluster size.
while (cluster_size > 4096)
{
cluster_size /= 2;
mkfs_error = f_mkfs("sd:", FM_FAT32, cluster_size, buf, SZ_4M);
if (!mkfs_error)
break;
}
if (mkfs_error) if (mkfs_error)
{ {
// Retry by halving cluster size. // Failed to format.
while (cluster_size > 4096) s_printf((char *)buf, "#FFDD00 Error:# Failed to format disk (%d)!\n\n"
{ "Remove the SD card and check that is OK.\nIf not, format it, reinsert it and\npress #FF8000 POWER#!", mkfs_error);
cluster_size /= 2;
mkfs_error = f_mkfs("sd:", FM_FAT32, cluster_size, buf, SZ_4M);
if (!mkfs_error) lv_label_set_text(lbl_status, (char *)buf);
break; lv_label_set_text(lbl_paths[0], " ");
manual_system_maintenance(true);
sd_end();
while (!(btn_wait() & BTN_POWER));
sd_mount();
if (!part_info.backup_possible)
{
f_chdrive("sd:");
f_mkdir(path);
} }
if (mkfs_error) lv_label_set_text(lbl_status, "#00DDFF Status:# Restoring files...");
manual_system_maintenance(true);
if (_backup_and_restore_files(path, &total_files, &total_size, "sd:", "ram:", NULL))
{ {
// Failed to format. lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to restore files!");
s_printf((char *)buf, "#FFDD00 Error:# Failed to format disk (%d)!\n\n"
"Remove the SD card and check that is OK.\nIf not, format it, reinsert it and\npress #FF8000 POWER#!", mkfs_error);
lv_label_set_text(lbl_status, (char *)buf);
lv_label_set_text(lbl_paths[0], " ");
manual_system_maintenance(true);
sd_end();
while (!(btn_wait() & BTN_POWER));
sd_mount();
if (!part_info.backup_possible)
{
f_chdrive("sd:");
f_mkdir(path);
}
lv_label_set_text(lbl_status, "#00DDFF Status:# Restoring files...");
manual_system_maintenance(true);
if (_backup_and_restore_files(path, &total_files, &total_size, "sd:", "ram:", NULL))
{
lv_label_set_text(lbl_status, "#FFDD00 Error:# Failed to restore files!");
free(buf);
goto error;
}
lv_label_set_text(lbl_status, "#00DDFF Status:# Restored files but the operation failed!");
f_mount(NULL, "ram:", 1); // Unmount ramdisk.
free(buf); free(buf);
goto error; goto error;
} }
lv_label_set_text(lbl_status, "#00DDFF Status:# Restored files but the operation failed!");
f_mount(NULL, "ram:", 1); // Unmount ramdisk.
free(buf);
goto error;
} }
mkfs_no_error:
free(buf); free(buf);
f_mount(&sd_fs, "sd:", 1); // Mount SD card. f_mount(&sd_fs, "sd:", 1); // Mount SD card.

View file

@ -138,67 +138,67 @@ lv_res_t launch_payload(lv_obj_t *list)
strcpy(path,"bootloader/payloads/"); strcpy(path,"bootloader/payloads/");
strcat(path, filename); strcat(path, filename);
if (sd_mount()) if (!sd_mount())
goto out;
FIL fp;
if (f_open(&fp, path, FA_READ))
{ {
FIL fp; EPRINTFARGS("Payload file is missing!\n(%s)", path);
if (f_open(&fp, path, FA_READ))
{
EPRINTFARGS("Payload file is missing!\n(%s)", path);
goto out; goto out;
} }
// Read and copy the payload to our chosen address // Read and copy the payload to our chosen address
void *buf; void *buf;
u32 size = f_size(&fp); u32 size = f_size(&fp);
if (size < 0x30000) if (size < 0x30000)
buf = (void *)RCM_PAYLOAD_ADDR; buf = (void *)RCM_PAYLOAD_ADDR;
else else
{ {
coreboot_addr = (void *)(COREBOOT_END_ADDR - size); coreboot_addr = (void *)(COREBOOT_END_ADDR - size);
buf = coreboot_addr; buf = coreboot_addr;
if (h_cfg.t210b01) if (h_cfg.t210b01)
{
f_close(&fp);
EPRINTF("Coreboot not allowed on Mariko!");
goto out;
}
}
if (f_read(&fp, buf, size, NULL))
{ {
f_close(&fp); f_close(&fp);
EPRINTF("Coreboot not allowed on Mariko!");
goto out; goto out;
} }
}
if (f_read(&fp, buf, size, NULL))
{
f_close(&fp); f_close(&fp);
sd_end(); goto out;
if (size < 0x30000)
{
reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10));
hw_reinit_workaround(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32))));
}
else
{
reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, 0x7000);
hw_reinit_workaround(true, 0);
}
void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR;
// Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms.
sdmmc_storage_init_wait_sd();
// Launch our payload.
(*ext_payload_ptr)();
} }
f_close(&fp);
sd_end();
if (size < 0x30000)
{
reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10));
hw_reinit_workaround(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32))));
}
else
{
reloc_patcher(PATCHED_RELOC_ENTRY, EXT_PAYLOAD_ADDR, 0x7000);
hw_reinit_workaround(true, 0);
}
void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR;
// Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms.
sdmmc_storage_init_wait_sd();
// Launch our payload.
(*ext_payload_ptr)();
out: out:
sd_unmount(); sd_unmount();
@ -210,71 +210,72 @@ void load_saved_configuration()
LIST_INIT(ini_sections); LIST_INIT(ini_sections);
LIST_INIT(ini_nyx_sections); LIST_INIT(ini_nyx_sections);
// Load hekate configuration. if (!ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) goto skip_main_cfg_parse;
{
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
{
// Only parse config section.
if (ini_sec->type == INI_CHOICE && !strcmp(ini_sec->name, "config"))
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
if (!strcmp("autoboot", kv->key))
h_cfg.autoboot = atoi(kv->val);
else if (!strcmp("autoboot_list", kv->key))
h_cfg.autoboot_list = atoi(kv->val);
else if (!strcmp("bootwait", kv->key))
h_cfg.bootwait = atoi(kv->val);
else if (!strcmp("backlight", kv->key))
{
h_cfg.backlight = atoi(kv->val);
if (h_cfg.backlight <= 20)
h_cfg.backlight = 30;
}
else if (!strcmp("autohosoff", kv->key))
h_cfg.autohosoff = atoi(kv->val);
else if (!strcmp("autonogc", kv->key))
h_cfg.autonogc = atoi(kv->val);
else if (!strcmp("updater2p", kv->key))
h_cfg.updater2p = atoi(kv->val);
else if (!strcmp("bootprotect", kv->key))
h_cfg.bootprotect = atoi(kv->val);
}
break; // Load hekate configuration.
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
{
// Only parse config section.
if (ini_sec->type == INI_CHOICE && !strcmp(ini_sec->name, "config"))
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
if (!strcmp("autoboot", kv->key))
h_cfg.autoboot = atoi(kv->val);
else if (!strcmp("autoboot_list", kv->key))
h_cfg.autoboot_list = atoi(kv->val);
else if (!strcmp("bootwait", kv->key))
h_cfg.bootwait = atoi(kv->val);
else if (!strcmp("backlight", kv->key))
{
h_cfg.backlight = atoi(kv->val);
if (h_cfg.backlight <= 20)
h_cfg.backlight = 30;
}
else if (!strcmp("autohosoff", kv->key))
h_cfg.autohosoff = atoi(kv->val);
else if (!strcmp("autonogc", kv->key))
h_cfg.autonogc = atoi(kv->val);
else if (!strcmp("updater2p", kv->key))
h_cfg.updater2p = atoi(kv->val);
else if (!strcmp("bootprotect", kv->key))
h_cfg.bootprotect = atoi(kv->val);
} }
break;
} }
} }
// Load Nyx configuration. skip_main_cfg_parse:
if (ini_parse(&ini_nyx_sections, "bootloader/nyx.ini", false)) if (!ini_parse(&ini_nyx_sections, "bootloader/nyx.ini", false))
{ return;
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_nyx_sections, link)
{
// Only parse config section.
if (ini_sec->type == INI_CHOICE && !strcmp(ini_sec->name, "config"))
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
if (!strcmp("themecolor", kv->key))
n_cfg.themecolor = atoi(kv->val);
else if (!strcmp("timeoff", kv->key))
n_cfg.timeoff = strtol(kv->val, NULL, 16);
else if (!strcmp("homescreen", kv->key))
n_cfg.home_screen = atoi(kv->val);
else if (!strcmp("verification", kv->key))
n_cfg.verification = atoi(kv->val);
else if (!strcmp("umsemmcrw", kv->key))
n_cfg.ums_emmc_rw = atoi(kv->val) == 1;
else if (!strcmp("jcdisable", kv->key))
n_cfg.jc_disable = atoi(kv->val) == 1;
else if (!strcmp("bpmpclock", kv->key))
n_cfg.bpmp_clock = strtol(kv->val, NULL, 10);
}
break; // Load Nyx configuration.
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_nyx_sections, link)
{
// Only parse config section.
if (ini_sec->type == INI_CHOICE && !strcmp(ini_sec->name, "config"))
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
if (!strcmp("themecolor", kv->key))
n_cfg.themecolor = atoi(kv->val);
else if (!strcmp("timeoff", kv->key))
n_cfg.timeoff = strtol(kv->val, NULL, 16);
else if (!strcmp("homescreen", kv->key))
n_cfg.home_screen = atoi(kv->val);
else if (!strcmp("verification", kv->key))
n_cfg.verification = atoi(kv->val);
else if (!strcmp("umsemmcrw", kv->key))
n_cfg.ums_emmc_rw = atoi(kv->val) == 1;
else if (!strcmp("jcdisable", kv->key))
n_cfg.jc_disable = atoi(kv->val) == 1;
else if (!strcmp("bpmpclock", kv->key))
n_cfg.bpmp_clock = strtol(kv->val, NULL, 10);
} }
break;
} }
} }
} }