From 98ca5e29275d2f7766ec38b2500263d94086e3ce Mon Sep 17 00:00:00 2001 From: hexkyz Date: Sat, 1 Aug 2020 17:20:56 +0100 Subject: [PATCH] fusee: re-design and fix emummc handling --- fusee/fusee-secondary/src/device_partition.c | 164 +++---- fusee/fusee-secondary/src/device_partition.h | 9 +- fusee/fusee-secondary/src/emu_dev.c | 489 ------------------- fusee/fusee-secondary/src/emu_dev.h | 34 -- fusee/fusee-secondary/src/fs_dev.c | 1 - fusee/fusee-secondary/src/gpt.c | 39 -- fusee/fusee-secondary/src/gpt.h | 1 - fusee/fusee-secondary/src/nxboot.c | 2 +- fusee/fusee-secondary/src/nxfs.c | 218 +++------ fusee/fusee-secondary/src/nxfs.h | 1 - fusee/fusee-secondary/src/raw_dev.c | 16 +- fusee/fusee-secondary/src/raw_dev.h | 3 + 12 files changed, 147 insertions(+), 830 deletions(-) delete mode 100644 fusee/fusee-secondary/src/emu_dev.c delete mode 100644 fusee/fusee-secondary/src/emu_dev.h diff --git a/fusee/fusee-secondary/src/device_partition.c b/fusee/fusee-secondary/src/device_partition.c index 0a7330aca..0cbbc8e35 100644 --- a/fusee/fusee-secondary/src/device_partition.c +++ b/fusee/fusee-secondary/src/device_partition.c @@ -18,67 +18,9 @@ #include #include "device_partition.h" -int device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors) -{ - int rc; - if (!devpart->initialized) { - rc = devpart->initializer(devpart); - if (rc != 0) { - return rc; - } - } - if ((devpart->read_cipher != NULL) && (devpart->crypto_mode != DevicePartitionCryptoMode_None)) { - for (uint64_t i = 0; i < num_sectors; i += devpart->crypto_work_buffer_num_sectors) { - uint64_t n = (i + devpart->crypto_work_buffer_num_sectors > num_sectors) ? (num_sectors - i) : devpart->crypto_work_buffer_num_sectors; - rc = devpart->reader(devpart, devpart->crypto_work_buffer, sector + i, n); - if (rc != 0) { - return rc; - } - rc = devpart->read_cipher(devpart, sector + i, n); - if (rc != 0) { - return rc; - } - memcpy(dst + (size_t)(devpart->sector_size * i), devpart->crypto_work_buffer, (size_t)(devpart->sector_size * n)); - } - return 0; - } else { - return devpart->reader(devpart, dst, sector, num_sectors); - } -} - -int device_partition_write_data(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors) -{ - int rc; - if (!devpart->initialized) { - rc = devpart->initializer(devpart); - if (rc != 0) { - return rc; - } - } - if ((devpart->write_cipher != NULL) && (devpart->crypto_mode != DevicePartitionCryptoMode_None)) { - for (uint64_t i = 0; i < num_sectors; i += devpart->crypto_work_buffer_num_sectors) { - uint64_t n = (i + devpart->crypto_work_buffer_num_sectors > num_sectors) ? (num_sectors - i) : devpart->crypto_work_buffer_num_sectors; - memcpy(devpart->crypto_work_buffer, src + (size_t)(devpart->sector_size * i), (size_t)(devpart->sector_size * n)); - rc = devpart->write_cipher(devpart, sector + i, n); - if (rc != 0) { - return rc; - } - rc = devpart->writer(devpart, devpart->crypto_work_buffer, sector + i, n); - if (rc != 0) { - return rc; - } - } - return 0; - } else { - return devpart->writer(devpart, src, sector, num_sectors); - } -} - -int emu_device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors, const char *origin_path, int num_parts, uint64_t part_limit) -{ +int device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors) { int rc = 0; uint64_t target_sector = sector; - char target_path[0x300 + 1] = {0}; /* Perform initialization steps, if necessary. */ if (!devpart->initialized) { @@ -88,33 +30,37 @@ int emu_device_partition_read_data(device_partition_t *devpart, void *dst, uint6 } } - /* Prepare the right file path if using file mode. */ - if (devpart->emu_use_file && (origin_path != NULL)) { - /* Handle data in multiple parts, if necessary. */ - if (num_parts > 0) { - int target_part = 0; - uint64_t data_offset = sector * devpart->sector_size; + /* Handle emulation. */ + if (devpart->is_emulated) { + /* Prepare the right file path if using file mode. */ + if (devpart->emu_use_file) { + int num_parts = devpart->emu_num_parts; + uint64_t part_limit = devpart->emu_part_limit; - if (data_offset >= part_limit) { - uint64_t data_offset_aligned = (data_offset + (part_limit - 1)) & ~(part_limit - 1); - target_part = (data_offset_aligned == data_offset) ? (data_offset / part_limit) : (data_offset_aligned / part_limit) - 1; - target_sector = (data_offset - (target_part * part_limit)) / devpart->sector_size; - - /* Target part is invalid. */ - if (target_part > num_parts) { - return -1; + /* Handle data in multiple parts, if necessary. */ + if (num_parts > 0) { + int target_part = 0; + char target_path[0x300 + 1] = {0}; + uint64_t data_offset = sector * devpart->sector_size; + + if (data_offset >= part_limit) { + uint64_t data_offset_aligned = (data_offset + (part_limit - 1)) & ~(part_limit - 1); + target_part = (data_offset_aligned == data_offset) ? (data_offset / part_limit) : (data_offset_aligned / part_limit) - 1; + target_sector = (data_offset - (target_part * part_limit)) / devpart->sector_size; + + /* Target part is invalid. */ + if (target_part > num_parts) { + return -1; + } } + + /* Treat the path as a folder with each part inside. */ + snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", devpart->emu_root_path, target_part); + + /* Update the target file path. */ + strcpy(devpart->emu_file_path, target_path); } - - /* Treat the path as a folder with each part inside. */ - snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", origin_path, target_part); - } else { - /* If there are no parts, copy the origin path directly. */ - strcpy(target_path, origin_path); } - - /* Update the target file path. */ - devpart->emu_file_path = target_path; } /* Read the partition data. */ @@ -147,11 +93,9 @@ int emu_device_partition_read_data(device_partition_t *devpart, void *dst, uint6 return rc; } -int emu_device_partition_write_data(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors, const char *origin_path, int num_parts, uint64_t part_limit) -{ +int device_partition_write_data(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors) { int rc = 0; uint64_t target_sector = sector; - char target_path[0x300 + 1] = {0}; /* Perform initialization steps, if necessary. */ if (!devpart->initialized) { @@ -161,33 +105,37 @@ int emu_device_partition_write_data(device_partition_t *devpart, const void *src } } - /* Prepare the right file path if using file mode. */ - if (devpart->emu_use_file && (origin_path != NULL)) { - /* Handle data in multiple parts, if necessary. */ - if (num_parts > 0) { - int target_part = 0; - uint64_t data_offset = sector * devpart->sector_size; + /* Handle emulation. */ + if (devpart->is_emulated) { + /* Prepare the right file path if using file mode. */ + if (devpart->emu_use_file) { + int num_parts = devpart->emu_num_parts; + uint64_t part_limit = devpart->emu_part_limit; - if (data_offset >= part_limit) { - uint64_t data_offset_aligned = (data_offset + (part_limit - 1)) & ~(part_limit - 1); - target_part = (data_offset_aligned == data_offset) ? (data_offset / part_limit) : (data_offset_aligned / part_limit) - 1; - target_sector = (data_offset - (target_part * part_limit)) / devpart->sector_size; - - /* Target part is invalid. */ - if (target_part > num_parts) { - return -1; + /* Handle data in multiple parts, if necessary. */ + if (num_parts > 0) { + int target_part = 0; + char target_path[0x300 + 1] = {0}; + uint64_t data_offset = sector * devpart->sector_size; + + if (data_offset >= part_limit) { + uint64_t data_offset_aligned = (data_offset + (part_limit - 1)) & ~(part_limit - 1); + target_part = (data_offset_aligned == data_offset) ? (data_offset / part_limit) : (data_offset_aligned / part_limit) - 1; + target_sector = (data_offset - (target_part * part_limit)) / devpart->sector_size; + + /* Target part is invalid. */ + if (target_part > num_parts) { + return -1; + } } + + /* Treat the path as a folder with each part inside. */ + snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", devpart->emu_root_path, target_part); + + /* Update the target file path. */ + strcpy(devpart->emu_file_path, target_path); } - - /* Treat the path as a folder with each part inside. */ - snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", origin_path, target_part); - } else { - /* If there are no parts, copy the origin path directly. */ - strcpy(target_path, origin_path); } - - /* Update the target file path. */ - devpart->emu_file_path = target_path; } /* Write the partition data. */ diff --git a/fusee/fusee-secondary/src/device_partition.h b/fusee/fusee-secondary/src/device_partition.h index 41f034803..a4a5df86e 100644 --- a/fusee/fusee-secondary/src/device_partition.h +++ b/fusee/fusee-secondary/src/device_partition.h @@ -67,13 +67,16 @@ typedef struct device_partition_t { uint8_t __attribute__((aligned(16))) iv[DEVPART_IV_MAX_SIZE]; /* IV. */ bool initialized; - char *emu_file_path; /* Emulated device file path. */ + /* Emulation only. */ + bool is_emulated; bool emu_use_file; + char emu_root_path[0x100 + 1]; + char emu_file_path[0x300 + 1]; + int emu_num_parts; + uint64_t emu_part_limit; } device_partition_t; int device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors); int device_partition_write_data(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors); -int emu_device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors, const char *origin_path, int num_parts, uint64_t part_limit); -int emu_device_partition_write_data(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors, const char *origin_path, int num_parts, uint64_t part_limit); #endif diff --git a/fusee/fusee-secondary/src/emu_dev.c b/fusee/fusee-secondary/src/emu_dev.c deleted file mode 100644 index 55949ef7c..000000000 --- a/fusee/fusee-secondary/src/emu_dev.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Copyright (c) 2018-2020 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" -#include "utils.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; - - char origin_path[0x300+1]; - int num_parts; - uint64_t part_limit; - 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 device_partition_t *devpart, const char *origin_path, int num_parts, uint64_t part_limit) { - 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, ":/"); - - /* Copy the file path for file mode. */ - if (devpart->emu_use_file) - strcpy(device->origin_path, origin_path); - - device->num_parts = num_parts; - device->part_limit = part_limit; - - device->devoptab.name = device->name; - device->devoptab.deviceData = device; - - /* Initialize immediately. */ - int rc = device->devpart.initializer(&device->devpart); - if (rc != 0) { - errno = rc; - return -1; - } - - /* 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; - } - - free(device->tmp_sector); - device->devpart.finalizer(&device->devpart); - 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)); - no = emu_device_partition_read_data(&device->devpart, device->tmp_sector, sector_begin, 1, device->origin_path, device->num_parts, device->part_limit); - if (no != 0) { - r->_errno = no; - return -1; - } - - memcpy(device->tmp_sector + (f->offset % sector_size), data, nb); - - no = emu_device_partition_write_data(&device->devpart, device->tmp_sector, sector_begin, 1, device->origin_path, device->num_parts, device->part_limit); - 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) { - no = emu_device_partition_write_data(&device->devpart, data, current_sector, sector_end_aligned - current_sector, device->origin_path, device->num_parts, device->part_limit); - 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) { - no = emu_device_partition_read_data(&device->devpart, device->tmp_sector, sector_end_aligned, 1, device->origin_path, device->num_parts, device->part_limit); - if (no != 0) { - r->_errno = no; - return -1; - } - - memcpy(device->tmp_sector, data, (size_t)((f->offset + len) % sector_size)); - - no = emu_device_partition_write_data(&device->devpart, device->tmp_sector, sector_end_aligned, 1, device->origin_path, device->num_parts, device->part_limit); - 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)); - no = emu_device_partition_read_data(&device->devpart, device->tmp_sector, sector_begin, 1, device->origin_path, device->num_parts, device->part_limit); - 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) { - no = emu_device_partition_read_data(&device->devpart, data, current_sector, sector_end_aligned - current_sector, device->origin_path, device->num_parts, device->part_limit); - 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) { - no = emu_device_partition_read_data(&device->devpart, device->tmp_sector, sector_end_aligned, 1, device->origin_path, device->num_parts, device->part_limit); - 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 deleted file mode 100644 index 435903eaa..000000000 --- a/fusee/fusee-secondary/src/emu_dev.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2018-2020 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 device_partition_t *devpart, const char *origin_path, int num_parts, uint64_t part_limit); -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/fs_dev.c b/fusee/fusee-secondary/src/fs_dev.c index 28b640438..93f8b4161 100644 --- a/fusee/fusee-secondary/src/fs_dev.c +++ b/fusee/fusee-secondary/src/fs_dev.c @@ -302,7 +302,6 @@ int fsdev_register_keys(const char *name, unsigned int target_firmware, BisParti return 0; } - int fsdev_unmount_all(void) { for (size_t i = 0; i < FF_VOLUMES; i++) { int ret = fsdev_unmount_device(g_fsdev_devices[i].name); diff --git a/fusee/fusee-secondary/src/gpt.c b/fusee/fusee-secondary/src/gpt.c index eecc5ea59..5f4183b12 100644 --- a/fusee/fusee-secondary/src/gpt.c +++ b/fusee/fusee-secondary/src/gpt.c @@ -112,42 +112,3 @@ int gpt_iterate_through_entries(FILE *disk, size_t sector_size, gpt_entry_iterat return 0; } - -int gpt_iterate_through_emu_entries(FILE *disk, size_t sector_size, gpt_emu_entry_iterator_t callback, void *param, const char *origin_path, int num_parts, uint64_t part_limit) { - efi_header_t hdr; - efi_entry_t entry; - size_t offset = 2 * 512; /* Sector #2. */ - size_t delta; - - /* Get the header. */ - if (gpt_get_header(&hdr, disk, sector_size) == -1) { - return -1; - } - - /* Seek to the entry table. */ - if (fseek(disk, sector_size * hdr.entries_first_lba - offset, SEEK_CUR) != 0) { - return -1; - } - - offset = sector_size * hdr.entries_first_lba; - delta = hdr.entry_size - sizeof(efi_entry_t); - - /* Iterate through the entries. */ - for (uint32_t i = 0; i < hdr.entry_count; i++) { - if (!fread(&entry, sizeof(efi_entry_t), 1, disk)) { - return -1; - } - - if (callback(&entry, param, offset, disk, origin_path, num_parts, part_limit) != 0) { - return -1; - } - - if (delta != 0 && fseek(disk, delta, SEEK_CUR) != 0) { - return -1; - } - - offset += hdr.entry_size; - } - - return 0; -} diff --git a/fusee/fusee-secondary/src/gpt.h b/fusee/fusee-secondary/src/gpt.h index 349aaa197..491dae4f6 100644 --- a/fusee/fusee-secondary/src/gpt.h +++ b/fusee/fusee-secondary/src/gpt.h @@ -56,6 +56,5 @@ typedef int (*gpt_emu_entry_iterator_t)(const efi_entry_t *entry, void *param, s int gpt_get_header(efi_header_t *out, FILE *disk, size_t sector_size); int gpt_iterate_through_entries(FILE *disk, size_t sector_size, gpt_entry_iterator_t callback, void *param); -int gpt_iterate_through_emu_entries(FILE *disk, size_t sector_size, gpt_emu_entry_iterator_t callback, void *param, const char *origin_path, int num_parts, uint64_t part_limit); #endif diff --git a/fusee/fusee-secondary/src/nxboot.c b/fusee/fusee-secondary/src/nxboot.c index ceb8bd834..8a3e4efa6 100644 --- a/fusee/fusee-secondary/src/nxboot.c +++ b/fusee/fusee-secondary/src/nxboot.c @@ -649,7 +649,7 @@ uint32_t nxboot_main(void) { } else { emummc_size = get_file_size("atmosphere/emummc.kip"); if (emummc_size != 0) { - /* Allocate memory for the TSEC firmware. */ + /* Allocate memory for the emummc KIP. */ emummc = memalign(0x100, emummc_size); if (emummc == NULL) { diff --git a/fusee/fusee-secondary/src/nxfs.c b/fusee/fusee-secondary/src/nxfs.c index 8758085a4..d63a1372e 100644 --- a/fusee/fusee-secondary/src/nxfs.c +++ b/fusee/fusee-secondary/src/nxfs.c @@ -36,7 +36,6 @@ static bool g_emmc_device_initialized = false; static bool g_fsdev_ready = false; static bool g_rawdev_ready = false; -static bool g_emudev_ready = false; static bool g_is_emummc = false; @@ -356,87 +355,6 @@ static int nxfs_mount_partition_gpt_callback(const efi_entry_t *entry, void *par return 0; } -static int nxfs_mount_emu_partition_gpt_callback(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk, const char *origin_path, int num_parts, uint64_t part_limit) { - (void)entry_offset; - (void)disk; - device_partition_t *parent = (device_partition_t *)param; - device_partition_t devpart = *parent; - char name_buffer[128]; - const uint16_t *utf16name = entry->name; - uint32_t name_len; - int rc; - - static const struct { - const char *partition_name; - const char *mount_point; - bool is_fat; - bool is_encrypted; - bool register_immediately; - } known_partitions[] = { - {"PRODINFO", "prodinfo", false, true, false}, - {"PRODINFOF", "prodinfof", true, true, false}, - {"BCPKG2-1-Normal-Main", "bcpkg21", false, false, true}, - {"BCPKG2-2-Normal-Sub", "bcpkg22", false, false, false}, - {"BCPKG2-3-SafeMode-Main", "bcpkg23", false, false, false}, - {"BCPKG2-4-SafeMode-Sub", "bcpkg24", false, false, false}, - {"BCPKG2-5-Repair-Main", "bcpkg25", false, false, false}, - {"BCPKG2-6-Repair-Sub", "bcpkg26", false, false, false}, - {"SAFE", "safe", true, true, false}, - {"SYSTEM", "system", true, true, true}, - {"USER", "user", true, true, false}, - }; - - /* Convert the partition name to ASCII, for comparison. */ - for (name_len = 0; name_len < sizeof(entry->name) && *utf16name != 0; name_len++) { - name_buffer[name_len] = (char)*utf16name++; - } - name_buffer[name_len] = '\0'; - - /* Mount the partition, if we know about it. */ - for (size_t i = 0; i < sizeof(known_partitions)/sizeof(known_partitions[0]); i++) { - if (strcmp(name_buffer, known_partitions[i].partition_name) == 0) { - devpart.start_sector += entry->first_lba; - devpart.num_sectors = (entry->last_lba + 1) - entry->first_lba; - if (parent->num_sectors < devpart.num_sectors) { - errno = EINVAL; - return -1; - } - - if (known_partitions[i].is_encrypted) { - devpart.read_cipher = nxfs_bis_crypto_decrypt; - devpart.write_cipher = nxfs_bis_crypto_encrypt; - devpart.crypto_mode = DevicePartitionCryptoMode_Xts; - } - - if (known_partitions[i].is_fat) { - rc = fsdev_mount_device(known_partitions[i].mount_point, &devpart, false); - if (rc == -1) { - return -1; - } - if (known_partitions[i].register_immediately) { - rc = fsdev_register_device(known_partitions[i].mount_point); - if (rc == -1) { - return -1; - } - } - } else { - rc = emudev_mount_device(known_partitions[i].mount_point, &devpart, origin_path, num_parts, part_limit); - if (rc == -1) { - return -1; - } - if (known_partitions[i].register_immediately) { - rc = emudev_register_device(known_partitions[i].mount_point); - if (rc == -1) { - return -1; - } - } - } - } - } - - return 0; -} - int nxfs_mount_sd() { device_partition_t model; int rc; @@ -446,6 +364,7 @@ int nxfs_mount_sd() { 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. */ + model.is_emulated = false; /* Mount the SD card device. */ rc = fsdev_mount_device("sdmc", &model, true); @@ -479,6 +398,7 @@ int nxfs_mount_emmc() { model.device_struct = &g_emmc_boot0_mmcpart; model.start_sector = 0; model.num_sectors = 0x184000 / model.sector_size; + model.is_emulated = false; /* Mount boot0 device. */ rc = rawdev_mount_device("boot0", &model, true); @@ -499,6 +419,7 @@ int nxfs_mount_emmc() { model.device_struct = &g_emmc_boot1_mmcpart; model.start_sector = 0; model.num_sectors = 0x80000 / model.sector_size; + model.is_emulated = false; /* Mount boot1 device. */ rc = rawdev_mount_device("boot1", &model, false); @@ -514,6 +435,7 @@ int nxfs_mount_emmc() { model.device_struct = &g_emmc_user_mmcpart; model.start_sector = 0; model.num_sectors = (256ull << 30) / model.sector_size; + model.is_emulated = false; /* Mount raw NAND device. */ rc = rawdev_mount_device("rawnand", &model, false); @@ -558,10 +480,11 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) { model = g_emummc_devpart_template; model.start_sector = emummc_start_sector + (0x400000 * 0 / model.sector_size); model.num_sectors = 0x400000 / model.sector_size; + model.is_emulated = true; model.emu_use_file = false; /* Mount emulated boot0 device. */ - rc = emudev_mount_device("boot0", &model, NULL, 0, 0); + rc = rawdev_mount_device("boot0", &model, true); /* Failed to mount boot0 device. */ if (rc == -1) { @@ -569,7 +492,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) { } /* Register emulated boot0 device. */ - rc = emudev_register_device("boot0"); + rc = rawdev_register_device("boot0"); /* Failed to register boot0 device. */ if (rc == -1) { @@ -580,10 +503,11 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) { model = g_emummc_devpart_template; model.start_sector = emummc_start_sector + (0x400000 * 1 / model.sector_size); model.num_sectors = 0x400000 / model.sector_size; + model.is_emulated = true; model.emu_use_file = false; /* Mount emulated boot1 device. */ - rc = emudev_mount_device("boot1", &model, NULL, 0, 0); + rc = rawdev_mount_device("boot1", &model, false); /* Failed to mount boot1. */ if (rc == -1) { @@ -596,10 +520,11 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) { model = g_emummc_devpart_template; model.start_sector = emummc_start_sector + (0x400000 * 2 / model.sector_size); model.num_sectors = (256ull << 30) / model.sector_size; + model.is_emulated = true; model.emu_use_file = false; /* Mount emulated raw NAND device. */ - rc = emudev_mount_device("rawnand", &model, NULL, 0, 0); + rc = rawdev_mount_device("rawnand", &model, false); /* Failed to mount raw NAND. */ if (rc == -1) { @@ -607,7 +532,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) { } /* Register emulated raw NAND device. */ - rc = emudev_register_device("rawnand"); + rc = rawdev_register_device("rawnand"); /* Failed to register raw NAND device. */ if (rc == -1) { @@ -623,14 +548,14 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) { } /* Iterate the GPT and mount each emulated raw NAND partition. */ - rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, NULL, 0, 0); + rc = gpt_iterate_through_entries(rawnand, model.sector_size, nxfs_mount_partition_gpt_callback, &model); /* Close emulated raw NAND device. */ fclose(rawnand); /* All emulated devices are ready. */ if (rc == 0) { - g_emudev_ready = true; + g_rawdev_ready = true; g_is_emummc = true; } @@ -641,10 +566,9 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part device_partition_t model; int rc; FILE *rawnand; - bool is_exfat; char emummc_boot0_path[0x300 + 1] = {0}; char emummc_boot1_path[0x300 + 1] = {0}; - + /* Check if the SD card is EXFAT formatted. */ rc = fsdev_is_exfat("sdmc"); @@ -652,29 +576,20 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part if (rc == -1) { return -1; } - - /* Set EXFAT status. */ - is_exfat = (rc == 1); - - /* Reject single part in FAT32. */ - /* NOTE: This check has no effect in the current design. */ - if (!is_exfat && (num_parts < 1)) { - return -2; - } - + /* We want a folder with the archive bit set. */ rc = fsdev_get_attr(emummc_path); /* Failed to get file DOS attributes. */ if (rc == -1) { - return -3; + return -2; } - + /* Our path is not a directory. */ if (!(rc & AM_DIR)) { - return -4; + return -3; } - + /* Check if the archive bit is not set. */ if (!(rc & AM_ARC)) { /* Try to set the archive bit. */ @@ -682,102 +597,117 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part /* Failed to set file DOS attributes. */ if (rc == -1) { - return -5; + return -4; } } - + + /* Prepare boot0 file path. */ + snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "%s/%s", emummc_path, "boot0"); + /* Setup an emulation template for boot0. */ model = g_emummc_devpart_template; model.start_sector = 0; model.num_sectors = 0x400000 / model.sector_size; + model.is_emulated = true; model.emu_use_file = true; - - /* Prepare boot0 file path. */ - snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "%s/%s", emummc_path, "boot0"); + model.emu_num_parts = 0; + model.emu_part_limit = 0; + strcpy(model.emu_root_path, emummc_path); + strcpy(model.emu_file_path, emummc_boot0_path); /* Mount emulated boot0 device. */ - rc = emudev_mount_device("boot0", &model, emummc_boot0_path, 0, 0); + rc = rawdev_mount_device("boot0", &model, true); /* Failed to mount boot0 device. */ if (rc == -1) { - return -6; + return -5; } - + /* Register emulated boot0 device. */ - rc = emudev_register_device("boot0"); + rc = rawdev_register_device("boot0"); /* Failed to register boot0 device. */ if (rc == -1) { - return -7; + return -6; } - + + /* Prepare boot1 file path. */ + snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "%s/%s", emummc_path, "boot1"); + /* Setup an emulation template for boot1. */ model = g_emummc_devpart_template; model.start_sector = 0; model.num_sectors = 0x400000 / model.sector_size; + model.is_emulated = true; model.emu_use_file = true; - - /* Prepare boot1 file path. */ - snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "%s/%s", emummc_path, "boot1"); - + model.emu_num_parts = 0; + model.emu_part_limit = 0; + strcpy(model.emu_root_path, emummc_path); + strcpy(model.emu_file_path, emummc_boot1_path); + /* Mount emulated boot1 device. */ - rc = emudev_mount_device("boot1", &model, emummc_boot1_path, 0, 0); + rc = rawdev_mount_device("boot1", &model, false); /* Failed to mount boot1. */ if (rc == -1) { - return -8; + return -7; } - + /* Register emulated boot1 device. */ - rc = emudev_register_device("boot1"); + rc = rawdev_register_device("boot1"); /* Failed to register boot1 device. */ if (rc == -1) { - return -9; + return -8; } - + /* Setup a template for raw NAND. */ model = g_emummc_devpart_template; model.start_sector = 0; model.num_sectors = (256ull << 30) / model.sector_size; + model.is_emulated = true; model.emu_use_file = true; + model.emu_num_parts = num_parts; + model.emu_part_limit = part_limit; + strcpy(model.emu_root_path, emummc_path); + strcpy(model.emu_file_path, emummc_path); /* Mount emulated raw NAND device from single or multiple parts. */ - rc = emudev_mount_device("rawnand", &model, emummc_path, num_parts, part_limit); + rc = rawdev_mount_device("rawnand", &model, false); /* Failed to mount raw NAND. */ if (rc == -1) { - return -10; + return -9; } - + /* Register emulated raw NAND device. */ - rc = emudev_register_device("rawnand"); + rc = rawdev_register_device("rawnand"); /* Failed to register raw NAND device. */ if (rc == -1) { - return -11; + return -10; } - + /* Open emulated raw NAND device. */ rawnand = fopen("rawnand:/", "rb"); /* Failed to open emulated raw NAND device. */ if (rawnand == NULL) { - return -12; + return -11; } - + /* Iterate the GPT and mount each emulated raw NAND partition. */ - rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, emummc_path, num_parts, part_limit); + rc = gpt_iterate_through_entries(rawnand, model.sector_size, nxfs_mount_partition_gpt_callback, &model); /* Close emulated raw NAND device. */ fclose(rawnand); /* All emulated devices are ready. */ if (rc == 0) { - g_emudev_ready = true; + g_rawdev_ready = true; g_is_emummc = true; } - + return rc; } @@ -805,18 +735,6 @@ int nxfs_unmount_emmc() { return rc; } -int nxfs_unmount_emummc() { - int rc = 0; - - /* Unmount all emulated devices. */ - if (g_emudev_ready) { - rc = emudev_unmount_all(); - g_emudev_ready = false; - } - - return rc; -} - int nxfs_init() { int rc; @@ -832,5 +750,5 @@ int nxfs_init() { } int nxfs_end() { - return ((nxfs_unmount_sd() || nxfs_unmount_emmc() || nxfs_unmount_emummc()) ? -1 : 0); + return ((nxfs_unmount_sd() || nxfs_unmount_emmc()) ? -1 : 0); } diff --git a/fusee/fusee-secondary/src/nxfs.h b/fusee/fusee-secondary/src/nxfs.h index e1a8c225a..685147f72 100644 --- a/fusee/fusee-secondary/src/nxfs.h +++ b/fusee/fusee-secondary/src/nxfs.h @@ -19,7 +19,6 @@ #include "fs_dev.h" #include "raw_dev.h" -#include "emu_dev.h" int nxfs_init(); int nxfs_end(); diff --git a/fusee/fusee-secondary/src/raw_dev.c b/fusee/fusee-secondary/src/raw_dev.c index 270e96eb1..e20c272dd 100644 --- a/fusee/fusee-secondary/src/raw_dev.c +++ b/fusee/fusee-secondary/src/raw_dev.c @@ -77,9 +77,6 @@ static rawdev_device_t *rawdev_find_device(const char *name) { int rawdev_mount_device(const char *name, const device_partition_t *devpart, bool initialize_immediately) { rawdev_device_t *device = NULL; - char drname[40]; - strcpy(drname, name); - strcat(drname, ":"); if (name[0] == '\0' || devpart == NULL) { errno = EINVAL; @@ -205,6 +202,19 @@ int rawdev_unmount_device(const char *name) { return 0; } +int rawdev_register_keys(const char *name, unsigned int target_firmware, BisPartition part) { + rawdev_device_t *device = rawdev_find_device(name); + + if (device == NULL) { + errno = ENOENT; + return -1; + } + + derive_bis_key(device->devpart.keys, part, target_firmware); + + return 0; +} + int rawdev_unmount_all(void) { for (size_t i = 0; i < RAWDEV_MAX_DEVICES; i++) { int rc = rawdev_unmount_device(g_rawdev_devices[i].name); diff --git a/fusee/fusee-secondary/src/raw_dev.h b/fusee/fusee-secondary/src/raw_dev.h index df2fac1f0..9a7454082 100644 --- a/fusee/fusee-secondary/src/raw_dev.h +++ b/fusee/fusee-secondary/src/raw_dev.h @@ -21,6 +21,7 @@ #include #include #include "device_partition.h" +#include "key_derivation.h" #define RAWDEV_MAX_DEVICES 16 @@ -29,6 +30,8 @@ int rawdev_register_device(const char *name); int rawdev_unregister_device(const char *name); int rawdev_unmount_device(const char *name); /* also unregisters. */ +int rawdev_register_keys(const char *name, unsigned int target_firmware, BisPartition part); + int rawdev_unmount_all(void); #endif