Nyx: emuMMC Manage window, Tools UI, and misc updates

- Add gui_emu_tools: emuMMC Manage window with correct positioning (LV_PROTECT_PARENT + re-parent to win)
- Tools: single SD button (tap = SD partition manager, 3s hold = eMMC)
- Remove emuSD from Nyx UI (tabs, UMS, partition manager); keep bootloader emusd
- Shorten Create emuMMC description text by one character
- Storage/build/config and dependency updates

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-02-20 20:49:48 +01:00
parent 4eead2c14d
commit fed7f05831
81 changed files with 6932 additions and 3462 deletions

View File

@@ -25,7 +25,6 @@
void set_default_configuration()
{
h_cfg.t210b01 = hw_get_chip_id() == GP_HIDREV_MAJOR_T210B01;
h_cfg.devmode = fuse_read_hw_state();
h_cfg.autoboot = 0;
h_cfg.autoboot_list = 0;

View File

@@ -35,7 +35,6 @@ typedef struct _hekate_config
u32 bootprotect;
// Global temporary config.
bool t210b01;
bool devmode;
bool emummc_force_disable;
bool rcm_patched;
u32 errors;

View File

@@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <storage/sd.h>
#include <string.h>
#include <bdk.h>
@@ -37,7 +38,7 @@ void print_fuseinfo()
gfx_con_setpos(0, 0);
gfx_printf("\nSKU: %X - ", FUSE(FUSE_SKU_INFO));
switch (h_cfg.devmode)
switch (fuse_read_hw_state())
{
case FUSE_NX_HW_STATE_PROD:
gfx_printf("Retail\n");
@@ -230,19 +231,18 @@ void print_sdcard_info()
sd_storage.ssr.app_class, sd_storage.csd.write_protect,
sd_errors[0], sd_errors[1], sd_errors[2]); // SD_ERROR_INIT_FAIL, SD_ERROR_RW_FAIL, SD_ERROR_RW_RETRY.
int res = f_mount(&sd_fs, "", 1);
if (!res)
if (sd_mount())
{
gfx_puts("Acquiring FAT volume info...\n\n");
gfx_printf("%kFound %s volume:%k\n Free: %d MiB\n Cluster: %d KiB\n",
TXT_CLR_CYAN_L, sd_fs.fs_type == FS_EXFAT ? "exFAT" : "FAT32", TXT_CLR_DEFAULT,
sd_fs.free_clst * sd_fs.csize >> SECTORS_TO_MIB_COEFF, (sd_fs.csize > 1) ? (sd_fs.csize >> 1) : 512);
f_unmount("");
sd_end();
}
else
{
EPRINTFARGS("Failed to mount SD card (FatFS Error %d).\n"
"Make sure that a FAT partition exists..", res);
EPRINTF("Failed to mount SD card.\n"
"Make sure that a FAT partition exists..");
}
sd_end();

View File

@@ -2,7 +2,7 @@
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 st4rk
* Copyright (c) 2018 Ced2911
* Copyright (c) 2018-2026 CTCaer
* Copyright (c) 2018-2025 CTCaer
* Copyright (c) 2018 balika011
*
* This program is free software; you can redistribute it and/or modify it
@@ -28,6 +28,8 @@
#include "../frontend/fe_tools.h"
#include "../config.h"
#include "../storage/emummc.h"
#include "../storage/emusd.h"
#include <storage/boot_storage.h>
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DPRINTF(...)
@@ -166,7 +168,7 @@ static void _hos_eks_get()
// Decrypt EKS blob.
hos_eks_mbr_t *eks = (hos_eks_mbr_t *)(mbr + 0x80);
se_aes_crypt_ecb(14, DECRYPT, eks, eks, sizeof(hos_eks_mbr_t));
se_aes_crypt_ecb(14, DECRYPT, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t));
// Check if valid and for this unit.
if (eks->magic == HOS_EKS_MAGIC && eks->lot0 == FUSE(FUSE_OPT_LOT_CODE_0))
@@ -212,7 +214,7 @@ static void _hos_eks_save()
// Get keys.
u8 *keys = (u8 *)zalloc(SZ_8K);
se_aes_ctx_get_keys(keys + SZ_4K, keys, SE_KEY_128_SIZE);
se_get_aes_keys(keys + SZ_4K, keys, SE_KEY_128_SIZE);
// Set magic and personalized info.
h_cfg.eks->magic = HOS_EKS_MAGIC;
@@ -227,7 +229,7 @@ static void _hos_eks_save()
// Encrypt EKS blob.
u8 *eks = malloc(sizeof(hos_eks_mbr_t));
memcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t));
se_aes_crypt_ecb(14, ENCRYPT, eks, eks, sizeof(hos_eks_mbr_t));
se_aes_crypt_ecb(14, ENCRYPT, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t));
// Write EKS blob to SD.
memcpy(mbr + 0x80, eks, sizeof(hos_eks_mbr_t));
@@ -262,7 +264,7 @@ static void _hos_eks_clear(u32 mkey)
// Encrypt EKS blob.
u8 *eks = malloc(sizeof(hos_eks_mbr_t));
memcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t));
se_aes_crypt_ecb(14, ENCRYPT, eks, eks, sizeof(hos_eks_mbr_t));
se_aes_crypt_ecb(14, ENCRYPT, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t));
// Write EKS blob to SD.
memcpy(mbr + 0x80, eks, sizeof(hos_eks_mbr_t));
@@ -350,7 +352,7 @@ static int _hos_keygen(pkg1_eks_t *eks, u32 mkey, tsec_ctxt_t *tsec_ctxt, bool s
*/
// Use custom TSEC Hovi Keygen firmware.
tsec_ctxt->fw = sd_file_read("bootloader/sys/thk.bin", NULL);
tsec_ctxt->fw = boot_storage_file_read("bootloader/sys/thk.bin", NULL);
if (!tsec_ctxt->fw)
{
_hos_crit_error("Failed to load thk.bin");
@@ -406,7 +408,7 @@ static int _hos_keygen(pkg1_eks_t *eks, u32 mkey, tsec_ctxt_t *tsec_ctxt, bool s
else
{
// Decrypt eks and set keyslots.
se_aes_crypt_ecb(12, DECRYPT, tsec_keys.tmp, eks_keyseeds[0], SE_KEY_128_SIZE);
se_aes_crypt_block_ecb(12, DECRYPT, tsec_keys.tmp, eks_keyseeds[0]);
se_aes_unwrap_key(15, 14, tsec_keys.tmp);
// Derive device keys.
@@ -442,7 +444,7 @@ static int _hos_keygen(pkg1_eks_t *eks, u32 mkey, tsec_ctxt_t *tsec_ctxt, bool s
else
{
// Decrypt eks and set keyslots for Exosphere 2.
se_aes_crypt_ecb(12, DECRYPT, tsec_keys.tmp, eks_keyseeds[0], SE_KEY_128_SIZE);
se_aes_crypt_block_ecb(12, DECRYPT, tsec_keys.tmp, eks_keyseeds[0]);
se_aes_unwrap_key(15, 14, tsec_keys.tmp);
// Derive device keys.
@@ -469,9 +471,9 @@ static int _hos_keygen(pkg1_eks_t *eks, u32 mkey, tsec_ctxt_t *tsec_ctxt, bool s
se_aes_key_set(13, tsec_keys.tsec, SE_KEY_128_SIZE);
// Derive eks keys from TSEC+SBK.
se_aes_crypt_ecb(13, DECRYPT, tsec_keys.tsec, eks_keyseeds[0], SE_KEY_128_SIZE);
se_aes_crypt_block_ecb(13, DECRYPT, tsec_keys.tsec, eks_keyseeds[0]);
se_aes_unwrap_key(15, 14, tsec_keys.tsec);
se_aes_crypt_ecb(13, DECRYPT, tsec_keys.tsec, eks_keyseeds[mkey], SE_KEY_128_SIZE);
se_aes_crypt_block_ecb(13, DECRYPT, tsec_keys.tsec, eks_keyseeds[mkey]);
se_aes_unwrap_key(13, 14, tsec_keys.tsec);
// Clear SBK.
@@ -481,21 +483,21 @@ static int _hos_keygen(pkg1_eks_t *eks, u32 mkey, tsec_ctxt_t *tsec_ctxt, bool s
// Verify eks CMAC.
u8 cmac[SE_KEY_128_SIZE];
se_aes_unwrap_key(11, 13, cmac_keyseed);
se_aes_hash_cmac(cmac, SE_KEY_128_SIZE, 11, (void *)eks->ctr, sizeof(eks->ctr) + sizeof(eks->keys));
se_aes_cmac(cmac, SE_KEY_128_SIZE, 11, (void *)eks->ctr, sizeof(eks->ctr) + sizeof(eks->keys));
if (!memcmp(eks->cmac, cmac, SE_KEY_128_SIZE))
return 0;
*/
se_aes_crypt_ecb(13, DECRYPT, tsec_keys.tsec, cmac_keyseed, SE_KEY_128_SIZE);
se_aes_crypt_block_ecb(13, DECRYPT, tsec_keys.tsec, cmac_keyseed);
se_aes_unwrap_key(11, 13, cmac_keyseed);
// Decrypt eks and set keyslots.
se_aes_crypt_ctr(13, &eks->keys, &eks->keys, sizeof(eks_keys_t), eks->ctr);
se_aes_crypt_ctr(13, &eks->keys, sizeof(eks_keys_t), &eks->keys, sizeof(eks_keys_t), eks->ctr);
se_aes_key_set(11, eks->keys.package1_key, SE_KEY_128_SIZE);
se_aes_key_set(12, eks->keys.master_kekseed, SE_KEY_128_SIZE);
se_aes_key_set(13, eks->keys.master_kekseed, SE_KEY_128_SIZE);
se_aes_crypt_ecb(12, DECRYPT, tsec_keys.tsec, master_keyseed_retail, SE_KEY_128_SIZE);
se_aes_crypt_block_ecb(12, DECRYPT, tsec_keys.tsec, master_keyseed_retail);
if (!is_exo)
{
@@ -666,7 +668,7 @@ static bool _get_fs_exfat_compatible(link_t *info, u32 *hos_revision)
if (strcmp((char *)ki->kip1->name, "FS"))
continue;
if (!se_sha_hash_256_oneshot(sha_buf, ki->kip1, ki->size))
if (!se_calc_sha256_oneshot(sha_buf, ki->kip1, ki->size))
break;
pkg2_get_ids(&kip_ids, &fs_ids_cnt);
@@ -726,8 +728,14 @@ void hos_launch(ini_sec_t *cfg)
goto error;
}
if (emusd_storage_init_mmc() || !emusd_mount()) {
_hos_crit_error("error: Failed to init emuSD.");
goto error;
}
// Check if SD Card is GPT.
if (sd_is_gpt())
if (emusd_is_gpt())
{
_hos_crit_error("SD has GPT only! Run Fix Hybrid MBR!");
goto error;
@@ -746,6 +754,8 @@ void hos_launch(ini_sec_t *cfg)
// Check if stock is enabled and device can boot in OFW.
if (ctxt.stock && (h_cfg.t210b01 || !tools_autorcm_enabled()))
{
emusd_storage_end();
emummc_storage_end();
emmc_end();
WPRINTF("\nRebooting to OFW in 5s...");
@@ -758,7 +768,8 @@ void hos_launch(ini_sec_t *cfg)
mkey = ctxt.pkg1_id->mkey;
bool emummc_enabled = emu_cfg.enabled && !h_cfg.emummc_force_disable;
// TODO: separate force_disable for emuSD?
bool emummc_enabled = (emu_cfg.enabled || emu_sd_cfg.enabled) && !h_cfg.emummc_force_disable;
// Enable emummc patching.
if (emummc_enabled)
@@ -839,7 +850,7 @@ void hos_launch(ini_sec_t *cfg)
if (h_cfg.t210b01)
{
u32 bek_vector[4] = {0};
se_aes_crypt_ecb(13, ENCRYPT, bek_vector, bek_vector, SE_KEY_128_SIZE);
se_aes_crypt_ecb(13, ENCRYPT, bek_vector, SE_KEY_128_SIZE, bek_vector, SE_KEY_128_SIZE);
if (bek_vector[0] == 0x59C14895) // Encrypted zeroes first 32bits.
EPRINTF("Pkg1 corrupt?");
else
@@ -947,9 +958,9 @@ void hos_launch(ini_sec_t *cfg)
// Hash only Kernel when it embeds INI1.
u8 kernel_hash[0x20];
if (!ctxt.new_pkg2)
se_sha_hash_256_oneshot(kernel_hash, ctxt.kernel, ctxt.kernel_size);
se_calc_sha256_oneshot(kernel_hash, ctxt.kernel, ctxt.kernel_size);
else
se_sha_hash_256_oneshot(kernel_hash, ctxt.kernel + PKG2_NEWKERN_START,
se_calc_sha256_oneshot(kernel_hash, ctxt.kernel + PKG2_NEWKERN_START,
pkg2_newkern_ini1_start - PKG2_NEWKERN_START);
ctxt.pkg2_kernel_id = pkg2_identify(kernel_hash);
@@ -989,12 +1000,12 @@ void hos_launch(ini_sec_t *cfg)
LIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link)
pkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1);
// Check if FS is compatible with exFAT and if 5.1.0 or 10.2.0.
// Check if FS is compatible with exFAT and if 5.1.0.
if (!ctxt.stock && (sd_fs.fs_type == FS_EXFAT || mkey == HOS_MKEY_VER_500 || ctxt.pkg1_id->fuses == 13))
{
bool exfat_compat = _get_fs_exfat_compatible(&kip1_info, &ctxt.exo_ctx.hos_revision);
if (sd_fs.fs_type == FS_EXFAT && !exfat_compat)
if (emusd_get_fs_type() == FS_EXFAT && !exfat_compat)
{
_hos_crit_error("SD Card is exFAT but installed HOS driver\nonly supports FAT32!");
@@ -1008,14 +1019,14 @@ void hos_launch(ini_sec_t *cfg)
{
EHPRINTFARGS("Failed to apply '%s'!", failed_patch);
bool emu_patch_failed = !strcmp(failed_patch, "emummc");
if (!emu_patch_failed)
bool emmc_patch_failed = !strcmp(failed_patch, "emummc");
if (!emmc_patch_failed)
{
gfx_puts("\nPress POWER to continue.\nPress VOL to go to the menu.\n");
display_backlight_brightness(h_cfg.backlight, 1000);
}
if (emu_patch_failed || !(btn_wait() & BTN_POWER))
if (emmc_patch_failed || !(btn_wait() & BTN_POWER))
goto error; // MUST stop here, because if user requests 'nogc' but it's not applied, their GC controller gets updated!
}
@@ -1027,6 +1038,9 @@ void hos_launch(ini_sec_t *cfg)
config_exosphere(&ctxt, warmboot_base);
// Unmount SD card and eMMC.
emummc_storage_end();
emusd_storage_end();
boot_storage_end();
sd_end();
emmc_end();
@@ -1127,6 +1141,8 @@ void hos_launch(ini_sec_t *cfg)
error:
_free_launch_components(&ctxt);
emummc_storage_end();
emusd_storage_end();
emmc_end();
EPRINTF("\nFailed to launch HOS!");

View File

@@ -15,6 +15,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <storage/boot_storage.h>
#include "../storage/emusd.h"
#include <string.h>
#include <bdk.h>
@@ -29,7 +31,7 @@
static int _config_warmboot(launch_ctxt_t *ctxt, const char *value)
{
ctxt->warmboot = sd_file_read(value, &ctxt->warmboot_size);
ctxt->warmboot = emusd_file_read(value, &ctxt->warmboot_size);
if (!ctxt->warmboot)
return 0;
@@ -38,7 +40,7 @@ static int _config_warmboot(launch_ctxt_t *ctxt, const char *value)
static int _config_secmon(launch_ctxt_t *ctxt, const char *value)
{
ctxt->secmon = sd_file_read(value, &ctxt->secmon_size);
ctxt->secmon = emusd_file_read(value, &ctxt->secmon_size);
if (!ctxt->secmon)
return 0;
@@ -47,7 +49,7 @@ static int _config_secmon(launch_ctxt_t *ctxt, const char *value)
static int _config_kernel(launch_ctxt_t *ctxt, const char *value)
{
ctxt->kernel = sd_file_read(value, &ctxt->kernel_size);
ctxt->kernel = emusd_file_read(value, &ctxt->kernel_size);
if (!ctxt->kernel)
return 0;
@@ -61,11 +63,12 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
if (value[strlen(value) - 1] == '*')
{
char *dir = (char *)malloc(256);
strcpy(dir, value);
strcpy(dir, "emusd:");
strcat(dir, value);
u32 dirlen = 0;
dir[strlen(dir) - 2] = 0;
dirlist_t *filelist = dirlist(dir, "*.kip*", 0);
dirlist_t *filelist = dirlist(dir, "*.kip*", false, false);
strcat(dir, "/");
dirlen = strlen(dir);
@@ -81,7 +84,7 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
strcpy(dir + dirlen, filelist->name[i]);
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = sd_file_read(dir, &size);
mkip1->kip1 = emusd_file_read(dir + 6, &size);
if (!mkip1->kip1)
{
free(mkip1);
@@ -103,7 +106,7 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
else
{
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = sd_file_read(value, &size);
mkip1->kip1 = emusd_file_read(value, &size);
if (!mkip1->kip1)
{
free(mkip1);
@@ -169,7 +172,7 @@ static int _config_stock(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Enabled stock mode\n");
DPRINTF("Disabled all patching\n");
ctxt->stock = true;
}
return 1;
@@ -262,7 +265,7 @@ static int _config_pkg3(launch_ctxt_t *ctxt, const char *value)
static int _config_exo_fatal_payload(launch_ctxt_t *ctxt, const char *value)
{
ctxt->exofatal = sd_file_read(value, &ctxt->exofatal_size);
ctxt->exofatal = emusd_file_read(value, &ctxt->exofatal_size);
if (!ctxt->exofatal)
return 0;

View File

@@ -17,6 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <storage/boot_storage.h>
#include "../storage/emusd.h"
#include <string.h>
#include <stdlib.h>
@@ -205,7 +207,7 @@ int pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1)
u8 *pkg11 = pkg1 + id->pkg11_off;
u32 pkg11_size = *(u32 *)pkg11;
hdr = (pk11_hdr_t *)(pkg11 + 0x20);
se_aes_crypt_ctr(11, hdr, hdr, pkg11_size, pkg11 + 0x10);
se_aes_crypt_ctr(11, hdr, pkg11_size, hdr, pkg11_size, pkg11 + 0x10);
}
else
{
@@ -216,7 +218,7 @@ int pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1)
// Use BEK for T210B01.
// Additionally, skip 0x20 bytes from decryption to maintain the header.
se_aes_iv_clear(13);
se_aes_crypt_cbc(13, DECRYPT, pkg1 + 0x20, pkg1 + 0x20, oem_hdr->size - 0x20);
se_aes_crypt_cbc(13, DECRYPT, pkg1 + 0x20, oem_hdr->size - 0x20, pkg1 + 0x20, oem_hdr->size - 0x20);
}
// Return if header is valid.

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2026 CTCaer
* Copyright (c) 2018-2025 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,
@@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <storage/boot_storage.h>
#include <string.h>
#include <bdk.h>
@@ -27,6 +28,7 @@
#include <libs/compr/blz.h>
#include <libs/fatfs/ff.h>
#include "../storage/emummc.h"
#include "../storage/emusd.h"
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DPRINTF(...)
@@ -64,6 +66,7 @@ static void parse_external_kip_patches()
return;
LIST_INIT(ini_kip_sections);
// TODO: load frome emusd?
if (ini_patch_parse(&ini_kip_sections, "bootloader/patches.ini"))
{
// Copy ids into a new patchset.
@@ -374,7 +377,7 @@ static int _kipm_inject(const char *kipm_path, char *target_name, pkg2_kip1_info
if (!strcmp((char *)ki->kip1->name, target_name))
{
u32 size = 0;
u8 *kipm_data = (u8 *)sd_file_read(kipm_path, &size);
u8 *kipm_data = (u8 *)boot_storage_file_read(kipm_path, &size);
if (!kipm_data)
return 1;
@@ -544,7 +547,7 @@ const char *pkg2_patch_kips(link_t *info, char *patch_names)
// Check if current KIP not hashed and hash it.
if (kip_hash[0] == 0)
if (!se_sha_hash_256_oneshot(kip_hash, ki->kip1, ki->size))
if (!se_calc_sha256_oneshot(kip_hash, ki->kip1, ki->size))
memset(kip_hash, 0, sizeof(kip_hash));
// Check if kip is the expected version.
@@ -656,6 +659,8 @@ const char *pkg2_patch_kips(link_t *info, char *patch_names)
if (kip_id_idx > 17)
emu_cfg.fs_ver -= 2;
emu_sd_cfg.fs_ver = emu_cfg.fs_ver;
// Inject emuMMC code.
gfx_printf("Injecting emuMMC. FS ID: %d\n", emu_cfg.fs_ver);
if (_kipm_inject("bootloader/sys/emummc.kipm", "FS", ki))
@@ -708,7 +713,7 @@ pkg2_hdr_t *pkg2_decrypt(void *data, u8 mkey, bool is_exo)
u8 tmp_mkey[SE_KEY_128_SIZE];
// Decrypt 7.0.0 encrypted mkey.
se_aes_crypt_ecb(!is_exo ? 7 : 13, DECRYPT, tmp_mkey, mkey_vector_7xx, SE_KEY_128_SIZE);
se_aes_crypt_ecb(!is_exo ? 7 : 13, DECRYPT, tmp_mkey, SE_KEY_128_SIZE, mkey_vector_7xx, SE_KEY_128_SIZE);
// Set and unwrap pkg2 key.
se_aes_key_set(9, tmp_mkey, SE_KEY_128_SIZE);
@@ -718,7 +723,7 @@ pkg2_hdr_t *pkg2_decrypt(void *data, u8 mkey, bool is_exo)
}
// Decrypt header.
se_aes_crypt_ctr(pkg2_keyslot, hdr, hdr, sizeof(pkg2_hdr_t), hdr);
se_aes_crypt_ctr(pkg2_keyslot, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr);
if (hdr->magic != PKG2_MAGIC)
return NULL;
@@ -730,7 +735,7 @@ DPRINTF("sec %d has size %08X\n", i, hdr->sec_size[i]);
if (!hdr->sec_size[i])
continue;
se_aes_crypt_ctr(pkg2_keyslot, pdata, pdata, hdr->sec_size[i], hdr->sec_ctr[i]);
se_aes_crypt_ctr(pkg2_keyslot, pdata, hdr->sec_size[i], pdata, hdr->sec_size[i], &hdr->sec_ctr[i * SE_AES_IV_SIZE]);
pdata += hdr->sec_size[i];
}
@@ -776,7 +781,7 @@ DPRINTF("adding kip1 '%s' @ %08X (%08X)\n", (char *)ki->kip1->name, (u32)ki->kip
{
hdr->sec_size[PKG2_SEC_INI1] = ini1_size;
hdr->sec_off[PKG2_SEC_INI1] = 0x14080000;
se_aes_crypt_ctr(8, ini1, ini1, ini1_size, hdr->sec_ctr[PKG2_SEC_INI1]);
se_aes_crypt_ctr(8, ini1, ini1_size, ini1, ini1_size, &hdr->sec_ctr[PKG2_SEC_INI1 * SE_AES_IV_SIZE]);
}
else
{
@@ -854,7 +859,7 @@ DPRINTF("%s @ %08X (%08X)\n", is_meso ? "Mesosphere": "kernel",(u32)ctxt->kernel
kernel_size += ini1_size;
}
hdr->sec_size[PKG2_SEC_KERNEL] = kernel_size;
se_aes_crypt_ctr(pkg2_keyslot, pdst, pdst, kernel_size, hdr->sec_ctr[PKG2_SEC_KERNEL]);
se_aes_crypt_ctr(pkg2_keyslot, pdst, kernel_size, pdst, kernel_size, &hdr->sec_ctr[PKG2_SEC_KERNEL * SE_AES_IV_SIZE]);
pdst += kernel_size;
DPRINTF("kernel encrypted\n");
@@ -870,7 +875,7 @@ DPRINTF("INI1 encrypted\n");
u8 *pk2_hash_data = (u8 *)dst + 0x100 + sizeof(pkg2_hdr_t);
for (u32 i = PKG2_SEC_KERNEL; i <= PKG2_SEC_UNUSED; i++)
{
se_sha_hash_256_oneshot(hdr->sec_sha256[i], (void *)pk2_hash_data, hdr->sec_size[i]);
se_calc_sha256_oneshot(&hdr->sec_sha256[SE_SHA_256_SIZE * i], (void *)pk2_hash_data, hdr->sec_size[i]);
pk2_hash_data += hdr->sec_size[i];
}
}
@@ -878,7 +883,7 @@ DPRINTF("INI1 encrypted\n");
// Encrypt header.
*(u32 *)hdr->ctr = 0x100 + sizeof(pkg2_hdr_t) + kernel_size + ini1_size;
hdr->ctr[4] = key_ver;
se_aes_crypt_ctr(pkg2_keyslot, hdr, hdr, sizeof(pkg2_hdr_t), hdr);
se_aes_crypt_ctr(pkg2_keyslot, hdr, sizeof(pkg2_hdr_t), hdr, sizeof(pkg2_hdr_t), hdr);
memset(hdr->ctr, 0 , SE_AES_IV_SIZE);
*(u32 *)hdr->ctr = 0x100 + sizeof(pkg2_hdr_t) + kernel_size + ini1_size;
hdr->ctr[4] = key_ver;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2026 CTCaer
* Copyright (c) 2018-2025 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,
@@ -71,7 +71,7 @@ enum
typedef struct _pkg2_hdr_t
{
/* 0x000 */ u8 ctr[0x10];
/* 0x010 */ u8 sec_ctr[4][SE_AES_IV_SIZE];
/* 0x010 */ u8 sec_ctr[0x40];
/* 0x050 */ u32 magic;
/* 0x054 */ u32 base;
/* 0x058 */ u32 pad0;
@@ -80,7 +80,7 @@ typedef struct _pkg2_hdr_t
/* 0x05E */ u16 pad1;
/* 0x060 */ u32 sec_size[4];
/* 0x070 */ u32 sec_off[4];
/* 0x080 */ u8 sec_sha256[4][SE_SHA_256_SIZE];
/* 0x080 */ u8 sec_sha256[0x80];
/* 0x100 */ u8 data[];
} pkg2_hdr_t;

View File

@@ -16,6 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <storage/boot_storage.h>
#include "../storage/emusd.h"
#include <string.h>
#include <bdk.h>
@@ -29,7 +31,7 @@
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DPRINTF(...)
extern bool is_ipl_updated(void *buf, u32 size, const char *path, bool force);
extern bool is_ipl_updated(void *buf, const char *path, bool force);
#define PKG3_KIP_SKIP_MAX 16
@@ -84,10 +86,9 @@ typedef struct _pkg3_content_t
static void _pkg3_update_r2p()
{
u32 size = 0;
u8 *r2p_payload = sd_file_read("atmosphere/reboot_payload.bin", &size);
u8 *r2p_payload = emusd_file_read("atmosphere/reboot_payload.bin", NULL);
is_ipl_updated(r2p_payload, size, "atmosphere/reboot_payload.bin", h_cfg.updater2p ? true : false);
is_ipl_updated(r2p_payload, "emusd:atmosphere/reboot_payload.bin", h_cfg.updater2p ? true : false);
free(r2p_payload);
}
@@ -125,6 +126,10 @@ static int _pkg3_kip1_skip(char ***pkg3_kip1_skip, u32 *pkg3_kip1_skip_num, char
int parse_pkg3(launch_ctxt_t *ctxt, const char *path)
{
char *path1 = (char *)malloc(256);
strcpy(path1, "emusd:");
strcat(path1, path);
FIL fp;
char **pkg3_kip1_skip = NULL;
@@ -152,16 +157,25 @@ int parse_pkg3(launch_ctxt_t *ctxt, const char *path)
}
#ifdef HOS_MARIKO_STOCK_SECMON
if (stock && emummc_disabled && (pkg1_old || h_cfg.t210b01))
if (stock && emummc_disabled && (pkg1_old || h_cfg.t210b01)) {
free(path1);
return 1;
}
#else
if (stock && emummc_disabled && pkg1_old)
if (stock && emummc_disabled && pkg1_old) {
free(path1);
return 1;
}
#endif
// Try to open PKG3.
if (f_open(&fp, path, FA_READ) != FR_OK)
if (f_open(&fp, path1, FA_READ) != FR_OK) {
free(path1);
return 0;
}
void *pkg3 = malloc(f_size(&fp));
@@ -267,6 +281,7 @@ int parse_pkg3(launch_ctxt_t *ctxt, const char *path)
_pkg3_update_r2p();
free(pkg3_kip1_skip);
free(path1);
return 1;
}

View File

@@ -24,12 +24,15 @@
#include "../config.h"
#include <libs/fatfs/ff.h>
#include "../storage/emummc.h"
#include "../storage/emusd.h"
enum emuMMC_Type
{
emuMMC_None = 0,
emuMMC_Partition,
emuMMC_File,
EmummcType_None = 0,
EmummcType_Partition_Sd = 1,
EmummcType_File_Sd = 2,
EmummcType_Partition_Emmc = 3,
EmummcType_File_Emmc = 4,
emuMMC_MAX
};
@@ -64,6 +67,22 @@ typedef struct
emummc_file_config_t file_cfg;
};
char nintendo_path[EMUMMC_FILE_PATH_MAX];
} emummc_emmc_config_t;
typedef struct
{
emummc_base_config_t base_cfg;
union
{
emummc_partition_config_t partition_cfg;
emummc_file_config_t file_cfg;
};
} emummc_sd_config_t;
typedef struct
{
emummc_emmc_config_t emmc_cfg;
emummc_sd_config_t sd_cfg;
} exo_emummc_config_t;
typedef struct _exo_cfg_t
@@ -75,7 +94,8 @@ typedef struct _exo_cfg_t
u8 uart_port;
u8 uart_invert;
u32 uart_baudrate;
u32 rsvd1[2];
u8 memory_mode_auto;
u8 rsvd1[7];
exo_emummc_config_t emummc_cfg;
} exo_cfg_t;
@@ -206,7 +226,7 @@ void config_exosphere(launch_ctxt_t *ctxt, u32 warmboot_base)
if (!ctxt->stock)
{
LIST_INIT(ini_exo_sections);
if (ini_parse(&ini_exo_sections, "exosphere.ini", false))
if (ini_parse(&ini_exo_sections, "emusd:exosphere.ini", false))
{
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_exo_sections, link)
{
@@ -214,6 +234,7 @@ void config_exosphere(launch_ctxt_t *ctxt, u32 warmboot_base)
if (!(ini_sec->type == INI_CHOICE) || strcmp(ini_sec->name, "exosphere"))
continue;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
if (!strcmp("debugmode_user", kv->key))
@@ -224,12 +245,14 @@ void config_exosphere(launch_ctxt_t *ctxt, u32 warmboot_base)
exo_cfg->uart_invert = atoi(kv->val);
else if (!strcmp("log_baud_rate", kv->key))
exo_cfg->uart_baudrate = atoi(kv->val);
else if (!strcmp("memory_mode_auto", kv->key)) {
exo_cfg->memory_mode_auto = atoi(kv->val);
}
else if (emu_cfg.enabled && !h_cfg.emummc_force_disable)
{
if (!strcmp("blank_prodinfo_emummc", kv->key))
cal0_blanking = atoi(kv->val);
}
else
} else
{
if (!strcmp("blank_prodinfo_sysmmc", kv->key))
cal0_blanking = atoi(kv->val);
@@ -245,7 +268,7 @@ void config_exosphere(launch_ctxt_t *ctxt, u32 warmboot_base)
if (!ctxt->exo_ctx.usb3_force)
{
LIST_INIT(ini_sys_sections);
if (ini_parse(&ini_sys_sections, "atmosphere/config/system_settings.ini", false))
if (ini_parse(&ini_sys_sections, "emusd:atmosphere/config/system_settings.ini", false))
{
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sys_sections, link)
{
@@ -314,22 +337,72 @@ void config_exosphere(launch_ctxt_t *ctxt, u32 warmboot_base)
pkg1_warmboot_rsa_mod(warmboot_base);
}
// By default, disable emuMMC
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.magic = EMUMMC_MAGIC;
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.type = EmummcType_None;
if (emu_cfg.enabled && !h_cfg.emummc_force_disable)
{
exo_cfg->emummc_cfg.base_cfg.magic = EMUMMC_MAGIC;
exo_cfg->emummc_cfg.base_cfg.type = emu_cfg.sector ? emuMMC_Partition : emuMMC_File;
exo_cfg->emummc_cfg.base_cfg.fs_ver = emu_cfg.fs_ver;
exo_cfg->emummc_cfg.base_cfg.id = emu_cfg.id;
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.fs_ver = emu_cfg.fs_ver;
exo_cfg->emummc_cfg.sd_cfg.base_cfg.fs_ver = emu_sd_cfg.fs_ver;
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.id = emu_cfg.id;
if (emu_cfg.enabled == 4 && emu_cfg.sector) {
// emmc partition based
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.type = EmummcType_Partition_Emmc;
} else if (emu_cfg.enabled == 4 && !emu_cfg.sector) {
// emmc file based
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.type = EmummcType_File_Emmc;
} else if (emu_cfg.enabled == 1 && emu_cfg.sector) {
// sd partition based
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.type = EmummcType_Partition_Sd;
} else if (emu_cfg.enabled == 1 && !emu_cfg.sector) {
// sd file based
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.type = EmummcType_File_Sd;
} else {
// disabled
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.type = EmummcType_None;
}
if (emu_cfg.sector)
exo_cfg->emummc_cfg.partition_cfg.start_sector = emu_cfg.sector;
exo_cfg->emummc_cfg.emmc_cfg.partition_cfg.start_sector = emu_cfg.sector;
else
strcpy((char *)exo_cfg->emummc_cfg.file_cfg.path, emu_cfg.path);
strcpy((char *)exo_cfg->emummc_cfg.emmc_cfg.file_cfg.path, emu_cfg.path);
if (!ctxt->stock && emu_cfg.nintendo_path && emu_cfg.nintendo_path[0])
strcpy((char *)exo_cfg->emummc_cfg.nintendo_path, emu_cfg.nintendo_path);
strcpy((char *)exo_cfg->emummc_cfg.emmc_cfg.nintendo_path, emu_cfg.nintendo_path);
else
strcpy((char *)exo_cfg->emummc_cfg.nintendo_path, "Nintendo");
strcpy((char *)exo_cfg->emummc_cfg.emmc_cfg.nintendo_path, "Nintendo");
}
exo_cfg->emummc_cfg.sd_cfg.base_cfg.magic = EMUMMC_MAGIC;
exo_cfg->emummc_cfg.sd_cfg.base_cfg.type = EmummcType_None;
if (emu_sd_cfg.enabled)
{
exo_cfg->emummc_cfg.sd_cfg.base_cfg.fs_ver = emu_sd_cfg.fs_ver;
exo_cfg->emummc_cfg.emmc_cfg.base_cfg.fs_ver = emu_sd_cfg.fs_ver;
exo_cfg->emummc_cfg.sd_cfg.base_cfg.id = emu_sd_cfg.id;
if (emu_sd_cfg.enabled == 4 && emu_sd_cfg.sector) {
// emmc partition based
exo_cfg->emummc_cfg.sd_cfg.base_cfg.type = EmummcType_Partition_Emmc;
} else if (emu_sd_cfg.enabled == 4 && !emu_sd_cfg.sector) {
// emmc file based
exo_cfg->emummc_cfg.sd_cfg.base_cfg.type = EmummcType_File_Emmc;
} else if (emu_sd_cfg.enabled == 1 && emu_sd_cfg.sector) {
// sd partition based
exo_cfg->emummc_cfg.sd_cfg.base_cfg.type = EmummcType_Partition_Sd;
} else if (emu_sd_cfg.enabled == 1 && !emu_sd_cfg.sector) {
// sd file based
exo_cfg->emummc_cfg.sd_cfg.base_cfg.type = EmummcType_File_Sd;
} else {
// disabled
exo_cfg->emummc_cfg.sd_cfg.base_cfg.type = EmummcType_None;
}
if (emu_sd_cfg.sector)
exo_cfg->emummc_cfg.sd_cfg.partition_cfg.start_sector = emu_sd_cfg.sector;
else
strcpy((char *)exo_cfg->emummc_cfg.sd_cfg.file_cfg.path, emu_sd_cfg.path);
}
// Copy over exosphere fatal for Mariko.

View File

@@ -25,6 +25,7 @@
#include "../hos/pkg1.h"
#include "l4t.h"
#include "l4t_config.inl"
#include <storage/boot_storage.h>
/*
* API Revision info
@@ -283,7 +284,7 @@ typedef struct _l4t_ctxt_t
} l4t_ctxt_t;
#define DRAM_VDD2_OC_MIN_VOLTAGE 1050
#define DRAM_VDD2_OC_MAX_VOLTAGE 1175
#define DRAM_VDD2_OC_MAX_VOLTAGE 1250
#define DRAM_VDD2Q_OC_MAX_VOLTAGE 1237
#define DRAM_VDDQ_OC_MIN_VOLTAGE 550
#define DRAM_VDDQ_OC_MAX_VOLTAGE 650
@@ -1026,7 +1027,9 @@ void launch_l4t(const ini_sec_t *ini_sec, int entry_idx, int is_list, bool t210b
return;
// Done loading bootloaders/firmware.
boot_storage_end();
sd_end();
emmc_end();
// We don't need AHB aperture open.
mc_disable_ahb_redirect();

View File

@@ -7,11 +7,39 @@
/* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/
#include <string.h>
#include "../../storage/emusd.h"
#include <storage/sd.h>
#include <storage/sdmmc.h>
#include <bdk.h>
#include <libs/fatfs/diskio.h> /* FatFs lower layer API */
#include <fatfs_cfg.h>
static bool ensure_partition(BYTE pdrv){
u8 part;
switch(pdrv){
case DRIVE_SD:
return true;
case DRIVE_BOOT1:
case DRIVE_BOOT1_1MB:
part = EMMC_BOOT1;
break;
case DRIVE_EMMC:
part = EMMC_GPP;
break;
case DRIVE_EMUSD:
return true;
default:
return false;
}
if(emmc_storage.partition != part){
return emmc_set_partition(part);
}
return true;
}
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
@@ -43,7 +71,33 @@ DRESULT disk_read (
UINT count /* Number of sectors to read */
)
{
return sdmmc_storage_read(&sd_storage, sector, count, buff) ? RES_OK : RES_ERROR;
if(!ensure_partition(pdrv)){
return RES_ERROR;
}
sdmmc_storage_t *storage = &sd_storage;
u32 actual_sector = sector;
switch(pdrv){
case DRIVE_SD:
break;
case DRIVE_BOOT1:
case DRIVE_EMMC:
storage = &emmc_storage;
break;
case DRIVE_BOOT1_1MB:
storage = &emmc_storage;
actual_sector = sector + (0x100000 / 512);
break;
case DRIVE_EMUSD:
return emusd_storage_read(sector, count, buff) ? RES_OK : RES_ERROR;
break;
default:
return RES_ERROR;
}
return sdmmc_storage_read(storage, actual_sector, count, buff) ? RES_OK : RES_ERROR;
}
/*-----------------------------------------------------------------------*/
@@ -56,7 +110,32 @@ DRESULT disk_write (
UINT count /* Number of sectors to write */
)
{
return sdmmc_storage_write(&sd_storage, sector, count, (void *)buff) ? RES_OK : RES_ERROR;
if(!ensure_partition(pdrv)){
return RES_ERROR;
}
sdmmc_storage_t *storage = &sd_storage;
u32 actual_sector = sector;
switch(pdrv){
case DRIVE_SD:
break;
case DRIVE_BOOT1:
case DRIVE_EMMC:
storage = &emmc_storage;
break;
case DRIVE_BOOT1_1MB:
storage = &emmc_storage;
actual_sector = sector + (0x100000 / 512);
break;
case DRIVE_EMUSD:
return emusd_storage_write(sector, count, (void*)buff) ? RES_OK : RES_ERROR;
default:
return RES_ERROR;
}
return sdmmc_storage_write(storage, actual_sector, count, (void*)buff) ? RES_OK : RES_ERROR;
}
/*-----------------------------------------------------------------------*/

View File

@@ -168,7 +168,7 @@
*/
#define FF_FS_RPATH 0
#define FF_FS_RPATH 2
/* This option configures support for relative path.
/
/ 0: Disable relative path and remove related functions.
@@ -181,12 +181,12 @@
/ Drive/Volume Configurations
/---------------------------------------------------------------------------*/
#define FF_VOLUMES 1
#define FF_VOLUMES 5
/* Number of volumes (logical drives) to be used. (1-10) */
#define FF_STR_VOLUME_ID 0
#define FF_VOLUME_STRS "sd"
#define FF_STR_VOLUME_ID 1
#define FF_VOLUME_STRS "sd", "boot1", "boot1_1mb", "emmc", "emusd"
/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.
/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive
/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each
@@ -303,5 +303,12 @@
/ included somewhere in the scope of ff.h. */
typedef enum {
DRIVE_SD = 0,
DRIVE_BOOT1 = 1,
DRIVE_BOOT1_1MB = 2,
DRIVE_EMMC = 3,
DRIVE_EMUSD = 4,
} DDRIVE;
/*--- End of configuration options ---*/

View File

@@ -22,6 +22,7 @@
#include <bdk.h>
#include "config.h"
#include "gfx/gfx.h"
#include "gfx/logos.h"
#include "gfx/tui.h"
#include "hos/hos.h"
@@ -31,9 +32,11 @@
#include <libs/compr/blz.h>
#include <libs/fatfs/ff.h>
#include "storage/emummc.h"
#include <storage/boot_storage.h>
#include "frontend/fe_tools.h"
#include "frontend/fe_info.h"
#include "storage/emusd.h"
hekate_config h_cfg;
boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;
@@ -92,7 +95,6 @@ static void _check_power_off_from_hos()
// This is a safe and unused DRAM region for our payloads.
#define RELOC_META_OFF 0x7C
#define PATCHED_RELOC_SZ 0x94
#define VERSION_RCFG_OFF 0x120
#define PATCHED_RELOC_STACK 0x40007000
#define PATCHED_RELOC_ENTRY 0x40010000
#define EXT_PAYLOAD_ADDR 0xC0000000
@@ -110,7 +112,7 @@ static void _reloc_append(u32 payload_dst, u32 payload_src, u32 payload_size)
relocator->ep = payload_dst;
}
bool is_ipl_updated(void *buf, u32 size, const char *path, bool force)
bool is_ipl_updated(void *buf, const char *path, bool force)
{
ipl_ver_meta_t *update_ft = (ipl_ver_meta_t *)(buf + PATCHED_RELOC_SZ + sizeof(boot_cfg_t));
@@ -120,32 +122,28 @@ bool is_ipl_updated(void *buf, u32 size, const char *path, bool force)
// Check if newer version.
if (!force && magic_valid)
{
// Copy reserved config.
if (size && !is_valid_old && memcmp((u8 *)(IPL_LOAD_ADDR + VERSION_RCFG_OFF), (u8 *)(buf + VERSION_RCFG_OFF), sizeof(rsvd_cfg_t)))
{
memcpy((u8 *)(buf + VERSION_RCFG_OFF), (u8 *)(IPL_LOAD_ADDR + VERSION_RCFG_OFF), sizeof(rsvd_cfg_t));
sd_save_to_file(buf, size, path);
}
if (byte_swap_32(update_ft->version) > byte_swap_32(ipl_ver.version))
return false;
}
// Update if old or broken.
if (force_update || is_valid_old)
{
boot_cfg_t tmp_cfg;
FIL fp;
reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF);
boot_cfg_t *tmp_cfg = zalloc(sizeof(boot_cfg_t));
f_open(&fp, path, FA_WRITE | FA_CREATE_ALWAYS);
f_write(&fp, (u8 *)reloc->start, reloc->end - reloc->start, NULL);
// Write needed tag in case injected ipl uses old versioning.
f_write(&fp, "ICTC49", 6, NULL);
// Reset boot storage configuration.
memcpy(&tmp_cfg, (u8 *)(reloc->start + PATCHED_RELOC_SZ), sizeof(boot_cfg_t));
memset((u8 *)(reloc->start + PATCHED_RELOC_SZ), 0, sizeof(boot_cfg_t));
f_lseek(&fp, PATCHED_RELOC_SZ);
f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL);
sd_save_to_file((u8 *)reloc->start, reloc->end - reloc->start, path);
// Restore boot storage configuration.
memcpy((u8 *)(reloc->start + PATCHED_RELOC_SZ), &tmp_cfg, sizeof(boot_cfg_t));
f_close(&fp);
free(tmp_cfg);
}
return true;
@@ -157,10 +155,8 @@ static void _launch_payload(char *path, bool update, bool clear_screen)
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
// Read payload.
u32 size = 0;
void *buf = sd_file_read(path, &size);
if (!buf)
FIL fp;
if (f_open(&fp, path, FA_READ))
{
gfx_con.mute = false;
EPRINTFARGS("Payload file is missing!\n(%s)", path);
@@ -168,8 +164,9 @@ static void _launch_payload(char *path, bool update, bool clear_screen)
goto out;
}
if (update && is_ipl_updated(buf, size, path, false))
goto out;
// Read and copy the payload to our chosen address
void *buf;
u32 size = f_size(&fp);
// Check if it safely fits IRAM.
if (size > 0x30000)
@@ -180,7 +177,21 @@ static void _launch_payload(char *path, bool update, bool clear_screen)
goto out;
}
if (f_read(&fp, buf, size, NULL))
{
f_close(&fp);
goto out;
}
f_close(&fp);
if (update && is_ipl_updated(buf, path, false))
goto out;
boot_storage_end();
sd_end();
emmc_end();
// Copy the payload to our chosen address.
memcpy((void *)RCM_PAYLOAD_ADDR, buf, size);
@@ -209,7 +220,6 @@ static void _launch_payload(char *path, bool update, bool clear_screen)
(*payload_ptr)();
out:
free(buf);
if (!update)
{
gfx_con.mute = false;
@@ -228,15 +238,15 @@ static void _launch_payloads()
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
if (!sd_mount())
goto failed_sd_mount;
if (!boot_storage_mount())
goto failed_boot_storage_mount;
ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3));
dir = (char *)malloc(256);
memcpy(dir, "bootloader/payloads", 20);
filelist = dirlist(dir, NULL, 0);
filelist = dirlist(dir, NULL, false, false);
u32 i = 0;
@@ -272,7 +282,7 @@ static void _launch_payloads()
free(ments);
free(dir);
free(filelist);
sd_end();
boot_storage_end();
return;
}
@@ -288,11 +298,11 @@ static void _launch_payloads()
_launch_payload(dir, false, true);
}
failed_sd_mount:
failed_boot_storage_mount:
free(dir);
free(ments);
free(filelist);
sd_end();
boot_storage_end();
btn_wait();
}
@@ -302,6 +312,7 @@ static void _launch_ini_list()
u8 max_entries = 61;
char *special_path = NULL;
char *emummc_path = NULL;
char *emusd_path = NULL;
ment_t *ments = NULL;
ini_sec_t *cfg_sec = NULL;
@@ -310,7 +321,7 @@ static void _launch_ini_list()
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
if (!sd_mount())
if (!boot_storage_mount())
goto parse_failed;
// Check that ini files exist and parse them.
@@ -366,13 +377,22 @@ static void _launch_ini_list()
h_cfg.emummc_force_disable = atoi(kv->val);
else if (!strcmp("emupath", kv->key))
emummc_path = kv->val;
else if (!strcmp("emusdpath", kv->key))
emusd_path = kv->val;
}
// TODO: also check emuSD path
if (emummc_path && !emummc_set_path(emummc_path))
{
EPRINTF("emupath is wrong!");
goto wrong_emupath;
}
if (emusd_path && !emusd_set_path(emusd_path)){
EPRINTFARGS("path: %s", emusd_path);
EPRINTF("error: emusdpath is wrong!");
goto wrong_emupath;
}
}
if (!cfg_sec)
@@ -415,9 +435,15 @@ parse_failed:
wrong_emupath:
if (emummc_path)
{
sd_mount();
boot_storage_mount();
emummc_load_cfg(); // Reload emuMMC config in case of emupath.
}
if (emusd_path)
{
boot_storage_mount();
emusd_load_cfg();
}
}
out:
@@ -431,6 +457,7 @@ static void _launch_config()
u8 max_entries = 61;
char *special_path = NULL;
char *emummc_path = NULL;
char *emusd_path = NULL;
ment_t *ments = NULL;
ini_sec_t *cfg_sec = NULL;
@@ -440,11 +467,12 @@ static void _launch_config()
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
if (!sd_mount())
if (!boot_storage_mount())
goto parse_failed;
// Load emuMMC configuration.
emummc_load_cfg();
emusd_load_cfg();
// Parse main configuration.
ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false);
@@ -511,6 +539,8 @@ static void _launch_config()
h_cfg.emummc_force_disable = atoi(kv->val);
if (!strcmp("emupath", kv->key))
emummc_path = kv->val;
if (!strcmp("emusdpath", kv->key))
emusd_path = kv->val;
}
if (emummc_path && !emummc_set_path(emummc_path))
@@ -518,12 +548,19 @@ static void _launch_config()
EPRINTF("emupath is wrong!");
goto wrong_emupath;
}
if (emusd_path && !emusd_set_path(emusd_path))
{
EPRINTFARGS("path: %s", emusd_path);
EPRINTF("error: emusdpath is wrong!");
goto wrong_emupath;
}
}
if (!cfg_sec)
{
free(ments);
sd_end();
boot_storage_end();
return;
}
@@ -560,13 +597,19 @@ parse_failed:
wrong_emupath:
if (emummc_path)
{
sd_mount();
boot_storage_mount();
emummc_load_cfg(); // Reload emuMMC config in case of emupath.
}
if (emusd_path)
{
boot_storage_mount();
emusd_load_cfg();
}
}
out:
sd_end();
boot_storage_end();
free(ments);
@@ -579,11 +622,13 @@ out:
static void _nyx_load_run()
{
u8 *nyx = sd_file_read("bootloader/sys/nyx.bin", NULL);
u8 *nyx = boot_storage_file_read("bootloader/sys/nyx.bin", NULL);
if (!nyx)
return;
boot_storage_end();
sd_end();
emmc_end();
render_static_bootlogo();
display_backlight_brightness(h_cfg.backlight, 1000);
@@ -652,13 +697,7 @@ static void _nyx_load_run()
(*nyx_ptr)();
}
void launch_nyx()
{
sd_mount();
_nyx_load_run();
}
static ini_sec_t *_get_ini_sec_from_id(ini_sec_t *ini_sec, char **bootlogoCustomEntry, char **emummc_path)
static ini_sec_t *_get_ini_sec_from_id(ini_sec_t *ini_sec, char **bootlogoCustomEntry, char **emummc_path, char **emusd_path)
{
ini_sec_t *cfg_sec = NULL;
@@ -677,10 +716,13 @@ static ini_sec_t *_get_ini_sec_from_id(ini_sec_t *ini_sec, char **bootlogoCustom
*bootlogoCustomEntry = kv->val;
else if (!strcmp("emummc_force_disable", kv->key))
h_cfg.emummc_force_disable = atoi(kv->val);
else if (!strcmp("emusdpath", kv->key))
*emusd_path = kv->val;
}
if (!cfg_sec)
{
*emummc_path = NULL;
*emusd_path = NULL;
*bootlogoCustomEntry = NULL;
h_cfg.emummc_force_disable = false;
}
@@ -713,7 +755,7 @@ static void _check_for_updated_bootloader()
else
{
u8 *buf = zalloc(0x200);
is_ipl_updated(buf, 0, "bootloader/update.bin", true);
is_ipl_updated(buf, "bootloader/update.bin", true);
free(buf);
}
}
@@ -735,9 +777,12 @@ static void _auto_launch()
u32 boot_entry_id = 0;
ini_sec_t *cfg_sec = NULL;
char *emummc_path = NULL;
char *emusd_path = NULL;
char *bootlogoCustomEntry = NULL;
bool config_entry_found = false;
_check_for_updated_bootloader();
bool boot_from_id = (b_cfg.boot_cfg & BOOT_CFG_FROM_ID) && (b_cfg.boot_cfg & BOOT_CFG_AUTOBOOT_EN);
if (boot_from_id)
b_cfg.id[7] = 0;
@@ -750,6 +795,7 @@ static void _auto_launch()
// Load emuMMC configuration.
emummc_load_cfg();
emusd_load_cfg();
// Parse hekate main configuration.
if (!ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
@@ -805,7 +851,7 @@ static void _auto_launch()
}
if (boot_from_id)
cfg_sec = _get_ini_sec_from_id(ini_sec, &bootlogoCustomEntry, &emummc_path);
cfg_sec = _get_ini_sec_from_id(ini_sec, &bootlogoCustomEntry, &emummc_path, &emusd_path);
else if (h_cfg.autoboot == boot_entry_id && config_entry_found)
{
cfg_sec = ini_sec;
@@ -815,6 +861,8 @@ static void _auto_launch()
bootlogoCustomEntry = kv->val;
else if (!strcmp("emupath", kv->key))
emummc_path = kv->val;
else if (!strcmp("emusdpath", kv->key))
emusd_path = kv->val;
else if (!strcmp("emummc_force_disable", kv->key))
h_cfg.emummc_force_disable = atoi(kv->val);
else if (!strcmp("bootwait", kv->key))
@@ -851,7 +899,7 @@ static void _auto_launch()
continue;
if (boot_from_id)
cfg_sec = _get_ini_sec_from_id(ini_sec_list, &bootlogoCustomEntry, &emummc_path);
cfg_sec = _get_ini_sec_from_id(ini_sec_list, &bootlogoCustomEntry, &emummc_path, &emusd_path);
else if (h_cfg.autoboot == boot_entry_id)
{
h_cfg.emummc_force_disable = false;
@@ -862,6 +910,8 @@ static void _auto_launch()
bootlogoCustomEntry = kv->val;
else if (!strcmp("emupath", kv->key))
emummc_path = kv->val;
else if (!strcmp("emusdpath", kv->key))
emusd_path = kv->val;
else if (!strcmp("emummc_force_disable", kv->key))
h_cfg.emummc_force_disable = atoi(kv->val);
else if (!strcmp("bootwait", kv->key))
@@ -892,11 +942,11 @@ skip_list:
// Check if user set custom logo path at the boot entry.
if (bootlogoCustomEntry)
bitmap = (u8 *)sd_file_read(bootlogoCustomEntry, &fsize);
bitmap = (u8 *)boot_storage_file_read(bootlogoCustomEntry, &fsize);
// Custom entry bootlogo not found, trying default custom one.
if (!bitmap)
bitmap = (u8 *)sd_file_read("bootloader/bootlogo.bmp", &fsize);
bitmap = (u8 *)boot_storage_file_read("bootloader/bootlogo.bmp", &fsize);
if (bitmap)
{
@@ -975,6 +1025,7 @@ skip_list:
}
else
{
// TODO: add boot_cfg for emusd
if (b_cfg.boot_cfg & BOOT_CFG_TO_EMUMMC)
emummc_set_path(b_cfg.emummc_path);
else if (emummc_path && !emummc_set_path(emummc_path))
@@ -984,15 +1035,29 @@ skip_list:
goto wrong_emupath;
}
if (emusd_path && !emusd_set_path(emusd_path))
{
gfx_con.mute = false;
EPRINTFARGS("path: %s", emusd_path);
EPRINTF("error: emusdpath is wrong!");
goto wrong_emupath;
}
hos_launch(cfg_sec);
wrong_emupath:
if (emummc_path || b_cfg.boot_cfg & BOOT_CFG_TO_EMUMMC)
{
sd_mount();
boot_storage_mount();
emummc_load_cfg(); // Reload emuMMC config in case of emupath.
}
if (emusd_path)
{
boot_storage_mount();
emusd_load_cfg();
}
error:
gfx_con.mute = false;
gfx_printf("\nPress any key...\n");
@@ -1157,7 +1222,7 @@ static void _show_errors()
static void _check_low_battery()
{
if (h_cfg.devmode)
if (fuse_read_hw_state() == FUSE_NX_HW_STATE_DEV)
goto out;
int enough_battery;
@@ -1417,7 +1482,6 @@ ment_t ment_top[] = {
MDEF_MENU("Console info", &menu_cinfo),
MDEF_CAPTION("---------------", TXT_CLR_GREY_DM),
MDEF_HANDLER("Reload", _ipl_reload),
MDEF_HANDLER("Load Nyx", launch_nyx),
MDEF_HANDLER_EX("Reboot (OFW)", &STATE_REBOOT_BYPASS_FUSES, power_set_state_ex),
MDEF_HANDLER_EX("Reboot (RCM)", &STATE_REBOOT_RCM, power_set_state_ex),
MDEF_HANDLER_EX("Power off", &STATE_POWER_OFF, power_set_state_ex),
@@ -1450,12 +1514,12 @@ void ipl_main()
uart_wait_xfer(DEBUG_UART_PORT, UART_TX_IDLE);
#endif
// Set bootloader's default configuration.
set_default_configuration();
// Check if battery is enough.
_check_low_battery();
// Set bootloader's default configuration.
set_default_configuration();
// Prep RTC regs for read. Needed for T210B01 R2C.
max77620_rtc_prep_read();
@@ -1466,7 +1530,8 @@ void ipl_main()
bpmp_clk_rate_set(h_cfg.t210b01 ? ipl_ver.rcfg.bclk_t210b01 : ipl_ver.rcfg.bclk_t210);
// Mount SD Card.
h_cfg.errors |= !sd_mount() ? ERR_SD_BOOT_EN : 0;
// TODO: boot storage may not be sd card -> set proper error
h_cfg.errors |= !boot_storage_mount() ? ERR_SD_BOOT_EN : 0;
// Check if watchdog was fired previously.
if (watchdog_fired())
@@ -1506,13 +1571,10 @@ skip_lp0_minerva_config:
// Load saved configuration and auto boot if enabled.
if (!(h_cfg.errors & ERR_SD_BOOT_EN))
{
_check_for_updated_bootloader();
_auto_launch();
}
// Failed to launch Nyx, unmount SD Card.
sd_end();
boot_storage_end();
// Set ram to a freq that doesn't need periodic training.
minerva_change_freq(FREQ_800);

View File

@@ -14,6 +14,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <storage/emmc.h>
#include <storage/sd.h>
#include <storage/sdmmc.h>
#include <string.h>
#include <stdlib.h>
@@ -22,6 +25,7 @@
#include "emummc.h"
#include "../config.h"
#include <libs/fatfs/ff.h>
#include <storage/emummc_file_based.h>
emummc_cfg_t emu_cfg = { 0 };
@@ -76,33 +80,68 @@ bool emummc_set_path(char *path)
FIL fp;
bool found = false;
strcpy(emu_cfg.emummc_file_based_path, path);
// strcpy(emu_cfg.emummc_file_based_path, "sd:");
strcpy(emu_cfg.emummc_file_based_path, "");
strcat(emu_cfg.emummc_file_based_path, path);
strcat(emu_cfg.emummc_file_based_path, "/raw_based");
if (!f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ))
{
if (!f_read(&fp, &emu_cfg.sector, 4, NULL))
if (emu_cfg.sector)
if (!f_read(&fp, &emu_cfg.sector, 4, NULL)){
if (emu_cfg.sector){
found = true;
}
else
{
strcpy(emu_cfg.emummc_file_based_path, path);
strcat(emu_cfg.emummc_file_based_path, "/file_based");
if (!f_stat(emu_cfg.emummc_file_based_path, NULL))
{
emu_cfg.sector = 0;
emu_cfg.path = path;
found = true;
emu_cfg.enabled = 1;
goto out;
}
}
}
if (found)
strcpy(emu_cfg.emummc_file_based_path, "");
strcat(emu_cfg.emummc_file_based_path, path);
strcat(emu_cfg.emummc_file_based_path, "/raw_emmc_based");
if (!f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ))
{
if (!f_read(&fp, &emu_cfg.sector, 4, NULL)){
if (emu_cfg.sector){
found = true;
emu_cfg.enabled = 4;
goto out;
}
}
}
// strcpy(emu_cfg.emummc_file_based_path, "sd:");
strcpy(emu_cfg.emummc_file_based_path, "");
strcat(emu_cfg.emummc_file_based_path, path);
strcat(emu_cfg.emummc_file_based_path, "/file_based");
if (!f_stat(emu_cfg.emummc_file_based_path, NULL))
{
emu_cfg.sector = 0;
emu_cfg.path = path;
emu_cfg.enabled = 1;
found = true;
goto out;
}
// strcpy(emu_cfg.emummc_file_based_path, "sd:");
strcpy(emu_cfg.emummc_file_based_path, "");
strcat(emu_cfg.emummc_file_based_path, path);
strcat(emu_cfg.emummc_file_based_path, "/file_emmc_based");
if (!f_stat(emu_cfg.emummc_file_based_path, NULL))
{
emu_cfg.sector = 0;
emu_cfg.path = path;
emu_cfg.enabled = 4;
found = true;
goto out;
}
out:
if (found)
{
// Get ID from path.
u32 id_from_path = 0;
u32 path_size = strlen(path);
@@ -133,7 +172,7 @@ static int emummc_raw_get_part_off(int part_idx)
int emummc_storage_init_mmc()
{
FILINFO fno;
// FILINFO fno;
emu_cfg.active_part = 0;
// Always init eMMC even when in emuMMC. eMMC is needed from the emuMMC driver anyway.
@@ -143,86 +182,80 @@ int emummc_storage_init_mmc()
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
return 0;
if (!sd_mount())
goto out;
bool file_based = false;
if (!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;
if(emu_cfg.enabled == 4){
// emmc based
if(!emu_cfg.sector){
// file based
if(!emmc_mount()){
gfx_printf("emmc mount fail\n");
return 1;
}
strcpy(emu_cfg.emummc_file_based_path, "emmc:");
strcat(emu_cfg.emummc_file_based_path, emu_cfg.path);
strcat(emu_cfg.emummc_file_based_path, "/eMMC/");
file_based = true;
}else{
// raw based
// emmc already initialized
}
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;
}else{
// sd based
if(!emu_cfg.sector){
// file based
if(!sd_mount()){
return 1;
}
strcpy(emu_cfg.emummc_file_based_path, "sd:");
strcat(emu_cfg.emummc_file_based_path, emu_cfg.path);
strcat(emu_cfg.emummc_file_based_path, "/eMMC/");
file_based = true;
}else{
// raw based
if(!sd_initialize(false)){
return 1;
}
}
emu_cfg.file_based_part_size = fno.fsize >> 9;
}
if(file_based){
gfx_printf("file based\n");
return emummc_storage_file_based_init(emu_cfg.emummc_file_based_path) == 0;
}
return 0;
out:
return 1;
}
int emummc_storage_end()
{
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
if(!h_cfg.emummc_force_disable && emu_cfg.enabled && !emu_cfg.sector){
emummc_storage_file_based_end();
}
if(!emu_cfg.enabled || h_cfg.emummc_force_disable || emu_cfg.enabled == 4){
emmc_end();
else
}else{
sd_end();
}
return 1;
}
int emummc_storage_read(u32 sector, u32 num_sectors, void *buf)
{
FIL fp;
sdmmc_storage_t *storage = emu_cfg.enabled == 4 ? &emmc_storage : &sd_storage;
// FIL fp;
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
return sdmmc_storage_read(&emmc_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);
return sdmmc_storage_read(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 emummc_storage_file_based_read(sector, num_sectors, buf);
}
return 1;
@@ -230,72 +263,44 @@ int emummc_storage_read(u32 sector, u32 num_sectors, void *buf)
int emummc_storage_write(u32 sector, u32 num_sectors, void *buf)
{
FIL fp;
sdmmc_storage_t *storage = emu_cfg.enabled == 4 ? &emmc_storage : &sd_storage;
// FIL fp;
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
return sdmmc_storage_write(&emmc_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);
return sdmmc_storage_write(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))
return 0;
f_lseek(&fp, (u64)sector << 9);
if (f_write(&fp, buf, (u64)num_sectors << 9, NULL))
{
f_close(&fp);
return 0;
}
f_close(&fp);
return 1;
return emummc_storage_file_based_write(sector, num_sectors, buf);
}
}
int emummc_storage_set_mmc_partition(u32 partition)
{
emu_cfg.active_part = partition;
emmc_set_partition(partition);
if (!emu_cfg.enabled || h_cfg.emummc_force_disable || 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;
}
if(h_cfg.emummc_force_disable || !emu_cfg.enabled){
emmc_set_partition(partition);
return 1;
}
if(!emu_cfg.sector){
emummc_storage_file_base_set_partition(partition);
return 1;
}
if(emu_cfg.enabled != 4){
emmc_set_partition(partition);
}else{
emmc_set_partition(EMMC_GPP);
}
return 1;
}
sdmmc_storage_t *emummc_get_storage(){
return emu_cfg.enabled == 4 ? &emmc_storage : &sd_storage;
}

View File

@@ -19,19 +19,6 @@
#include <bdk.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;
@@ -55,5 +42,6 @@ int emummc_storage_end();
int emummc_storage_read(u32 sector, u32 num_sectors, void *buf);
int emummc_storage_write(u32 sector, u32 num_sectors, void *buf);
int emummc_storage_set_mmc_partition(u32 partition);
sdmmc_storage_t *emummc_get_storage();
#endif

295
bootloader/storage/emusd.c Normal file
View File

@@ -0,0 +1,295 @@
#include "emusd.h"
#include <bdk.h>
#include <storage/boot_storage.h>
#include <storage/emmc.h>
#include <storage/file_based_storage.h>
#include <storage/sd.h>
#include <storage/sdmmc.h>
#include <string.h>
#include <utils/ini.h>
#include <libs/fatfs/ff.h>
#include "../config.h"
#include "gfx_utils.h"
FATFS emusd_fs;
bool emusd_mounted = false;
bool emusd_initialized = false;
emusd_cfg_t emu_sd_cfg = {0};
extern hekate_config h_cfg;
static bool emusd_get_mounted() {
return emusd_mounted;
}
void emusd_load_cfg()
{
emu_sd_cfg.enabled = 0;
emu_sd_cfg.fs_ver = 0;
emu_sd_cfg.id = 0;
emu_sd_cfg.sector = 0;
if(!emu_sd_cfg.path) {
emu_sd_cfg.path = (char*)malloc(0x200);
}
if(!emu_sd_cfg.emummc_file_based_path){
emu_sd_cfg.emummc_file_based_path = (char*)malloc(0x200);
}
LIST_INIT(ini_sections);
if(ini_parse(&ini_sections, "emuSD/emusd.ini", false))
{
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
{
if(ini_sec->type == INI_CHOICE)
{
if(strcmp(ini_sec->name, "emusd")){
continue;
}
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
if(!strcmp(kv->key, "enabled")){
emu_sd_cfg.enabled = atoi(kv->val);
} else if(!strcmp(kv->key, "sector")){
emu_sd_cfg.sector = strtol(kv->val, NULL, 16);
} else if(!strcmp(kv->key, "path")){
emu_sd_cfg.path = kv->val;
}
}
break;
}
}
}
}
bool emusd_mount() {
if (emusd_mounted) {
return true;
}
if (emusd_storage_init_mmc()){
return false;
}
int res = f_mount(&emusd_fs, "emusd:", 1);
if(res) {
EPRINTFARGS("emusd mount fail %d", res);
return false;
}
return true;
}
bool emusd_unmount() {
f_mount(NULL, "emusd:", 1);
emusd_mounted = false;
return true;
}
bool emusd_set_path(char *path) {
FIL fp;
bool found = false;
// TODO: use emu_sd.file_path instead
strcat(emu_sd_cfg.emummc_file_based_path, "");
strcpy(emu_sd_cfg.emummc_file_based_path, path);
strcat(emu_sd_cfg.emummc_file_based_path, "/raw_emmc_based");
if(!f_open(&fp, emu_sd_cfg.emummc_file_based_path, FA_READ))
{
if(!f_read(&fp, &emu_sd_cfg.sector, 4, NULL)){
if(emu_sd_cfg.sector){
found = true;
emu_sd_cfg.enabled = 4;
goto out;
}
}
}
strcpy(emu_sd_cfg.emummc_file_based_path, "");
strcat(emu_sd_cfg.emummc_file_based_path, path);
strcat(emu_sd_cfg.emummc_file_based_path, "/raw_emmc_based");
if (!f_open(&fp, emu_sd_cfg.emummc_file_based_path, FA_READ))
{
if (!f_read(&fp, &emu_sd_cfg.sector, 4, NULL)){
if (emu_sd_cfg.sector){
found = true;
emu_sd_cfg.enabled = 4;
goto out;
}
}
}
// strcpy(emu_sd_cfg.emummc_file_based_path, "sd:");
strcpy(emu_sd_cfg.emummc_file_based_path, "");
strcat(emu_sd_cfg.emummc_file_based_path, path);
strcat(emu_sd_cfg.emummc_file_based_path, "/file_based");
if (!f_stat(emu_sd_cfg.emummc_file_based_path, NULL))
{
emu_sd_cfg.sector = 0;
emu_sd_cfg.path = path;
emu_sd_cfg.enabled = 1;
found = true;
goto out;
}
// strcpy(emu_sd_cfg.emummc_file_based_path, "sd:");
strcpy(emu_sd_cfg.emummc_file_based_path, "");
strcat(emu_sd_cfg.emummc_file_based_path, path);
strcat(emu_sd_cfg.emummc_file_based_path, "/file_emmc_based");
if (!f_stat(emu_sd_cfg.emummc_file_based_path, NULL))
{
emu_sd_cfg.sector = 0;
emu_sd_cfg.path = path;
emu_sd_cfg.enabled = 4;
found = true;
goto out;
}
out:
return found;
}
int emusd_storage_init_mmc() {
if(!emusd_initialized) {
if (!emu_sd_cfg.enabled || h_cfg.emummc_force_disable) {
if(!sd_initialize(false)){
return 1;
}
emusd_initialized = true;
return 0;
}
bool file_based = false;
if(emu_sd_cfg.enabled == 4){
if(!emu_sd_cfg.sector){
//file based
if(!emmc_mount()){
return 1;
}
strcpy(emu_sd_cfg.emummc_file_based_path, "emmc:");
strcat(emu_sd_cfg.emummc_file_based_path, emu_sd_cfg.path);
strcat(emu_sd_cfg.emummc_file_based_path, "/SD/");
file_based = true;
}else{
if(!emmc_initialize(false)){
return 1;
}
}
}else{
if(!emu_sd_cfg.sector){
//file based
if(!sd_mount()){
return 1;
}
strcpy(emu_sd_cfg.emummc_file_based_path, "sd:");
strcat(emu_sd_cfg.emummc_file_based_path, emu_sd_cfg.path);
strcat(emu_sd_cfg.emummc_file_based_path, "/SD/");
file_based = true;
}else{
if(!sd_initialize(false)){
return 1;
}
}
}
if(file_based){
return file_based_storage_init(emu_sd_cfg.emummc_file_based_path) == 0;
}
emusd_initialized = true;
}
return 0;
}
int emusd_storage_end() {
if(!h_cfg.emummc_force_disable && emu_sd_cfg.enabled && !emu_sd_cfg.sector){
file_based_storage_end();
}
if(!emu_sd_cfg.enabled || h_cfg.emummc_force_disable || emu_sd_cfg.enabled == 1){
sd_unmount();
}else{
emmc_unmount();
}
emusd_initialized = false;
return 0;
}
int emusd_storage_write(u32 sector, u32 num_sectors, void *buf) {
if(!emu_sd_cfg.enabled || h_cfg.emummc_force_disable){
return sdmmc_storage_write(&sd_storage, sector, num_sectors, buf);
}else if(emu_sd_cfg.sector){
sdmmc_storage_t *storage = emu_sd_cfg.enabled == 1 ? &sd_storage : &emmc_storage;
sector += emu_sd_cfg.sector;
return sdmmc_storage_write(storage, sector, num_sectors, buf);
}else{
return file_based_storage_write(sector, num_sectors, buf);
}
}
int emusd_storage_read(u32 sector, u32 num_sectors, void *buf) {
if(!emu_sd_cfg.enabled || h_cfg.emummc_force_disable){
return sdmmc_storage_read(&sd_storage, sector, num_sectors, buf);
}else if(emu_sd_cfg.sector){
sdmmc_storage_t *storage = emu_sd_cfg.enabled == 1 ? &sd_storage : &emmc_storage;
sector += emu_sd_cfg.sector;
return sdmmc_storage_read(storage, sector, num_sectors, buf);
}else{
return file_based_storage_read(sector, num_sectors, buf);
}
}
sdmmc_storage_t *emusd_get_storage() {
return emu_sd_cfg.enabled == 4 ? &emmc_storage : &sd_storage;
}
bool emusd_is_gpt() {
if(emu_sd_cfg.enabled) {
return emusd_fs.part_type;
} else {
return sd_fs.part_type;
}
}
int emusd_get_fs_type() {
if(emu_sd_cfg.enabled) {
return emusd_fs.fs_type;
} else {
return sd_fs.fs_type;
}
}
void *emusd_file_read(const char *path, u32 *fsize) {
if(emu_sd_cfg.enabled) {
char *path1 = malloc(0x100);
strcpy(path1, "emusd:");
strcat(path1, path);
FIL fp;
if (!emusd_get_mounted())
return NULL;
if (f_open(&fp, path, FA_READ) != FR_OK)
return NULL;
u32 size = f_size(&fp);
if (fsize)
*fsize = size;
void *buf = malloc(size);
if (f_read(&fp, buf, size, NULL) != FR_OK)
{
free(buf);
f_close(&fp);
return NULL;
}
f_close(&fp);
return buf;
} else {
return boot_storage_file_read(path, fsize);
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2019-2021 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 _EMUSD_H
#define _EMUSD_H
#include <bdk.h>
typedef struct _emusd_cfg_t
{
int enabled;
u64 sector;
u32 id;
char *path;
// Internal.
int fs_ver;
char *emummc_file_based_path;
} emusd_cfg_t;
extern emusd_cfg_t emu_sd_cfg;
void emusd_load_cfg();
bool emusd_set_path(char *path);
int emusd_storage_init_mmc();
int emusd_storage_end();
int emusd_storage_read(u32 sector, u32 num_sectors, void *buf);
int emusd_storage_write(u32 sector, u32 num_sectors, void *buf);
sdmmc_storage_t *emusd_get_storage();
bool emusd_is_gpt();
int emusd_get_fs_type();
bool emusd_mount();
bool emusd_unmount();
void *emusd_file_read(const char *path, u32 *fsize);
#endif