mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +00:00
Redesign fs_dev, raw_dev, introducing device_partition and switch_fs.
In theory, one could mount an encrypted FAT partition itself coming from a disk image, etc.
This commit is contained in:
parent
396a646fa3
commit
4f50d412f5
18 changed files with 878 additions and 674 deletions
|
@ -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
|
||||
|
|
58
fusee/fusee-secondary/src/device_partition.c
Normal file
58
fusee/fusee-secondary/src/device_partition.c
Normal file
|
@ -0,0 +1,58 @@
|
|||
#include <string.h>
|
||||
#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);
|
||||
}
|
||||
}
|
48
fusee/fusee-secondary/src/device_partition.h
Normal file
48
fusee/fusee-secondary/src/device_partition.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#ifndef FUSEE_DEVICE_PARTITION_H
|
||||
#define FUSEE_DEVICE_PARTITION_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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
|
|
@ -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 <stdio.h>
|
||||
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]);
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#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
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include <errno.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -10,20 +10,11 @@
|
|||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) */
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#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();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#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. */
|
||||
}
|
||||
|
|
396
fusee/fusee-secondary/src/raw_dev.c
Normal file
396
fusee/fusee-secondary/src/raw_dev.c
Normal file
|
@ -0,0 +1,396 @@
|
|||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/iosupport.h>
|
||||
#include <sys/param.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
16
fusee/fusee-secondary/src/raw_dev.h
Normal file
16
fusee/fusee-secondary/src/raw_dev.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef FUSEE_RAW_DEV_H
|
||||
#define FUSEE_RAW_DEV_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#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
|
|
@ -1,485 +0,0 @@
|
|||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/iosupport.h>
|
||||
#include <sys/param.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
#ifndef FUSEE_RAW_MMC_DEV_H
|
||||
#define FUSEE_RAW_MMC_DEV_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#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
|
248
fusee/fusee-secondary/src/switch_fs.c
Normal file
248
fusee/fusee-secondary/src/switch_fs.c
Normal file
|
@ -0,0 +1,248 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <errno.h>
|
||||
#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;
|
||||
}
|
10
fusee/fusee-secondary/src/switch_fs.h
Normal file
10
fusee/fusee-secondary/src/switch_fs.h
Normal file
|
@ -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
|
Loading…
Reference in a new issue