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

275
bdk/storage/boot_storage.c Normal file
View File

@@ -0,0 +1,275 @@
#include "boot_storage.h"
#include <libs/fatfs/ff.h>
#include <fatfs_cfg.h>
#include <storage/sd.h>
#include <storage/emmc.h>
#include <utils/types.h>
#include <gfx_utils.h>
#include <stdlib.h>
#define DEV_INVALID 0xff
static FATFS boot_storage_fs;
static BYTE drive_cur = -1;
static BYTE drive = -1;
static const char* drive_base_paths[] = {
[DRIVE_SD] = "sd:",
[DRIVE_BOOT1] = "boot1_:",
[DRIVE_BOOT1_1MB] = "boot1_1mb:",
[DRIVE_EMMC] = "emmc:",
};
static bool _is_eligible(){
if(f_stat(".no_boot_storage", NULL) == FR_OK){
return false;
}
return true;
}
bool boot_storage_get_mounted(){
switch(drive_cur){
case DRIVE_SD:
return sd_get_card_mounted();
case DRIVE_EMMC:
return emmc_get_mounted();
case DRIVE_BOOT1:
case DRIVE_BOOT1_1MB:
return drive_cur != DEV_INVALID;
}
return false;
}
bool boot_storage_get_initialized(){
switch(drive_cur){
case DRIVE_BOOT1:
case DRIVE_EMMC:
case DRIVE_BOOT1_1MB:
return emmc_get_initialized();
case DRIVE_SD:
return sd_get_card_initialized();
}
return false;
}
static bool _boot_storage_initialize(){
switch(drive_cur){
case DRIVE_BOOT1:
case DRIVE_EMMC:
case DRIVE_BOOT1_1MB:
return emmc_initialize(false);
case DRIVE_SD:
return sd_initialize(false);
}
return false;
}
static void _boot_storage_end(bool deinit){
if(boot_storage_get_mounted()){
switch(drive_cur){
case DRIVE_SD:
sd_unmount();
break;
case DRIVE_EMMC:
emmc_unmount();
break;
case DRIVE_BOOT1:
case DRIVE_BOOT1_1MB:
f_mount(NULL, drive_base_paths[drive_cur], 0);
}
drive_cur = DEV_INVALID;
}
if(deinit){
switch(drive_cur){
case DRIVE_SD:
sd_end();
break;
case DRIVE_EMMC:
case DRIVE_BOOT1:
case DRIVE_BOOT1_1MB:
emmc_end();
break;
}
}
}
void boot_storage_unmount(){
_boot_storage_end(false);
}
void boot_storage_end(){
_boot_storage_end(true);
}
u8 boot_storage_get_drive(){
return drive;
}
static bool _boot_storage_mount(){
// may want to check sd card first and prioritize it
FRESULT res;
bool prev_emmc_initialized = emmc_get_initialized();
bool prev_sd_initialized = sd_get_card_initialized();
if(!prev_emmc_initialized && !emmc_initialize(false)){
goto emmc_init_fail;
}
static const BYTE emmc_drives[] = {DRIVE_BOOT1_1MB, DRIVE_BOOT1};
for(BYTE i = 0; i < ARRAY_SIZE(emmc_drives); i++){
res = f_mount(&boot_storage_fs, drive_base_paths[emmc_drives[i]], true);
if(res == FR_OK){
res = f_chdrive(drive_base_paths[emmc_drives[i]]);
if(res == FR_OK && _is_eligible()){
drive_cur = emmc_drives[i];
drive = drive_cur;
break;
}else{
f_mount(NULL, drive_base_paths[emmc_drives[i]],false);
res = FR_INVALID_DRIVE;
}
}
}
if(res != FR_OK){
if(!prev_emmc_initialized) {
emmc_end();
}
}
if(res == FR_OK){
return true;
}
emmc_init_fail:
if(!emmc_initialize(false)){
goto emmc_init_fail2;
}
if(!emmc_mount()){
if(!prev_emmc_initialized) {
emmc_end();
}
goto emmc_init_fail2;
}
res = f_chdrive(drive_base_paths[DRIVE_EMMC]);
if(res == FR_OK && _is_eligible()){
drive_cur = DRIVE_EMMC;
drive = drive_cur;
return true;
}
emmc_init_fail2:
if(!sd_initialize(false)){
goto out;
}
if(!sd_mount()){
if(!prev_sd_initialized) {
sd_end();
}
goto out;
}
res = f_chdrive(drive_base_paths[DRIVE_SD]);
if(res == FR_OK && _is_eligible()){
drive_cur = DRIVE_SD;
drive = drive_cur;
return true;
}
if(!prev_sd_initialized) {
sd_end();
}
out:
return false;
}
bool boot_storage_mount(){
bool mounted = boot_storage_get_mounted();
bool initialized = boot_storage_get_initialized();
bool res = mounted && initialized;
if(!mounted){
// not mounted. mounting will also initialize.
res = _boot_storage_mount();
}else if(!initialized){
res = _boot_storage_initialize();
}
if(res){
res = f_chdrive(drive_base_paths[drive_cur]) == FR_OK;
}
return res;
}
void *boot_storage_file_read(const char *path, u32 *fsize)
{
FIL fp;
if (!boot_storage_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;
}
int boot_storage_save_to_file(const void *buf, u32 size, const char *filename)
{
FIL fp;
u32 res = 0;
if (!boot_storage_get_mounted())
return FR_DISK_ERR;
res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE);
if (res)
{
EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename);
return res;
}
f_write(&fp, buf, size, NULL);
f_close(&fp);
return 0;
}
FATFS *boot_storage_get_fs() {
switch(drive_cur){
case DRIVE_BOOT1:
return &boot_storage_fs;
case DRIVE_EMMC:
return &emmc_fs;
case DRIVE_BOOT1_1MB:
return &boot_storage_fs;
case DRIVE_SD:
return &sd_fs;
}
return NULL;
}

View File

@@ -0,0 +1,24 @@
#ifndef _BOOT_STORAGE_H
#define _BOOT_STORAGE_H
#include <libs/fatfs/ff.h>
#include <utils/types.h>
// check if boot1 (1mb), boot1, gpp, sd (in that order) have fat32 partition,
// mount the partition and set the current drive to it
bool boot_storage_mount();
void boot_storage_unmount();
void boot_storage_end();
bool boot_storage_get_mounted();
bool boot_storage_get_initialized();
void *boot_storage_file_read(const char *path, u32 *fsize);
int boot_storage_save_to_file(const void *buf, u32 size, const char *filename);
FATFS *boot_storage_get_fs();
u8 boot_storage_get_drive();
#endif

View File

@@ -21,10 +21,14 @@
#include <mem/heap.h>
#include <soc/fuse.h>
#include <storage/mbr_gpt.h>
#include <gfx_utils.h>
#include <utils/list.h>
#include <storage/emummc_file_based.h>
static u16 emmc_errors[3] = { 0 }; // Init and Read/Write errors.
static u32 emmc_mode = EMMC_MMC_HS400;
static bool emmc_init_done = false;
static bool emmc_mounted = false;
sdmmc_t emmc_sdmmc;
sdmmc_storage_t emmc_storage;
@@ -61,7 +65,26 @@ u32 emmc_get_mode()
return emmc_mode;
}
void emmc_end() { sdmmc_storage_end(&emmc_storage); }
static void _emmc_deinit(bool deinit){
if(emmc_init_done){
// TODO: Allow unmount even when not init'd?
if(emmc_mounted){
f_mount(NULL, "emmc:", 0);
}
if(deinit){
sdmmc_storage_end(&emmc_storage);
emmc_init_done = false;
}
}
emmc_mounted = false;
}
void emmc_end() { _emmc_deinit(true); }
bool emmc_get_initialized(){
return emmc_init_done;
}
int emmc_init_retry(bool power_cycle)
{
@@ -97,7 +120,13 @@ int emmc_init_retry(bool power_cycle)
emmc_mode = EMMC_MMC_HS400;
}
return sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, bus_width, type);
int res = sdmmc_storage_init_mmc(&emmc_storage, &emmc_sdmmc, bus_width, type);
if(res){
emmc_init_done = true;
}else{
emmc_init_done = false;
}
return res;
}
bool emmc_initialize(bool power_cycle)
@@ -212,6 +241,14 @@ int emmc_part_write(emmc_part_t *part, u32 sector_off, u32 num_sectors, void *bu
#endif
}
sdmmc_storage_t *emmc_part_get_storage(){
#ifdef BDK_EMUMMC_ENABLE
return emummc_get_storage();
#else
return &emmc_storage;
#endif
}
void nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1)
{
if (fuse_read_hw_state() == FUSE_NX_HW_STATE_PROD)
@@ -225,3 +262,44 @@ void nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1)
*mod1 = 0x84;
}
}
bool emmc_mount()
{
if (emmc_init_done && emmc_mounted)
return true;
int res = 0;
if (!emmc_init_done)
res = !emmc_initialize(false);
if (res)
{
gfx_con.mute = false;
EPRINTF("Failed to init eMMC.");
}
else
{
if (!emmc_mounted)
res = f_mount(&emmc_fs, "emmc:", 1); // Volume 0 is SD.
if (res == FR_OK)
{
emmc_mounted = true;
return true;
}
else
{
gfx_con.mute = false;
EPRINTFARGS("Failed to mount eMMC (FatFS Error %d).\nMake sure that a FAT partition exists..", res);
}
}
return false;
}
bool emmc_get_mounted(){
return emmc_mounted;
}
void emmc_unmount() { _emmc_deinit(false); }

View File

@@ -65,12 +65,17 @@ int emmc_init_retry(bool power_cycle);
bool emmc_initialize(bool power_cycle);
int emmc_set_partition(u32 partition);
void emmc_end();
bool emmc_mount();
void emmc_unmount();
bool emmc_get_initialized();
bool emmc_get_mounted();
void emmc_gpt_parse(link_t *gpt);
void emmc_gpt_free(link_t *gpt);
emmc_part_t *emmc_part_find(link_t *gpt, const char *name);
int emmc_part_read(emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf);
int emmc_part_write(emmc_part_t *part, u32 sector_off, u32 num_sectors, void *buf);
sdmmc_storage_t *emmc_part_get_storage();
void nx_emmc_get_autorcm_masks(u8 *mod0, u8 *mod1);

View File

@@ -0,0 +1,233 @@
#include "emummc_file_based.h"
#include <string.h>
#include <stdlib.h>
#include <libs/fatfs/ff.h>
#include <gfx_utils.h>
// TODO: fast read/writes
static FIL active_file;
// -0xff: none, -1: boot 0, -2: boot1, 0+: gpp
static s32 active_file_idx;
static char file_based_base_path[0x80];
static u32 file_part_sz_sct;
static u32 active_part;
static u32 file_based_base_path_len;
static int _emummc_storage_file_based_read_write_single(u32 sector, u32 num_sectors, void *buf, bool is_write){
#if FF_FS_READONLY == 1
if(is_write){
return FR_WRITE_PROTECTED;
}
#endif
int res = f_lseek(&active_file, (u64)sector << 9);
if(res != FR_OK){
return res;
}
if(is_write){
res = f_write(&active_file, buf, (u64)num_sectors << 9, NULL);
}else{
res = f_read(&active_file, buf, (u64)num_sectors << 9, NULL);
}
if(res != FR_OK){
return res;
}
return FR_OK;
}
static int _emummc_storage_file_based_change_file(const char *name, s32 idx){
int res;
if(active_file_idx == idx){
return FR_OK;
}
if(active_file_idx != -0xff){
f_close(&active_file);
active_file_idx = -0xff;
}
strcpy(file_based_base_path + file_based_base_path_len, name);
#if FF_FS_READONLY == 1
res = f_open(&active_file, file_based_base_path, FA_READ);
#else
res = f_open(&active_file, file_based_base_path, FA_READ | FA_WRITE);
#endif
if(res != FR_OK){
return res;
}
active_file_idx = idx;
return FR_OK;
}
static int _emummc_storage_file_based_read_write(u32 sector, u32 num_sectors, void *buf, bool is_write){
#if FF_FS_READONLY == 1
if(is_write){
return 0;
}
#endif
if(file_part_sz_sct == 0){
return 0;
}
int res;
if(active_part == 1){
// boot0
res = _emummc_storage_file_based_change_file("BOOT0", -1);
if(res != FR_OK){
return 0;
}
res = _emummc_storage_file_based_read_write_single(sector, num_sectors, buf, is_write);
if(res != FR_OK){
return 0;
}
f_sync(&active_file);
return 1;
}else if(active_part == 2){
// boot1
res = _emummc_storage_file_based_change_file("BOOT1", -2);
if(res != FR_OK){
return 0;
}
res = _emummc_storage_file_based_read_write_single(sector, num_sectors, buf, is_write) == FR_OK;
if(res != FR_OK){
return 0;
}
f_sync(&active_file);
return 1;
}else if(active_part == 0){
// GPP
if(file_part_sz_sct == 0){
return 0;
}
u32 scts_left = num_sectors;
u32 cur_sct = sector;
while(scts_left){
// offset within file
u32 offset = cur_sct % file_part_sz_sct;
// read up to start of next file or sectors left, whatever is less
u32 sct_cnt = file_part_sz_sct - offset;
sct_cnt = MIN(sct_cnt, scts_left);
u32 file_idx = cur_sct / file_part_sz_sct;
if((s32)file_idx != active_file_idx){
char name[3] = "";
if(file_idx < 10){
strcpy(name, "0");
}
itoa(file_idx, name + strlen(name), 10);
res = _emummc_storage_file_based_change_file(name, file_idx);
if(res != FR_OK){
return 0;
}
}
res = _emummc_storage_file_based_read_write_single(offset, sct_cnt, buf + ((u64)(num_sectors - scts_left) << 9), is_write);
if(res != FR_OK){
return 0;
}
cur_sct += sct_cnt;
scts_left -= sct_cnt;
}
if(res != FR_OK){
return 0;
}
f_sync(&active_file);
return 1;
}
return 0;
}
int emummc_storage_file_base_set_partition(u32 partition){
active_part = partition;
return 1;
}
int emummc_storage_file_based_init(const char *path){
strcpy(file_based_base_path, path);
file_based_base_path_len = strlen(file_based_base_path);
strcat(file_based_base_path + file_based_base_path_len, "00");
active_part = 0;
FILINFO fi;
if(f_stat(file_based_base_path, &fi) != FR_OK){
return 0;
}
file_part_sz_sct = 0;
if(fi.fsize){
file_part_sz_sct = fi.fsize >> 9;
}
active_file_idx = -0xff;
return 1;
}
void emummc_storage_file_based_end(){
if(active_file_idx != -0xff){
f_close(&active_file);
}
active_file_idx = -0xff;
file_based_base_path[0] = '\0';
file_part_sz_sct = 0;
}
#if FF_FS_READONLY == 0
int emummc_storage_file_based_write(u32 sector, u32 num_sectors, void *buf){
return _emummc_storage_file_based_read_write(sector, num_sectors, buf, true);
}
#endif
int emummc_storage_file_based_read(u32 sector, u32 num_sectors, void *buf){
return _emummc_storage_file_based_read_write(sector, num_sectors, buf, false);
}
u32 emummc_storage_file_based_get_total_gpp_size(const char *path){
u32 path_len = strlen(path);
u32 total_size_sct = 0;
char file_path[0x80];
u32 cur_idx = 0;
int res;
strcpy(file_path, path);
strcpy(file_path + path_len, "00");
FILINFO fi;
res = f_stat(file_path, &fi);
while(res == FR_OK){
cur_idx++;
total_size_sct += fi.fsize >> 9;
char name[3] = "0";
if(cur_idx >= 10){
name[0] = '\0';
}
itoa(cur_idx, name + strlen(name), 10);
strcpy(file_path + path_len, name);
res = f_stat(file_path, &fi);
}
return total_size_sct;
}

View File

@@ -0,0 +1,14 @@
#ifndef _EMUMMC_FILE_BASED_H
#define _EMUMMC_FILE_BASED_H
#include <bdk.h>
int emummc_storage_file_base_set_partition(u32 partition);
int emummc_storage_file_based_init(const char *path);
void emummc_storage_file_based_end();
int emummc_storage_file_based_write(u32 sector, u32 num_sectors, void *buf);
int emummc_storage_file_based_read(u32 sector, u32 num_sectors, void *buf);
u32 emummc_storage_file_based_get_total_gpp_size(const char *path);
sdmmc_storage_t *emummc_get_storage();
#endif

View File

@@ -0,0 +1,184 @@
#include "file_based_storage.h"
#include <libs/fatfs/ff.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
FIL active_file;
s32 active_file_idx;
char base_path[0x80];
u32 part_sz_sct;
u32 base_path_len;
}file_based_storage_ctxt_t;
static file_based_storage_ctxt_t ctx;
int file_based_storage_init(const char *base_path) {
ctx.active_file_idx = -0xff;
ctx.base_path_len = strlen(base_path);
strcpy(ctx.base_path, base_path);
strcat(ctx.base_path, "00");
FILINFO fi;
if(f_stat(ctx.base_path, &fi) != FR_OK) {
return 0;
}
if(fi.fsize) {
ctx.part_sz_sct = fi.fsize >> 9;
}else{
return 0;
}
ctx.part_sz_sct = fi.fsize;
return 1;
}
void file_based_storage_end() {
if(ctx.active_file_idx != -0xff) {
f_close(&ctx.active_file);
}
ctx.active_file_idx = -0xff;
ctx.part_sz_sct = 0;
}
static int file_based_storage_change_file(const char *name, s32 idx) {
int res;
if(ctx.active_file_idx == idx){
return FR_OK;
}
if(ctx.active_file_idx != -0xff){
f_close(&ctx.active_file);
ctx.active_file_idx = -0xff;
}
strcpy(ctx.base_path + ctx.base_path_len, name);
#if FF_FS_READONLY == 1
res = f_open(&ctx.active_file, ctx.base_path, FA_READ);
#else
res = f_open(&ctx.active_file, ctx.base_path, FA_READ | FA_WRITE);
#endif
if(res != FR_OK){
return res;
}
ctx.active_file_idx = idx;
return FR_OK;
}
static int file_based_storage_readwrite_single(u32 sector, u32 num_sectors, void *buf, bool is_write){
#if FF_FS_READONLY == 1
if(is_write){
return FR_WRITE_PROTECTED;
}
#endif
int res = f_lseek(&ctx.active_file, (u64)sector << 9);
if(res != FR_OK){
return res;
}
if(is_write){
res = f_write(&ctx.active_file, buf, (u64)num_sectors << 9, NULL);
}else{
res = f_read(&ctx.active_file, buf, (u64)num_sectors << 9, NULL);
}
if(res != FR_OK){
return res;
}
return FR_OK;
}
int file_based_storage_readwrite(u32 sector, u32 num_sectors, void *buf, bool is_write) {
#if FF_FS_READONLY == 1
if(is_write){
return 0;
}
#endif
if(ctx.part_sz_sct == 0){
return 0;
}
int res;
u32 scts_left = num_sectors;
u32 cur_sct = sector;
while(scts_left){
u32 offset = cur_sct % ctx.part_sz_sct;
u32 sct_cnt = ctx.part_sz_sct - offset;
sct_cnt = MIN(scts_left, sct_cnt);
u32 file_idx = cur_sct / ctx.part_sz_sct;
if((s32) file_idx != ctx.active_file_idx) {
char name[3];
if(file_idx < 10){
strcpy(name, "0");
}
itoa(file_idx, name + strlen(name), 10);
res = file_based_storage_change_file(name, file_idx);
if(res != FR_OK){
return 0;
}
}
res = file_based_storage_readwrite_single(offset, sct_cnt, buf + ((u64)(num_sectors - scts_left) << 9), is_write);
if(res != FR_OK){
return 0;
}
cur_sct += sct_cnt;
scts_left -= sct_cnt;
}
f_sync(&ctx.active_file);
return 1;
}
int file_based_storage_read(u32 sector, u32 num_sectors, void *buf) {
return file_based_storage_readwrite(sector, num_sectors, buf, false);
}
int file_based_storage_write(u32 sector, u32 num_sectors, void *buf) {
return file_based_storage_readwrite(sector, num_sectors, buf, true);
}
u32 file_based_storage_get_total_size() {
u32 total_size_sct = 0;
char file_path[0x80];
u32 cur_idx = 0;
int res;
strcpy(file_path, ctx.base_path);
strcpy(file_path + ctx.base_path_len, "00");
FILINFO fi;
res = f_stat(file_path, &fi);
while(res == FR_OK){
cur_idx++;
total_size_sct += fi.fsize >> 9;
char name[3] = "0";
if(cur_idx >= 10){
name[0] = '\0';
}
itoa(cur_idx, name + strlen(name), 10);
strcpy(file_path + ctx.base_path_len, name);
res = f_stat(file_path, &fi);
}
return total_size_sct;
}

View File

@@ -0,0 +1,15 @@
#ifndef _FILE_BASED_STORAGE_H
#define _FILE_BASED_STORAGE_H
#include <bdk.h>
int file_based_storage_init(const char *base_path);
void file_based_storage_end();
int file_based_storage_read(u32 sector, u32 num_sectors, void *buf);
int file_based_storage_write(u32 sector, u32 num_sectors, void *buf);
u32 file_based_storage_get_total_size();
#endif

39
bdk/storage/mbr_gpt.c Normal file
View File

@@ -0,0 +1,39 @@
#include "mbr_gpt.h"
#include <utils/types.h>
#include <string.h>
bool mbr_has_gpt(const mbr_t *mbr){
for(u32 i = 0; i < 4; i++){
if(mbr->partitions[i].type == 0xee){
return true;
}
}
return false;
}
void wctombs(const u16 *src, char *dest, u32 len_max){
const u16 *cur = src;
do{
*dest++ = *cur & 0xff;
len_max--;
}while(*cur++ && len_max);
}
void ctowcs(const char *src, u16 *dest, u32 len_max){
const char *cur = src;
do{
*dest++ = *cur;
len_max--;
}while(*cur++ && len_max);
}
s32 gpt_get_part_by_name(gpt_t *gpt, const char* name, s32 prev){
u16 wc_name[36];
ctowcs(name, wc_name, 36);
for(s32 i = prev + 1; i < (s32)gpt->header.num_part_ents && i < 128; i++){
if(!memcmp(wc_name, gpt->entries[i].name, strlen(name) * 2)){
return i;
}
}
return -1;
}

View File

@@ -81,4 +81,10 @@ typedef struct _gpt_t
gpt_entry_t entries[128];
} gpt_t;
bool mbr_has_gpt(const mbr_t *mbr);
void wctombs(const u16 *src, char *dest, u32 len_max);
void ctowcs(const char *src, u16 *dest, u32 len_max);
s32 gpt_get_part_by_name(gpt_t *gpt, const char* name, s32 prev);
#endif

View File

@@ -17,6 +17,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libs/fatfs/ff.h>
#include <stdlib.h>
#include <storage/nx_emmc_bis.h>
#include <string.h>
#include <memory_map.h>
@@ -26,6 +29,7 @@
#include <storage/emmc.h>
#include <storage/sd.h>
#include <storage/sdmmc.h>
#include <storage/emummc_file_based.h>
#include <utils/types.h>
#define BIS_CLUSTER_SECTORS 32
@@ -56,6 +60,8 @@ static u32 emu_offset = 0;
static emmc_part_t *system_part = NULL;
static u32 *cache_lookup_tbl = (u32 *)NX_BIS_LOOKUP_ADDR;
static bis_cache_t *bis_cache = (bis_cache_t *)NX_BIS_CACHE_ADDR;
static sdmmc_storage_t *emu_storage = NULL;
static bool file_based = false;
static int nx_emmc_bis_write_block(u32 sector, u32 count, void *buff, bool flush)
{
@@ -91,14 +97,18 @@ static int nx_emmc_bis_write_block(u32 sector, u32 count, void *buff, bool flush
}
// Encrypt cluster.
if (!se_aes_crypt_xts_sec_nx(ks_tweak, ks_crypt, ENCRYPT, cluster, tweak, true, sector_in_cluster, bis_cache->dma_buff, buff, count * EMMC_BLOCKSIZE))
if (!se_aes_xts_crypt_sec_nx(ks_tweak, ks_crypt, ENCRYPT, cluster, tweak, true, sector_in_cluster, bis_cache->dma_buff, buff, count * EMMC_BLOCKSIZE))
return 1; // Encryption error.
// If not reading from cache, do a regular read and decrypt.
if (!emu_offset)
if(emu_storage){
res = sdmmc_storage_write(emu_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff);
}else if(file_based){
res = emummc_storage_file_based_write(system_part->lba_start + sector, count, bis_cache->dma_buff);
}else{
res = emmc_part_write(system_part, sector, count, bis_cache->dma_buff);
else
res = sdmmc_storage_write(&sd_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff);
}
if (!res)
return 1; // R/W error.
@@ -155,10 +165,13 @@ static int nx_emmc_bis_read_block_normal(u32 sector, u32 count, void *buff)
u32 sector_in_cluster = sector % BIS_CLUSTER_SECTORS;
// If not reading from cache, do a regular read and decrypt.
if (!emu_offset)
if(emu_storage){
res = sdmmc_storage_read(emu_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff);
}else if(file_based){
res = emummc_storage_file_based_read(system_part->lba_start + sector, count, bis_cache->dma_buff);
}else{
res = emmc_part_read(system_part, sector, count, bis_cache->dma_buff);
else
res = sdmmc_storage_read(&sd_storage, emu_offset + system_part->lba_start + sector, count, bis_cache->dma_buff);
}
if (!res)
return 1; // R/W error.
@@ -177,7 +190,7 @@ static int nx_emmc_bis_read_block_normal(u32 sector, u32 count, void *buff)
tweak_exp = sector_in_cluster;
// Maximum one cluster (1 XTS crypto block 16KB).
if (!se_aes_crypt_xts_sec_nx(ks_tweak, ks_crypt, DECRYPT, prev_cluster, tweak, regen_tweak, tweak_exp, buff, bis_cache->dma_buff, count * EMMC_BLOCKSIZE))
if (!se_aes_xts_crypt_sec_nx(ks_tweak, ks_crypt, DECRYPT, prev_cluster, tweak, regen_tweak, tweak_exp, buff, bis_cache->dma_buff, count * EMMC_BLOCKSIZE))
return 1; // R/W error.
prev_sector = sector + count - 1;
@@ -212,15 +225,19 @@ static int nx_emmc_bis_read_block_cached(u32 sector, u32 count, void *buff)
cache_lookup_tbl[cluster] = bis_cache->top_idx;
// Read the whole cluster the sector resides in.
if (!emu_offset)
if (emu_storage){
res = sdmmc_storage_read(emu_storage, emu_offset + system_part->lba_start + cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff);
}else if(file_based){
res = emummc_storage_file_based_read(system_part->lba_start + cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff);
}else{
res = emmc_part_read(system_part, cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff);
else
res = sdmmc_storage_read(&sd_storage, emu_offset + system_part->lba_start + cluster_sector, BIS_CLUSTER_SECTORS, bis_cache->dma_buff);
}
if (!res)
return 1; // R/W error.
// Decrypt cluster.
if (!se_aes_crypt_xts_sec_nx(ks_tweak, ks_crypt, DECRYPT, cluster, cache_tweak, true, 0, bis_cache->dma_buff, bis_cache->dma_buff, BIS_CLUSTER_SIZE))
if (!se_aes_xts_crypt_sec_nx(ks_tweak, ks_crypt, DECRYPT, cluster, cache_tweak, true, 0, bis_cache->dma_buff, bis_cache->dma_buff, BIS_CLUSTER_SIZE))
return 1; // Decryption error.
// Copy to cluster cache.
@@ -292,10 +309,11 @@ int nx_emmc_bis_write(u32 sector, u32 count, void *buff)
return 1;
}
void nx_emmc_bis_init(emmc_part_t *part, bool enable_cache, u32 emummc_offset)
void nx_emmc_bis_init(emmc_part_t *part, bool enable_cache, sdmmc_storage_t *storage, u32 emummc_offset)
{
system_part = part;
emu_offset = emummc_offset;
emu_storage = storage;
_nx_emmc_bis_cluster_cache_init(enable_cache);
@@ -318,8 +336,31 @@ void nx_emmc_bis_init(emmc_part_t *part, bool enable_cache, u32 emummc_offset)
system_part = NULL;
}
void nx_emmc_bis_init_file_based(emmc_part_t *part, bool enable_cache, const char *base_path){
emummc_storage_file_based_init(base_path);
file_based = true;
nx_emmc_bis_init(part, enable_cache, NULL, 0);
}
void nx_emmc_bis_end()
{
_nx_emmc_bis_flush_cache();
if(file_based){
emummc_storage_file_based_end();
}
system_part = NULL;
emu_storage = NULL;
emu_offset = 0;
file_based = false;
}
sdmmc_storage_t *nx_emmc_bis_get_storage(){
if(emu_storage == &emmc_storage){
return &emmc_storage;
}else{
return emmc_part_get_storage();
}
}

View File

@@ -237,7 +237,10 @@ typedef struct _nx_emmc_cal0_t
int nx_emmc_bis_read(u32 sector, u32 count, void *buff);
int nx_emmc_bis_write(u32 sector, u32 count, void *buff);
void nx_emmc_bis_init(emmc_part_t *part, bool enable_cache, u32 emummc_offset);
// when storage == NULL, use active emummc config, otherwise, access storage at offset
void nx_emmc_bis_init(emmc_part_t *part, bool enable_cache, sdmmc_storage_t *storage, u32 emummc_offset);
void nx_emmc_bis_init_file_based(emmc_part_t *part, bool enable_cache, const char *base_path);
void nx_emmc_bis_end();
sdmmc_storage_t *nx_emmc_bis_get_storage();
#endif

View File

@@ -44,7 +44,7 @@ int ram_disk_init(void *ram_fs, u32 ramdisk_size)
disk_set_info(DRIVE_RAM, SET_SECTOR_COUNT, &ramdisk_size);
// Unmount ramdisk.
f_unmount("ram:");
f_mount(NULL, "ram:", 1);
// Format as exFAT w/ 32KB cluster with no MBR.
res = f_mkfs("ram:", FM_EXFAT | FM_SFD, RAMDISK_CLUSTER_SZ, buf, 0x400000);

View File

@@ -199,7 +199,7 @@ bool sd_mount()
else
{
if (!sd_mounted)
res = f_mount(&sd_fs, "0:", 1); // Volume 0 is SD.
res = f_mount(&sd_fs, "sd:", 1); // Volume 0 is SD.
if (res == FR_OK)
{
sd_mounted = true;
@@ -227,7 +227,7 @@ static void _sd_deinit(bool deinit)
if (sd_init_done)
{
if (sd_mounted)
f_unmount("0:"); // Volume 0 is SD.
f_mount(NULL, "sd:", 1); // Volume 0 is SD.
if (deinit)
{
@@ -246,14 +246,30 @@ bool sd_is_gpt()
return sd_fs.part_type;
}
void *sd_file_read(const char *path, u32 *fsize)
{
FIL fp;
if (!sd_get_card_mounted())
return NULL;
if (f_open(&fp, path, FA_READ) != FR_OK)
char *cwd = (char*)malloc(0x200);
if(f_getcwd(cwd, 0x200) != FR_OK){
free(cwd);
return NULL;
}
if(f_chdrive("sd:") != FR_OK){
free(cwd);
return NULL;
}
if (f_open(&fp, path, FA_READ) != FR_OK){
f_chdrive(cwd);
free(cwd);
return NULL;
}
u32 size = f_size(&fp);
if (fsize)
@@ -263,13 +279,17 @@ void *sd_file_read(const char *path, u32 *fsize)
if (f_read(&fp, buf, size, NULL) != FR_OK)
{
f_chdrive(cwd);
free(buf);
free(cwd);
f_close(&fp);
return NULL;
}
f_chdrive(cwd);
f_close(&fp);
free(cwd);
return buf;
}
@@ -281,13 +301,33 @@ int sd_save_to_file(const void *buf, u32 size, const char *filename)
if (!sd_get_card_mounted())
return FR_DISK_ERR;
char *cwd = malloc(0x200);
res = f_getcwd(cwd, 0x200);
if(res != FR_OK){
free(cwd);
return res;
}
res = f_chdrive("sd:");
if(res != FR_OK){
free(cwd);
return res;
}
res = f_open(&fp, filename, FA_CREATE_ALWAYS | FA_WRITE);
if (res)
{
EPRINTFARGS("Error (%d) creating file\n%s.\n", res, filename);
f_chdrive(cwd);
free(cwd);
return res;
}
f_chdrive(cwd);
free(cwd);
f_write(&fp, buf, size, NULL);
f_close(&fp);

View File

@@ -31,8 +31,13 @@ extern u32 sd_power_cycle_time_start;
typedef enum _sdmmc_type
{
MMC_SD = 0,
MMC_EMMC = 1,
MMC_SD = 0,
MMC_EMMC = 1,
MMC_EMUMMC_FILE = 2,
MMC_EMUMMC_RAW_SD = 3,
MMC_EMUMMC_RAW_EMMC = 4,
MMC_EMUMMC_FILE_EMMC = 5,
MMC_FILE_BASED = 6,
EMMC_GPP = 0,
EMMC_BOOT0 = 1,