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

@@ -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!");