emunand: Add multipart support for rawnand images in fusee
This commit is contained in:
@@ -131,6 +131,26 @@ static int mmc_partition_write(device_partition_t *devpart, const void *src, uin
|
||||
return sdmmc_device_write(mmcpart->device, (uint32_t)(devpart->start_sector + sector), (uint32_t)num_sectors, (void *)src) ? 0 : EIO;
|
||||
}
|
||||
|
||||
static int emummc_partition_initialize(device_partition_t *devpart) {
|
||||
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;
|
||||
}
|
||||
devpart->initialized = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void emummc_partition_finalize(device_partition_t *devpart) {
|
||||
free(devpart->crypto_work_buffer);
|
||||
}
|
||||
|
||||
static int nxfs_bis_crypto_decrypt(device_partition_t *devpart, uint64_t sector, uint64_t num_sectors) {
|
||||
unsigned int keyslot_a = 4; /* These keyslots are never used by exosphere, and should be safe. */
|
||||
unsigned int keyslot_b = 5;
|
||||
@@ -181,8 +201,8 @@ static const device_partition_t g_mmc_devpart_template = {
|
||||
|
||||
static const device_partition_t g_emummc_devpart_template = {
|
||||
.sector_size = 512,
|
||||
.initializer = NULL,
|
||||
.finalizer = NULL,
|
||||
.initializer = emummc_partition_initialize,
|
||||
.finalizer = emummc_partition_finalize,
|
||||
.reader = NULL,
|
||||
.writer = NULL,
|
||||
};
|
||||
@@ -268,6 +288,94 @@ static int nxfs_mount_partition_gpt_callback(const efi_entry_t *entry, void *par
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nxfs_mount_emu_partition_gpt_callback(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk, const char *origin_path, bool is_multipart, int num_parts, uint64_t part_limit) {
|
||||
(void)entry_offset;
|
||||
(void)disk;
|
||||
device_partition_t *parent = (device_partition_t *)param;
|
||||
device_partition_t devpart = *parent;
|
||||
char name_buffer[128];
|
||||
const uint16_t *utf16name = entry->name;
|
||||
uint32_t name_len;
|
||||
int rc;
|
||||
|
||||
static const struct {
|
||||
const char *partition_name;
|
||||
const char *mount_point;
|
||||
bool is_fat;
|
||||
bool is_encrypted;
|
||||
bool register_immediately;
|
||||
} known_partitions[] = {
|
||||
{"PRODINFO", "prodinfo", false, true, false},
|
||||
{"PRODINFOF", "prodinfof", true, true, false},
|
||||
{"BCPKG2-1-Normal-Main", "bcpkg21", false, false, true},
|
||||
{"BCPKG2-2-Normal-Sub", "bcpkg22", false, false, false},
|
||||
{"BCPKG2-3-SafeMode-Main", "bcpkg23", false, false, false},
|
||||
{"BCPKG2-4-SafeMode-Sub", "bcpkg24", false, false, false},
|
||||
{"BCPKG2-5-Repair-Main", "bcpkg25", false, false, false},
|
||||
{"BCPKG2-6-Repair-Sub", "bcpkg26", false, false, false},
|
||||
{"SAFE", "safe", true, true, false},
|
||||
{"SYSTEM", "system", true, true, false},
|
||||
{"USER", "user", true, true, false},
|
||||
};
|
||||
|
||||
/* Convert the partition name to ASCII, for comparison. */
|
||||
for (name_len = 0; name_len < sizeof(entry->name) && *utf16name != 0; name_len++) {
|
||||
name_buffer[name_len] = (char)*utf16name++;
|
||||
}
|
||||
name_buffer[name_len] = '\0';
|
||||
|
||||
/* Mount the partition, if we know about it. */
|
||||
for (size_t i = 0; i < sizeof(known_partitions)/sizeof(known_partitions[0]); i++) {
|
||||
if (strcmp(name_buffer, known_partitions[i].partition_name) == 0) {
|
||||
devpart.start_sector += entry->first_lba;
|
||||
devpart.num_sectors = (entry->last_lba + 1) - entry->first_lba;
|
||||
if (parent->num_sectors < devpart.num_sectors) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (known_partitions[i].is_encrypted) {
|
||||
devpart.read_cipher = nxfs_bis_crypto_decrypt;
|
||||
devpart.write_cipher = nxfs_bis_crypto_encrypt;
|
||||
devpart.crypto_mode = DevicePartitionCryptoMode_Xts;
|
||||
}
|
||||
|
||||
if (known_partitions[i].is_fat) {
|
||||
rc = fsdev_mount_device(known_partitions[i].mount_point, &devpart, false);
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
}
|
||||
if (known_partitions[i].register_immediately) {
|
||||
rc = fsdev_register_device(known_partitions[i].mount_point);
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (is_multipart) {
|
||||
rc = emudev_mount_device_multipart(known_partitions[i].mount_point, &devpart, origin_path, num_parts, part_limit);
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
rc = emudev_mount_device(known_partitions[i].mount_point, &devpart, origin_path);
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (known_partitions[i].register_immediately) {
|
||||
rc = emudev_register_device(known_partitions[i].mount_point);
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nxfs_mount_sd() {
|
||||
device_partition_t model;
|
||||
int rc;
|
||||
@@ -380,7 +488,7 @@ int nxfs_mount_emmc() {
|
||||
return rc;
|
||||
}
|
||||
|
||||
int nxfs_mount_emu_emmc(const char *emunand_boot0_path, const char *emunand_boot1_path, const char *emunand_rawnand_base_path) {
|
||||
int nxfs_mount_emu_emmc(const char *emunand_boot0_path, const char *emunand_boot1_path, const char *emunand_rawnand_base_path, int num_parts, uint64_t part_limit) {
|
||||
device_partition_t model;
|
||||
int rc;
|
||||
FILE *rawnand;
|
||||
@@ -436,7 +544,12 @@ int nxfs_mount_emu_emmc(const char *emunand_boot0_path, const char *emunand_boot
|
||||
model.num_sectors = (256ull << 30) / model.sector_size;
|
||||
|
||||
if (!is_exfat) {
|
||||
/* TODO: Use file concatenation for FAT32. */
|
||||
/* Mount emulated raw NAND device from multiple parts. */
|
||||
rc = emudev_mount_device_multipart("rawnand", &model, emunand_rawnand_base_path, num_parts, part_limit);
|
||||
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* Mount emulated raw NAND device. */
|
||||
rc = emudev_mount_device("rawnand", &model, emunand_rawnand_base_path);
|
||||
@@ -444,27 +557,27 @@ int nxfs_mount_emu_emmc(const char *emunand_boot0_path, const char *emunand_boot
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Register emulated raw NAND device. */
|
||||
rc = emudev_register_device("rawnand");
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Open emulated raw NAND device. */
|
||||
rawnand = fopen("rawnand:/", "rb");
|
||||
|
||||
if (rawnand == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Iterate the GPT and mount each emulated raw NAND partition. */
|
||||
rc = gpt_iterate_through_entries(rawnand, model.sector_size, nxfs_mount_partition_gpt_callback, &model);
|
||||
|
||||
/* Close emulated raw NAND device. */
|
||||
fclose(rawnand);
|
||||
}
|
||||
|
||||
/* Register emulated raw NAND device. */
|
||||
rc = emudev_register_device("rawnand");
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Open emulated raw NAND device. */
|
||||
rawnand = fopen("rawnand:/", "rb");
|
||||
|
||||
if (rawnand == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Iterate the GPT and mount each emulated raw NAND partition. */
|
||||
rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, emunand_rawnand_base_path, !is_exfat, num_parts, part_limit);
|
||||
|
||||
/* Close emulated raw NAND device. */
|
||||
fclose(rawnand);
|
||||
|
||||
/* All emulated devices are ready. */
|
||||
if (rc == 0) {
|
||||
g_emudev_ready = true;
|
||||
|
||||
Reference in New Issue
Block a user