mirror of
https://github.com/Decscots/Lockpick_RCM.git
synced 2024-11-01 06:25:06 +01:00
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 "ini.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../gfx/tui.h"
|
||||
#include "../libs/fatfs/ff.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
@ -53,616 +52,3 @@ void set_default_configuration()
|
||||
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;
|
||||
|
||||
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_ */
|
||||
|
227
source/gfx/tui.c
Normal file
227
source/gfx/tui.c
Normal file
@ -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;
|
||||
}
|
66
source/gfx/tui.h
Normal file
66
source/gfx/tui.h
Normal file
@ -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 "../gfx/di.h"
|
||||
#include "../gfx/gfx.h"
|
||||
#include "../gfx/tui.h"
|
||||
#include "../hos/pkg1.h"
|
||||
#include "../hos/pkg2.h"
|
||||
#include "../hos/sept.h"
|
||||
@ -32,6 +33,7 @@
|
||||
#include "../soc/fuse.h"
|
||||
#include "../soc/smmu.h"
|
||||
#include "../soc/t210.h"
|
||||
#include "../storage/emummc.h"
|
||||
#include "../storage/nx_emmc.h"
|
||||
#include "../storage/sdmmc.h"
|
||||
#include "../utils/btn.h"
|
||||
@ -91,8 +93,6 @@ static u8 temp_key[0x10],
|
||||
package2_key[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
|
||||
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);
|
||||
@ -105,26 +105,27 @@ static void _update_ctr(u8 *ctr, u32 ofs);
|
||||
|
||||
void dump_keys() {
|
||||
display_backlight_brightness(100, 1000);
|
||||
gfx_clear_grey(0x1B);
|
||||
gfx_clear_partial_grey(0x1B, 0, 1256);
|
||||
gfx_con_setpos(0, 0);
|
||||
|
||||
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);
|
||||
|
||||
start_time = get_tmr_us();
|
||||
u32 begin_time = get_tmr_us();
|
||||
u32 retries = 0;
|
||||
u32 color_idx = 0;
|
||||
|
||||
tsec_ctxt_t tsec_ctxt;
|
||||
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]);
|
||||
|
||||
// Read package1.
|
||||
u8 *pkg1 = (u8 *)malloc(0x40000);
|
||||
sdmmc_storage_set_mmc_partition(&storage, 1);
|
||||
sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
||||
emummc_storage_set_mmc_partition(&storage, 1);
|
||||
emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
||||
if (!pkg1_id) {
|
||||
EPRINTF("Unknown pkg1 version.");
|
||||
@ -154,6 +155,7 @@ void dump_keys() {
|
||||
}
|
||||
|
||||
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700) {
|
||||
sd_mount();
|
||||
if (!f_stat("sd:/sept/payload.bak", NULL)) {
|
||||
f_unlink("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
|
||||
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_cmac(3, keyblob_mac, 0x10, keyblob_block + 0x10, 0xa0);
|
||||
if (memcmp(keyblob_block, keyblob_mac, 0x10)) {
|
||||
@ -336,7 +338,7 @@ get_tsec: ;
|
||||
u8 *pkg2 = NULL;
|
||||
pkg2_kip1_info_t *ki = NULL;
|
||||
|
||||
sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||
emummc_storage_set_mmc_partition(&storage, 0);
|
||||
// Parse eMMC GPT.
|
||||
LIST_INIT(gpt);
|
||||
nx_emmc_gpt_parse(&gpt, &storage);
|
||||
@ -380,7 +382,7 @@ get_tsec: ;
|
||||
EPRINTF("Failed to derive Package2 key.");
|
||||
goto pkg2_done;
|
||||
} 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);
|
||||
if (!pkg2_hdr) {
|
||||
@ -749,7 +751,7 @@ pkg2_done:
|
||||
dismount:
|
||||
f_mount(NULL, "emmc:", 1);
|
||||
nx_emmc_gpt_free(&gpt);
|
||||
sdmmc_storage_end(&storage);
|
||||
emummc_storage_end(&storage);
|
||||
|
||||
// derive eticket_rsa_kek and ssl_rsa_kek
|
||||
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;
|
||||
|
||||
TPRINTFARGS("\n%kFound %d keys.\n%kLockpick totally", colors[(color_idx) % 6], _key_count, colors[(color_idx + 1) % 6]);
|
||||
color_idx += 2;
|
||||
end_time = get_tmr_us();
|
||||
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/";
|
||||
if (!(fuse_read_odm(4) & 3))
|
||||
sprintf(&keyfile_path[11], "prod.keys");
|
||||
else
|
||||
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);
|
||||
} else
|
||||
EPRINTF("Failed to save keys to SD.");
|
||||
sd_unmount();
|
||||
h_cfg.emummc_force_disable = emummc_load_cfg();
|
||||
|
||||
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();
|
||||
if (btn & BTN_VOL_UP)
|
||||
reboot_rcm();
|
||||
else if (btn & BTN_VOL_DOWN)
|
||||
reboot_normal();
|
||||
else
|
||||
power_off();
|
||||
btn_wait();
|
||||
}
|
||||
|
||||
static void _save_key(const char *name, const void *data, const u32 len, char *outbuf) {
|
||||
|
@ -42,10 +42,11 @@ typedef struct {
|
||||
u32 visit_count;
|
||||
u8 tweak[0x10];
|
||||
u8 cached_sector[0x200];
|
||||
u8 align[8];
|
||||
} sector_cache_t;
|
||||
|
||||
#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;
|
||||
|
||||
DSTATUS disk_status (
|
||||
|
@ -25,7 +25,7 @@
|
||||
/ 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().
|
||||
/
|
||||
/ 0: Disable string functions.
|
||||
@ -33,7 +33,7 @@
|
||||
/ 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
|
||||
/ 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) */
|
||||
|
||||
|
||||
#define FF_USE_CHMOD 0
|
||||
#define FF_USE_CHMOD 1
|
||||
/* 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. */
|
||||
|
||||
|
@ -21,13 +21,16 @@
|
||||
#include "config/config.h"
|
||||
#include "gfx/di.h"
|
||||
#include "gfx/gfx.h"
|
||||
#include "gfx/tui.h"
|
||||
#include "libs/fatfs/ff.h"
|
||||
#include "mem/heap.h"
|
||||
#include "power/max77620.h"
|
||||
#include "rtc/max77620-rtc.h"
|
||||
#include "soc/bpmp.h"
|
||||
#include "soc/hw_init.h"
|
||||
#include "storage/emummc.h"
|
||||
#include "storage/sdmmc.h"
|
||||
#include "utils/sprintf.h"
|
||||
#include "utils/util.h"
|
||||
|
||||
#include "keys/keys.h"
|
||||
@ -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_HEAP_START 0x90020000
|
||||
|
||||
@ -166,6 +197,25 @@ void ipl_main()
|
||||
|
||||
bpmp_clk_rate_set(BPMP_CLK_SUPER_BOOST);
|
||||
|
||||
sd_mount();
|
||||
h_cfg.emummc_force_disable = emummc_load_cfg();
|
||||
|
||||
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 */
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("Os")
|
||||
|
||||
int max17050_get_property(enum MAX17050_reg reg, int *value)
|
||||
{
|
||||
u16 data;
|
||||
@ -264,3 +267,5 @@ int max17050_fix_configuration()
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma GCC pop_options
|
266
source/storage/emummc.c
Normal file
266
source/storage/emummc.c
Normal file
@ -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;
|
||||
}
|
59
source/storage/emummc.h
Normal file
59
source/storage/emummc.h
Normal file
@ -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 "nx_emmc.h"
|
||||
#include "emummc.h"
|
||||
#include "../mem/heap.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);
|
||||
|
||||
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;
|
||||
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.
|
||||
if (part->lba_start + sector_off > part->lba_end)
|
||||
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)
|
||||
|
@ -68,6 +68,8 @@ typedef volatile unsigned char vu8;
|
||||
typedef volatile unsigned short vu16;
|
||||
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;
|
||||
#define true 1
|
||||
#define false 0
|
||||
@ -76,6 +78,8 @@ typedef int bool;
|
||||
#define BOOT_CFG_FROM_LAUNCH (1 << 1)
|
||||
#define BOOT_CFG_SEPT_RUN (1 << 7)
|
||||
|
||||
#define EXTRA_CFG_DUMP_EMUMMC (1 << 0)
|
||||
|
||||
typedef struct __attribute__((__packed__)) _boot_cfg_t
|
||||
{
|
||||
u8 boot_cfg;
|
||||
|
Loading…
Reference in New Issue
Block a user