Add menu and option to dump keys from emuMMC
This commit is contained in:
parent
19796e486c
commit
250f068211
|
@ -20,7 +20,6 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "ini.h"
|
#include "ini.h"
|
||||||
#include "../gfx/gfx.h"
|
#include "../gfx/gfx.h"
|
||||||
#include "../gfx/tui.h"
|
|
||||||
#include "../libs/fatfs/ff.h"
|
#include "../libs/fatfs/ff.h"
|
||||||
#include "../soc/t210.h"
|
#include "../soc/t210.h"
|
||||||
#include "../storage/sdmmc.h"
|
#include "../storage/sdmmc.h"
|
||||||
|
@ -53,616 +52,3 @@ void set_default_configuration()
|
||||||
sd_power_cycle_time_start = 0xFFFFFFF;
|
sd_power_cycle_time_start = 0xFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_config_entry()
|
|
||||||
{
|
|
||||||
if (!sd_mount())
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
char lbuf[32];
|
|
||||||
FIL fp;
|
|
||||||
bool mainIniFound = false;
|
|
||||||
|
|
||||||
LIST_INIT(ini_sections);
|
|
||||||
|
|
||||||
if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
|
|
||||||
mainIniFound = true;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
u8 res = f_open(&fp, "bootloader/hekate_ipl.ini", FA_READ);
|
|
||||||
if (res == FR_NO_FILE || res == FR_NO_PATH)
|
|
||||||
{
|
|
||||||
f_mkdir("bootloader");
|
|
||||||
f_mkdir("bootloader/ini");
|
|
||||||
f_mkdir("bootloader/payloads");
|
|
||||||
f_mkdir("bootloader/sys");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!res)
|
|
||||||
f_close(&fp);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (f_open(&fp, "bootloader/hekate_ipl.ini", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)
|
|
||||||
return 1;
|
|
||||||
// Add config entry.
|
|
||||||
f_puts("[config]\nautoboot=", &fp);
|
|
||||||
itoa(h_cfg.autoboot, lbuf, 10);
|
|
||||||
f_puts(lbuf, &fp);
|
|
||||||
f_puts("\nautoboot_list=", &fp);
|
|
||||||
itoa(h_cfg.autoboot_list, lbuf, 10);
|
|
||||||
f_puts(lbuf, &fp);
|
|
||||||
f_puts("\nbootwait=", &fp);
|
|
||||||
itoa(h_cfg.bootwait, lbuf, 10);
|
|
||||||
f_puts(lbuf, &fp);
|
|
||||||
f_puts("\nverification=", &fp);
|
|
||||||
itoa(h_cfg.verification, lbuf, 10);
|
|
||||||
f_puts(lbuf, &fp);
|
|
||||||
f_puts("\nbacklight=", &fp);
|
|
||||||
itoa(h_cfg.backlight, lbuf, 10);
|
|
||||||
f_puts(lbuf, &fp);
|
|
||||||
f_puts("\nautohosoff=", &fp);
|
|
||||||
itoa(h_cfg.autohosoff, lbuf, 10);
|
|
||||||
f_puts(lbuf, &fp);
|
|
||||||
f_puts("\nautonogc=", &fp);
|
|
||||||
itoa(h_cfg.autonogc, lbuf, 10);
|
|
||||||
f_puts(lbuf, &fp);
|
|
||||||
if (h_cfg.brand)
|
|
||||||
{
|
|
||||||
f_puts("\nbrand=", &fp);
|
|
||||||
f_puts(h_cfg.brand, &fp);
|
|
||||||
}
|
|
||||||
if (h_cfg.tagline)
|
|
||||||
{
|
|
||||||
f_puts("\ntagline=", &fp);
|
|
||||||
f_puts(h_cfg.tagline, &fp);
|
|
||||||
}
|
|
||||||
f_puts("\n", &fp);
|
|
||||||
|
|
||||||
if (mainIniFound)
|
|
||||||
{
|
|
||||||
// Re-construct existing entries.
|
|
||||||
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
|
|
||||||
{
|
|
||||||
if (!strcmp(ini_sec->name, "config"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
switch (ini_sec->type)
|
|
||||||
{
|
|
||||||
case INI_CHOICE: // Re-construct Boot entry [ ].
|
|
||||||
f_puts("[", &fp);
|
|
||||||
f_puts(ini_sec->name, &fp);
|
|
||||||
f_puts("]\n", &fp);
|
|
||||||
// Re-construct boot entry's config.
|
|
||||||
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
|
|
||||||
{
|
|
||||||
f_puts(kv->key, &fp);
|
|
||||||
f_puts("=", &fp);
|
|
||||||
f_puts(kv->val, &fp);
|
|
||||||
f_puts("\n", &fp);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case INI_CAPTION: // Re-construct caption entry { }.
|
|
||||||
f_puts("{", &fp);
|
|
||||||
f_puts(ini_sec->name, &fp);
|
|
||||||
f_puts("}\n", &fp);
|
|
||||||
break;
|
|
||||||
case INI_NEWLINE: // Re-construct cosmetic newline \n.
|
|
||||||
f_puts("\n", &fp);
|
|
||||||
break;
|
|
||||||
case INI_COMMENT: // Re-construct comment entry #.
|
|
||||||
f_puts("#", &fp);
|
|
||||||
f_puts(ini_sec->name, &fp);
|
|
||||||
f_puts("\n", &fp);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f_close(&fp);
|
|
||||||
sd_unmount();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma GCC push_options
|
|
||||||
#pragma GCC optimize ("Os")
|
|
||||||
|
|
||||||
static void _save_config()
|
|
||||||
{
|
|
||||||
gfx_clear_grey(0x1B);
|
|
||||||
gfx_con_setpos(0, 0);
|
|
||||||
|
|
||||||
if (!create_config_entry())
|
|
||||||
gfx_puts("\nConfiguration was saved!\n");
|
|
||||||
else
|
|
||||||
EPRINTF("\nConfiguration saving failed!");
|
|
||||||
gfx_puts("\nPress any key...");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _config_autoboot_list(void *ent)
|
|
||||||
{
|
|
||||||
gfx_clear_grey(0x1B);
|
|
||||||
gfx_con_setpos(0, 0);
|
|
||||||
|
|
||||||
u32 *temp_autoboot = NULL;
|
|
||||||
|
|
||||||
LIST_INIT(ini_sections);
|
|
||||||
|
|
||||||
u8 max_entries = 30;
|
|
||||||
|
|
||||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3));
|
|
||||||
u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries);
|
|
||||||
char *boot_text = (char *)malloc(512 * max_entries);
|
|
||||||
|
|
||||||
for (u32 j = 0; j < max_entries; j++)
|
|
||||||
boot_values[j] = j;
|
|
||||||
|
|
||||||
if (sd_mount())
|
|
||||||
{
|
|
||||||
if (ini_parse(&ini_sections, "bootloader/ini", true))
|
|
||||||
{
|
|
||||||
// Build configuration menu.
|
|
||||||
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_sections, link)
|
|
||||||
{
|
|
||||||
// Skip other ini entries for autoboot.
|
|
||||||
if (ini_sec->type == INI_CHOICE)
|
|
||||||
{
|
|
||||||
if (!strcmp(ini_sec->name, "config"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (strlen(ini_sec->name) > 510)
|
|
||||||
ments[i].caption = ini_sec->name;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (h_cfg.autoboot != (i - 1) || !h_cfg.autoboot_list)
|
|
||||||
boot_text[(i - 1) * 512] = ' ';
|
|
||||||
|
|
||||||
else
|
|
||||||
boot_text[(i - 1) * 512] = '*';
|
|
||||||
memcpy(boot_text + (i - 1) * 512 + 1, ini_sec->name, strlen(ini_sec->name) + 1);
|
|
||||||
boot_text[strlen(ini_sec->name) + (i - 1) * 512 + 1] = 0;
|
|
||||||
ments[i].caption = &boot_text[(i - 1) * 512];
|
|
||||||
}
|
|
||||||
ments[i].type = ini_sec->type;
|
|
||||||
ments[i].data = &boot_values[i - 1];
|
|
||||||
i++;
|
|
||||||
|
|
||||||
if ((i - 1) > max_entries)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&ments[i], 0, sizeof(ment_t));
|
|
||||||
menu_t menu = {ments, "Select an entry to auto boot", 0, 0};
|
|
||||||
temp_autoboot = (u32 *)tui_do_menu(&menu);
|
|
||||||
if (temp_autoboot != NULL)
|
|
||||||
{
|
|
||||||
h_cfg.autoboot = *(u32 *)temp_autoboot;
|
|
||||||
h_cfg.autoboot_list = 1;
|
|
||||||
_save_config();
|
|
||||||
|
|
||||||
ment_t *tmp = (ment_t *)ent;
|
|
||||||
tmp->data = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
goto out2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!.");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out:;
|
|
||||||
btn_wait();
|
|
||||||
out2:;
|
|
||||||
free(ments);
|
|
||||||
free(boot_values);
|
|
||||||
free(boot_text);
|
|
||||||
|
|
||||||
sd_unmount();
|
|
||||||
}
|
|
||||||
|
|
||||||
void config_autoboot()
|
|
||||||
{
|
|
||||||
gfx_clear_grey(0x1B);
|
|
||||||
gfx_con_setpos(0, 0);
|
|
||||||
|
|
||||||
u32 *temp_autoboot = NULL;
|
|
||||||
|
|
||||||
LIST_INIT(ini_sections);
|
|
||||||
|
|
||||||
u8 max_entries = 30;
|
|
||||||
|
|
||||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5));
|
|
||||||
u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries);
|
|
||||||
char *boot_text = (char *)malloc(512 * max_entries);
|
|
||||||
|
|
||||||
for (u32 j = 0; j < max_entries; j++)
|
|
||||||
boot_values[j] = j;
|
|
||||||
|
|
||||||
if (sd_mount())
|
|
||||||
{
|
|
||||||
if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
|
|
||||||
{
|
|
||||||
// Build configuration menu.
|
|
||||||
ments[0].type = MENT_BACK;
|
|
||||||
ments[0].caption = "Back";
|
|
||||||
|
|
||||||
ments[1].type = MENT_CHGLINE;
|
|
||||||
|
|
||||||
ments[2].type = MENT_DATA;
|
|
||||||
if (!h_cfg.autoboot)
|
|
||||||
ments[2].caption = "*Disable";
|
|
||||||
else
|
|
||||||
ments[2].caption = " Disable";
|
|
||||||
ments[2].data = &boot_values[0];
|
|
||||||
|
|
||||||
ments[3].type = MENT_HDLR_RE;
|
|
||||||
if (h_cfg.autoboot_list)
|
|
||||||
ments[3].caption = "*More configs...";
|
|
||||||
else
|
|
||||||
ments[3].caption = " More configs...";
|
|
||||||
ments[3].handler = _config_autoboot_list;
|
|
||||||
ments[3].data = (void *)0xCAFE;
|
|
||||||
|
|
||||||
ments[4].type = MENT_CHGLINE;
|
|
||||||
|
|
||||||
u32 i = 5;
|
|
||||||
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"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (strlen(ini_sec->name) > 510)
|
|
||||||
ments[i].caption = ini_sec->name;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (h_cfg.autoboot != (i - 4) || h_cfg.autoboot_list)
|
|
||||||
boot_text[(i - 4) * 512] = ' ';
|
|
||||||
|
|
||||||
else
|
|
||||||
boot_text[(i - 4) * 512] = '*';
|
|
||||||
memcpy(boot_text + (i - 4) * 512 + 1, ini_sec->name, strlen(ini_sec->name) + 1);
|
|
||||||
boot_text[strlen(ini_sec->name) + (i - 4) * 512 + 1] = 0;
|
|
||||||
ments[i].caption = &boot_text[(i - 4) * 512];
|
|
||||||
}
|
|
||||||
ments[i].type = ini_sec->type;
|
|
||||||
ments[i].data = &boot_values[i - 4];
|
|
||||||
i++;
|
|
||||||
|
|
||||||
if ((i - 4) > max_entries)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (i < 6 && !h_cfg.autoboot_list)
|
|
||||||
{
|
|
||||||
ments[i].type = MENT_CAPTION;
|
|
||||||
ments[i].caption = "No main configurations found...";
|
|
||||||
ments[i].color = 0xFFFFDD00;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&ments[i], 0, sizeof(ment_t));
|
|
||||||
menu_t menu = {ments, "Disable or select entry to auto boot", 0, 0};
|
|
||||||
temp_autoboot = (u32 *)tui_do_menu(&menu);
|
|
||||||
if (temp_autoboot != NULL)
|
|
||||||
{
|
|
||||||
h_cfg.autoboot = *(u32 *)temp_autoboot;
|
|
||||||
h_cfg.autoboot_list = 0;
|
|
||||||
_save_config();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
goto out2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EPRINTF("Could not open 'bootloader/hekate_ipl.ini'.\nMake sure it exists!.");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out:;
|
|
||||||
btn_wait();
|
|
||||||
out2:;
|
|
||||||
free(ments);
|
|
||||||
free(boot_values);
|
|
||||||
free(boot_text);
|
|
||||||
|
|
||||||
sd_unmount();
|
|
||||||
|
|
||||||
if (temp_autoboot == NULL)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void config_bootdelay()
|
|
||||||
{
|
|
||||||
gfx_clear_grey(0x1B);
|
|
||||||
gfx_con_setpos(0, 0);
|
|
||||||
|
|
||||||
u32 delay_entries = 6;
|
|
||||||
|
|
||||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (delay_entries + 3));
|
|
||||||
u32 *delay_values = (u32 *)malloc(sizeof(u32) * delay_entries);
|
|
||||||
char *delay_text = (char *)malloc(32 * delay_entries);
|
|
||||||
|
|
||||||
for (u32 j = 0; j < delay_entries; j++)
|
|
||||||
delay_values[j] = j;
|
|
||||||
|
|
||||||
ments[0].type = MENT_BACK;
|
|
||||||
ments[0].caption = "Back";
|
|
||||||
|
|
||||||
ments[1].type = MENT_CHGLINE;
|
|
||||||
|
|
||||||
ments[2].type = MENT_DATA;
|
|
||||||
if (h_cfg.bootwait)
|
|
||||||
ments[2].caption = " 0 seconds (Bootlogo disabled)";
|
|
||||||
else
|
|
||||||
ments[2].caption = "*0 seconds (Bootlogo disabled)";
|
|
||||||
ments[2].data = &delay_values[0];
|
|
||||||
|
|
||||||
u32 i = 0;
|
|
||||||
for (i = 1; i < delay_entries; i++)
|
|
||||||
{
|
|
||||||
if (h_cfg.bootwait != i)
|
|
||||||
delay_text[i * 32] = ' ';
|
|
||||||
else
|
|
||||||
delay_text[i * 32] = '*';
|
|
||||||
delay_text[i * 32 + 1] = i + '0';
|
|
||||||
memcpy(delay_text + i * 32 + 2, " seconds", 9);
|
|
||||||
|
|
||||||
ments[i + 2].type = MENT_DATA;
|
|
||||||
ments[i + 2].caption = delay_text + i * 32;
|
|
||||||
ments[i + 2].data = &delay_values[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&ments[i + 2], 0, sizeof(ment_t));
|
|
||||||
menu_t menu = {ments, "Time delay for entering bootloader menu", 0, 0};
|
|
||||||
|
|
||||||
u32 *temp_bootwait = (u32 *)tui_do_menu(&menu);
|
|
||||||
if (temp_bootwait != NULL)
|
|
||||||
{
|
|
||||||
h_cfg.bootwait = *(u32 *)temp_bootwait;
|
|
||||||
_save_config();
|
|
||||||
}
|
|
||||||
|
|
||||||
free(ments);
|
|
||||||
free(delay_values);
|
|
||||||
free(delay_text);
|
|
||||||
|
|
||||||
if (temp_bootwait == NULL)
|
|
||||||
return;
|
|
||||||
btn_wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
void config_verification()
|
|
||||||
{
|
|
||||||
gfx_clear_grey(0x1B);
|
|
||||||
gfx_con_setpos(0, 0);
|
|
||||||
|
|
||||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
|
|
||||||
u32 *vr_values = (u32 *)malloc(sizeof(u32) * 3);
|
|
||||||
char *vr_text = (char *)malloc(64 * 3);
|
|
||||||
|
|
||||||
for (u32 j = 0; j < 3; j++)
|
|
||||||
{
|
|
||||||
vr_values[j] = j;
|
|
||||||
ments[j + 2].type = MENT_DATA;
|
|
||||||
ments[j + 2].data = &vr_values[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
ments[0].type = MENT_BACK;
|
|
||||||
ments[0].caption = "Back";
|
|
||||||
|
|
||||||
ments[1].type = MENT_CHGLINE;
|
|
||||||
|
|
||||||
memcpy(vr_text, " Disable (Fastest - Unsafe)", 28);
|
|
||||||
memcpy(vr_text + 64, " Sparse (Fast - Safe)", 23);
|
|
||||||
memcpy(vr_text + 128, " Full (Slow - Safe)", 23);
|
|
||||||
|
|
||||||
for (u32 i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
if (h_cfg.verification != i)
|
|
||||||
vr_text[64 * i] = ' ';
|
|
||||||
else
|
|
||||||
vr_text[64 * i] = '*';
|
|
||||||
ments[2 + i].caption = vr_text + (i * 64);
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&ments[5], 0, sizeof(ment_t));
|
|
||||||
menu_t menu = {ments, "Backup & Restore verification", 0, 0};
|
|
||||||
|
|
||||||
u32 *temp_verification = (u32 *)tui_do_menu(&menu);
|
|
||||||
if (temp_verification != NULL)
|
|
||||||
{
|
|
||||||
h_cfg.verification = *(u32 *)temp_verification;
|
|
||||||
_save_config();
|
|
||||||
}
|
|
||||||
|
|
||||||
free(ments);
|
|
||||||
free(vr_values);
|
|
||||||
free(vr_text);
|
|
||||||
|
|
||||||
if (temp_verification == NULL)
|
|
||||||
return;
|
|
||||||
btn_wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
void config_backlight()
|
|
||||||
{
|
|
||||||
gfx_clear_grey(0x1B);
|
|
||||||
gfx_con_setpos(0, 0);
|
|
||||||
|
|
||||||
u32 bri_entries = 11;
|
|
||||||
|
|
||||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (bri_entries + 3));
|
|
||||||
u32 *bri_values = (u32 *)malloc(sizeof(u32) * bri_entries);
|
|
||||||
char *bri_text = (char *)malloc(8 * bri_entries);
|
|
||||||
|
|
||||||
for (u32 j = 1; j < bri_entries; j++)
|
|
||||||
bri_values[j] = j * 10;
|
|
||||||
|
|
||||||
ments[0].type = MENT_BACK;
|
|
||||||
ments[0].caption = "Back";
|
|
||||||
|
|
||||||
ments[1].type = MENT_CHGLINE;
|
|
||||||
|
|
||||||
u32 i = 0;
|
|
||||||
for (i = 1; i < bri_entries; i++)
|
|
||||||
{
|
|
||||||
if ((h_cfg.backlight / 20) != i)
|
|
||||||
bri_text[i * 32] = ' ';
|
|
||||||
else
|
|
||||||
bri_text[i * 32] = '*';
|
|
||||||
|
|
||||||
if (i < 10)
|
|
||||||
{
|
|
||||||
bri_text[i * 32 + 1] = i + '0';
|
|
||||||
memcpy(bri_text + i * 32 + 2, "0%", 3);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
memcpy(bri_text + i * 32 + 1, "100%", 5);
|
|
||||||
|
|
||||||
ments[i + 1].type = MENT_DATA;
|
|
||||||
ments[i + 1].caption = bri_text + i * 32;
|
|
||||||
ments[i + 1].data = &bri_values[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&ments[i + 1], 0, sizeof(ment_t));
|
|
||||||
menu_t menu = {ments, "Backlight brightness", 0, 0};
|
|
||||||
|
|
||||||
u32 *temp_backlight = (u32 *)tui_do_menu(&menu);
|
|
||||||
if (temp_backlight != NULL)
|
|
||||||
{
|
|
||||||
h_cfg.backlight = (*(u32 *)temp_backlight) * 2;
|
|
||||||
_save_config();
|
|
||||||
}
|
|
||||||
|
|
||||||
free(ments);
|
|
||||||
free(bri_values);
|
|
||||||
free(bri_text);
|
|
||||||
|
|
||||||
if (temp_backlight == NULL)
|
|
||||||
return;
|
|
||||||
btn_wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
void config_auto_hos_poweroff()
|
|
||||||
{
|
|
||||||
gfx_clear_grey(0x1B);
|
|
||||||
gfx_con_setpos(0, 0);
|
|
||||||
|
|
||||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 6);
|
|
||||||
u32 *hp_values = (u32 *)malloc(sizeof(u32) * 3);
|
|
||||||
|
|
||||||
for (u32 j = 0; j < 3; j++)
|
|
||||||
{
|
|
||||||
hp_values[j] = j;
|
|
||||||
ments[j + 2].type = MENT_DATA;
|
|
||||||
ments[j + 2].data = &hp_values[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
ments[0].type = MENT_BACK;
|
|
||||||
ments[0].caption = "Back";
|
|
||||||
|
|
||||||
ments[1].type = MENT_CHGLINE;
|
|
||||||
|
|
||||||
if (h_cfg.autohosoff == 1)
|
|
||||||
{
|
|
||||||
ments[2].caption = " Disable";
|
|
||||||
ments[3].caption = "*Enable";
|
|
||||||
ments[4].caption = " Enable (No logo)";
|
|
||||||
}
|
|
||||||
else if (h_cfg.autohosoff >= 2)
|
|
||||||
{
|
|
||||||
ments[2].caption = " Disable";
|
|
||||||
ments[3].caption = " Enable";
|
|
||||||
ments[4].caption = "*Enable (No logo)";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ments[2].caption = "*Disable";
|
|
||||||
ments[3].caption = " Enable";
|
|
||||||
ments[4].caption = " Enable (No logo)";
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&ments[5], 0, sizeof(ment_t));
|
|
||||||
menu_t menu = {ments, "Power off if woke up from HOS", 0, 0};
|
|
||||||
|
|
||||||
u32 *temp_autohosoff = (u32 *)tui_do_menu(&menu);
|
|
||||||
if (temp_autohosoff != NULL)
|
|
||||||
{
|
|
||||||
h_cfg.autohosoff = *(u32 *)temp_autohosoff;
|
|
||||||
_save_config();
|
|
||||||
}
|
|
||||||
|
|
||||||
free(ments);
|
|
||||||
free(hp_values);
|
|
||||||
|
|
||||||
if (temp_autohosoff == NULL)
|
|
||||||
return;
|
|
||||||
btn_wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
void config_nogc()
|
|
||||||
{
|
|
||||||
gfx_clear_grey(0x1B);
|
|
||||||
gfx_con_setpos(0, 0);
|
|
||||||
|
|
||||||
ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * 5);
|
|
||||||
u32 *cb_values = (u32 *)malloc(sizeof(u32) * 2);
|
|
||||||
|
|
||||||
for (u32 j = 0; j < 2; j++)
|
|
||||||
{
|
|
||||||
cb_values[j] = j;
|
|
||||||
ments[j + 2].type = MENT_DATA;
|
|
||||||
ments[j + 2].data = &cb_values[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
ments[0].type = MENT_BACK;
|
|
||||||
ments[0].caption = "Back";
|
|
||||||
|
|
||||||
ments[1].type = MENT_CHGLINE;
|
|
||||||
|
|
||||||
if (h_cfg.autonogc)
|
|
||||||
{
|
|
||||||
ments[2].caption = " Disable";
|
|
||||||
ments[3].caption = "*Auto";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ments[2].caption = "*Disable";
|
|
||||||
ments[3].caption = " Auto";
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&ments[4], 0, sizeof(ment_t));
|
|
||||||
menu_t menu = {ments, "No Gamecard", 0, 0};
|
|
||||||
|
|
||||||
u32 *temp_nogc = (u32 *)tui_do_menu(&menu);
|
|
||||||
if (temp_nogc != NULL)
|
|
||||||
{
|
|
||||||
h_cfg.autonogc = *(u32 *)temp_nogc;
|
|
||||||
_save_config();
|
|
||||||
}
|
|
||||||
|
|
||||||
free(ments);
|
|
||||||
free(cb_values);
|
|
||||||
|
|
||||||
if (temp_nogc == NULL)
|
|
||||||
return;
|
|
||||||
btn_wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma GCC pop_options
|
|
||||||
|
|
|
@ -46,12 +46,5 @@ typedef enum
|
||||||
} hsysmodule_t;
|
} hsysmodule_t;
|
||||||
|
|
||||||
void set_default_configuration();
|
void set_default_configuration();
|
||||||
int create_config_entry();
|
|
||||||
void config_autoboot();
|
|
||||||
void config_bootdelay();
|
|
||||||
void config_verification();
|
|
||||||
void config_backlight();
|
|
||||||
void config_auto_hos_poweroff();
|
|
||||||
void config_nogc();
|
|
||||||
|
|
||||||
#endif /* _CONFIG_H_ */
|
#endif /* _CONFIG_H_ */
|
||||||
|
|
|
@ -0,0 +1,227 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (c) 2018 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "di.h"
|
||||||
|
#include "tui.h"
|
||||||
|
#include "../utils/btn.h"
|
||||||
|
#include "../config/config.h"
|
||||||
|
#include "../power/max17050.h"
|
||||||
|
#include "../utils/util.h"
|
||||||
|
|
||||||
|
#ifdef MENU_LOGO_ENABLE
|
||||||
|
extern u8 *Kc_MENU_LOGO;
|
||||||
|
#define X_MENU_LOGO 119
|
||||||
|
#define Y_MENU_LOGO 57
|
||||||
|
#define X_POS_MENU_LOGO 577
|
||||||
|
#define Y_POS_MENU_LOGO 1179
|
||||||
|
#endif //MENU_LOGO_ENABLE
|
||||||
|
|
||||||
|
extern hekate_config h_cfg;
|
||||||
|
|
||||||
|
void tui_sbar(bool force_update)
|
||||||
|
{
|
||||||
|
u32 cx, cy;
|
||||||
|
|
||||||
|
u32 timePassed = get_tmr_s() - h_cfg.sbar_time_keeping;
|
||||||
|
if (!force_update)
|
||||||
|
if (timePassed < 5)
|
||||||
|
return;
|
||||||
|
|
||||||
|
u8 prevFontSize = gfx_con.fntsz;
|
||||||
|
gfx_con.fntsz = 16;
|
||||||
|
h_cfg.sbar_time_keeping = get_tmr_s();
|
||||||
|
|
||||||
|
u32 battPercent = 0;
|
||||||
|
int battVoltCurr = 0;
|
||||||
|
|
||||||
|
gfx_con_getpos(&cx, &cy);
|
||||||
|
gfx_con_setpos(0, 1260);
|
||||||
|
|
||||||
|
max17050_get_property(MAX17050_RepSOC, (int *)&battPercent);
|
||||||
|
max17050_get_property(MAX17050_VCELL, &battVoltCurr);
|
||||||
|
|
||||||
|
gfx_clear_partial_grey(0x30, 1256, 24);
|
||||||
|
gfx_printf("%K%k Battery: %d.%d%% (%d mV) - Charge:", 0xFF303030, 0xFF888888,
|
||||||
|
(battPercent >> 8) & 0xFF, (battPercent & 0xFF) / 26, battVoltCurr);
|
||||||
|
|
||||||
|
max17050_get_property(MAX17050_Current, &battVoltCurr);
|
||||||
|
|
||||||
|
if (battVoltCurr >= 0)
|
||||||
|
gfx_printf(" %k+%d mA%k%K\n",
|
||||||
|
0xFF008800, battVoltCurr / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
|
||||||
|
else
|
||||||
|
gfx_printf(" %k-%d mA%k%K\n",
|
||||||
|
0xFF880000, (~battVoltCurr) / 1000, 0xFFCCCCCC, 0xFF1B1B1B);
|
||||||
|
gfx_con.fntsz = prevFontSize;
|
||||||
|
gfx_con_setpos(cx, cy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol)
|
||||||
|
{
|
||||||
|
u32 cx, cy;
|
||||||
|
if (val > 200)
|
||||||
|
val = 200;
|
||||||
|
|
||||||
|
gfx_con_getpos(&cx, &cy);
|
||||||
|
|
||||||
|
gfx_con_setpos(x, y);
|
||||||
|
|
||||||
|
gfx_printf("%k[%3d%%]%k", fgcol, val, 0xFFCCCCCC);
|
||||||
|
|
||||||
|
x += 7 * gfx_con.fntsz;
|
||||||
|
|
||||||
|
for (int i = 0; i < (gfx_con.fntsz >> 3) * 6; i++)
|
||||||
|
{
|
||||||
|
gfx_line(x, y + i + 1, x + 3 * val, y + i + 1, fgcol);
|
||||||
|
gfx_line(x + 3 * val, y + i + 1, x + 3 * 100, y + i + 1, bgcol);
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx_con_setpos(cx, cy);
|
||||||
|
|
||||||
|
// Update status bar.
|
||||||
|
tui_sbar(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *tui_do_menu(menu_t *menu)
|
||||||
|
{
|
||||||
|
int idx = 0, prev_idx = 0, cnt = 0x7FFFFFFF;
|
||||||
|
|
||||||
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
|
tui_sbar(true);
|
||||||
|
|
||||||
|
#ifdef MENU_LOGO_ENABLE
|
||||||
|
gfx_set_rect_rgb(Kc_MENU_LOGO,
|
||||||
|
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
|
||||||
|
#endif //MENU_LOGO_ENABLE
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||||
|
gfx_con_setpos(menu->x, menu->y);
|
||||||
|
gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n",
|
||||||
|
colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC);
|
||||||
|
|
||||||
|
// Skip caption or seperator lines selection.
|
||||||
|
while (menu->ents[idx].type == MENT_CAPTION ||
|
||||||
|
menu->ents[idx].type == MENT_CHGLINE)
|
||||||
|
{
|
||||||
|
if (prev_idx <= idx || (!idx && prev_idx == cnt - 1))
|
||||||
|
{
|
||||||
|
idx++;
|
||||||
|
if (idx > (cnt - 1))
|
||||||
|
{
|
||||||
|
idx = 0;
|
||||||
|
prev_idx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
idx--;
|
||||||
|
if (idx < 0)
|
||||||
|
{
|
||||||
|
idx = cnt - 1;
|
||||||
|
prev_idx = cnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev_idx = idx;
|
||||||
|
|
||||||
|
// Draw the menu.
|
||||||
|
for (cnt = 0; menu->ents[cnt].type != MENT_END; cnt++)
|
||||||
|
{
|
||||||
|
if (cnt == idx)
|
||||||
|
gfx_con_setcol(0xFF1B1B1B, 1, 0xFFCCCCCC);
|
||||||
|
else
|
||||||
|
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||||
|
// if (menu->ents[cnt].type == MENT_CAPTION)
|
||||||
|
// gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);
|
||||||
|
if (menu->ents[cnt].type != MENT_CHGLINE) {
|
||||||
|
if (cnt == idx)
|
||||||
|
gfx_printf(" %s", menu->ents[cnt].caption);
|
||||||
|
else
|
||||||
|
gfx_printf("%k %s", menu->ents[cnt].color, menu->ents[cnt].caption);//gfx_printf(" %s", menu->ents[cnt].caption);
|
||||||
|
}
|
||||||
|
if(menu->ents[cnt].type == MENT_MENU)
|
||||||
|
gfx_printf("%k...", 0xFF0099EE);
|
||||||
|
gfx_printf(" \n");
|
||||||
|
}
|
||||||
|
gfx_con_setcol(0xFFCCCCCC, 1, 0xFF1B1B1B);
|
||||||
|
gfx_putc('\n');
|
||||||
|
|
||||||
|
// Print help and battery status.
|
||||||
|
gfx_con_setpos(0, 1127);
|
||||||
|
if (h_cfg.emummc_force_disable)
|
||||||
|
gfx_printf("%kNo emuMMC config found.\n", 0xFF800000);
|
||||||
|
gfx_con_setpos(0, 1191);
|
||||||
|
gfx_printf("%k VOL: Move up/down\n PWR: Select option%k", 0xFF555555, 0xFFCCCCCC);
|
||||||
|
|
||||||
|
display_backlight_brightness(h_cfg.backlight, 1000);
|
||||||
|
|
||||||
|
// Wait for user command.
|
||||||
|
u32 btn = btn_wait();
|
||||||
|
|
||||||
|
if (btn & BTN_VOL_DOWN && idx < (cnt - 1))
|
||||||
|
idx++;
|
||||||
|
else if (btn & BTN_VOL_DOWN && idx == (cnt - 1))
|
||||||
|
{
|
||||||
|
idx = 0;
|
||||||
|
prev_idx = -1;
|
||||||
|
}
|
||||||
|
if (btn & BTN_VOL_UP && idx > 0)
|
||||||
|
idx--;
|
||||||
|
else if (btn & BTN_VOL_UP && idx == 0)
|
||||||
|
{
|
||||||
|
idx = cnt - 1;
|
||||||
|
prev_idx = cnt;
|
||||||
|
}
|
||||||
|
if (btn & BTN_POWER)
|
||||||
|
{
|
||||||
|
ment_t *ent = &menu->ents[idx];
|
||||||
|
switch (ent->type)
|
||||||
|
{
|
||||||
|
case MENT_HANDLER:
|
||||||
|
ent->handler(ent->data);
|
||||||
|
break;
|
||||||
|
case MENT_MENU:
|
||||||
|
return tui_do_menu(ent->menu);
|
||||||
|
break;
|
||||||
|
case MENT_DATA:
|
||||||
|
return ent->data;
|
||||||
|
break;
|
||||||
|
case MENT_BACK:
|
||||||
|
return NULL;
|
||||||
|
break;
|
||||||
|
case MENT_HDLR_RE:
|
||||||
|
ent->handler(ent);
|
||||||
|
if (!ent->data)
|
||||||
|
return NULL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gfx_con.fntsz = 16;
|
||||||
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
|
#ifdef MENU_LOGO_ENABLE
|
||||||
|
gfx_set_rect_rgb(Kc_MENU_LOGO,
|
||||||
|
X_MENU_LOGO, Y_MENU_LOGO, X_POS_MENU_LOGO, Y_POS_MENU_LOGO);
|
||||||
|
#endif //MENU_LOGO_ENABLE
|
||||||
|
}
|
||||||
|
tui_sbar(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 naehrwert
|
||||||
|
* Copyright (C) 2018 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TUI_H_
|
||||||
|
#define _TUI_H_
|
||||||
|
|
||||||
|
#include "../utils/types.h"
|
||||||
|
#include "gfx.h"
|
||||||
|
|
||||||
|
#define MENT_END 0
|
||||||
|
#define MENT_HANDLER 1
|
||||||
|
#define MENT_MENU 2
|
||||||
|
#define MENT_DATA 3
|
||||||
|
#define MENT_BACK 4
|
||||||
|
#define MENT_CAPTION 5
|
||||||
|
#define MENT_CHGLINE 6
|
||||||
|
#define MENT_HDLR_RE 7
|
||||||
|
|
||||||
|
typedef struct _ment_t
|
||||||
|
{
|
||||||
|
u32 type;
|
||||||
|
const char *caption;
|
||||||
|
u32 color;
|
||||||
|
void *data;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
void(*handler)(void *);
|
||||||
|
struct _menu_t *menu;
|
||||||
|
};
|
||||||
|
} ment_t;
|
||||||
|
|
||||||
|
typedef struct _menu_t
|
||||||
|
{
|
||||||
|
ment_t *ents;
|
||||||
|
const char *caption;
|
||||||
|
u32 x;
|
||||||
|
u32 y;
|
||||||
|
} menu_t;
|
||||||
|
|
||||||
|
#define MDEF_END() {MENT_END}
|
||||||
|
#define MDEF_HANDLER(caption, _handler, color) { MENT_HANDLER, caption, color, NULL, { .handler = _handler } }
|
||||||
|
#define MDEF_HANDLER_EX(caption, data, _handler, color) { MENT_HANDLER, caption, color, data, { .handler = _handler } }
|
||||||
|
#define MDEF_MENU(caption, _menu) { MENT_MENU, caption, 0, NULL, { .menu = _menu } }
|
||||||
|
#define MDEF_BACK() { MENT_BACK, "Back" }
|
||||||
|
#define MDEF_CAPTION(caption, color) { MENT_CAPTION, caption, color }
|
||||||
|
#define MDEF_CHGLINE() {MENT_CHGLINE}
|
||||||
|
|
||||||
|
void tui_sbar(bool force_update);
|
||||||
|
void tui_pbar(int x, int y, u32 val, u32 fgcol, u32 bgcol);
|
||||||
|
void *tui_do_menu(menu_t *menu);
|
||||||
|
|
||||||
|
#endif
|
|
@ -19,6 +19,7 @@
|
||||||
#include "../config/config.h"
|
#include "../config/config.h"
|
||||||
#include "../gfx/di.h"
|
#include "../gfx/di.h"
|
||||||
#include "../gfx/gfx.h"
|
#include "../gfx/gfx.h"
|
||||||
|
#include "../gfx/tui.h"
|
||||||
#include "../hos/pkg1.h"
|
#include "../hos/pkg1.h"
|
||||||
#include "../hos/pkg2.h"
|
#include "../hos/pkg2.h"
|
||||||
#include "../hos/sept.h"
|
#include "../hos/sept.h"
|
||||||
|
@ -32,6 +33,7 @@
|
||||||
#include "../soc/fuse.h"
|
#include "../soc/fuse.h"
|
||||||
#include "../soc/smmu.h"
|
#include "../soc/smmu.h"
|
||||||
#include "../soc/t210.h"
|
#include "../soc/t210.h"
|
||||||
|
#include "../storage/emummc.h"
|
||||||
#include "../storage/nx_emmc.h"
|
#include "../storage/nx_emmc.h"
|
||||||
#include "../storage/sdmmc.h"
|
#include "../storage/sdmmc.h"
|
||||||
#include "../utils/btn.h"
|
#include "../utils/btn.h"
|
||||||
|
@ -91,8 +93,6 @@ static u8 temp_key[0x10],
|
||||||
package2_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0},
|
package2_key[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0},
|
||||||
titlekek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0};
|
titlekek[KB_FIRMWARE_VERSION_MAX+1][0x10] = {0};
|
||||||
|
|
||||||
static const u32 colors[6] = {COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_VIOLET};
|
|
||||||
|
|
||||||
// key functions
|
// key functions
|
||||||
static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); };
|
static bool _key_exists(const void *data) { return memcmp(data, zeros, 0x10); };
|
||||||
static void _save_key(const char *name, const void *data, const u32 len, char *outbuf);
|
static void _save_key(const char *name, const void *data, const u32 len, char *outbuf);
|
||||||
|
@ -105,26 +105,27 @@ static void _update_ctr(u8 *ctr, u32 ofs);
|
||||||
|
|
||||||
void dump_keys() {
|
void dump_keys() {
|
||||||
display_backlight_brightness(100, 1000);
|
display_backlight_brightness(100, 1000);
|
||||||
gfx_clear_grey(0x1B);
|
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||||
gfx_con_setpos(0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
|
|
||||||
gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n",
|
gfx_printf("[%kLo%kck%kpi%kck%k_R%kCM%k v%d.%d.%d%k]\n\n",
|
||||||
colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC);
|
colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], 0xFFFF00FF, LP_VER_MJ, LP_VER_MN, LP_VER_BF, 0xFFCCCCCC);
|
||||||
|
|
||||||
start_time = get_tmr_us();
|
start_time = get_tmr_us();
|
||||||
|
u32 begin_time = get_tmr_us();
|
||||||
u32 retries = 0;
|
u32 retries = 0;
|
||||||
u32 color_idx = 0;
|
u32 color_idx = 0;
|
||||||
|
|
||||||
tsec_ctxt_t tsec_ctxt;
|
tsec_ctxt_t tsec_ctxt;
|
||||||
sdmmc_t sdmmc;
|
sdmmc_t sdmmc;
|
||||||
|
|
||||||
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4);
|
emummc_storage_init_mmc(&storage, &sdmmc);
|
||||||
TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]);
|
TPRINTFARGS("%kMMC init... ", colors[(color_idx++) % 6]);
|
||||||
|
|
||||||
// Read package1.
|
// Read package1.
|
||||||
u8 *pkg1 = (u8 *)malloc(0x40000);
|
u8 *pkg1 = (u8 *)malloc(0x40000);
|
||||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
emummc_storage_set_mmc_partition(&storage, 1);
|
||||||
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
||||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
||||||
if (!pkg1_id) {
|
if (!pkg1_id) {
|
||||||
EPRINTF("Unknown pkg1 version.");
|
EPRINTF("Unknown pkg1 version.");
|
||||||
|
@ -154,6 +155,7 @@ void dump_keys() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700) {
|
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700) {
|
||||||
|
sd_mount();
|
||||||
if (!f_stat("sd:/sept/payload.bak", NULL)) {
|
if (!f_stat("sd:/sept/payload.bak", NULL)) {
|
||||||
f_unlink("sd:/sept/payload.bin");
|
f_unlink("sd:/sept/payload.bin");
|
||||||
f_rename("sd:/sept/payload.bak", "sd:/sept/payload.bin");
|
f_rename("sd:/sept/payload.bak", "sd:/sept/payload.bin");
|
||||||
|
@ -277,7 +279,7 @@ get_tsec: ;
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify keyblob is not corrupt
|
// verify keyblob is not corrupt
|
||||||
sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block);
|
emummc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + i, 1, keyblob_block);
|
||||||
se_aes_key_set(3, keyblob_mac_key[i], 0x10);
|
se_aes_key_set(3, keyblob_mac_key[i], 0x10);
|
||||||
se_aes_cmac(3, keyblob_mac, 0x10, keyblob_block + 0x10, 0xa0);
|
se_aes_cmac(3, keyblob_mac, 0x10, keyblob_block + 0x10, 0xa0);
|
||||||
if (memcmp(keyblob_block, keyblob_mac, 0x10)) {
|
if (memcmp(keyblob_block, keyblob_mac, 0x10)) {
|
||||||
|
@ -336,7 +338,7 @@ get_tsec: ;
|
||||||
u8 *pkg2 = NULL;
|
u8 *pkg2 = NULL;
|
||||||
pkg2_kip1_info_t *ki = NULL;
|
pkg2_kip1_info_t *ki = NULL;
|
||||||
|
|
||||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
emummc_storage_set_mmc_partition(&storage, 0);
|
||||||
// Parse eMMC GPT.
|
// Parse eMMC GPT.
|
||||||
LIST_INIT(gpt);
|
LIST_INIT(gpt);
|
||||||
nx_emmc_gpt_parse(&gpt, &storage);
|
nx_emmc_gpt_parse(&gpt, &storage);
|
||||||
|
@ -380,7 +382,7 @@ get_tsec: ;
|
||||||
EPRINTF("Failed to derive Package2 key.");
|
EPRINTF("Failed to derive Package2 key.");
|
||||||
goto pkg2_done;
|
goto pkg2_done;
|
||||||
} else if (pkg2_kb != pkg1_id->kb)
|
} else if (pkg2_kb != pkg1_id->kb)
|
||||||
EPRINTF("Warning: Package1-Package2 mismatch.");
|
EPRINTFARGS("Warning! Package1-Package2 mismatch: %d, %d", pkg1_id->kb, pkg2_kb);
|
||||||
|
|
||||||
pkg2_hdr = pkg2_decrypt(pkg2);
|
pkg2_hdr = pkg2_decrypt(pkg2);
|
||||||
if (!pkg2_hdr) {
|
if (!pkg2_hdr) {
|
||||||
|
@ -749,7 +751,7 @@ pkg2_done:
|
||||||
dismount:
|
dismount:
|
||||||
f_mount(NULL, "emmc:", 1);
|
f_mount(NULL, "emmc:", 1);
|
||||||
nx_emmc_gpt_free(&gpt);
|
nx_emmc_gpt_free(&gpt);
|
||||||
sdmmc_storage_end(&storage);
|
emummc_storage_end(&storage);
|
||||||
|
|
||||||
// derive eticket_rsa_kek and ssl_rsa_kek
|
// derive eticket_rsa_kek and ssl_rsa_kek
|
||||||
if (_key_exists(es_keys[0]) && _key_exists(es_keys[1]) && _key_exists(master_key[0])) {
|
if (_key_exists(es_keys[0]) && _key_exists(es_keys[1]) && _key_exists(master_key[0])) {
|
||||||
|
@ -828,31 +830,29 @@ key_output: ;
|
||||||
|
|
||||||
//gfx_con.fntsz = 8; gfx_puts(text_buffer); gfx_con.fntsz = 16;
|
//gfx_con.fntsz = 8; gfx_puts(text_buffer); gfx_con.fntsz = 16;
|
||||||
|
|
||||||
TPRINTFARGS("\n%kFound %d keys.\n%kLockpick totally", colors[(color_idx) % 6], _key_count, colors[(color_idx + 1) % 6]);
|
end_time = get_tmr_us();
|
||||||
color_idx += 2;
|
gfx_printf("\n%kFound %d keys.", colors[(color_idx++) % 6], _key_count);
|
||||||
|
_key_count = 0;
|
||||||
|
gfx_printf("\n%kLockpick totally done in %d us", colors[(color_idx++) % 6], end_time - begin_time);
|
||||||
|
gfx_printf("\n%kFound through master_key_%02x\n", colors[(color_idx++) % 6], MAX_KEY - 1);
|
||||||
|
|
||||||
f_mkdir("switch");
|
f_mkdir("sd:/switch");
|
||||||
char keyfile_path[30] = "sd:/switch/";
|
char keyfile_path[30] = "sd:/switch/";
|
||||||
if (!(fuse_read_odm(4) & 3))
|
if (!(fuse_read_odm(4) & 3))
|
||||||
sprintf(&keyfile_path[11], "prod.keys");
|
sprintf(&keyfile_path[11], "prod.keys");
|
||||||
else
|
else
|
||||||
sprintf(&keyfile_path[11], "dev.keys");
|
sprintf(&keyfile_path[11], "dev.keys");
|
||||||
if (!sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) {
|
if (sd_mount() && !sd_save_to_file(text_buffer, strlen(text_buffer), keyfile_path) && !f_stat(keyfile_path, &fno)) {
|
||||||
gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path);
|
gfx_printf("%kWrote %d bytes to %s\n", colors[(color_idx++) % 6], (u32)fno.fsize, keyfile_path);
|
||||||
} else
|
} else
|
||||||
EPRINTF("Failed to save keys to SD.");
|
EPRINTF("Failed to save keys to SD.");
|
||||||
sd_unmount();
|
h_cfg.emummc_force_disable = emummc_load_cfg();
|
||||||
|
|
||||||
out_wait:
|
out_wait:
|
||||||
gfx_printf("\n%kVOL + -> Reboot to RCM\n%kVOL - -> Reboot normally\n%kPower -> Power off", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]);
|
sd_unmount();
|
||||||
|
gfx_printf("\n%kPress any key to return to the main menu.", colors[(color_idx) % 6], colors[(color_idx + 1) % 6], colors[(color_idx + 2) % 6]);
|
||||||
|
|
||||||
u32 btn = btn_wait();
|
btn_wait();
|
||||||
if (btn & BTN_VOL_UP)
|
|
||||||
reboot_rcm();
|
|
||||||
else if (btn & BTN_VOL_DOWN)
|
|
||||||
reboot_normal();
|
|
||||||
else
|
|
||||||
power_off();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _save_key(const char *name, const void *data, const u32 len, char *outbuf) {
|
static void _save_key(const char *name, const void *data, const u32 len, char *outbuf) {
|
||||||
|
|
|
@ -42,10 +42,11 @@ typedef struct {
|
||||||
u32 visit_count;
|
u32 visit_count;
|
||||||
u8 tweak[0x10];
|
u8 tweak[0x10];
|
||||||
u8 cached_sector[0x200];
|
u8 cached_sector[0x200];
|
||||||
|
u8 align[8];
|
||||||
} sector_cache_t;
|
} sector_cache_t;
|
||||||
|
|
||||||
#define MAX_SEC_CACHE_ENTRIES 64
|
#define MAX_SEC_CACHE_ENTRIES 64
|
||||||
static sector_cache_t *sector_cache = (sector_cache_t*)0x40020000;
|
static sector_cache_t *sector_cache = (sector_cache_t*)0x40022000;
|
||||||
static u32 secindex = 0;
|
static u32 secindex = 0;
|
||||||
|
|
||||||
DSTATUS disk_status (
|
DSTATUS disk_status (
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
/ 3: f_lseek() function is removed in addition to 2. */
|
/ 3: f_lseek() function is removed in addition to 2. */
|
||||||
|
|
||||||
|
|
||||||
#define FF_USE_STRFUNC 0
|
#define FF_USE_STRFUNC 2
|
||||||
/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().
|
/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().
|
||||||
/
|
/
|
||||||
/ 0: Disable string functions.
|
/ 0: Disable string functions.
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
/ 2: Enable with LF-CRLF conversion. */
|
/ 2: Enable with LF-CRLF conversion. */
|
||||||
|
|
||||||
|
|
||||||
#define FF_USE_FIND 0
|
#define FF_USE_FIND 1
|
||||||
/* This option switches filtered directory read functions, f_findfirst() and
|
/* This option switches filtered directory read functions, f_findfirst() and
|
||||||
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
|
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
/* This option switches f_expand function. (0:Disable or 1:Enable) */
|
/* This option switches f_expand function. (0:Disable or 1:Enable) */
|
||||||
|
|
||||||
|
|
||||||
#define FF_USE_CHMOD 0
|
#define FF_USE_CHMOD 1
|
||||||
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
|
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
|
||||||
/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
|
/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
|
||||||
|
|
||||||
|
|
|
@ -21,13 +21,16 @@
|
||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
#include "gfx/di.h"
|
#include "gfx/di.h"
|
||||||
#include "gfx/gfx.h"
|
#include "gfx/gfx.h"
|
||||||
|
#include "gfx/tui.h"
|
||||||
#include "libs/fatfs/ff.h"
|
#include "libs/fatfs/ff.h"
|
||||||
#include "mem/heap.h"
|
#include "mem/heap.h"
|
||||||
#include "power/max77620.h"
|
#include "power/max77620.h"
|
||||||
#include "rtc/max77620-rtc.h"
|
#include "rtc/max77620-rtc.h"
|
||||||
#include "soc/bpmp.h"
|
#include "soc/bpmp.h"
|
||||||
#include "soc/hw_init.h"
|
#include "soc/hw_init.h"
|
||||||
|
#include "storage/emummc.h"
|
||||||
#include "storage/sdmmc.h"
|
#include "storage/sdmmc.h"
|
||||||
|
#include "utils/sprintf.h"
|
||||||
#include "utils/util.h"
|
#include "utils/util.h"
|
||||||
|
|
||||||
#include "keys/keys.h"
|
#include "keys/keys.h"
|
||||||
|
@ -79,27 +82,27 @@ void sd_unmount()
|
||||||
|
|
||||||
void *sd_file_read(const char *path, u32 *fsize)
|
void *sd_file_read(const char *path, u32 *fsize)
|
||||||
{
|
{
|
||||||
FIL fp;
|
FIL fp;
|
||||||
if (f_open(&fp, path, FA_READ) != FR_OK)
|
if (f_open(&fp, path, FA_READ) != FR_OK)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
u32 size = f_size(&fp);
|
u32 size = f_size(&fp);
|
||||||
if (fsize)
|
if (fsize)
|
||||||
*fsize = size;
|
*fsize = size;
|
||||||
|
|
||||||
void *buf = malloc(size);
|
void *buf = malloc(size);
|
||||||
|
|
||||||
if (f_read(&fp, buf, size, NULL) != FR_OK)
|
if (f_read(&fp, buf, size, NULL) != FR_OK)
|
||||||
{
|
{
|
||||||
free(buf);
|
free(buf);
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
|
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd_save_to_file(void *buf, u32 size, const char *filename)
|
int sd_save_to_file(void *buf, u32 size, const char *filename)
|
||||||
|
@ -145,6 +148,34 @@ void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dump_sysnand()
|
||||||
|
{
|
||||||
|
h_cfg.emummc_force_disable = true;
|
||||||
|
b_cfg.extra_cfg &= ~EXTRA_CFG_DUMP_EMUMMC;
|
||||||
|
dump_keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
void dump_emunand()
|
||||||
|
{
|
||||||
|
if (h_cfg.emummc_force_disable)
|
||||||
|
return;
|
||||||
|
emu_cfg.enabled = 1;
|
||||||
|
b_cfg.extra_cfg |= EXTRA_CFG_DUMP_EMUMMC;
|
||||||
|
dump_keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
ment_t ment_top[] = {
|
||||||
|
MDEF_HANDLER("Dump keys from SysNAND", dump_sysnand, COLOR_RED),
|
||||||
|
MDEF_HANDLER("Dump keys from emuMMC", dump_emunand, COLOR_ORANGE),
|
||||||
|
MDEF_CAPTION("---------------", COLOR_YELLOW),
|
||||||
|
MDEF_HANDLER("Reboot (Normal)", reboot_normal, COLOR_GREEN),
|
||||||
|
MDEF_HANDLER("Reboot (RCM)", reboot_rcm, COLOR_BLUE),
|
||||||
|
MDEF_HANDLER("Power off", power_off, COLOR_VIOLET),
|
||||||
|
MDEF_END()
|
||||||
|
};
|
||||||
|
|
||||||
|
menu_t menu_top = { ment_top, NULL, 0, 0 };
|
||||||
|
|
||||||
#define IPL_STACK_TOP 0x4003F000
|
#define IPL_STACK_TOP 0x4003F000
|
||||||
#define IPL_HEAP_START 0x90020000
|
#define IPL_HEAP_START 0x90020000
|
||||||
|
|
||||||
|
@ -166,6 +197,25 @@ void ipl_main()
|
||||||
|
|
||||||
bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST);
|
bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST);
|
||||||
|
|
||||||
sd_mount();
|
h_cfg.emummc_force_disable = emummc_load_cfg();
|
||||||
dump_keys();
|
|
||||||
|
if (b_cfg.boot_cfg & BOOT_CFG_SEPT_RUN)
|
||||||
|
{
|
||||||
|
if (!(b_cfg.extra_cfg & EXTRA_CFG_DUMP_EMUMMC))
|
||||||
|
h_cfg.emummc_force_disable = true;
|
||||||
|
dump_keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h_cfg.emummc_force_disable)
|
||||||
|
{
|
||||||
|
ment_top[1].type = MENT_CAPTION;
|
||||||
|
ment_top[1].color = 0xFF555555;
|
||||||
|
ment_top[1].handler = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
tui_do_menu(&menu_top);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
bpmp_halt();
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,9 @@
|
||||||
|
|
||||||
#define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */
|
#define MAX17050_VMAX_TOLERANCE 50 /* 50 mV */
|
||||||
|
|
||||||
|
#pragma GCC push_options
|
||||||
|
#pragma GCC optimize ("Os")
|
||||||
|
|
||||||
int max17050_get_property(enum MAX17050_reg reg, int *value)
|
int max17050_get_property(enum MAX17050_reg reg, int *value)
|
||||||
{
|
{
|
||||||
u16 data;
|
u16 data;
|
||||||
|
@ -264,3 +267,5 @@ int max17050_fix_configuration()
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma GCC pop_options
|
|
@ -0,0 +1,266 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "emummc.h"
|
||||||
|
#include "sdmmc.h"
|
||||||
|
#include "../config/config.h"
|
||||||
|
#include "../config/ini.h"
|
||||||
|
#include "../gfx/gfx.h"
|
||||||
|
#include "../libs/fatfs/ff.h"
|
||||||
|
#include "../mem/heap.h"
|
||||||
|
#include "../utils/list.h"
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
extern sdmmc_t sd_sdmmc;
|
||||||
|
extern sdmmc_storage_t sd_storage;
|
||||||
|
extern FATFS sd_fs;
|
||||||
|
|
||||||
|
extern hekate_config h_cfg;
|
||||||
|
|
||||||
|
extern bool sd_mount();
|
||||||
|
extern void sd_unmount();
|
||||||
|
|
||||||
|
bool emummc_load_cfg()
|
||||||
|
{
|
||||||
|
sd_mount();
|
||||||
|
emu_cfg.enabled = 0;
|
||||||
|
emu_cfg.path = NULL;
|
||||||
|
emu_cfg.nintendo_path = NULL;
|
||||||
|
emu_cfg.sector = 0;
|
||||||
|
emu_cfg.id = 0;
|
||||||
|
emu_cfg.file_based_part_size = 0;
|
||||||
|
emu_cfg.active_part = 0;
|
||||||
|
emu_cfg.fs_ver = 0;
|
||||||
|
emu_cfg.emummc_file_based_path = (char *)malloc(0x80);
|
||||||
|
|
||||||
|
LIST_INIT(ini_sections);
|
||||||
|
if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false))
|
||||||
|
{
|
||||||
|
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
|
||||||
|
{
|
||||||
|
if (ini_sec->type == INI_CHOICE)
|
||||||
|
{
|
||||||
|
if (strcmp(ini_sec->name, "emummc"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
|
||||||
|
{
|
||||||
|
if (!strcmp("enabled", kv->key))
|
||||||
|
emu_cfg.enabled = atoi(kv->val);
|
||||||
|
else if (!strcmp("sector", kv->key))
|
||||||
|
emu_cfg.sector = strtol(kv->val, NULL, 16);
|
||||||
|
else if (!strcmp("id", kv->key))
|
||||||
|
emu_cfg.id = strtol(kv->val, NULL, 16);
|
||||||
|
else if (!strcmp("path", kv->key))
|
||||||
|
emu_cfg.path = kv->val;
|
||||||
|
else if (!strcmp("nintendo_path", kv->key))
|
||||||
|
emu_cfg.nintendo_path = kv->val;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int emummc_raw_get_part_off(int part_idx)
|
||||||
|
{
|
||||||
|
switch (part_idx)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return 2;
|
||||||
|
case 1:
|
||||||
|
return 0;
|
||||||
|
case 2:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc)
|
||||||
|
{
|
||||||
|
FILINFO fno;
|
||||||
|
if (!sdmmc_storage_init_mmc(storage, sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4))
|
||||||
|
{
|
||||||
|
EPRINTF("Failed to init eMMC.");
|
||||||
|
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (h_cfg.emummc_force_disable)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
emu_cfg.active_part = 0;
|
||||||
|
if (!sd_mount())
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (emu_cfg.enabled && !emu_cfg.sector)
|
||||||
|
{
|
||||||
|
strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path);
|
||||||
|
strcat(emu_cfg.emummc_file_based_path, "/eMMC");
|
||||||
|
|
||||||
|
if (f_stat(emu_cfg.emummc_file_based_path, &fno))
|
||||||
|
{
|
||||||
|
EPRINTF("Failed to open eMMC folder.");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
f_chmod(emu_cfg.emummc_file_based_path, AM_ARC, AM_ARC);
|
||||||
|
|
||||||
|
strcat(emu_cfg.emummc_file_based_path, "/00");
|
||||||
|
if (f_stat(emu_cfg.emummc_file_based_path, &fno))
|
||||||
|
{
|
||||||
|
EPRINTF("Failed to open emuMMC rawnand.");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
emu_cfg.file_based_part_size = fno.fsize >> 9;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
out:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int emummc_storage_end(sdmmc_storage_t *storage)
|
||||||
|
{
|
||||||
|
sd_unmount();
|
||||||
|
sdmmc_storage_end(storage);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
|
||||||
|
{
|
||||||
|
FIL fp;
|
||||||
|
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||||
|
return sdmmc_storage_read(storage, sector, num_sectors, buf);
|
||||||
|
else if (emu_cfg.sector)
|
||||||
|
{
|
||||||
|
sector += emu_cfg.sector;
|
||||||
|
sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000;
|
||||||
|
return sdmmc_storage_read(&sd_storage, sector, num_sectors, buf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!emu_cfg.active_part)
|
||||||
|
{
|
||||||
|
u32 file_part = sector / emu_cfg.file_based_part_size;
|
||||||
|
sector = sector % emu_cfg.file_based_part_size;
|
||||||
|
if (file_part >= 10)
|
||||||
|
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0';
|
||||||
|
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ))
|
||||||
|
{
|
||||||
|
EPRINTF("Failed to open emuMMC image.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
f_lseek(&fp, (u64)sector << 9);
|
||||||
|
if (f_read(&fp, buf, (u64)num_sectors << 9, NULL))
|
||||||
|
{
|
||||||
|
EPRINTF("Failed to read emuMMC image.");
|
||||||
|
f_close(&fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
f_close(&fp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf)
|
||||||
|
{
|
||||||
|
FIL fp;
|
||||||
|
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||||
|
return sdmmc_storage_write(storage, sector, num_sectors, buf);
|
||||||
|
else if (emu_cfg.sector)
|
||||||
|
{
|
||||||
|
sector += emu_cfg.sector;
|
||||||
|
sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000;
|
||||||
|
return sdmmc_storage_write(&sd_storage, sector, num_sectors, buf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!emu_cfg.active_part)
|
||||||
|
{
|
||||||
|
u32 file_part = sector / emu_cfg.file_based_part_size;
|
||||||
|
sector = sector % emu_cfg.file_based_part_size;
|
||||||
|
if (file_part >= 10)
|
||||||
|
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0';
|
||||||
|
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_WRITE))
|
||||||
|
{
|
||||||
|
gfx_printf("e5\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
f_lseek(&fp, (u64)sector << 9);
|
||||||
|
if (f_write(&fp, buf, (u64)num_sectors << 9, NULL))
|
||||||
|
{
|
||||||
|
gfx_printf("e6\n");
|
||||||
|
f_close(&fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
f_close(&fp);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition)
|
||||||
|
{
|
||||||
|
emu_cfg.active_part = partition;
|
||||||
|
|
||||||
|
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
|
||||||
|
sdmmc_storage_set_mmc_partition(storage, partition);
|
||||||
|
else if (emu_cfg.sector)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path);
|
||||||
|
strcat(emu_cfg.emummc_file_based_path, "/eMMC");
|
||||||
|
|
||||||
|
switch (partition)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
strcat(emu_cfg.emummc_file_based_path, "/00");
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
strcat(emu_cfg.emummc_file_based_path, "/BOOT0");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
strcat(emu_cfg.emummc_file_based_path, "/BOOT1");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2019 CTCaer
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EMUMMC_H
|
||||||
|
#define EMUMMC_H
|
||||||
|
|
||||||
|
#include "sdmmc.h"
|
||||||
|
#include "../utils/types.h"
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
EMUMMC_TYPE_NONE = 0,
|
||||||
|
EMUMMC_TYPE_PARTITION = 1,
|
||||||
|
EMUMMC_TYPE_FILES = 2,
|
||||||
|
} emummc_type_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EMUMMC_MMC_NAND = 0,
|
||||||
|
EMUMMC_MMC_SD = 1,
|
||||||
|
EMUMMC_MMC_GC = 2,
|
||||||
|
} emummc_mmc_t;
|
||||||
|
|
||||||
|
typedef struct _emummc_cfg_t
|
||||||
|
{
|
||||||
|
int enabled;
|
||||||
|
u64 sector;
|
||||||
|
u16 id;
|
||||||
|
char *path;
|
||||||
|
char *nintendo_path;
|
||||||
|
// Internal.
|
||||||
|
char *emummc_file_based_path;
|
||||||
|
u32 file_based_part_size;
|
||||||
|
u32 active_part;
|
||||||
|
int fs_ver;
|
||||||
|
} emummc_cfg_t;
|
||||||
|
|
||||||
|
emummc_cfg_t emu_cfg;
|
||||||
|
|
||||||
|
bool emummc_load_cfg();
|
||||||
|
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
|
||||||
|
int emummc_storage_end(sdmmc_storage_t *storage);
|
||||||
|
int emummc_storage_read(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
|
||||||
|
int emummc_storage_write(sdmmc_storage_t *storage, u32 sector, u32 num_sectors, void *buf);
|
||||||
|
int emummc_storage_set_mmc_partition(sdmmc_storage_t *storage, u32 partition);
|
||||||
|
|
||||||
|
#endif
|
|
@ -17,6 +17,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "nx_emmc.h"
|
#include "nx_emmc.h"
|
||||||
|
#include "emummc.h"
|
||||||
#include "../mem/heap.h"
|
#include "../mem/heap.h"
|
||||||
#include "../utils/list.h"
|
#include "../utils/list.h"
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ void nx_emmc_gpt_parse(link_t *gpt, sdmmc_storage_t *storage)
|
||||||
{
|
{
|
||||||
u8 *buf = (u8 *)malloc(NX_GPT_NUM_BLOCKS * NX_EMMC_BLOCKSIZE);
|
u8 *buf = (u8 *)malloc(NX_GPT_NUM_BLOCKS * NX_EMMC_BLOCKSIZE);
|
||||||
|
|
||||||
sdmmc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, buf);
|
emummc_storage_read(storage, NX_GPT_FIRST_LBA, NX_GPT_NUM_BLOCKS, buf);
|
||||||
|
|
||||||
gpt_header_t *hdr = (gpt_header_t *)buf;
|
gpt_header_t *hdr = (gpt_header_t *)buf;
|
||||||
for (u32 i = 0; i < hdr->num_part_ents; i++)
|
for (u32 i = 0; i < hdr->num_part_ents; i++)
|
||||||
|
@ -65,7 +66,7 @@ int nx_emmc_part_read(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_of
|
||||||
// The last LBA is inclusive.
|
// The last LBA is inclusive.
|
||||||
if (part->lba_start + sector_off > part->lba_end)
|
if (part->lba_start + sector_off > part->lba_end)
|
||||||
return 0;
|
return 0;
|
||||||
return sdmmc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf);
|
return emummc_storage_read(storage, part->lba_start + sector_off, num_sectors, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf)
|
int nx_emmc_part_write(sdmmc_storage_t *storage, emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf)
|
||||||
|
|
|
@ -68,6 +68,8 @@ typedef volatile unsigned char vu8;
|
||||||
typedef volatile unsigned short vu16;
|
typedef volatile unsigned short vu16;
|
||||||
typedef volatile unsigned int vu32;
|
typedef volatile unsigned int vu32;
|
||||||
|
|
||||||
|
static const u32 colors[6] = {COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_BLUE, COLOR_VIOLET};
|
||||||
|
|
||||||
typedef int bool;
|
typedef int bool;
|
||||||
#define true 1
|
#define true 1
|
||||||
#define false 0
|
#define false 0
|
||||||
|
@ -76,6 +78,8 @@ typedef int bool;
|
||||||
#define BOOT_CFG_FROM_LAUNCH (1 << 1)
|
#define BOOT_CFG_FROM_LAUNCH (1 << 1)
|
||||||
#define BOOT_CFG_SEPT_RUN (1 << 7)
|
#define BOOT_CFG_SEPT_RUN (1 << 7)
|
||||||
|
|
||||||
|
#define EXTRA_CFG_DUMP_EMUMMC (1 << 0)
|
||||||
|
|
||||||
typedef struct __attribute__((__packed__)) _boot_cfg_t
|
typedef struct __attribute__((__packed__)) _boot_cfg_t
|
||||||
{
|
{
|
||||||
u8 boot_cfg;
|
u8 boot_cfg;
|
||||||
|
|
Loading…
Reference in New Issue