diff --git a/source/config/config.c b/source/config/config.c
index f9df696..2fa964b 100644
--- a/source/config/config.c
+++ b/source/config/config.c
@@ -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
diff --git a/source/config/config.h b/source/config/config.h
index 8cd34e1..1f6c36d 100644
--- a/source/config/config.h
+++ b/source/config/config.h
@@ -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_ */
diff --git a/source/gfx/tui.c b/source/gfx/tui.c
new file mode 100644
index 0000000..4960c8c
--- /dev/null
+++ b/source/gfx/tui.c
@@ -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 .
+ */
+
+#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;
+}
diff --git a/source/gfx/tui.h b/source/gfx/tui.h
new file mode 100644
index 0000000..2b7d3f7
--- /dev/null
+++ b/source/gfx/tui.h
@@ -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 .
+*/
+
+#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
diff --git a/source/keys/keys.c b/source/keys/keys.c
index 6572449..6c25aec 100644
--- a/source/keys/keys.c
+++ b/source/keys/keys.c
@@ -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) {
diff --git a/source/libs/fatfs/diskio.c b/source/libs/fatfs/diskio.c
index f33f011..97f8336 100644
--- a/source/libs/fatfs/diskio.c
+++ b/source/libs/fatfs/diskio.c
@@ -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 (
diff --git a/source/libs/fatfs/ffconf.h b/source/libs/fatfs/ffconf.h
index ca13b33..221c909 100644
--- a/source/libs/fatfs/ffconf.h
+++ b/source/libs/fatfs/ffconf.h
@@ -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. */
diff --git a/source/main.c b/source/main.c
index fb03dc7..3fcdef5 100644
--- a/source/main.c
+++ b/source/main.c
@@ -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"
@@ -79,27 +82,27 @@ void sd_unmount()
void *sd_file_read(const char *path, u32 *fsize)
{
- FIL fp;
- if (f_open(&fp, path, FA_READ) != FR_OK)
- return NULL;
+ FIL fp;
+ if (f_open(&fp, path, FA_READ) != FR_OK)
+ return NULL;
- u32 size = f_size(&fp);
- if (fsize)
- *fsize = size;
+ u32 size = f_size(&fp);
+ if (fsize)
+ *fsize = size;
- void *buf = malloc(size);
+ void *buf = malloc(size);
- if (f_read(&fp, buf, size, NULL) != FR_OK)
- {
- free(buf);
- f_close(&fp);
+ if (f_read(&fp, buf, size, NULL) != FR_OK)
+ {
+ free(buf);
+ 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)
@@ -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();
- dump_keys();
+ 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();
}
diff --git a/source/power/max17050.c b/source/power/max17050.c
index 2a2c8f6..d34c340 100644
--- a/source/power/max17050.c
+++ b/source/power/max17050.c
@@ -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
\ No newline at end of file
diff --git a/source/storage/emummc.c b/source/storage/emummc.c
new file mode 100644
index 0000000..deae70e
--- /dev/null
+++ b/source/storage/emummc.c
@@ -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 .
+ */
+
+#include
+#include
+
+#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;
+}
diff --git a/source/storage/emummc.h b/source/storage/emummc.h
new file mode 100644
index 0000000..635332f
--- /dev/null
+++ b/source/storage/emummc.h
@@ -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 .
+ */
+
+#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
\ No newline at end of file
diff --git a/source/storage/nx_emmc.c b/source/storage/nx_emmc.c
index a65dced..8e0fb63 100644
--- a/source/storage/nx_emmc.c
+++ b/source/storage/nx_emmc.c
@@ -17,6 +17,7 @@
#include
#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)
diff --git a/source/utils/types.h b/source/utils/types.h
index 579c274..e5dcb22 100644
--- a/source/utils/types.h
+++ b/source/utils/types.h
@@ -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;