From e5045556bf68d9914b955f091c83e6a5cbca3ddf Mon Sep 17 00:00:00 2001 From: hexkyz Date: Sat, 6 Apr 2019 19:35:27 +0100 Subject: [PATCH] emunand: Preliminary skeleton for emunand in fusee --- fusee/fusee-primary/src/main.c | 40 ++- fusee/fusee-primary/src/stage2.h | 2 + fusee/fusee-secondary/src/emu_dev.c | 513 ++++++++++++++++++++++++++++ fusee/fusee-secondary/src/emu_dev.h | 34 ++ fusee/fusee-secondary/src/main.c | 4 +- fusee/fusee-secondary/src/nxfs.c | 213 ++++++++---- fusee/fusee-secondary/src/nxfs.h | 5 +- fusee/fusee-secondary/src/stage2.h | 2 + 8 files changed, 747 insertions(+), 66 deletions(-) create mode 100644 fusee/fusee-secondary/src/emu_dev.c create mode 100644 fusee/fusee-secondary/src/emu_dev.h diff --git a/fusee/fusee-primary/src/main.c b/fusee/fusee-primary/src/main.c index 8299c70e8..e1fa9fa10 100644 --- a/fusee/fusee-primary/src/main.c +++ b/fusee/fusee-primary/src/main.c @@ -35,7 +35,14 @@ extern void (*__program_exit_callback)(int rc); static void *g_framebuffer; static char g_bct0_buffer[BCTO_MAX_SIZE]; +typedef struct { + bool enabled; + char* path; +} emunand_config_t; + #define CONFIG_LOG_LEVEL_KEY "log_level" +#define EMUNAND_ENABLED_KEY "emunand_enabled" +#define EMUNAND_PATH_KEY "emunand_path" #define DEFAULT_BCT0_FOR_DEBUG \ "BCT0\n"\ @@ -84,6 +91,26 @@ static int config_ini_handler(void *user, const char *section, const char *name, return 1; } +static int emunand_ini_handler(void *user, const char *section, const char *name, const char *value) { + emunand_config_t *emunand_cfg = (emunand_config_t *)user; + if (strcmp(section, "emunand") == 0) { + if (strcmp(name, EMUNAND_ENABLED_KEY) == 0) { + int tmp = 0; + sscanf(value, "%d", &tmp); + emunand_cfg->enabled = (tmp != 0); + } + if (strcmp(name, EMUNAND_PATH_KEY) == 0) { + strncpy(emunand_cfg->path, value, sizeof(emunand_cfg->path) - 1); + emunand_cfg->path[sizeof(emunand_cfg->path) - 1] = '\0'; + } else { + return 0; + } + } else { + return 0; + } + return 1; +} + static void setup_env(void) { g_framebuffer = (void *)0xC0000000; @@ -132,6 +159,11 @@ int main(void) { stage2_args_t *stage2_args; uint32_t stage2_version = 0; ScreenLogLevel log_level = SCREEN_LOG_LEVEL_MANDATORY; + emunand_config_t emunand_cfg = {0}; + + /* Set default values for emunand settings. */ + emunand_cfg.enabled = false; + emunand_cfg.path = "atmosphere/emunand"; /* Override the global logging level. */ log_set_log_level(log_level); @@ -142,8 +174,9 @@ int main(void) { /* Load the BCT0 configuration ini off of the SD. */ bct0 = load_config(); - /* Extract the logging level from the BCT.ini file. */ - if (ini_parse_string(bct0, config_ini_handler, &log_level) < 0) { + /* Extract the logging level and emunand settings from the BCT.ini file. */ + if ((ini_parse_string(bct0, config_ini_handler, &log_level) < 0) || + (ini_parse_string(bct0, emunand_ini_handler, &emunand_cfg) < 0)) { fatal_error("Failed to parse BCT.ini!\n"); } @@ -161,6 +194,9 @@ int main(void) { memcpy(&stage2_args->version, &stage2_version, 4); memcpy(&stage2_args->log_level, &log_level, sizeof(log_level)); stage2_args->display_initialized = false; + stage2_args->emunand_enabled = emunand_cfg.enabled; + strncpy(stage2_args->emunand_path, emunand_cfg.path, sizeof(stage2_args->emunand_path) - 1); + stage2_args->emunand_path[sizeof(stage2_args->emunand_path) - 1] = '\0'; strcpy(stage2_args->bct0, bct0); g_chainloader_argc = 2; diff --git a/fusee/fusee-primary/src/stage2.h b/fusee/fusee-primary/src/stage2.h index e453d159f..88dbc0b01 100644 --- a/fusee/fusee-primary/src/stage2.h +++ b/fusee/fusee-primary/src/stage2.h @@ -46,6 +46,8 @@ typedef struct { uint32_t version; ScreenLogLevel log_level; bool display_initialized; + bool emunand_enabled; + char emunand_path[0x100]; char bct0[BCTO_MAX_SIZE]; } stage2_args_t; diff --git a/fusee/fusee-secondary/src/emu_dev.c b/fusee/fusee-secondary/src/emu_dev.c new file mode 100644 index 000000000..b7bbe7af9 --- /dev/null +++ b/fusee/fusee-secondary/src/emu_dev.c @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "emu_dev.h" + +static int emudev_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode); +static int emudev_close(struct _reent *r, void *fd); +static ssize_t emudev_write(struct _reent *r, void *fd, const char *ptr, size_t len); +static ssize_t emudev_read(struct _reent *r, void *fd, char *ptr, size_t len); +static off_t emudev_seek(struct _reent *r, void *fd, off_t pos, int whence); +static int emudev_fstat(struct _reent *r, void *fd, struct stat *st); +static int emudev_stat(struct _reent *r, const char *file, struct stat *st); +static int emudev_fsync(struct _reent *r, void *fd); + +typedef struct emudev_device_t { + devoptab_t devoptab; + + FILE *origin; + uint8_t *tmp_sector; + device_partition_t devpart; + char name[32+1]; + char root_path[34+1]; + bool setup, registered; +} emudev_device_t; + +typedef struct emudev_file_t { + emudev_device_t *device; + int open_flags; + uint64_t offset; +} emudev_file_t; + +static emudev_device_t g_emudev_devices[EMUDEV_MAX_DEVICES] = {0}; + +static devoptab_t g_emudev_devoptab = { + .structSize = sizeof(emudev_file_t), + .open_r = emudev_open, + .close_r = emudev_close, + .write_r = emudev_write, + .read_r = emudev_read, + .seek_r = emudev_seek, + .fstat_r = emudev_fstat, + .stat_r = emudev_stat, + .fsync_r = emudev_fsync, + .deviceData = NULL, +}; + +static emudev_device_t *emudev_find_device(const char *name) { + for (size_t i = 0; i < EMUDEV_MAX_DEVICES; i++) { + if (g_emudev_devices[i].setup && strcmp(g_emudev_devices[i].name, name) == 0) { + return &g_emudev_devices[i]; + } + } + + return NULL; +} + +int emudev_mount_device(const char *name, const char *origin_path, const device_partition_t *devpart) { + emudev_device_t *device = NULL; + + if (name[0] == '\0' || devpart == NULL) { + errno = EINVAL; + return -1; + } + + if (strlen(name) > 32) { + errno = ENAMETOOLONG; + return -1; + } + if (emudev_find_device(name) != NULL) { + errno = EEXIST; /* Device already exists */ + return -1; + } + + /* Find an unused slot. */ + for (size_t i = 0; i < EMUDEV_MAX_DEVICES; i++) { + if (!g_emudev_devices[i].setup) { + device = &g_emudev_devices[i]; + break; + } + } + if (device == NULL) { + errno = ENOMEM; + return -1; + } + + memset(device, 0, sizeof(emudev_device_t)); + device->devoptab = g_emudev_devoptab; + device->devpart = *devpart; + strcpy(device->name, name); + strcpy(device->root_path, name); + strcat(device->root_path, ":/"); + + device->devoptab.name = device->name; + device->devoptab.deviceData = device; + + /* Try to open the backing file for this emulated device. */ + FILE *origin = fopen(origin_path, "rb"); + + /* Return invalid if we can't open the file. */ + if (origin == NULL) { + errno = EINVAL; + return -1; + } + + /* Bind the backing file to this device. */ + device->origin = origin; + + /* Allocate memory for our intermediate sector. */ + device->tmp_sector = (uint8_t *)malloc(devpart->sector_size); + if (device->tmp_sector == NULL) { + errno = ENOMEM; + return -1; + } + + device->setup = true; + device->registered = false; + + return 0; +} + +int emudev_register_device(const char *name) { + emudev_device_t *device = emudev_find_device(name); + if (device == NULL) { + errno = ENOENT; + return -1; + } + + if (device->registered) { + /* Do nothing if the device is already registered. */ + return 0; + } + + if (AddDevice(&device->devoptab) == -1) { + errno = ENOMEM; + return -1; + } else { + device->registered = true; + return 0; + } +} + +int emudev_unregister_device(const char *name) { + emudev_device_t *device = emudev_find_device(name); + char drname[40]; + + if (device == NULL) { + errno = ENOENT; + return -1; + } + + if (!device->registered) { + /* Do nothing if the device is not registered. */ + return 0; + } + + strcpy(drname, name); + strcat(drname, ":"); + + if (RemoveDevice(drname) == -1) { + errno = ENOENT; + return -1; + } else { + device->registered = false; + return 0; + } +} + +int emudev_unmount_device(const char *name) { + int rc; + emudev_device_t *device = emudev_find_device(name); + + if (device == NULL) { + errno = ENOENT; + return -1; + } + + rc = emudev_unregister_device(name); + if (rc == -1) { + return -1; + } + + /* Close the backing file, if there is one. */ + if (device->origin != NULL) + fclose(device->origin); + + free(device->tmp_sector); + memset(device, 0, sizeof(emudev_device_t)); + + return 0; +} + +int emudev_unmount_all(void) { + for (size_t i = 0; i < EMUDEV_MAX_DEVICES; i++) { + int rc = emudev_unmount_device(g_emudev_devices[i].name); + if (rc != 0) { + return rc; + } + } + + return 0; +} + +static int emudev_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode) { + (void)mode; + emudev_file_t *f = (emudev_file_t *)fileStruct; + emudev_device_t *device = (emudev_device_t *)(r->deviceData); + + /* Only allow "device:/". */ + if (strcmp(path, device->root_path) != 0) { + r->_errno = ENOENT; + return -1; + } + + /* Forbid some flags that we explicitly don't support.*/ + if (flags & (O_APPEND | O_TRUNC | O_EXCL)) { + r->_errno = EINVAL; + return -1; + } + + memset(f, 0, sizeof(emudev_file_t)); + f->device = device; + f->open_flags = flags; + return 0; +} + +static int emudev_close(struct _reent *r, void *fd) { + (void)r; + emudev_file_t *f = (emudev_file_t *)fd; + memset(f, 0, sizeof(emudev_file_t)); + + return 0; +} + +static ssize_t emudev_write(struct _reent *r, void *fd, const char *ptr, size_t len) { + emudev_file_t *f = (emudev_file_t *)fd; + emudev_device_t *device = f->device; + size_t sector_size = device->devpart.sector_size; + uint64_t sector_begin = f->offset / sector_size; + uint64_t sector_end = (f->offset + len + sector_size - 1) / sector_size; + uint64_t sector_end_aligned; + uint64_t current_sector = sector_begin; + const uint8_t *data = (const uint8_t *)ptr; + + int no = 0; + + if (sector_end >= device->devpart.num_sectors) { + len = (size_t)(sector_size * device->devpart.num_sectors - f->offset); + sector_end = device->devpart.num_sectors; + } + + sector_end_aligned = sector_end - ((f->offset + len) % sector_size != 0 ? 1 : 0); + + if (len == 0) { + return 0; + } + + /* Unaligned at the start, we need to read the sector and incorporate the data. */ + if (f->offset % sector_size != 0) { + size_t nb = (size_t)(len <= (sector_size - (f->offset % sector_size)) ? len : sector_size - (f->offset % sector_size)); + + /* Read partition data using our backing file. */ + fseek(device->origin, sector_begin, SEEK_CUR); + no = (fread(device->tmp_sector, sector_size, 1, device->origin) > 0) ? 0 : EIO; + + if (no != 0) { + r->_errno = no; + return -1; + } + + memcpy(device->tmp_sector + (f->offset % sector_size), data, nb); + + /* Write partition data using our backing file. */ + fseek(device->origin, sector_begin, SEEK_CUR); + no = (fwrite(device->tmp_sector, sector_size, 1, device->origin) > 0) ? 0 : EIO; + + if (no != 0) { + r->_errno = no; + return -1; + } + + /* Advance */ + data += sector_size - (f->offset % sector_size); + current_sector++; + } + + /* Check if we're already done (otherwise this causes a bug in handling the last sector of the range). */ + if (current_sector == sector_end) { + f->offset += len; + return len; + } + + /* Write all of the sector-aligned data. */ + if (current_sector != sector_end_aligned) { + /* Write partition data using our backing file. */ + fseek(device->origin, current_sector, SEEK_CUR); + no = (fwrite(device->tmp_sector, sector_size, sector_end_aligned - current_sector, device->origin) > 0) ? 0 : EIO; + + if (no != 0) { + r->_errno = no; + return -1; + } + } + + data += sector_size * (sector_end_aligned - current_sector); + current_sector = sector_end_aligned; + + /* Unaligned at the end, we need to read the sector and incorporate the data. */ + if (sector_end != sector_end_aligned) { + /* Read partition data using our backing file. */ + fseek(device->origin, sector_end_aligned, SEEK_CUR); + no = (fread(device->tmp_sector, sector_size, 1, device->origin) > 0) ? 0 : EIO; + + if (no != 0) { + r->_errno = no; + return -1; + } + + memcpy(device->tmp_sector, data, (size_t)((f->offset + len) % sector_size)); + + /* Write partition data using our backing file. */ + fseek(device->origin, sector_end_aligned, SEEK_CUR); + no = (fwrite(device->tmp_sector, sector_size, 1, device->origin) > 0) ? 0 : EIO; + + if (no != 0) { + r->_errno = no; + return -1; + } + + /* Advance */ + data += sector_size - ((f->offset + len) % sector_size); + current_sector++; + } + + f->offset += len; + return len; +} + +static ssize_t emudev_read(struct _reent *r, void *fd, char *ptr, size_t len) { + emudev_file_t *f = (emudev_file_t *)fd; + emudev_device_t *device = f->device; + size_t sector_size = device->devpart.sector_size; + uint64_t sector_begin = f->offset / sector_size; + uint64_t sector_end = (f->offset + len + sector_size - 1) / sector_size; + uint64_t sector_end_aligned; + uint64_t current_sector = sector_begin; + uint8_t *data = (uint8_t *)ptr; + + int no = 0; + + if (sector_end >= device->devpart.num_sectors) { + len = (size_t)(sector_size * device->devpart.num_sectors - f->offset); + sector_end = device->devpart.num_sectors; + } + + sector_end_aligned = sector_end - ((f->offset + len) % sector_size != 0 ? 1 : 0); + + if (len == 0) { + return 0; + } + + /* Unaligned at the start, we need to read the sector and incorporate the data. */ + if (f->offset % sector_size != 0) { + size_t nb = (size_t)(len <= (sector_size - (f->offset % sector_size)) ? len : sector_size - (f->offset % sector_size)); + + /* Read partition data using our backing file. */ + fseek(device->origin, sector_begin, SEEK_CUR); + no = (fread(device->tmp_sector, sector_size, 1, device->origin) > 0) ? 0 : EIO; + + if (no != 0) { + r->_errno = no; + return -1; + } + + memcpy(data, device->tmp_sector + (f->offset % sector_size), nb); + + /* Advance */ + data += sector_size - (f->offset % sector_size); + current_sector++; + } + + /* Check if we're already done (otherwise this causes a bug in handling the last sector of the range). */ + if (current_sector == sector_end) { + f->offset += len; + return len; + } + + /* Read all of the sector-aligned data. */ + if (current_sector != sector_end_aligned) { + /* Read partition data using our backing file. */ + fseek(device->origin, current_sector, SEEK_CUR); + no = (fread(device->tmp_sector, sector_size, sector_end_aligned - current_sector, device->origin) > 0) ? 0 : EIO; + + if (no != 0) { + r->_errno = no; + return -1; + } + } + + data += sector_size * (sector_end_aligned - current_sector); + current_sector = sector_end_aligned; + + /* Unaligned at the end, we need to read the sector and incorporate the data. */ + if (sector_end != sector_end_aligned) { + /* Read partition data using our backing file. */ + fseek(device->origin, sector_end_aligned, SEEK_CUR); + no = (fread(device->tmp_sector, sector_size, 1, device->origin) > 0) ? 0 : EIO; + + if (no != 0) { + r->_errno = no; + return -1; + } + + memcpy(data, device->tmp_sector, (size_t)((f->offset + len) % sector_size)); + + /* Advance */ + data += sector_size - ((f->offset + len) % sector_size); + current_sector++; + } + + f->offset += len; + return len; +} + +static off_t emudev_seek(struct _reent *r, void *fd, off_t pos, int whence) { + emudev_file_t *f = (emudev_file_t *)fd; + emudev_device_t *device = f->device; + uint64_t off; + + switch (whence) { + case SEEK_SET: + off = 0; + break; + case SEEK_CUR: + off = f->offset; + break; + case SEEK_END: + off = device->devpart.num_sectors * device->devpart.sector_size; + break; + default: + r->_errno = EINVAL; + return -1; + } + + if (pos < 0 && pos + off < 0) { + /* don't allow seek to before the beginning of the file */ + r->_errno = EINVAL; + return -1; + } + + f->offset = (uint64_t)(pos + off); + return (off_t)(pos + off); +} + +static void emudev_stat_impl(emudev_device_t *device, struct stat *st) { + memset(st, 0, sizeof(struct stat)); + st->st_size = (off_t)(device->devpart.num_sectors * device->devpart.sector_size); + st->st_nlink = 1; + + st->st_blksize = device->devpart.sector_size; + st->st_blocks = st->st_size / st->st_blksize; + + st->st_mode = S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; +} + +static int emudev_fstat(struct _reent *r, void *fd, struct stat *st) { + (void)r; + emudev_file_t *f = (emudev_file_t *)fd; + emudev_device_t *device = f->device; + emudev_stat_impl(device, st); + + return 0; +} + +static int emudev_stat(struct _reent *r, const char *file, struct stat *st) { + emudev_device_t *device = (emudev_device_t *)(r->deviceData); + if (strcmp(file, device->root_path) != 0) { + r->_errno = ENOENT; + return -1; + } + + emudev_stat_impl(device, st); + return 0; +} + +static int emudev_fsync(struct _reent *r, void *fd) { + /* Nothing to do. */ + (void)r; + (void)fd; + return 0; +} diff --git a/fusee/fusee-secondary/src/emu_dev.h b/fusee/fusee-secondary/src/emu_dev.h new file mode 100644 index 000000000..a62079afd --- /dev/null +++ b/fusee/fusee-secondary/src/emu_dev.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef FUSEE_EMU_DEV_H +#define FUSEE_EMU_DEV_H + +#include +#include +#include +#include "device_partition.h" + +#define EMUDEV_MAX_DEVICES 16 + +int emudev_mount_device(const char *name, const char *origin_path, const device_partition_t *devpart); +int emudev_register_device(const char *name); + +int emudev_unregister_device(const char *name); +int emudev_unmount_device(const char *name); /* also unregisters. */ +int emudev_unmount_all(void); + +#endif diff --git a/fusee/fusee-secondary/src/main.c b/fusee/fusee-secondary/src/main.c index f0ba2c261..84779fbf0 100644 --- a/fusee/fusee-secondary/src/main.c +++ b/fusee/fusee-secondary/src/main.c @@ -51,8 +51,8 @@ static void setup_env(void) { /* Set up exception handlers. */ setup_exception_handlers(); - if (nxfs_mount_all() < 0) { - fatal_error("Failed to mount at least one parition: %s\n", strerror(errno)); + if (nxfs_mount_all(g_stage2_args->emunand_enabled, g_stage2_args->emunand_path) < 0) { + fatal_error("Failed to mount at least one partition: %s\n", strerror(errno)); } /* Train DRAM. */ diff --git a/fusee/fusee-secondary/src/nxfs.c b/fusee/fusee-secondary/src/nxfs.c index 0f11c22a3..f11984993 100644 --- a/fusee/fusee-secondary/src/nxfs.c +++ b/fusee/fusee-secondary/src/nxfs.c @@ -175,6 +175,14 @@ static const device_partition_t g_mmc_devpart_template = { .writer = mmc_partition_write, }; +static const device_partition_t g_emummc_devpart_template = { + .sector_size = 512, + .initializer = NULL, + .finalizer = NULL, + .reader = NULL, + .writer = NULL, +}; + static int nxfs_mount_partition_gpt_callback(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk) { (void)entry_offset; (void)disk; @@ -256,88 +264,173 @@ static int nxfs_mount_partition_gpt_callback(const efi_entry_t *entry, void *par return 0; } -int nxfs_mount_all(void) { +int nxfs_mount_all(bool emunand_enabled, const char *emunand_path) { device_partition_t model; int rc; FILE *rawnand; - /* Initialize the SD card and its primary partition. */ + /* Setup a template for the SD card. */ model = g_mmc_devpart_template; model.device_struct = &g_sd_mmcpart; model.start_sector = 0; model.num_sectors = 1u << 30; /* arbitrary numbers of sectors. TODO: find the size of the SD in sectors. */ + /* Mount the SD card device. */ rc = fsdev_mount_device("sdmc", &model, true); if (rc == -1) { return -1; } + /* Register the SD card device. */ rc = fsdev_register_device("sdmc"); if (rc == -1) { return -1; } - /* Boot0. */ - model = g_mmc_devpart_template; - model.device_struct = &g_emmc_boot0_mmcpart; - model.start_sector = 0; - model.num_sectors = 0x184000 / model.sector_size; + if (emunand_enabled) { + /* Setup emunand paths. */ + char emu_boot0_path[0x100]; + char emu_boot1_path[0x100]; + char emu_rawnand_path[0x100]; + snprintf(emu_boot0_path, sizeof(emu_boot0_path) - 1, "sdmc:/%s/%s", emunand_path, "boot0"); + snprintf(emu_boot1_path, sizeof(emu_boot1_path) - 1, "sdmc:/%s/%s", emunand_path, "boot1"); + snprintf(emu_rawnand_path, sizeof(emu_rawnand_path) - 1, "sdmc:/%s/%s", emunand_path, "rawnand"); - rc = rawdev_mount_device("boot0", &model, true); - - if (rc == -1) { - return -1; - } - - rc = rawdev_register_device("boot0"); - - if (rc == -1) { - return -1; - } - - /* Boot1. */ - model = g_mmc_devpart_template; - model.device_struct = &g_emmc_boot1_mmcpart; - model.start_sector = 0; - model.num_sectors = 0x80000 / model.sector_size; - - rc = rawdev_mount_device("boot1", &model, false); - - if (rc == -1) { - return -1; + /* Setup an emulation template for boot0. */ + model = g_emummc_devpart_template; + model.start_sector = 0; + model.num_sectors = 0x184000 / model.sector_size; + + /* Mount emulated boot0 device. */ + rc = emudev_mount_device("boot0", emu_boot0_path, &model); + + if (rc == -1) { + return -1; + } + + /* Register emulated boot0 device. */ + rc = emudev_register_device("boot0"); + + if (rc == -1) { + return -1; + } + + /* Setup an emulation template for boot1. */ + model = g_emummc_devpart_template; + model.start_sector = 0; + model.num_sectors = 0x80000 / model.sector_size; + + /* Mount emulated boot1 device. */ + rc = emudev_mount_device("boot1", emu_boot1_path, &model); + + if (rc == -1) { + return -1; + } + + /* Don't register emulated boot1 for now. */ + + /* Setup a template for raw NAND. */ + model = g_emummc_devpart_template; + model.start_sector = 0; + model.num_sectors = (256ull << 30) / model.sector_size; + + /* Mount emulated raw NAND device. */ + rc = emudev_mount_device("rawnand", emu_rawnand_path, &model); + + if (rc == -1) { + return -1; + } + + /* Register emulated raw NAND device. */ + rc = emudev_register_device("rawnand"); + if (rc == -1) { + return -1; + } + + /* Open emulated raw NAND device. */ + rawnand = fopen("rawnand:/", "rb"); + + if (rawnand == NULL) { + return -1; + } + + /* Iterate the GPT and mount each emulated raw NAND partition. */ + rc = gpt_iterate_through_entries(rawnand, model.sector_size, nxfs_mount_partition_gpt_callback, &model); + + /* Close emulated raw NAND device. */ + fclose(rawnand); + } else { + /* Setup a template for boot0. */ + model = g_mmc_devpart_template; + model.device_struct = &g_emmc_boot0_mmcpart; + model.start_sector = 0; + model.num_sectors = 0x184000 / model.sector_size; + + /* Mount boot0 device. */ + rc = rawdev_mount_device("boot0", &model, true); + + if (rc == -1) { + return -1; + } + + /* Register boot0 device. */ + rc = rawdev_register_device("boot0"); + + if (rc == -1) { + return -1; + } + + /* Setup a template for boot1. */ + model = g_mmc_devpart_template; + model.device_struct = &g_emmc_boot1_mmcpart; + model.start_sector = 0; + model.num_sectors = 0x80000 / model.sector_size; + + /* Mount boot1 device. */ + rc = rawdev_mount_device("boot1", &model, false); + + if (rc == -1) { + return -1; + } + + /* Don't register boot1 for now. */ + + /* Setup a template for raw NAND. */ + model = g_mmc_devpart_template; + model.device_struct = &g_emmc_user_mmcpart; + model.start_sector = 0; + model.num_sectors = (256ull << 30) / model.sector_size; + + /* Mount raw NAND device. */ + rc = rawdev_mount_device("rawnand", &model, false); + + if (rc == -1) { + return -1; + } + + /* Register raw NAND device. */ + rc = rawdev_register_device("rawnand"); + if (rc == -1) { + return -1; + } + + /* Open raw NAND device. */ + rawnand = fopen("rawnand:/", "rb"); + + if (rawnand == NULL) { + return -1; + } + + /* Iterate the GPT and mount each raw NAND partition. */ + rc = gpt_iterate_through_entries(rawnand, model.sector_size, nxfs_mount_partition_gpt_callback, &model); + + /* Close raw NAND device. */ + fclose(rawnand); } - /* Don't register boot1 for now. */ - - /* Raw NAND (excluding boot partitions), and its partitions. */ - model = g_mmc_devpart_template; - model = g_mmc_devpart_template; - model.device_struct = &g_emmc_user_mmcpart; - model.start_sector = 0; - model.num_sectors = (256ull << 30) / model.sector_size; - - rc = rawdev_mount_device("rawnand", &model, false); - - if (rc == -1) { - return -1; - } - - rc = rawdev_register_device("rawnand"); - if (rc == -1) { - return -1; - } - - rawnand = fopen("rawnand:/", "rb"); - - if (rawnand == NULL) { - return -1; - } - - rc = gpt_iterate_through_entries(rawnand, model.sector_size, nxfs_mount_partition_gpt_callback, &model); - fclose(rawnand); - + /* Set the default file system device. */ if (rc == 0) { rc = fsdev_set_default_device("sdmc"); } @@ -345,6 +438,6 @@ int nxfs_mount_all(void) { return rc; } -int nxfs_unmount_all(void) { - return ((fsdev_unmount_all() || rawdev_unmount_all()) ? -1 : 0); +int nxfs_unmount_all() { + return ((fsdev_unmount_all() || rawdev_unmount_all() || emudev_unmount_all()) ? -1 : 0); } diff --git a/fusee/fusee-secondary/src/nxfs.h b/fusee/fusee-secondary/src/nxfs.h index 20f9f9721..6578b2b80 100644 --- a/fusee/fusee-secondary/src/nxfs.h +++ b/fusee/fusee-secondary/src/nxfs.h @@ -19,8 +19,9 @@ #include "fs_dev.h" #include "raw_dev.h" +#include "emu_dev.h" -int nxfs_mount_all(void); -int nxfs_unmount_all(void); +int nxfs_mount_all(bool emunand_enabled, const char *emunand_path); +int nxfs_unmount_all(); #endif diff --git a/fusee/fusee-secondary/src/stage2.h b/fusee/fusee-secondary/src/stage2.h index 1274efeee..ffb583e01 100644 --- a/fusee/fusee-secondary/src/stage2.h +++ b/fusee/fusee-secondary/src/stage2.h @@ -32,6 +32,8 @@ typedef struct { uint32_t version; ScreenLogLevel log_level; bool display_initialized; + bool emunand_enabled; + char emunand_path[0x100]; char bct0[BCTO_MAX_SIZE]; } stage2_args_t;