mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
emummc: implement SD partition mode; clean up and rename emunand code
This commit is contained in:
parent
4c4f037361
commit
0986b48a55
8 changed files with 274 additions and 136 deletions
|
@ -4,9 +4,9 @@ stage2_path = atmosphere/fusee-secondary.bin
|
||||||
stage2_addr = 0xF0000000
|
stage2_addr = 0xF0000000
|
||||||
stage2_entrypoint = 0xF0000000
|
stage2_entrypoint = 0xF0000000
|
||||||
|
|
||||||
[emunand]
|
[emummc]
|
||||||
emunand_enabled = 0
|
emummc_enabled = 0
|
||||||
emunand_path = atmosphere/emunand
|
emummc_path = atmosphere/emummc
|
||||||
|
|
||||||
[exosphere]
|
[exosphere]
|
||||||
; Note: Disabling debugmode will cause parts of ams.tma to not work, in the future.
|
; Note: Disabling debugmode will cause parts of ams.tma to not work, in the future.
|
||||||
|
|
|
@ -88,27 +88,33 @@ int emu_device_partition_read_data(device_partition_t *devpart, void *dst, uint6
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle data in multiple parts, if necessary. */
|
/* Prepare the right file path if using file mode. */
|
||||||
if (num_parts > 0) {
|
if (devpart->emu_use_file && (origin_path != NULL)) {
|
||||||
int target_part = 0;
|
/* Handle data in multiple parts, if necessary. */
|
||||||
uint64_t data_offset = sector * devpart->sector_size;
|
if (num_parts > 0) {
|
||||||
|
int target_part = 0;
|
||||||
if (data_offset >= part_limit) {
|
uint64_t data_offset = sector * devpart->sector_size;
|
||||||
uint64_t data_offset_aligned = (data_offset + (part_limit - 1)) & ~(part_limit - 1);
|
|
||||||
target_part = (data_offset_aligned == data_offset) ? (data_offset / part_limit) : (data_offset_aligned / part_limit) - 1;
|
|
||||||
target_sector = (data_offset - (target_part * part_limit)) / devpart->sector_size;
|
|
||||||
|
|
||||||
/* Target part is invalid. */
|
if (data_offset >= part_limit) {
|
||||||
if (target_part > num_parts) {
|
uint64_t data_offset_aligned = (data_offset + (part_limit - 1)) & ~(part_limit - 1);
|
||||||
return -1;
|
target_part = (data_offset_aligned == data_offset) ? (data_offset / part_limit) : (data_offset_aligned / part_limit) - 1;
|
||||||
|
target_sector = (data_offset - (target_part * part_limit)) / devpart->sector_size;
|
||||||
|
|
||||||
|
/* Target part is invalid. */
|
||||||
|
if (target_part > num_parts) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Treat the path as a folder with each part inside. */
|
||||||
|
snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", origin_path, target_part);
|
||||||
|
} else {
|
||||||
|
target_sector = sector;
|
||||||
|
strcpy(target_path, origin_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Treat the path as a folder with each part inside. */
|
/* Update the target file path. */
|
||||||
snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", origin_path, target_part);
|
devpart->emu_file_path = target_path;
|
||||||
} else {
|
|
||||||
target_sector = sector;
|
|
||||||
strcpy(target_path, origin_path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read the partition data. */
|
/* Read the partition data. */
|
||||||
|
@ -116,11 +122,8 @@ int emu_device_partition_read_data(device_partition_t *devpart, void *dst, uint6
|
||||||
for (uint64_t i = 0; i < num_sectors; i += devpart->crypto_work_buffer_num_sectors) {
|
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;
|
uint64_t n = (i + devpart->crypto_work_buffer_num_sectors > num_sectors) ? (num_sectors - i) : devpart->crypto_work_buffer_num_sectors;
|
||||||
|
|
||||||
/* Read partition data using our backing file. */
|
/* Read partition data. */
|
||||||
FILE *origin = fopen(target_path, "rb");
|
rc = devpart->reader(devpart, devpart->crypto_work_buffer, target_sector + i, n);
|
||||||
fseek(origin, (target_sector + i) * devpart->sector_size, SEEK_CUR);
|
|
||||||
rc = (fread(dst, devpart->sector_size, n, origin) > 0) ? 0 : -1;
|
|
||||||
fclose(origin);
|
|
||||||
|
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -137,11 +140,8 @@ int emu_device_partition_read_data(device_partition_t *devpart, void *dst, uint6
|
||||||
memcpy(dst + (size_t)(devpart->sector_size * i), devpart->crypto_work_buffer, (size_t)(devpart->sector_size * n));
|
memcpy(dst + (size_t)(devpart->sector_size * i), devpart->crypto_work_buffer, (size_t)(devpart->sector_size * n));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Read partition data using our backing file. */
|
/* Read partition data. */
|
||||||
FILE *origin = fopen(target_path, "rb");
|
rc = devpart->reader(devpart, dst, target_sector, num_sectors);
|
||||||
fseek(origin, target_sector * devpart->sector_size, SEEK_CUR);
|
|
||||||
rc = (fread(dst, devpart->sector_size, num_sectors, origin) > 0) ? 0 : -1;
|
|
||||||
fclose(origin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -161,27 +161,33 @@ int emu_device_partition_write_data(device_partition_t *devpart, const void *src
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle data in multiple parts, if necessary. */
|
/* Prepare the right file path if using file mode. */
|
||||||
if (num_parts > 0) {
|
if (devpart->emu_use_file && (origin_path != NULL)) {
|
||||||
int target_part = 0;
|
/* Handle data in multiple parts, if necessary. */
|
||||||
uint64_t data_offset = sector * devpart->sector_size;
|
if (num_parts > 0) {
|
||||||
|
int target_part = 0;
|
||||||
if (data_offset >= part_limit) {
|
uint64_t data_offset = sector * devpart->sector_size;
|
||||||
uint64_t data_offset_aligned = (data_offset + (part_limit - 1)) & ~(part_limit - 1);
|
|
||||||
target_part = (data_offset_aligned == data_offset) ? (data_offset / part_limit) : (data_offset_aligned / part_limit) - 1;
|
|
||||||
target_sector = (data_offset - (target_part * part_limit)) / devpart->sector_size;
|
|
||||||
|
|
||||||
/* Target part is invalid. */
|
if (data_offset >= part_limit) {
|
||||||
if (target_part > num_parts) {
|
uint64_t data_offset_aligned = (data_offset + (part_limit - 1)) & ~(part_limit - 1);
|
||||||
return -1;
|
target_part = (data_offset_aligned == data_offset) ? (data_offset / part_limit) : (data_offset_aligned / part_limit) - 1;
|
||||||
|
target_sector = (data_offset - (target_part * part_limit)) / devpart->sector_size;
|
||||||
|
|
||||||
|
/* Target part is invalid. */
|
||||||
|
if (target_part > num_parts) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Treat the path as a folder with each part inside. */
|
||||||
|
snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", origin_path, target_part);
|
||||||
|
} else {
|
||||||
|
target_sector = sector;
|
||||||
|
strcpy(target_path, origin_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Treat the path as a folder with each part inside. */
|
/* Update the target file path. */
|
||||||
snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", origin_path, target_part);
|
devpart->emu_file_path = target_path;
|
||||||
} else {
|
|
||||||
target_sector = sector;
|
|
||||||
strcpy(target_path, origin_path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write the partition data. */
|
/* Write the partition data. */
|
||||||
|
@ -199,22 +205,16 @@ int emu_device_partition_write_data(device_partition_t *devpart, const void *src
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write partition data using our backing file. */
|
/* Write partition data. */
|
||||||
FILE *origin = fopen(target_path, "wb");
|
rc = devpart->writer(devpart, devpart->crypto_work_buffer, target_sector + i, n);
|
||||||
fseek(origin, (target_sector + i) * devpart->sector_size, SEEK_CUR);
|
|
||||||
rc = (fwrite(src, devpart->sector_size, n, origin) > 0) ? 0 : -1;
|
|
||||||
fclose(origin);
|
|
||||||
|
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Write partition data using our backing file. */
|
/* Write partition data. */
|
||||||
FILE *origin = fopen(target_path, "wb");
|
rc = devpart->writer(devpart, src, sector, num_sectors);
|
||||||
fseek(origin, sector * devpart->sector_size, SEEK_CUR);
|
|
||||||
rc = (fwrite(src, devpart->sector_size, num_sectors, origin) > 0) ? 0 : -1;
|
|
||||||
fclose(origin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
@ -65,6 +65,9 @@ typedef struct device_partition_t {
|
||||||
uint8_t __attribute__((aligned(16))) keys[DEVPART_KEY_MAX][DEVPART_KEY_MAX_SIZE]; /* Key. */
|
uint8_t __attribute__((aligned(16))) keys[DEVPART_KEY_MAX][DEVPART_KEY_MAX_SIZE]; /* Key. */
|
||||||
uint8_t __attribute__((aligned(16))) iv[DEVPART_IV_MAX_SIZE]; /* IV. */
|
uint8_t __attribute__((aligned(16))) iv[DEVPART_IV_MAX_SIZE]; /* IV. */
|
||||||
bool initialized;
|
bool initialized;
|
||||||
|
|
||||||
|
char *emu_file_path; /* Emulated device file path. */
|
||||||
|
bool emu_use_file;
|
||||||
} device_partition_t;
|
} device_partition_t;
|
||||||
|
|
||||||
int device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors);
|
int device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors);
|
||||||
|
|
|
@ -114,7 +114,11 @@ int emudev_mount_device(const char *name, const device_partition_t *devpart, con
|
||||||
strcpy(device->name, name);
|
strcpy(device->name, name);
|
||||||
strcpy(device->root_path, name);
|
strcpy(device->root_path, name);
|
||||||
strcat(device->root_path, ":/");
|
strcat(device->root_path, ":/");
|
||||||
strcpy(device->origin_path, origin_path);
|
|
||||||
|
/* Copy the file path for file mode. */
|
||||||
|
if (devpart->emu_use_file)
|
||||||
|
strcpy(device->origin_path, origin_path);
|
||||||
|
|
||||||
device->num_parts = 0;
|
device->num_parts = 0;
|
||||||
device->part_limit = 0;
|
device->part_limit = 0;
|
||||||
|
|
||||||
|
|
|
@ -100,17 +100,21 @@ static const uint8_t dev_pkc_modulus[0x100] = {
|
||||||
0xD5, 0x52, 0xDA, 0xEC, 0x41, 0xA4, 0xAD, 0x7B, 0x36, 0x86, 0x18, 0xB4, 0x5B, 0xD1, 0x30, 0xBB
|
0xD5, 0x52, 0xDA, 0xEC, 0x41, 0xA4, 0xAD, 0x7B, 0x36, 0x86, 0x18, 0xB4, 0x5B, 0xD1, 0x30, 0xBB
|
||||||
};
|
};
|
||||||
|
|
||||||
static int emunand_ini_handler(void *user, const char *section, const char *name, const char *value) {
|
static int emummc_ini_handler(void *user, const char *section, const char *name, const char *value) {
|
||||||
emunand_config_t *emunand_cfg = (emunand_config_t *)user;
|
emummc_config_t *emummc_cfg = (emummc_config_t *)user;
|
||||||
if (strcmp(section, "emunand") == 0) {
|
if (strcmp(section, "emummc") == 0) {
|
||||||
if (strcmp(name, EMUNAND_ENABLED_KEY) == 0) {
|
if (strcmp(name, EMUMMC_ENABLED_KEY) == 0) {
|
||||||
int tmp = 0;
|
int tmp = 0;
|
||||||
sscanf(value, "%d", &tmp);
|
sscanf(value, "%d", &tmp);
|
||||||
emunand_cfg->enabled = (tmp != 0);
|
emummc_cfg->enabled = (tmp != 0);
|
||||||
}
|
}
|
||||||
if (strcmp(name, EMUNAND_PATH_KEY) == 0) {
|
if (strcmp(name, EMUMMC_SECTOR_KEY) == 0) {
|
||||||
strncpy(emunand_cfg->path, value, sizeof(emunand_cfg->path) - 1);
|
uint64_t sector = 0;
|
||||||
emunand_cfg->path[sizeof(emunand_cfg->path) - 1] = '\0';
|
sscanf(value, "%llu", §or);
|
||||||
|
emummc_cfg->sector = sector;
|
||||||
|
} else if (strcmp(name, EMUMMC_PATH_KEY) == 0) {
|
||||||
|
strncpy(emummc_cfg->path, value, sizeof(emummc_cfg->path) - 1);
|
||||||
|
emummc_cfg->path[sizeof(emummc_cfg->path) - 1] = '\0';
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -204,59 +208,63 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool nxboot_configure_emunand() {
|
static bool nxboot_configure_emummc() {
|
||||||
emunand_config_t emunand_cfg = {.enabled = false, .path = ""};
|
emummc_config_t emummc_cfg = {.enabled = false, .sector = -1, .path = ""};
|
||||||
|
|
||||||
/* Load emunand settings from BCT.ini file. */
|
/* Load emummc settings from BCT.ini file. */
|
||||||
if (ini_parse_string(get_loader_ctx()->bct0, emunand_ini_handler, &emunand_cfg) < 0) {
|
if (ini_parse_string(get_loader_ctx()->bct0, emummc_ini_handler, &emummc_cfg) < 0) {
|
||||||
fatal_error("[NXBOOT] Failed to parse BCT.ini!\n");
|
fatal_error("[NXBOOT] Failed to parse BCT.ini!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (emunand_cfg.enabled) {
|
if (emummc_cfg.enabled) {
|
||||||
int num_parts = 0;
|
if (emummc_cfg.sector >= 0) {
|
||||||
uint64_t part_limit = 0;
|
/* Mount emulated NAND from SD card partition. */
|
||||||
char emunand_boot0_path[0x300 + 1] = {0};
|
if (nxfs_mount_emummc_partition(emummc_cfg.sector) < 0) {
|
||||||
char emunand_boot1_path[0x300 + 1] = {0};
|
fatal_error("[NXBOOT] Failed to mount EmuMMC from SD card partition!\n");
|
||||||
char emunand_rawnand_path[0x300 + 1] = {0};
|
|
||||||
|
|
||||||
/* Check if the supplied path is valid. */
|
|
||||||
if (!is_valid_folder(emunand_cfg.path)) {
|
|
||||||
fatal_error("[NXBOOT] Failed to find EmuNAND folder!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Prepare expected file paths. */
|
|
||||||
snprintf(emunand_boot0_path, sizeof(emunand_boot0_path) - 1, "sdmc:/%s/%s", emunand_cfg.path, "boot0");
|
|
||||||
snprintf(emunand_boot1_path, sizeof(emunand_boot1_path) - 1, "sdmc:/%s/%s", emunand_cfg.path, "boot1");
|
|
||||||
|
|
||||||
/* Check if boot0 and boot1 image files are present. */
|
|
||||||
if (!is_valid_file(emunand_boot0_path) || !is_valid_file(emunand_boot1_path)) {
|
|
||||||
fatal_error("[NXBOOT] Failed to find EmuNAND boot0/boot1 image files!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find raw image files (single or multi part). */
|
|
||||||
for (int i = 0; i < 64; i++) {
|
|
||||||
snprintf(emunand_rawnand_path, sizeof(emunand_rawnand_path) - 1, "sdmc:/%s/%02d", emunand_cfg.path, i);
|
|
||||||
if (is_valid_file(emunand_rawnand_path)) {
|
|
||||||
if (i == 0) {
|
|
||||||
/* The size of the first file should tell us the part limit. */
|
|
||||||
part_limit = get_file_size(emunand_rawnand_path);
|
|
||||||
}
|
|
||||||
num_parts++;
|
|
||||||
}
|
}
|
||||||
}
|
} else if (is_valid_folder(emummc_cfg.path)) {
|
||||||
|
int num_parts = 0;
|
||||||
/* Check if at least one raw image file is present. */
|
uint64_t part_limit = 0;
|
||||||
if ((num_parts == 0) || (part_limit == 0)) {
|
char emummc_boot0_path[0x300 + 1] = {0};
|
||||||
fatal_error("[NXBOOT] Failed to find EmuNAND raw image files!\n");
|
char emummc_boot1_path[0x300 + 1] = {0};
|
||||||
}
|
char emummc_rawnand_path[0x300 + 1] = {0};
|
||||||
|
|
||||||
/* Mount emulated NAND. */
|
/* Prepare expected file paths. */
|
||||||
if (nxfs_mount_emu_emmc(emunand_cfg.path, num_parts, part_limit) < 0) {
|
snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "sdmc:/%s/%s", emummc_cfg.path, "boot0");
|
||||||
fatal_error("[NXBOOT] Failed to mount emulated eMMC!\n");
|
snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "sdmc:/%s/%s", emummc_cfg.path, "boot1");
|
||||||
|
|
||||||
|
/* Check if boot0 and boot1 image files are present. */
|
||||||
|
if (!is_valid_file(emummc_boot0_path) || !is_valid_file(emummc_boot1_path)) {
|
||||||
|
fatal_error("[NXBOOT] Failed to find EmuMMC boot0/boot1 image files!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find raw image files (single or multi part). */
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
snprintf(emummc_rawnand_path, sizeof(emummc_rawnand_path) - 1, "sdmc:/%s/%02d", emummc_cfg.path, i);
|
||||||
|
if (is_valid_file(emummc_rawnand_path)) {
|
||||||
|
if (i == 0) {
|
||||||
|
/* The size of the first file should tell us the part limit. */
|
||||||
|
part_limit = get_file_size(emummc_rawnand_path);
|
||||||
|
}
|
||||||
|
num_parts++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if at least one raw image file is present. */
|
||||||
|
if ((num_parts == 0) || (part_limit == 0)) {
|
||||||
|
fatal_error("[NXBOOT] Failed to find EmuMMC raw image files!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mount emulated NAND from files. */
|
||||||
|
if (nxfs_mount_emummc_file(emummc_cfg.path, num_parts, part_limit) < 0) {
|
||||||
|
fatal_error("[NXBOOT] Failed to mount EmuMMC from files!\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fatal_error("[NXBOOT] Invalid EmuMMC setting!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return emunand_cfg.enabled;
|
return emummc_cfg.enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nxboot_configure_exosphere(uint32_t target_firmware, unsigned int keygen_type) {
|
static void nxboot_configure_exosphere(uint32_t target_firmware, unsigned int keygen_type) {
|
||||||
|
@ -417,8 +425,8 @@ uint32_t nxboot_main(void) {
|
||||||
FILE *boot0, *pk2file;
|
FILE *boot0, *pk2file;
|
||||||
void *exosphere_memaddr;
|
void *exosphere_memaddr;
|
||||||
|
|
||||||
/* Configure emunand or mount the real NAND. */
|
/* Configure emummc or mount the real NAND. */
|
||||||
if (!nxboot_configure_emunand()) {
|
if (!nxboot_configure_emummc()) {
|
||||||
if (nxfs_mount_emmc() < 0) {
|
if (nxfs_mount_emmc() < 0) {
|
||||||
fatal_error("[NXBOOT] Failed to mount eMMC!\n");
|
fatal_error("[NXBOOT] Failed to mount eMMC!\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,15 @@
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#define EMUNAND_ENABLED_KEY "emunand_enabled"
|
#define EMUMMC_ENABLED_KEY "emummc_enabled"
|
||||||
#define EMUNAND_PATH_KEY "emunand_path"
|
#define EMUMMC_SECTOR_KEY "emummc_sector"
|
||||||
|
#define EMUMMC_PATH_KEY "emummc_path"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool enabled;
|
bool enabled;
|
||||||
|
uint64_t sector;
|
||||||
char path[0x100];
|
char path[0x100];
|
||||||
} emunand_config_t;
|
} emummc_config_t;
|
||||||
|
|
||||||
#define MAILBOX_NX_BOOTLOADER_BASE_100_620 0x40002E00
|
#define MAILBOX_NX_BOOTLOADER_BASE_100_620 0x40002E00
|
||||||
#define MAILBOX_NX_BOOTLOADER_BASE_700 0x40000000
|
#define MAILBOX_NX_BOOTLOADER_BASE_700 0x40000000
|
||||||
|
|
|
@ -180,6 +180,36 @@ static void emummc_partition_finalize(device_partition_t *devpart) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int emummc_partition_read(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors) {
|
||||||
|
if (devpart->emu_use_file) {
|
||||||
|
/* Read partition data using our backing file. */
|
||||||
|
int rc = 0;
|
||||||
|
FILE *emummc_file = fopen(devpart->emu_file_path, "rb");
|
||||||
|
fseek(emummc_file, sector * devpart->sector_size, SEEK_CUR);
|
||||||
|
rc = (fread(dst, devpart->sector_size, num_sectors, emummc_file) > 0) ? 0 : -1;
|
||||||
|
fclose(emummc_file);
|
||||||
|
return rc;
|
||||||
|
} else {
|
||||||
|
/* Read partition data directly from the SD card device. */
|
||||||
|
return sdmmc_device_read(&g_sd_device, (uint32_t)(devpart->start_sector + sector), (uint32_t)num_sectors, dst) ? 0 : EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int emummc_partition_write(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors) {
|
||||||
|
if (devpart->emu_use_file) {
|
||||||
|
/* Write partition data using our backing file. */
|
||||||
|
int rc = 0;
|
||||||
|
FILE *emummc_file = fopen(devpart->emu_file_path, "wb");
|
||||||
|
fseek(emummc_file, sector * devpart->sector_size, SEEK_CUR);
|
||||||
|
rc = (fwrite(src, devpart->sector_size, num_sectors, emummc_file) > 0) ? 0 : -1;
|
||||||
|
fclose(emummc_file);
|
||||||
|
return rc;
|
||||||
|
} else {
|
||||||
|
/* Write partition data directly to the SD card device. */
|
||||||
|
return sdmmc_device_write(&g_sd_device, (uint32_t)(devpart->start_sector + sector), (uint32_t)num_sectors, (void *)src) ? 0 : EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int nxfs_bis_crypto_decrypt(device_partition_t *devpart, uint64_t sector, uint64_t num_sectors) {
|
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_a = 4; /* These keyslots are never used by exosphere, and should be safe. */
|
||||||
unsigned int keyslot_b = 5;
|
unsigned int keyslot_b = 5;
|
||||||
|
@ -232,8 +262,8 @@ static const device_partition_t g_emummc_devpart_template = {
|
||||||
.sector_size = 512,
|
.sector_size = 512,
|
||||||
.initializer = emummc_partition_initialize,
|
.initializer = emummc_partition_initialize,
|
||||||
.finalizer = emummc_partition_finalize,
|
.finalizer = emummc_partition_finalize,
|
||||||
.reader = NULL,
|
.reader = emummc_partition_read,
|
||||||
.writer = NULL,
|
.writer = emummc_partition_write,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int nxfs_mount_partition_gpt_callback(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk) {
|
static int nxfs_mount_partition_gpt_callback(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk) {
|
||||||
|
@ -517,14 +547,101 @@ int nxfs_mount_emmc() {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nxfs_mount_emu_emmc(const char *emunand_path, int num_parts, uint64_t part_limit) {
|
int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
|
||||||
|
device_partition_t model;
|
||||||
|
int rc;
|
||||||
|
FILE *rawnand;
|
||||||
|
|
||||||
|
/* Setup an emulation template for boot0. */
|
||||||
|
model = g_emummc_devpart_template;
|
||||||
|
model.start_sector = emummc_start_sector;
|
||||||
|
model.num_sectors = 0x184000 / model.sector_size;
|
||||||
|
model.emu_use_file = false;
|
||||||
|
|
||||||
|
/* Mount emulated boot0 device. */
|
||||||
|
rc = emudev_mount_device("boot0", &model, NULL);
|
||||||
|
|
||||||
|
/* Failed to mount boot0 device. */
|
||||||
|
if (rc == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register emulated boot0 device. */
|
||||||
|
rc = emudev_register_device("boot0");
|
||||||
|
|
||||||
|
/* Failed to register boot0 device. */
|
||||||
|
if (rc == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup an emulation template for boot1. */
|
||||||
|
model = g_emummc_devpart_template;
|
||||||
|
model.start_sector = emummc_start_sector;
|
||||||
|
model.num_sectors = 0x80000 / model.sector_size;
|
||||||
|
model.emu_use_file = false;
|
||||||
|
|
||||||
|
/* Mount emulated boot1 device. */
|
||||||
|
rc = emudev_mount_device("boot1", &model, NULL);
|
||||||
|
|
||||||
|
/* Failed to mount boot1. */
|
||||||
|
if (rc == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Don't register emulated boot1 for now. */
|
||||||
|
|
||||||
|
/* Setup a template for raw NAND. */
|
||||||
|
model = g_emummc_devpart_template;
|
||||||
|
model.start_sector = emummc_start_sector;
|
||||||
|
model.num_sectors = (256ull << 30) / model.sector_size;
|
||||||
|
model.emu_use_file = false;
|
||||||
|
|
||||||
|
/* Mount emulated raw NAND device. */
|
||||||
|
rc = emudev_mount_device("rawnand", &model, NULL);
|
||||||
|
|
||||||
|
/* Failed to mount raw NAND. */
|
||||||
|
if (rc == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register emulated raw NAND device. */
|
||||||
|
rc = emudev_register_device("rawnand");
|
||||||
|
|
||||||
|
/* Failed to register raw NAND device. */
|
||||||
|
if (rc == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open emulated raw NAND device. */
|
||||||
|
rawnand = fopen("rawnand:/", "rb");
|
||||||
|
|
||||||
|
/* Failed to open emulated raw NAND device. */
|
||||||
|
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, NULL, false, 0, 0);
|
||||||
|
|
||||||
|
/* Close emulated raw NAND device. */
|
||||||
|
fclose(rawnand);
|
||||||
|
|
||||||
|
/* All emulated devices are ready. */
|
||||||
|
if (rc == 0) {
|
||||||
|
g_emudev_ready = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part_limit) {
|
||||||
device_partition_t model;
|
device_partition_t model;
|
||||||
int rc;
|
int rc;
|
||||||
FILE *rawnand;
|
FILE *rawnand;
|
||||||
bool is_exfat;
|
bool is_exfat;
|
||||||
char emunand_boot0_path[0x300 + 1] = {0};
|
char emummc_boot0_path[0x300 + 1] = {0};
|
||||||
char emunand_boot1_path[0x300 + 1] = {0};
|
char emummc_boot1_path[0x300 + 1] = {0};
|
||||||
char emunand_rawnand_path[0x300 + 1] = {0};
|
char emummc_rawnand_path[0x300 + 1] = {0};
|
||||||
|
|
||||||
/* Check if the SD card is EXFAT formatted. */
|
/* Check if the SD card is EXFAT formatted. */
|
||||||
rc = fsdev_is_exfat("sdmc");
|
rc = fsdev_is_exfat("sdmc");
|
||||||
|
@ -538,7 +655,7 @@ int nxfs_mount_emu_emmc(const char *emunand_path, int num_parts, uint64_t part_l
|
||||||
is_exfat = (rc == 1);
|
is_exfat = (rc == 1);
|
||||||
|
|
||||||
/* We want a folder with the archive bit set. */
|
/* We want a folder with the archive bit set. */
|
||||||
rc = fsdev_get_attr(emunand_path);
|
rc = fsdev_get_attr(emummc_path);
|
||||||
|
|
||||||
/* Failed to get file DOS attributes. */
|
/* Failed to get file DOS attributes. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
|
@ -553,7 +670,7 @@ int nxfs_mount_emu_emmc(const char *emunand_path, int num_parts, uint64_t part_l
|
||||||
/* Check if the archive bit is not set. */
|
/* Check if the archive bit is not set. */
|
||||||
if (!(rc & AM_ARC)) {
|
if (!(rc & AM_ARC)) {
|
||||||
/* Try to set the archive bit. */
|
/* Try to set the archive bit. */
|
||||||
rc = fsdev_set_attr(emunand_path, AM_ARC, AM_ARC);
|
rc = fsdev_set_attr(emummc_path, AM_ARC, AM_ARC);
|
||||||
|
|
||||||
/* Failed to set file DOS attributes. */
|
/* Failed to set file DOS attributes. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
|
@ -565,12 +682,13 @@ int nxfs_mount_emu_emmc(const char *emunand_path, int num_parts, uint64_t part_l
|
||||||
model = g_emummc_devpart_template;
|
model = g_emummc_devpart_template;
|
||||||
model.start_sector = 0;
|
model.start_sector = 0;
|
||||||
model.num_sectors = 0x184000 / model.sector_size;
|
model.num_sectors = 0x184000 / model.sector_size;
|
||||||
|
model.emu_use_file = true;
|
||||||
|
|
||||||
/* Prepare boot0 file path. */
|
/* Prepare boot0 file path. */
|
||||||
snprintf(emunand_boot0_path, sizeof(emunand_boot0_path) - 1, "sdmc:/%s/%s", emunand_path, "boot0");
|
snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "sdmc:/%s/%s", emummc_path, "boot0");
|
||||||
|
|
||||||
/* Mount emulated boot0 device. */
|
/* Mount emulated boot0 device. */
|
||||||
rc = emudev_mount_device("boot0", &model, emunand_boot0_path);
|
rc = emudev_mount_device("boot0", &model, emummc_boot0_path);
|
||||||
|
|
||||||
/* Failed to mount boot0 device. */
|
/* Failed to mount boot0 device. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
|
@ -589,12 +707,13 @@ int nxfs_mount_emu_emmc(const char *emunand_path, int num_parts, uint64_t part_l
|
||||||
model = g_emummc_devpart_template;
|
model = g_emummc_devpart_template;
|
||||||
model.start_sector = 0;
|
model.start_sector = 0;
|
||||||
model.num_sectors = 0x80000 / model.sector_size;
|
model.num_sectors = 0x80000 / model.sector_size;
|
||||||
|
model.emu_use_file = true;
|
||||||
|
|
||||||
/* Prepare boot1 file path. */
|
/* Prepare boot1 file path. */
|
||||||
snprintf(emunand_boot1_path, sizeof(emunand_boot1_path) - 1, "sdmc:/%s/%s", emunand_path, "boot1");
|
snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "sdmc:/%s/%s", emummc_path, "boot1");
|
||||||
|
|
||||||
/* Mount emulated boot1 device. */
|
/* Mount emulated boot1 device. */
|
||||||
rc = emudev_mount_device("boot1", &model, emunand_boot1_path);
|
rc = emudev_mount_device("boot1", &model, emummc_boot1_path);
|
||||||
|
|
||||||
/* Failed to mount boot1. */
|
/* Failed to mount boot1. */
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
|
@ -607,15 +726,16 @@ int nxfs_mount_emu_emmc(const char *emunand_path, int num_parts, uint64_t part_l
|
||||||
model = g_emummc_devpart_template;
|
model = g_emummc_devpart_template;
|
||||||
model.start_sector = 0;
|
model.start_sector = 0;
|
||||||
model.num_sectors = (256ull << 30) / model.sector_size;
|
model.num_sectors = (256ull << 30) / model.sector_size;
|
||||||
|
model.emu_use_file = true;
|
||||||
|
|
||||||
/* Prepare single raw NAND file path. */
|
/* Prepare single raw NAND file path. */
|
||||||
snprintf(emunand_rawnand_path, sizeof(emunand_rawnand_path) - 1, "sdmc:/%s/%02d", emunand_path, 0);
|
snprintf(emummc_rawnand_path, sizeof(emummc_rawnand_path) - 1, "sdmc:/%s/%02d", emummc_path, 0);
|
||||||
|
|
||||||
/* Mount emulated raw NAND device from single or multiple parts. */
|
/* Mount emulated raw NAND device from single or multiple parts. */
|
||||||
if (!is_exfat) {
|
if (!is_exfat) {
|
||||||
rc = emudev_mount_device_multipart("rawnand", &model, emunand_path, num_parts, part_limit);
|
rc = emudev_mount_device_multipart("rawnand", &model, emummc_path, num_parts, part_limit);
|
||||||
} else {
|
} else {
|
||||||
rc = emudev_mount_device("rawnand", &model, emunand_rawnand_path);
|
rc = emudev_mount_device("rawnand", &model, emummc_rawnand_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Failed to mount raw NAND. */
|
/* Failed to mount raw NAND. */
|
||||||
|
@ -641,9 +761,9 @@ int nxfs_mount_emu_emmc(const char *emunand_path, int num_parts, uint64_t part_l
|
||||||
|
|
||||||
/* Iterate the GPT and mount each emulated raw NAND partition. */
|
/* Iterate the GPT and mount each emulated raw NAND partition. */
|
||||||
if (!is_exfat) {
|
if (!is_exfat) {
|
||||||
rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, emunand_path, true, num_parts, part_limit);
|
rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, emummc_path, true, num_parts, part_limit);
|
||||||
} else {
|
} else {
|
||||||
rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, emunand_rawnand_path, false, num_parts, part_limit);
|
rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, emummc_rawnand_path, false, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Close emulated raw NAND device. */
|
/* Close emulated raw NAND device. */
|
||||||
|
@ -681,7 +801,7 @@ int nxfs_unmount_emmc() {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nxfs_unmount_emu_emmc() {
|
int nxfs_unmount_emummc() {
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
/* Unmount all emulated devices. */
|
/* Unmount all emulated devices. */
|
||||||
|
@ -708,5 +828,5 @@ int nxfs_init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int nxfs_end() {
|
int nxfs_end() {
|
||||||
return ((nxfs_unmount_sd() || nxfs_unmount_emmc() || nxfs_unmount_emu_emmc()) ? -1 : 0);
|
return ((nxfs_unmount_sd() || nxfs_unmount_emmc() || nxfs_unmount_emummc()) ? -1 : 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,9 +26,10 @@ int nxfs_end();
|
||||||
|
|
||||||
int nxfs_mount_sd();
|
int nxfs_mount_sd();
|
||||||
int nxfs_mount_emmc();
|
int nxfs_mount_emmc();
|
||||||
int nxfs_mount_emu_emmc(const char *emunand_path, int num_parts, uint64_t part_limit);
|
int nxfs_mount_emummc_partition(uint64_t emummc_start_sector);
|
||||||
|
int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part_limit);
|
||||||
int nxfs_unmount_sd();
|
int nxfs_unmount_sd();
|
||||||
int nxfs_unmount_emmc();
|
int nxfs_unmount_emmc();
|
||||||
int nxfs_unmount_emu_emmc();
|
int nxfs_unmount_emummc();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue