diff --git a/fusee/fusee-primary/src/hwinit.h b/fusee/fusee-primary/src/hwinit.h index 2e7994bca..7b66f07b7 100644 --- a/fusee/fusee-primary/src/hwinit.h +++ b/fusee/fusee-primary/src/hwinit.h @@ -35,4 +35,5 @@ void display_enable_backlight(bool on); void cluster_enable_cpu0(u64 entry, u32 ns_disable); +void mc_enable_ahb_redirect(); #endif diff --git a/fusee/fusee-secondary/src/device_partition.c b/fusee/fusee-secondary/src/device_partition.c new file mode 100644 index 000000000..4fbfc120d --- /dev/null +++ b/fusee/fusee-secondary/src/device_partition.c @@ -0,0 +1,58 @@ +#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) { + 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->read_cipher != NULL) { + 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); + } +} diff --git a/fusee/fusee-secondary/src/device_partition.h b/fusee/fusee-secondary/src/device_partition.h new file mode 100644 index 000000000..b61ab7a65 --- /dev/null +++ b/fusee/fusee-secondary/src/device_partition.h @@ -0,0 +1,48 @@ +#ifndef FUSEE_DEVICE_PARTITION_H +#define FUSEE_DEVICE_PARTITION_H + +#include +#include +#include + +#define DEVPART_IV_MAX_SIZE 16 + +struct device_partition_t; + +typedef int (*device_partition_initializer_t)(struct device_partition_t *devpart); +typedef void (*device_partition_finalizer_t)(struct device_partition_t *devpart); + +/* Note: only random-access ciphers supporting in-place encryption/decryption are supported */ +typedef int (*device_partition_cipher_t)(struct device_partition_t *devpart, uint64_t sector, uint64_t num_sectors); + +typedef int (*device_partition_reader_t)(struct device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors); +typedef int (*device_partition_writer_t)(struct device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors); + +typedef struct device_partition_t { + size_t sector_size; /* The size of a sector */ + uint64_t start_sector; /* Offset in the parent device, in sectors. */ + uint64_t num_sectors; /* Maximum size of the partition, in sectors (optional). */ + + device_partition_cipher_t read_cipher; /* Cipher for read operations. */ + device_partition_cipher_t write_cipher; /* Cipher for write operations. */ + uint64_t crypto_flags; /* Additional information for crypto, for conveniency. */ + + device_partition_initializer_t initializer; /* Initializer. */ + device_partition_finalizer_t finalizer; /* Finalizer. */ + + device_partition_reader_t reader; /* Reader. */ + device_partition_writer_t writer; /* Writer. */ + + void *device_struct; /* Pointer to struct for additional info. */ + + void *crypto_work_buffer; /* Work buffer for crypto. */ + uint64_t crypto_work_buffer_num_sectors; /* Size of the crypto work buffer in sectors. */ + + uint8_t iv[DEVPART_IV_MAX_SIZE]; /* IV. */ + bool initialized; +} 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); + +#endif diff --git a/fusee/fusee-secondary/src/fs_dev.c b/fusee/fusee-secondary/src/fs_dev.c index 31052e0dc..3bd669370 100644 --- a/fusee/fusee-secondary/src/fs_dev.c +++ b/fusee/fusee-secondary/src/fs_dev.c @@ -11,7 +11,6 @@ #include "lib/fatfs/ff.h" #include "fs_dev.h" - /* Quite a bit of code comes from https://github.com/switchbrew/libnx/blob/master/nx/source/runtime/devices/fs_dev.c */ static int fsdev_convert_rc(struct _reent *r, FRESULT rc); @@ -69,23 +68,33 @@ static devoptab_t g_fsdev_devoptab = { }; typedef struct fsdev_fsdevice_t { + devoptab_t devoptab; + device_partition_t devpart; + FATFS fatfs; char name[32+1]; bool setup; - devoptab_t devoptab; - FATFS fatfs; } fsdev_fsdevice_t; static fsdev_fsdevice_t g_fsdev_devices[FF_VOLUMES] = { 0 }; -const char *VolumeStr[FF_VOLUMES] = { 0 }; -int fsdev_mount_device(const char *name, unsigned int id) { - fsdev_fsdevice_t *device = &g_fsdev_devices[id]; +/* Required by ff.c */ +/* FF_VOLUMES = 10 */ +#define FKNAM "\xff$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" /* Workaround for fatfs. */ + +const char *VolumeStr[FF_VOLUMES] = { FKNAM, FKNAM, FKNAM, FKNAM, FKNAM, FKNAM, FKNAM, FKNAM, FKNAM, FKNAM }; + +/* For diskio.c code */ +device_partition_t *g_volume_to_devparts[FF_VOLUMES] = { NULL }; + +#include +int fsdev_mount_device(const char *name, const device_partition_t *devpart, bool initialize_immediately) { + fsdev_fsdevice_t *device = NULL; FRESULT rc; char drname[40]; strcpy(drname, name); strcat(drname, ":"); - if (id >= FF_VOLUMES || name[0] == '\0') { + if (name[0] == '\0' || strcmp(name, FKNAM) == 0 || devpart == NULL) { errno = EINVAL; return -1; } @@ -93,19 +102,35 @@ int fsdev_mount_device(const char *name, unsigned int id) { errno = ENAMETOOLONG; return -1; } - if (FindDevice(drname) != -1 || g_fsdev_devices[id].setup) { + + if (FindDevice(drname) != -1) { errno = EEXIST; /* Device already exists */ return -1; } + /* Find an unused slot. */ + for(size_t i = 0; i < FF_VOLUMES; i++) { + if (!g_fsdev_devices[i].setup) { + device = &g_fsdev_devices[i]; + break; + } + } + if (device == NULL) { + errno = ENOMEM; + return -1; + } strcpy(device->name, name); - memcpy(&device->devoptab, &g_fsdev_devoptab, sizeof(devoptab_t)); + device->devoptab = g_fsdev_devoptab; + device->devpart = *devpart; + device->devoptab.name = device->name; device->devoptab.deviceData = device; - VolumeStr[id] = device->name; - rc = f_mount(&device->fatfs, drname, 1); + VolumeStr[device - g_fsdev_devices] = device->name; + g_volume_to_devparts[device - g_fsdev_devices] = &device->devpart; + + rc = f_mount(&device->fatfs, drname, initialize_immediately ? 1 : 0); if (rc != FR_OK) { return fsdev_convert_rc(NULL, rc); @@ -113,7 +138,8 @@ int fsdev_mount_device(const char *name, unsigned int id) { if (AddDevice(&device->devoptab) == -1) { f_unmount(drname); - VolumeStr[id] = NULL; + g_volume_to_devparts[device - g_fsdev_devices] = NULL; + VolumeStr[device - g_fsdev_devices] = FKNAM; errno = ENOMEM; return -1; } else { @@ -166,26 +192,15 @@ int fsdev_unmount_device(const char *name) { if (ret == 0) { fsdev_fsdevice_t *device = (fsdev_fsdevice_t *)(GetDeviceOpTab(name)->deviceData); RemoveDevice(drname); + VolumeStr[device - g_fsdev_devices] = FKNAM; + g_volume_to_devparts[device - g_fsdev_devices] = NULL; + device->devpart.finalizer(&device->devpart); memset(device, 0, sizeof(fsdev_fsdevice_t)); } return ret; } -int fsdev_mount_all(void) { - /* Change this accordingly: */ - static const char* const volumes[] = { "sdmc" }; - - for (size_t i = 0; i < FF_VOLUMES; i++) { - int ret = fsdev_mount_device(volumes[i], i); - if (ret != 0) { - return ret; - } - } - - return 0; -} - int fsdev_unmount_all(void) { for (size_t i = 0; i < FF_VOLUMES; i++) { int ret = fsdev_unmount_device(VolumeStr[i]); diff --git a/fusee/fusee-secondary/src/fs_dev.h b/fusee/fusee-secondary/src/fs_dev.h index 415c1d611..f5b1bd58b 100644 --- a/fusee/fusee-secondary/src/fs_dev.h +++ b/fusee/fusee-secondary/src/fs_dev.h @@ -4,12 +4,12 @@ #include #include #include +#include "device_partition.h" -int fsdev_mount_device(const char *name, unsigned int id); +int fsdev_mount_device(const char *name, const device_partition_t *devpart, bool initialize_immediately); int fsdev_set_default_device(const char *name); int fsdev_unmount_device(const char *name); -int fsdev_mount_all(void); int fsdev_unmount_all(void); #endif diff --git a/fusee/fusee-secondary/src/gpt.c b/fusee/fusee-secondary/src/gpt.c index d6025e8da..ad37896b9 100644 --- a/fusee/fusee-secondary/src/gpt.c +++ b/fusee/fusee-secondary/src/gpt.c @@ -2,7 +2,7 @@ #include #include "gpt.h" -int gpt_get_header(efi_header_t *out, FILE *disk) { +int gpt_get_header(efi_header_t *out, FILE *disk, size_t sector_size) { union { uint8_t sector[512]; efi_header_t hdr; @@ -17,6 +17,10 @@ int gpt_get_header(efi_header_t *out, FILE *disk) { if (fread(d.sector, 512, 1, disk) == 0) { return -1; } + if (fseek(disk, sector_size - 512, SEEK_CUR) != 0) { + return -1; + } + if (d.sector[0x1FE] != 0x55 || d.sector[0x1FF] != 0xAA) { errno = EILSEQ; return -1; @@ -26,6 +30,9 @@ int gpt_get_header(efi_header_t *out, FILE *disk) { if (fread(d.sector, 512, 1, disk) == 0) { return -1; } + if (fseek(disk, sector_size - 512, SEEK_CUR) != 0) { + return -1; + } /* Check for "EFI PART". */ if (memcmp(d.hdr.magic, "EFI PART", 8) != 0) { errno = EILSEQ; @@ -41,7 +48,7 @@ int gpt_get_header(efi_header_t *out, FILE *disk) { return -1; } /* Some more checks: */ - if(d.hdr.header_size > 512 || d.hdr.revision != 0x10000) { + if(d.hdr.header_size > sector_size || d.hdr.revision != 0x10000) { errno = ENOTSUP; return -1; } @@ -51,32 +58,33 @@ int gpt_get_header(efi_header_t *out, FILE *disk) { return 0; } -int gpt_iterate_through_entries(FILE *disk, gpt_entry_iterator_t callback) { +int gpt_iterate_through_entries(FILE *disk, size_t sector_size, gpt_entry_iterator_t callback, void *param) { 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) == -1) { + if (gpt_get_header(&hdr, disk, sector_size) == -1) { return -1; } /* Seek to the entry table. */ - if (fseek(disk, 512 * hdr.entries_first_lba - offset, SEEK_CUR) != 0) { + if (fseek(disk, sector_size * hdr.entries_first_lba - offset, SEEK_CUR) != 0) { return -1; } - offset = 512 * hdr.entries_first_lba; + 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++) { + printf("%lu/%lu\n", i, hdr.entry_count); if (fread(&entry, sizeof(efi_entry_t), 1, disk) == 0) { return -1; } - if (callback(&entry, offset, disk) != 0) { + if (callback(&entry, param, offset, disk) != 0) { return -1; } diff --git a/fusee/fusee-secondary/src/gpt.h b/fusee/fusee-secondary/src/gpt.h index 1ab5c537d..690897637 100644 --- a/fusee/fusee-secondary/src/gpt.h +++ b/fusee/fusee-secondary/src/gpt.h @@ -35,9 +35,9 @@ typedef struct efi_header { uint32_t entries_crc32; } __attribute__((packed, aligned(4))) efi_header_t; -typedef int (*gpt_entry_iterator_t)(const efi_entry_t *entry, size_t entry_offset, FILE *disk); +typedef int (*gpt_entry_iterator_t)(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk); -int gpt_get_header(efi_header_t *out, FILE *disk); -int gpt_iterate_through_entries(FILE *disk, gpt_entry_iterator_t callback); +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); #endif diff --git a/fusee/fusee-secondary/src/hwinit.h b/fusee/fusee-secondary/src/hwinit.h index 2e7994bca..11e328718 100644 --- a/fusee/fusee-secondary/src/hwinit.h +++ b/fusee/fusee-secondary/src/hwinit.h @@ -35,4 +35,6 @@ void display_enable_backlight(bool on); void cluster_enable_cpu0(u64 entry, u32 ns_disable); +void mc_enable_ahb_redirect(); + #endif diff --git a/fusee/fusee-secondary/src/lib/fatfs/diskio.c b/fusee/fusee-secondary/src/lib/fatfs/diskio.c index 450a234f4..9c6644ec0 100644 --- a/fusee/fusee-secondary/src/lib/fatfs/diskio.c +++ b/fusee/fusee-secondary/src/lib/fatfs/diskio.c @@ -10,20 +10,11 @@ #include #include #include "diskio.h" /* FatFs lower layer API */ -#include "../../sdmmc.h" -#include "../../hwinit.h" +#include "ffconf.h" +#include "../../device_partition.h" -/* Global sd struct. */ -struct mmc g_sd_mmc = {0}; -static bool g_sd_initialized = false; - -static bool g_ahb_redirect_enabled = false; - -/* -Uncomment if needed: -struct mmc nand_mmc = {0}; -static bool g_nand_initialized = false; -*/ +/* fs_dev.c */ +extern device_partition_t *g_volume_to_devparts[FF_VOLUMES]; /*-----------------------------------------------------------------------*/ /* Get Drive Status */ @@ -46,27 +37,15 @@ DSTATUS disk_initialize ( BYTE pdrv /* Physical drive nmuber to identify the drive */ ) { - if (!g_ahb_redirect_enabled) { - mc_enable_ahb_redirect(); - g_ahb_redirect_enabled = true; - } - - switch (pdrv) { - case 0: { - if (!g_sd_initialized) { - int rc = sdmmc_init(&g_sd_mmc, SWITCH_MICROSD); - if (rc == 0) { - g_sd_initialized = true; - return 0; - } else { - return rc; - } - } else { - return 0; - } - } - default: - return STA_NODISK; + /* We aren't using FF_MULTI_PARTITION, so pdrv = volume id. */ + device_partition_t *devpart = g_volume_to_devparts[pdrv]; + if (devpart == NULL) { + return STA_NODISK; + } else if (devpart->initializer != NULL) { + int rc = devpart->initializer(devpart); + return rc == 0 ? 0 : STA_NOINIT; + } else { + return 0; } } @@ -83,11 +62,15 @@ DRESULT disk_read ( UINT count /* Number of sectors to read */ ) { - switch (pdrv) { - case 0: - return sdmmc_read(&g_sd_mmc, buff, sector, count) == 0 ? RES_OK : RES_ERROR; - default: - return RES_PARERR; + /* We aren't using FF_MULTI_PARTITION, so pdrv = volume id. */ + device_partition_t *devpart = g_volume_to_devparts[pdrv]; + if (devpart == NULL) { + return RES_PARERR; + } else if (devpart->reader != NULL) { + int rc = devpart->reader(devpart, buff, sector, count); + return rc == 0 ? 0 : RES_ERROR; + } else { + return RES_ERROR; } } @@ -104,11 +87,15 @@ DRESULT disk_write ( UINT count /* Number of sectors to write */ ) { - switch (pdrv) { - case 0: - return sdmmc_write(&g_sd_mmc, buff, sector, count) == 0 ? RES_OK : RES_ERROR; - default: - return RES_PARERR; + /* We aren't using FF_MULTI_PARTITION, so pdrv = volume id. */ + device_partition_t *devpart = g_volume_to_devparts[pdrv]; + if (devpart == NULL) { + return RES_PARERR; + } else if (devpart->writer != NULL) { + int rc = devpart->writer(devpart, buff, sector, count); + return rc == 0 ? 0 : RES_ERROR; + } else { + return RES_ERROR; } } diff --git a/fusee/fusee-secondary/src/lib/fatfs/ffconf.h b/fusee/fusee-secondary/src/lib/fatfs/ffconf.h index 5a38ae01d..c7d15edc2 100644 --- a/fusee/fusee-secondary/src/lib/fatfs/ffconf.h +++ b/fusee/fusee-secondary/src/lib/fatfs/ffconf.h @@ -163,7 +163,7 @@ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ -#define FF_VOLUMES 1 +#define FF_VOLUMES 10 /* Number of volumes (logical drives) to be used. (1-10) */ diff --git a/fusee/fusee-secondary/src/main.c b/fusee/fusee-secondary/src/main.c index 17ae0cd48..4584ae793 100644 --- a/fusee/fusee-secondary/src/main.c +++ b/fusee/fusee-secondary/src/main.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include "utils.h" @@ -9,7 +10,8 @@ #include "nxboot.h" #include "console.h" #include "sd_utils.h" -#include "fs_dev.h" +#include "switch_fs.h" +#include "gpt.h" #include "display/video_fb.h" extern void (*__program_exit_callback)(int rc); @@ -23,18 +25,17 @@ static void setup_env(void) { generic_panic(); } - if(fsdev_mount_all() == -1) { - perror("Failed to mount at least one FAT parition"); + if(switchfs_mount_all() == -1) { + perror("Failed to mount at least one parition"); generic_panic(); } - fsdev_set_default_device("sdmc"); /* TODO: What other hardware init should we do here? */ } static void cleanup_env(void) { /* Unmount everything (this causes all open files to be flushed and closed) */ - fsdev_unmount_all(); + switchfs_unmount_all(); //console_end(); } diff --git a/fusee/fusee-secondary/src/nxboot.c b/fusee/fusee-secondary/src/nxboot.c index 10d4d811b..c0cf74848 100644 --- a/fusee/fusee-secondary/src/nxboot.c +++ b/fusee/fusee-secondary/src/nxboot.c @@ -1,12 +1,8 @@ #include #include -#include -#include "sdmmc.h" -#include "raw_mmc_dev.h" #include "utils.h" #include "nxboot.h" #include "key_derivation.h" -#include "gpt.h" #include "package1.h" #include "package2.h" #include "loader.h" @@ -49,64 +45,10 @@ void nxboot_configure_exosphere(void) { *(MAILBOX_EXOSPHERE_CONFIGURATION) = exo_cfg; } -static struct mmc nand_mmc; /* TODO: Remove, move it elsewhere and actually initalize the controller!! */ - -static int init_rawnand_and_boot0_devices(void) { - if (rawmmcdev_mount_unencrypted_device("rawnand", &nand_mmc, SDMMC_PARTITION_USER, 0, 32ull<<30) == -1) { - return -1; - } - if (rawmmcdev_mount_unencrypted_device("boot0", &nand_mmc, SDMMC_PARTITION_BOOT0, 0, 0x184000) == -1) { - return -1; - } - - return 0; -} - -static bool g_bcpkg2_initialized = false; -static int bcpkg2_finder_callback(const efi_entry_t *entry, size_t entry_offset, FILE *disk) { - /* TODO: what about backup partitions? */ - static const uint16_t part_name[] = u"BCPKG2-1-Normal-Main"; - if (memcmp(entry->name, part_name, sizeof(part_name)) == 0) { - uint64_t part_offset = 512 * entry->first_lba; - uint64_t part_size = 512 * (entry->last_lba - entry->first_lba); - - int rc = rawmmcdev_mount_unencrypted_device("bcpkg2", &nand_mmc, SDMMC_PARTITION_USER, part_offset, part_size); - - g_bcpkg2_initialized = rc == 0; - return rc; - } - - return 0; -} - -/* Find BCPKG2-1-Normal-Main using the GPT, then register it. */ -static int init_bcpkg2_device(void) { - FILE *rawnand = fopen("rawnand:/", "rb"); - int rc; - if (rawnand == NULL) { - return -1; - } - - rc = gpt_iterate_through_entries(rawnand, bcpkg2_finder_callback); - fclose(rawnand); - - if (rc == 0 && !g_bcpkg2_initialized) { - errno = ENOENT; - return -1; - } - - return rc; -} - /* This is the main function responsible for booting Horizon. */ void nxboot_main(void) { loader_ctx_t *loader_ctx = get_loader_ctx(); - /* TODO: this is not always necessary */ - if (init_rawnand_and_boot0_devices()) { - printf("Error: Failed to mount rawnand and/or boot0: %s!\n", strerror(errno)); - generic_panic(); - } /* TODO: Validate that we're capable of booting. */ /* TODO: Initialize Boot Reason. */ @@ -120,10 +62,6 @@ void nxboot_main(void) { //derive_nx_keydata(MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware); if (loader_ctx->package2_loadfile.load_address == 0) { - if (init_bcpkg2_device() == -1) { - printf("Error: Failed to mount BCPKG2-1-Normal-Main: %s!\n", strerror(errno)); - generic_panic(); - } /* TODO: read package2 somewhere. */ } @@ -151,7 +89,5 @@ void nxboot_main(void) { /* Display splash screen. */ display_splash_screen_bmp(loader_ctx->custom_splash_path); - rawmmcdev_unmount_all(); - /* TODO: Halt ourselves. */ } diff --git a/fusee/fusee-secondary/src/raw_dev.c b/fusee/fusee-secondary/src/raw_dev.c new file mode 100644 index 000000000..01150669c --- /dev/null +++ b/fusee/fusee-secondary/src/raw_dev.c @@ -0,0 +1,396 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "raw_dev.h" + +static int rawdev_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode); +static int rawdev_close(struct _reent *r, void *fd); +static ssize_t rawdev_write(struct _reent *r, void *fd, const char *ptr, size_t len); +static ssize_t rawdev_read(struct _reent *r, void *fd, char *ptr, size_t len); +static off_t rawdev_seek(struct _reent *r, void *fd, off_t pos, int whence); +static int rawdev_fstat(struct _reent *r, void *fd, struct stat *st); +static int rawdev_stat(struct _reent *r, const char *file, struct stat *st); +static int rawdev_fsync(struct _reent *r, void *fd); + +typedef struct rawdev_device_t { + devoptab_t devoptab; + + uint8_t *tmp_sector; + device_partition_t devpart; + char name[32+1]; + char root_path[34+1]; + bool setup; +} rawdev_device_t; + +typedef struct rawdev_file_t { + rawdev_device_t *device; + int open_flags; + uint64_t offset; +} rawdev_file_t; + +static rawdev_device_t g_rawdev_devices[RAWDEV_MAX_DEVICES] = {0}; + +static devoptab_t g_rawdev_devoptab = { + .structSize = sizeof(rawdev_file_t), + .open_r = rawdev_open, + .close_r = rawdev_close, + .write_r = rawdev_write, + .read_r = rawdev_read, + .seek_r = rawdev_seek, + .fstat_r = rawdev_fstat, + .stat_r = rawdev_stat, + .fsync_r = rawdev_fsync, + .deviceData = NULL, +}; + +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; + return -1; + } + + if (strlen(name) > 32) { + errno = ENAMETOOLONG; + return -1; + } + if (FindDevice(drname) != -1) { + errno = EEXIST; /* Device already exists */ + return -1; + } + + /* Find an unused slot. */ + for(size_t i = 0; i < RAWDEV_MAX_DEVICES; i++) { + if (!g_rawdev_devices[i].setup) { + device = &g_rawdev_devices[i]; + break; + } + } + if (device == NULL) { + errno = ENOMEM; + return -1; + } + + memset(device, 0, sizeof(rawdev_device_t)); + device->devoptab = g_rawdev_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; + + if (initialize_immediately) { + int rc = device->devpart.initializer(&device->devpart); + if (rc != 0) { + errno = rc; + return -1; + } + } + + device->tmp_sector = (uint8_t *)malloc(devpart->sector_size); + if (device->tmp_sector == NULL) { + errno = ENOMEM; + return -1; + } + + if (AddDevice(&device->devoptab) == -1) { + errno = ENOMEM; + return -1; + } else { + device->setup = true; + return 0; + } +} + +int rawdev_unmount_device(const char *name) { + char drname[40]; + int devid; + rawdev_device_t *device; + + strcpy(drname, name); + strcat(drname, ":"); + + devid = FindDevice(drname); + + if (devid == -1) { + errno = ENOENT; + return -1; + } + + device = (rawdev_device_t *)(GetDeviceOpTab(name)->deviceData); + RemoveDevice(drname); + free(device->tmp_sector); + device->devpart.finalizer(&device->devpart); + memset(device, 0, sizeof(rawdev_device_t)); + + return 0; +} + +int rawdev_unmount_all(void) { + for (size_t i = 0; i < RAWDEV_MAX_DEVICES; i++) { + RemoveDevice(g_rawdev_devices[i].root_path); + memset(&g_rawdev_devices[i], 0, sizeof(rawdev_device_t)); + } + + return 0; +} + +static int rawdev_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode) { + (void)mode; + rawdev_file_t *f = (rawdev_file_t *)fileStruct; + rawdev_device_t *device = (rawdev_device_t *)(r->deviceData); + + /* Only allow "device:/". */ + if (strcmp(path, device->root_path) != 0) { + r->_errno = ENOENT; + return -1; + } + + /* Forbid some flags that we explicitely don't support.*/ + if (flags & (O_APPEND | O_TRUNC | O_EXCL)) { + r->_errno = EINVAL; + return -1; + } + + memset(f, 0, sizeof(rawdev_file_t)); + f->device = device; + f->open_flags = flags; + return 0; +} + +static int rawdev_close(struct _reent *r, void *fd) { + (void)r; + rawdev_file_t *f = (rawdev_file_t *)fd; + memset(f, 0, sizeof(rawdev_file_t)); + + return 0; +} + +static ssize_t rawdev_write(struct _reent *r, void *fd, const char *ptr, size_t len) { + rawdev_file_t *f = (rawdev_file_t *)fd; + rawdev_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 = sector_end - ((f->offset + len) % sector_size != 0 ? 1 : 0); + 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); + } + + /* 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 = device_partition_read_data(&device->devpart, device->tmp_sector, sector_begin, 1); + if (no != 0) { + r->_errno = no; + return -1; + } + + memcpy(device->tmp_sector + (f->offset % sector_size), data, nb); + + no = device_partition_write_data(&device->devpart, device->tmp_sector, sector_begin, 1); + 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 = device_partition_write_data(&device->devpart, data, current_sector, sector_end_aligned - current_sector); + 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 = device_partition_read_data(&device->devpart, device->tmp_sector, sector_end_aligned, 1); + if (no != 0) { + r->_errno = no; + return -1; + } + + memcpy(device->tmp_sector, data, (size_t)((f->offset + len) % sector_size)); + + no = device_partition_write_data(&device->devpart, device->tmp_sector, sector_end_aligned, 1); + 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 rawdev_read(struct _reent *r, void *fd, char *ptr, size_t len) { + rawdev_file_t *f = (rawdev_file_t *)fd; + rawdev_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 = sector_end - ((f->offset + len) % sector_size != 0 ? 1 : 0); + 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); + } + + /* 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 = device_partition_read_data(&device->devpart, device->tmp_sector, sector_begin, 1); + 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 = device_partition_read_data(&device->devpart, data, current_sector, sector_end_aligned - current_sector); + 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 = device_partition_read_data(&device->devpart, device->tmp_sector, sector_end_aligned, 1); + 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 rawdev_seek(struct _reent *r, void *fd, off_t pos, int whence) { + rawdev_file_t *f = (rawdev_file_t *)fd; + rawdev_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 rawdev_stat_impl(rawdev_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 rawdev_fstat(struct _reent *r, void *fd, struct stat *st) { + (void)r; + rawdev_file_t *f = (rawdev_file_t *)fd; + rawdev_device_t *device = f->device; + rawdev_stat_impl(device, st); + + return 0; +} + +static int rawdev_stat(struct _reent *r, const char *file, struct stat *st) { + rawdev_device_t *device = (rawdev_device_t *)(r->deviceData); + if (strcmp(file, device->root_path) != 0) { + r->_errno = ENOENT; + return -1; + } + + rawdev_stat_impl(device, st); + return 0; +} + +static int rawdev_fsync(struct _reent *r, void *fd) { + /* Nothing to do. */ + (void)r; + (void)fd; + return 0; +} diff --git a/fusee/fusee-secondary/src/raw_dev.h b/fusee/fusee-secondary/src/raw_dev.h new file mode 100644 index 000000000..134016267 --- /dev/null +++ b/fusee/fusee-secondary/src/raw_dev.h @@ -0,0 +1,16 @@ +#ifndef FUSEE_RAW_DEV_H +#define FUSEE_RAW_DEV_H + +#include +#include +#include +#include "device_partition.h" + +#define RAWDEV_MAX_DEVICES 16 + +int rawdev_mount_device(const char *name, const device_partition_t *device, bool mount_immediately); + +int rawdev_unmount_device(const char *name); +int rawdev_unmount_all(void); + +#endif diff --git a/fusee/fusee-secondary/src/raw_mmc_dev.c b/fusee/fusee-secondary/src/raw_mmc_dev.c deleted file mode 100644 index e1918bbd8..000000000 --- a/fusee/fusee-secondary/src/raw_mmc_dev.c +++ /dev/null @@ -1,485 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "raw_mmc_dev.h" - -static int rawmmcdev_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode); -static int rawmmcdev_close(struct _reent *r, void *fd); -static ssize_t rawmmcdev_write(struct _reent *r, void *fd, const char *ptr, size_t len); -static ssize_t rawmmcdev_read(struct _reent *r, void *fd, char *ptr, size_t len); -static off_t rawmmcdev_seek(struct _reent *r, void *fd, off_t pos, int whence); -static int rawmmcdev_fstat(struct _reent *r, void *fd, struct stat *st); -static int rawmmcdev_stat(struct _reent *r, const char *file, struct stat *st); -static int rawmmcdev_fsync(struct _reent *r, void *fd); - -typedef struct rawmmcdev_device_t { - devoptab_t devoptab; - - struct mmc *mmc; - enum sdmmc_partition partition; - uint64_t offset; - uint64_t size; - rawmmc_crypt_func_t read_crypt_func; - rawmmc_crypt_func_t write_crypt_func; - uint64_t crypt_flags; - uint8_t iv[16]; - - char name[32+1]; - char root_path[34+1]; - bool setup, encrypted; -} rawmmcdev_device_t; - -typedef struct rawmmcdev_file_t { - rawmmcdev_device_t *device; - int open_flags; - uint64_t offset; -} rawmmcdev_file_t; - -static rawmmcdev_device_t g_rawmmcdev_devices[RAWMMC_MAX_DEVICES] = {0}; - -static devoptab_t g_rawmmcdev_devoptab = { - .structSize = sizeof(rawmmcdev_file_t), - .open_r = rawmmcdev_open, - .close_r = rawmmcdev_close, - .write_r = rawmmcdev_write, - .read_r = rawmmcdev_read, - .seek_r = rawmmcdev_seek, - .fstat_r = rawmmcdev_fstat, - .stat_r = rawmmcdev_stat, - .fsync_r = rawmmcdev_fsync, - .deviceData = NULL, -}; - -int rawmmcdev_mount_device( - const char *name, - struct mmc *mmc, - enum sdmmc_partition partition, - uint64_t offset, - uint64_t size, - rawmmc_crypt_func_t read_crypt_func, - rawmmc_crypt_func_t write_crypt_func, - uint64_t crypt_flags, - const uint8_t *iv -) { - rawmmcdev_device_t *device = NULL; - char drname[40]; - strcpy(drname, name); - strcat(drname, ":"); - - if (name[0] == '\0') { - errno = EINVAL; - return -1; - } - if ((read_crypt_func == NULL && write_crypt_func != NULL) || (read_crypt_func != NULL && write_crypt_func == NULL)) { - errno = EINVAL; - return -1; - } - if((offset % 512) != 0 || (size % 512) != 0) { - errno = EINVAL; - return -1; - } - if (strlen(name) > 32) { - errno = ENAMETOOLONG; - return -1; - } - if (FindDevice(drname) != -1) { - errno = EEXIST; /* Device already exists */ - return -1; - } - - /* Find an unused slot. */ - for(size_t i = 0; i < RAWMMC_MAX_DEVICES; i++) { - if (!g_rawmmcdev_devices[i].setup) { - device = &g_rawmmcdev_devices[i]; - } - } - if (device == NULL) { - errno = ENOMEM; - return -1; - } - - memset(device, 0, sizeof(rawmmcdev_device_t)); - memcpy(&device->devoptab, &g_rawmmcdev_devoptab, sizeof(devoptab_t)); - strcpy(device->name, name); - strcpy(device->root_path, name); - strcat(device->root_path, ":/"); - device->mmc = mmc; - device->partition = partition; - device->offset = offset; - device->size = size; - device->read_crypt_func = read_crypt_func; - device->write_crypt_func = write_crypt_func; - device->encrypted = read_crypt_func != NULL || write_crypt_func != NULL; - device->crypt_flags = crypt_flags; - if (iv != NULL) { - memcpy(device->iv, iv, 16); - } - - device->devoptab.name = device->name; - device->devoptab.deviceData = device; - - if (AddDevice(&device->devoptab) == -1) { - errno = ENOMEM; - return -1; - } else { - device->setup = true; - return 0; - } -} - -int rawmmcdev_mount_unencrypted_device( - const char *name, - struct mmc *mmc, - enum sdmmc_partition partition, - uint64_t offset, - uint64_t size -) { - return rawmmcdev_mount_device(name, mmc, partition, offset, size, NULL, NULL, 0, NULL); -} - -int rawmmcdev_unmount_device(const char *name) { - char drname[40]; - int devid; - rawmmcdev_device_t *device; - - strcpy(drname, name); - strcat(drname, ":"); - - devid = FindDevice(drname); - - if (devid == -1) { - errno = ENOENT; - return -1; - } - - device = (rawmmcdev_device_t *)(GetDeviceOpTab(name)->deviceData); - RemoveDevice(drname); - memset(device, 0, sizeof(rawmmcdev_device_t)); - - return 0; -} - -int rawmmcdev_unmount_all(void) { - for (size_t i = 0; i < RAWMMC_MAX_DEVICES; i++) { - RemoveDevice(g_rawmmcdev_devices[i].root_path); - memset(&g_rawmmcdev_devices[i], 0, sizeof(rawmmcdev_device_t)); - } - - return 0; -} - -static int rawmmcdev_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode) { - (void)mode; - rawmmcdev_file_t *f = (rawmmcdev_file_t *)fileStruct; - rawmmcdev_device_t *device = (rawmmcdev_device_t *)(r->deviceData); - - /* Only allow "device:/". */ - if (strcmp(path, device->root_path) != 0) { - r->_errno = ENOENT; - return -1; - } - - /* Forbid some flags that we explicitely don't support.*/ - if (flags & (O_APPEND | O_TRUNC | O_EXCL)) { - r->_errno = EINVAL; - return -1; - } - - memset(f, 0, sizeof(rawmmcdev_file_t)); - f->device = device; - f->open_flags = flags; - return 0; -} - -static int rawmmcdev_close(struct _reent *r, void *fd) { - (void)r; - rawmmcdev_file_t *f = (rawmmcdev_file_t *)fd; - memset(f, 0, sizeof(rawmmcdev_file_t)); - - return 0; -} - -static __attribute__((aligned(16))) uint8_t g_crypto_buffer[512 * 16] = {0}; - -static ssize_t rawmmcdev_write(struct _reent *r, void *fd, const char *ptr, size_t len) { - rawmmcdev_file_t *f = (rawmmcdev_file_t *)fd; - rawmmcdev_device_t *device = f->device; - uint32_t device_sector_offset = (uint32_t)(device->offset / 512); - uint32_t sector_begin = (uint32_t)((device->offset + f->offset) / 512); /* NAND offset */ - uint32_t sector_end = (uint32_t)((device->offset + f->offset + len + 511) / 512); - uint32_t sector_end_aligned = sector_end - ((f->offset + len) % 512 != 0 ? 1 : 0); - uint32_t current_sector = sector_begin; - const uint8_t *data = (const uint8_t *)ptr; - - int no = 0; - - if (f->offset + len >= device->offset + device->size) { - len = (size_t)(device->size - f->offset); - } - - /* Change the partition, if needed. */ - no = sdmmc_select_partition(device->mmc, device->partition); - if (no != 0 && no != ENOTTY) { - r->_errno = no; - return -1; - } - - /* Unaligned at the start, we need to read the sector and incorporate the data. */ - if (f->offset % 512 != 0) { - no = sdmmc_read(device->mmc, g_crypto_buffer, sector_begin, 1); - if (no != 0) { - r->_errno = no; - return -1; - } - if (device->encrypted) { - device->read_crypt_func(g_crypto_buffer, g_crypto_buffer, 512 * (sector_begin - device_sector_offset), 512, device->iv, device->crypt_flags); - } - memcpy(g_crypto_buffer, data, len <= (512 - (uint32_t)(f->offset % 512)) ? len : 512 - (uint32_t)(f->offset % 512)); - if (device->encrypted) { - device->write_crypt_func(g_crypto_buffer, g_crypto_buffer, 512 * (sector_begin - device_sector_offset), 512, device->iv, device->crypt_flags); - } - no = sdmmc_write(device->mmc, g_crypto_buffer, sector_begin, 1); - if (no != 0) { - r->_errno = no; - return -1; - } - - /* Advance */ - data += 512 - (uint32_t)(f->offset % 512); - 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; - } - - if (device->encrypted) { - size_t sectors_remaining = sector_end_aligned - current_sector; - for (size_t i = 0; i < len; i += sizeof(g_crypto_buffer)/512) { - size_t n = sectors_remaining <= sizeof(g_crypto_buffer)/512 ? sectors_remaining : sizeof(g_crypto_buffer)/512; - - memcpy(g_crypto_buffer, data, 512 * n); - device->write_crypt_func(g_crypto_buffer, g_crypto_buffer, current_sector - device_sector_offset, 512 * n, device->iv, device->crypt_flags); - no = sdmmc_write(device->mmc, g_crypto_buffer, current_sector, n); - - if (no != 0) { - r->_errno = no; - return -1; - } - - data += 512 * n; - current_sector += n; - } - } else { - /* We can write everything aligned at once. */ - size_t sectors_remaining = sector_end_aligned - current_sector; - - no = sdmmc_write(device->mmc, data, current_sector, sectors_remaining); - if (no != 0) { - r->_errno = no; - return -1; - } - - data += 512 * sectors_remaining; - current_sector += sectors_remaining; - } - - /* Unaligned at the end, we need to read the sector and incorporate the data. */ - if (sector_end != sector_end_aligned) { - no = sdmmc_read(device->mmc, g_crypto_buffer, sector_end_aligned, 1); - if (no != 0) { - r->_errno = no; - return -1; - } - if (device->encrypted) { - device->read_crypt_func(g_crypto_buffer, g_crypto_buffer, 512 * (sector_end_aligned - device_sector_offset), 512, device->iv, device->crypt_flags); - } - memcpy(g_crypto_buffer, data, (uint32_t)((f->offset + len) % 512)); - if (device->encrypted) { - device->write_crypt_func(g_crypto_buffer, g_crypto_buffer, 512 * (sector_end_aligned - device_sector_offset), 512, device->iv, device->crypt_flags); - } - no = sdmmc_write(device->mmc, g_crypto_buffer, sector_end_aligned, 1); - if (no != 0) { - r->_errno = no; - return -1; - } - - /* Advance */ - data += 512 - (uint32_t)((f->offset + len) % 512); - current_sector++; - } - - f->offset += len; - return len; -} - -static ssize_t rawmmcdev_read(struct _reent *r, void *fd, char *ptr, size_t len) { - rawmmcdev_file_t *f = (rawmmcdev_file_t *)fd; - rawmmcdev_device_t *device = f->device; - uint32_t device_sector_offset = (uint32_t)(device->offset / 512); - uint32_t sector_begin = (uint32_t)((device->offset + f->offset) / 512); /* NAND offset */ - uint32_t sector_end = (uint32_t)((device->offset + f->offset + len + 511) / 512); - uint32_t sector_end_aligned = sector_end - ((f->offset + len) % 512 != 0 ? 1 : 0); - uint32_t current_sector = sector_begin; - uint8_t *data = (uint8_t *)ptr; - - int no = 0; - - if (f->offset + len >= device->offset + device->size) { - len = (size_t)(device->size - f->offset); - } - - /* Change the partition, if needed. */ - no = sdmmc_select_partition(device->mmc, device->partition); - if (no != 0 && no != ENOTTY) { - r->_errno = no; - return -1; - } - - /* Unaligned at the start. */ - if (f->offset % 512 != 0) { - no = sdmmc_read(device->mmc, g_crypto_buffer, sector_begin, 1); - if (no != 0) { - r->_errno = no; - return -1; - } - if (device->encrypted) { - device->read_crypt_func(g_crypto_buffer, g_crypto_buffer, 512 * (sector_begin - device_sector_offset), 512, device->iv, device->crypt_flags); - } - memcpy(data, g_crypto_buffer + (f->offset % 512), len <= (512 - (uint32_t)(f->offset % 512)) ? len : 512 - (uint32_t)(f->offset % 512)); - - /* Advance */ - data += 512 - (uint32_t)(f->offset % 512); - 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) { - return 0; - } - - if (device->encrypted) { - size_t sectors_remaining = sector_end_aligned - current_sector; - for (size_t i = 0; i < len; i += sizeof(g_crypto_buffer)/512) { - size_t n = sectors_remaining <= sizeof(g_crypto_buffer)/512 ? sectors_remaining : sizeof(g_crypto_buffer)/512; - - no = sdmmc_read(device->mmc, g_crypto_buffer, current_sector, n); - if (no != 0) { - r->_errno = no; - return -1; - } - device->read_crypt_func(g_crypto_buffer, g_crypto_buffer, current_sector - device_sector_offset, 512 * n, device->iv, device->crypt_flags); - memcpy(data, g_crypto_buffer, 512 * n); - - data += 512 * n; - current_sector += n; - } - } else { - /* We can read everything aligned at once. */ - size_t sectors_remaining = sector_end_aligned - current_sector; - - no = sdmmc_read(device->mmc, data, current_sector, sectors_remaining); - if (no != 0) { - r->_errno = no; - return -1; - } - - data += 512 * sectors_remaining; - current_sector += sectors_remaining; - } - - /* Unaligned at the end, we need to read the sector and incorporate the data. */ - if (sector_end != sector_end_aligned) { - no = sdmmc_read(device->mmc, g_crypto_buffer, sector_end_aligned, 1); - if (no != 0) { - r->_errno = no; - return -1; - } - if (device->encrypted) { - device->read_crypt_func(g_crypto_buffer, g_crypto_buffer, 512 * (sector_end_aligned - device_sector_offset), 512, device->iv, device->crypt_flags); - } - memcpy(data, g_crypto_buffer, (uint32_t)((f->offset + len) % 512)); - - /* Advance */ - data += 512 - (uint32_t)(f->offset % 512); - current_sector++; - } - - f->offset += len; - return len; -} - -static off_t rawmmcdev_seek(struct _reent *r, void *fd, off_t pos, int whence) { - rawmmcdev_file_t *f = (rawmmcdev_file_t *)fd; - rawmmcdev_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->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; - } - - return (off_t)(pos + off); -} - -static void rawmmcdev_stat_impl(rawmmcdev_device_t *device, struct stat *st) { - memset(st, 0, sizeof(struct stat)); - st->st_size = (off_t)(device->size); - st->st_nlink = 1; - - st->st_blksize = 512; - 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 rawmmcdev_fstat(struct _reent *r, void *fd, struct stat *st) { - (void)r; - rawmmcdev_file_t *f = (rawmmcdev_file_t *)fd; - rawmmcdev_device_t *device = f->device; - rawmmcdev_stat_impl(device, st); - - return 0; -} - -static int rawmmcdev_stat(struct _reent *r, const char *file, struct stat *st) { - rawmmcdev_device_t *device = (rawmmcdev_device_t *)(r->deviceData); - if (strcmp(file, device->root_path) != 0) { - r->_errno = ENOENT; - return -1; - } - - rawmmcdev_stat_impl(device, st); - return 0; -} - -static int rawmmcdev_fsync(struct _reent *r, void *fd) { - /* Nothing to do. */ - (void)r; - (void)fd; - return 0; -} diff --git a/fusee/fusee-secondary/src/raw_mmc_dev.h b/fusee/fusee-secondary/src/raw_mmc_dev.h deleted file mode 100644 index d11d9206d..000000000 --- a/fusee/fusee-secondary/src/raw_mmc_dev.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef FUSEE_RAW_MMC_DEV_H -#define FUSEE_RAW_MMC_DEV_H - -#include -#include -#include -#include "sdmmc.h" - -#define RAWMMC_MAX_DEVICES 16 - -/* Note: only XTS, CTR and ECB are supported */ -typedef void (*rawmmc_crypt_func_t)(void *dst, const void *src, size_t offset, size_t len, const uint8_t *iv, uint64_t flags); - -int rawmmcdev_mount_device( - const char *name, - struct mmc *mmc, - enum sdmmc_partition partition, - uint64_t offset, - uint64_t size, - rawmmc_crypt_func_t read_crypt_func, - rawmmc_crypt_func_t write_crypt_func, - uint64_t crypt_flags, - const uint8_t *iv -); - -int rawmmcdev_mount_unencrypted_device( - const char *name, - struct mmc *mmc, - enum sdmmc_partition partition, - uint64_t offset, - uint64_t size -); - -int rawmmcdev_unmount_device(const char *name); -int rawmmcdev_unmount_all(void); - -#endif diff --git a/fusee/fusee-secondary/src/switch_fs.c b/fusee/fusee-secondary/src/switch_fs.c new file mode 100644 index 000000000..fb0daab2f --- /dev/null +++ b/fusee/fusee-secondary/src/switch_fs.c @@ -0,0 +1,248 @@ +#include +#include +#include +#include +#include "switch_fs.h" +#include "gpt.h" +#include "sdmmc.h" +#include "se.h" +#include "hwinit.h" + +static bool g_ahb_redirect_enabled = false; +static bool g_sd_mmc_initialized = false; +static bool g_nand_mmc_initialized = false; + +static struct mmc g_sd_mmc = {0}; +static struct mmc g_nand_mmc = {0}; + +typedef struct mmc_partition_info_t { + struct mmc *mmc; + enum sdmmc_controller controller; + enum sdmmc_partition mmc_partition; +} mmc_partition_info_t; + +static int mmc_partition_initialize(device_partition_t *devpart) { + mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct; + + if (devpart->read_cipher != NULL || devpart->write_cipher != NULL) { + devpart->crypto_work_buffer = memalign(16, devpart->sector_size * 16); + if (devpart->crypto_work_buffer == NULL) { + return ENOMEM; + } else { + devpart->crypto_work_buffer_num_sectors = devpart->sector_size * 16; + } + } else { + devpart->crypto_work_buffer = NULL; + devpart->crypto_work_buffer_num_sectors = 0; + } + + if (!g_ahb_redirect_enabled) { + mc_enable_ahb_redirect(); + g_ahb_redirect_enabled = true; + } + + if (mmcpart->mmc == &g_sd_mmc && !g_sd_mmc_initialized) { + int rc = sdmmc_init(mmcpart->mmc, mmcpart->controller); + if (rc == 0) { + g_sd_mmc_initialized = true; + } + return rc; + } else if (mmcpart->mmc == &g_nand_mmc && !g_nand_mmc_initialized) { + int rc = sdmmc_init(mmcpart->mmc, mmcpart->controller); + if (rc == 0) { + g_nand_mmc_initialized = true; + } + return rc; + } + + return 0; +} + +static void mmc_partition_finalize(device_partition_t *devpart) { + free(devpart->crypto_work_buffer); +} + +static enum sdmmc_partition g_current_emmc_partition = SDMMC_PARTITION_USER; + +static int mmc_partition_read(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors) { + mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct; + if (mmcpart->mmc == &g_nand_mmc && g_current_emmc_partition != mmcpart->mmc_partition) { + int rc = sdmmc_select_partition(mmcpart->mmc, mmcpart->mmc_partition); + if (rc != 0 && rc != ENOTTY) { + return rc; + } + g_current_emmc_partition = mmcpart->mmc_partition; + } + return sdmmc_read(mmcpart->mmc, dst, (uint32_t)(devpart->start_sector + sector), (uint32_t)num_sectors); +} + +static int mmc_partition_write(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors) { + mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct; + if (mmcpart->mmc == &g_nand_mmc && g_current_emmc_partition != mmcpart->mmc_partition) { + int rc = sdmmc_select_partition(mmcpart->mmc, mmcpart->mmc_partition); + if (rc != 0 && rc != ENOTTY) { + return rc; + } + g_current_emmc_partition = mmcpart->mmc_partition; + } + + return sdmmc_write(mmcpart->mmc, src, (uint32_t)(devpart->start_sector + sector), (uint32_t)num_sectors); +} + +static int switchfs_bis_crypto_decrypt(device_partition_t *devpart, uint64_t sector, uint64_t num_sectors) { + unsigned int keyslot = (unsigned int)devpart->crypto_flags; + (void)keyslot; + (void)sector; + (void)num_sectors; + /*devpart->crypto_work_buffer*/ + /* TODO */ + return 0; +} + +static int switchfs_bis_crypto_encrypt(device_partition_t *devpart, uint64_t sector, uint64_t num_sectors) { + unsigned int keyslot = (unsigned int)devpart->crypto_flags; + (void)keyslot; + (void)sector; + (void)num_sectors; + /*devpart->crypto_work_buffer*/ + /* TODO */ + return 0; +} + +static mmc_partition_info_t g_sd_mmcpart = { &g_sd_mmc, SWITCH_MICROSD, SDMMC_PARTITION_USER }; +static mmc_partition_info_t g_nand_boot0_mmcpart = { &g_sd_mmc, SWITCH_EMMC, SDMMC_PARTITION_BOOT0 }; +static mmc_partition_info_t g_nand_boot1_mmcpart = { &g_sd_mmc, SWITCH_EMMC, SDMMC_PARTITION_BOOT1 }; +static mmc_partition_info_t g_nand_user_mmcpart = { &g_sd_mmc, SWITCH_EMMC, SDMMC_PARTITION_USER }; + +static const device_partition_t g_mmc_devpart_template = { + .sector_size = 512, + .initializer = mmc_partition_initialize, + .finalizer = mmc_partition_finalize, + .reader = mmc_partition_read, + .writer = mmc_partition_write, +}; + +static int switchfs_mount_partition_gpt_callback(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk) { + (void)entry_offset; + (void)disk; + device_partition_t *parent = (device_partition_t *)param; + device_partition_t devpart = *parent; + char name_buffer[64]; + 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; + } known_partitions[] = { + {"PRODINFO", "prodinfo", false, true}, + {"PRODINFOF", "prodinfof", true, true}, + {"BCPKG2-1-Normal-Main", "bcpkg21", false, false}, + {"BCPKG2-2-Normal-Sub", "bcpkg22", false, false}, + {"BCPKG2-3-SafeMode-Main", "bcpkg23", false, false}, + {"BCPKG2-4-SafeMode-Sub", "bcpkg24", false, false}, + {"BCPKG2-5-Repair-Main", "bcpkg25", false, false}, + {"BCPKG2-6-Repair-Sub", "bcpkg26", false, false}, + {"SAFE", "safe", true, true}, + {"SYSTEM", "system", true, true}, + {"USER", "user", true, true}, + }; + + /* 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 - entry->first_lba; + if (parent->num_sectors < devpart.num_sectors) { + errno = EINVAL; + return -1; + } + + if (known_partitions[i].is_encrypted) { + devpart.read_cipher = switchfs_bis_crypto_decrypt; + devpart.write_cipher = switchfs_bis_crypto_encrypt; + } + + if (known_partitions[i].is_fat) { + rc = fsdev_mount_device(known_partitions[i].partition_name, &devpart, false); + if (rc == -1) { + return -1; + } + } else { + rc = rawdev_mount_device(known_partitions[i].partition_name, &devpart, false); + if (rc == -1) { + return -1; + } + } + } + } + + return 0; +} + +int switchfs_mount_all(void) { + device_partition_t model; + int rc; + FILE *rawnand; + + /* Initialize the SD card and its primary partition. */ + 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. */ + rc = fsdev_mount_device("sdmc", &model, true); + if (rc == -1) { + return -1; + } + + /* Boot0. */ + model = g_mmc_devpart_template; + model.device_struct = &g_nand_boot0_mmcpart; + model.start_sector = 0; + model.num_sectors = 0x184000 / model.sector_size; + rc = rawdev_mount_device("boot0", &model, true); + if (rc == -1) { + return -1; + } + + /* Boot1. */ + model = g_mmc_devpart_template; + model.device_struct = &g_nand_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; + } + + /* Raw NAND (excluding boot partitions), and its partitions. */ + model = g_mmc_devpart_template; + model = g_mmc_devpart_template; + model.device_struct = &g_nand_user_mmcpart; + model.start_sector = 0; + model.num_sectors = (32ull << 30) / model.sector_size; + rc = rawdev_mount_device("rawnand", &model, false); + if (rc == -1) { + return -1; + } + rawnand = fopen("rawnand:/", "rb"); + rc = gpt_iterate_through_entries(rawnand, model.sector_size, switchfs_mount_partition_gpt_callback, &model); + fclose(rawnand); + if (rc != 0) { + rc = fsdev_set_default_device("sdmc"); + } + return rc; +} + +int switchfs_unmount_all(void) { + return fsdev_unmount_all() != 0 || rawdev_unmount_all() != 0 ? -1 : 0; +} diff --git a/fusee/fusee-secondary/src/switch_fs.h b/fusee/fusee-secondary/src/switch_fs.h new file mode 100644 index 000000000..376694edc --- /dev/null +++ b/fusee/fusee-secondary/src/switch_fs.h @@ -0,0 +1,10 @@ +#ifndef FUSEE_SWITCH_FS_H +#define FUSEE_SWITCH_FS_H + +#include "fs_dev.h" +#include "raw_dev.h" + +int switchfs_mount_all(void); +int switchfs_unmount_all(void); + +#endif