emunand: Implement folder and file detection (boot0/boot1 now work from SD)

This commit is contained in:
hexkyz 2019-04-09 19:32:18 +01:00
parent 5868e0769a
commit fe62ab9aed
12 changed files with 198 additions and 159 deletions

View file

@ -14,6 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdio.h>
#include <string.h> #include <string.h>
#include "device_partition.h" #include "device_partition.h"
@ -72,3 +73,29 @@ int device_partition_write_data(device_partition_t *devpart, const void *src, ui
return devpart->writer(devpart, src, sector, num_sectors); return devpart->writer(devpart, src, sector, num_sectors);
} }
} }
int emu_device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors, const char *origin_path)
{
int rc = 0;
/* Read partition data using our backing file. */
FILE *origin = fopen(origin_path, "rb");
fseek(origin, sector * devpart->sector_size, SEEK_CUR);
rc = (fread(dst, devpart->sector_size, num_sectors, origin) > 0) ? 0 : -1;
fclose(origin);
return rc;
}
int emu_device_partition_write_data(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors, const char *origin_path)
{
int rc = 0;
/* Write partition data using our backing file. */
FILE *origin = fopen(origin_path, "wb");
fseek(origin, sector * devpart->sector_size, SEEK_CUR);
rc = (fwrite(src, devpart->sector_size, num_sectors, origin) > 0) ? 0 : -1;
fclose(origin);
return rc;
}

View file

@ -69,5 +69,7 @@ typedef struct 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);
int device_partition_write_data(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors); int device_partition_write_data(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors);
int emu_device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors, const char *origin_path);
int emu_device_partition_write_data(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors, const char *origin_path);
#endif #endif

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018 Atmosphère-NX * Copyright (c) 2018-2019 Atmosphère-NX
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@ -38,7 +38,7 @@ static int emudev_fsync(struct _reent *r, void *fd);
typedef struct emudev_device_t { typedef struct emudev_device_t {
devoptab_t devoptab; devoptab_t devoptab;
FILE *origin; char origin_path[0x300+1];
uint8_t *tmp_sector; uint8_t *tmp_sector;
device_partition_t devpart; device_partition_t devpart;
char name[32+1]; char name[32+1];
@ -77,7 +77,7 @@ static emudev_device_t *emudev_find_device(const char *name) {
return NULL; return NULL;
} }
int emudev_mount_device(const char *name, const char *origin_path, const device_partition_t *devpart) { int emudev_mount_device(const char *name, const device_partition_t *devpart, const char *origin_path) {
emudev_device_t *device = NULL; emudev_device_t *device = NULL;
if (name[0] == '\0' || devpart == NULL) { if (name[0] == '\0' || devpart == NULL) {
@ -112,22 +112,11 @@ int emudev_mount_device(const char *name, const char *origin_path, const device_
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);
device->devoptab.name = device->name; device->devoptab.name = device->name;
device->devoptab.deviceData = device; device->devoptab.deviceData = device;
/* Try to open the backing file for this emulated device. */
FILE *origin = fopen(origin_path, "rb");
/* Return invalid if we can't open the file. */
if (origin == NULL) {
errno = EINVAL;
return -1;
}
/* Bind the backing file to this device. */
device->origin = origin;
/* Allocate memory for our intermediate sector. */ /* Allocate memory for our intermediate sector. */
device->tmp_sector = (uint8_t *)malloc(devpart->sector_size); device->tmp_sector = (uint8_t *)malloc(devpart->sector_size);
if (device->tmp_sector == NULL) { if (device->tmp_sector == NULL) {
@ -202,10 +191,6 @@ int emudev_unmount_device(const char *name) {
return -1; return -1;
} }
/* Close the backing file, if there is one. */
if (device->origin != NULL)
fclose(device->origin);
free(device->tmp_sector); free(device->tmp_sector);
memset(device, 0, sizeof(emudev_device_t)); memset(device, 0, sizeof(emudev_device_t));
@ -280,11 +265,7 @@ static ssize_t emudev_write(struct _reent *r, void *fd, const char *ptr, size_t
/* Unaligned at the start, we need to read the sector and incorporate the data. */ /* Unaligned at the start, we need to read the sector and incorporate the data. */
if (f->offset % sector_size != 0) { 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)); size_t nb = (size_t)(len <= (sector_size - (f->offset % sector_size)) ? len : sector_size - (f->offset % sector_size));
no = emu_device_partition_read_data(&device->devpart, device->tmp_sector, sector_begin, 1, device->origin_path);
/* Read partition data using our backing file. */
fseek(device->origin, sector_begin, SEEK_CUR);
no = (fread(device->tmp_sector, sector_size, 1, device->origin) > 0) ? 0 : EIO;
if (no != 0) { if (no != 0) {
r->_errno = no; r->_errno = no;
return -1; return -1;
@ -292,10 +273,7 @@ static ssize_t emudev_write(struct _reent *r, void *fd, const char *ptr, size_t
memcpy(device->tmp_sector + (f->offset % sector_size), data, nb); memcpy(device->tmp_sector + (f->offset % sector_size), data, nb);
/* Write partition data using our backing file. */ no = emu_device_partition_write_data(&device->devpart, device->tmp_sector, sector_begin, 1, device->origin_path);
fseek(device->origin, sector_begin, SEEK_CUR);
no = (fwrite(device->tmp_sector, sector_size, 1, device->origin) > 0) ? 0 : EIO;
if (no != 0) { if (no != 0) {
r->_errno = no; r->_errno = no;
return -1; return -1;
@ -314,10 +292,7 @@ static ssize_t emudev_write(struct _reent *r, void *fd, const char *ptr, size_t
/* Write all of the sector-aligned data. */ /* Write all of the sector-aligned data. */
if (current_sector != sector_end_aligned) { if (current_sector != sector_end_aligned) {
/* Write partition data using our backing file. */ no = emu_device_partition_write_data(&device->devpart, data, current_sector, sector_end_aligned - current_sector, device->origin_path);
fseek(device->origin, current_sector, SEEK_CUR);
no = (fwrite(device->tmp_sector, sector_size, sector_end_aligned - current_sector, device->origin) > 0) ? 0 : EIO;
if (no != 0) { if (no != 0) {
r->_errno = no; r->_errno = no;
return -1; return -1;
@ -329,10 +304,7 @@ static ssize_t emudev_write(struct _reent *r, void *fd, const char *ptr, size_t
/* Unaligned at the end, we need to read the sector and incorporate the data. */ /* Unaligned at the end, we need to read the sector and incorporate the data. */
if (sector_end != sector_end_aligned) { if (sector_end != sector_end_aligned) {
/* Read partition data using our backing file. */ no = emu_device_partition_read_data(&device->devpart, device->tmp_sector, sector_end_aligned, 1, device->origin_path);
fseek(device->origin, sector_end_aligned, SEEK_CUR);
no = (fread(device->tmp_sector, sector_size, 1, device->origin) > 0) ? 0 : EIO;
if (no != 0) { if (no != 0) {
r->_errno = no; r->_errno = no;
return -1; return -1;
@ -340,10 +312,7 @@ static ssize_t emudev_write(struct _reent *r, void *fd, const char *ptr, size_t
memcpy(device->tmp_sector, data, (size_t)((f->offset + len) % sector_size)); memcpy(device->tmp_sector, data, (size_t)((f->offset + len) % sector_size));
/* Write partition data using our backing file. */ no = emu_device_partition_write_data(&device->devpart, device->tmp_sector, sector_end_aligned, 1, device->origin_path);
fseek(device->origin, sector_end_aligned, SEEK_CUR);
no = (fwrite(device->tmp_sector, sector_size, 1, device->origin) > 0) ? 0 : EIO;
if (no != 0) { if (no != 0) {
r->_errno = no; r->_errno = no;
return -1; return -1;
@ -384,11 +353,7 @@ static ssize_t emudev_read(struct _reent *r, void *fd, char *ptr, size_t len) {
/* Unaligned at the start, we need to read the sector and incorporate the data. */ /* Unaligned at the start, we need to read the sector and incorporate the data. */
if (f->offset % sector_size != 0) { 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)); size_t nb = (size_t)(len <= (sector_size - (f->offset % sector_size)) ? len : sector_size - (f->offset % sector_size));
no = emu_device_partition_read_data(&device->devpart, device->tmp_sector, sector_begin, 1, device->origin_path);
/* Read partition data using our backing file. */
fseek(device->origin, sector_begin, SEEK_CUR);
no = (fread(device->tmp_sector, sector_size, 1, device->origin) > 0) ? 0 : EIO;
if (no != 0) { if (no != 0) {
r->_errno = no; r->_errno = no;
return -1; return -1;
@ -409,10 +374,7 @@ static ssize_t emudev_read(struct _reent *r, void *fd, char *ptr, size_t len) {
/* Read all of the sector-aligned data. */ /* Read all of the sector-aligned data. */
if (current_sector != sector_end_aligned) { if (current_sector != sector_end_aligned) {
/* Read partition data using our backing file. */ no = emu_device_partition_read_data(&device->devpart, data, current_sector, sector_end_aligned - current_sector, device->origin_path);
fseek(device->origin, current_sector, SEEK_CUR);
no = (fread(device->tmp_sector, sector_size, sector_end_aligned - current_sector, device->origin) > 0) ? 0 : EIO;
if (no != 0) { if (no != 0) {
r->_errno = no; r->_errno = no;
return -1; return -1;
@ -424,10 +386,7 @@ static ssize_t emudev_read(struct _reent *r, void *fd, char *ptr, size_t len) {
/* Unaligned at the end, we need to read the sector and incorporate the data. */ /* Unaligned at the end, we need to read the sector and incorporate the data. */
if (sector_end != sector_end_aligned) { if (sector_end != sector_end_aligned) {
/* Read partition data using our backing file. */ no = emu_device_partition_read_data(&device->devpart, device->tmp_sector, sector_end_aligned, 1, device->origin_path);
fseek(device->origin, sector_end_aligned, SEEK_CUR);
no = (fread(device->tmp_sector, sector_size, 1, device->origin) > 0) ? 0 : EIO;
if (no != 0) { if (no != 0) {
r->_errno = no; r->_errno = no;
return -1; return -1;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018 Atmosphère-NX * Copyright (c) 2018-2019 Atmosphère-NX
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@ -24,11 +24,11 @@
#define EMUDEV_MAX_DEVICES 16 #define EMUDEV_MAX_DEVICES 16
int emudev_mount_device(const char *name, const char *origin_path, const device_partition_t *devpart); int emudev_mount_device(const char *name, const device_partition_t *devpart, const char *origin_path);
int emudev_register_device(const char *name); int emudev_register_device(const char *name);
int emudev_unregister_device(const char *name); int emudev_unregister_device(const char *name);
int emudev_unmount_device(const char *name); /* also unregisters. */ int emudev_unmount_device(const char *name); /* also unregisters. */
int emudev_unmount_all(void); int emudev_unmount_all(void);
#endif #endif

View file

@ -246,6 +246,19 @@ int fsdev_set_default_device(const char *name) {
return ret; return ret;
} }
int fsdev_is_exfat(const char *name) {
fsdev_device_t *device = fsdev_find_device(name);
if (device != NULL) {
if (device->registered) {
return ((device->fatfs.fs_type == FS_EXFAT) ? 1 : 0);
}
}
errno = ENOENT;
return -1;
}
int fsdev_unmount_device(const char *name) { int fsdev_unmount_device(const char *name) {
int ret; int ret;
char drname[40]; char drname[40];

View file

@ -24,11 +24,12 @@
int fsdev_mount_device(const char *name, const device_partition_t *devpart, bool initialize_immediately); int fsdev_mount_device(const char *name, const device_partition_t *devpart, bool initialize_immediately);
int fsdev_register_device(const char *name); int fsdev_register_device(const char *name);
int fsdev_set_default_device(const char *name); /* must be registered. */
int fsdev_unregister_device(const char *name); int fsdev_unregister_device(const char *name);
int fsdev_unmount_device(const char *name); /* also unregisters. */ int fsdev_unmount_device(const char *name); /* also unregisters. */
int fsdev_set_default_device(const char *name); /* must be registered. */
int fsdev_is_exfat(const char *name); /* must be registered. */
int fsdev_unmount_all(void); int fsdev_unmount_all(void);
#endif #endif

View file

@ -48,3 +48,21 @@ size_t dump_to_file(const void *src, size_t src_size, const char *filename) {
return sz; return sz;
} }
} }
bool is_valid_folder(const char *path) {
struct stat st;
if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
return true;
}
return false;
}
bool is_valid_file(const char *path) {
struct stat st;
if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
return true;
}
return false;
}

View file

@ -23,5 +23,7 @@
size_t get_file_size(const char *filename); size_t get_file_size(const char *filename);
size_t read_from_file(void *dst, size_t dst_size, const char *filename); size_t read_from_file(void *dst, size_t dst_size, const char *filename);
size_t dump_to_file(const void *src, size_t src_size, const char *filename); size_t dump_to_file(const void *src, size_t src_size, const char *filename);
bool is_valid_folder(const char *path);
bool is_valid_file(const char *path);
#endif #endif

View file

@ -187,13 +187,13 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
} else if (memcmp(package1loader_header->build_timestamp, "20181107", 8) == 0) { } else if (memcmp(package1loader_header->build_timestamp, "20181107", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_620; return ATMOSPHERE_TARGET_FIRMWARE_620;
} else { } else {
fatal_error("[NXBOOT]: Unable to identify package1!\n"); fatal_error("[NXBOOT] Unable to identify package1!\n");
} }
} }
case 0x0F: case 0x0F:
return ATMOSPHERE_TARGET_FIRMWARE_700; return ATMOSPHERE_TARGET_FIRMWARE_700;
default: default:
fatal_error("[NXBOOT]: Unable to identify package1!\n"); fatal_error("[NXBOOT] Unable to identify package1!\n");
} }
} }
@ -202,33 +202,45 @@ static bool nxboot_configure_emunand() {
/* Load emunand settings from BCT.ini file. */ /* Load emunand 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, emunand_ini_handler, &emunand_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 (emunand_cfg.enabled) {
bool do_nand_backup = false; bool do_nand_backup = false;
char emunand_boot0_path[0x300 + 1] = {0};
char emunand_boot1_path[0x300 + 1] = {0};
char emunand_rawnand_base_path[0x300 + 1] = {0};
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");
snprintf(emunand_rawnand_base_path, sizeof(emunand_rawnand_base_path) - 1, "sdmc:/%s/%s", emunand_cfg.path, "rawnand");
/* TODO: Check if the supplied path is valid. */ /* Check if the supplied path is valid. */
if (!is_valid_folder(emunand_cfg.path)) {
fatal_error("[NXBOOT] Failed to find EmuNAND folder!\n");
}
/* TODO: Check if all emunand image files are present. */ /* Check if all emunand image files are present. */
if (!is_valid_file(emunand_boot0_path) || !is_valid_file(emunand_boot1_path) || !is_valid_file(emunand_rawnand_base_path)) {
fatal_error("[NXBOOT] Failed to find EmuNAND image files!\n");
}
if (do_nand_backup) { if (do_nand_backup) {
/* Mount real NAND. */ /* Mount real NAND. */
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");
} }
/* TODO: Read real NAND and create a backup image. */ /* TODO: Read real NAND and create a backup image. */
/* Unmount real NAND. */ /* Unmount real NAND. */
if (nxfs_unmount_emmc() < 0) { if (nxfs_unmount_emmc() < 0) {
fatal_error("[NXBOOT]: Failed to unmount eMMC!\n"); fatal_error("[NXBOOT] Failed to unmount eMMC!\n");
} }
} }
/* Mount emulated NAND. */ /* Mount emulated NAND. */
if (nxfs_mount_emu_emmc(emunand_cfg.path) < 0) { if (nxfs_mount_emu_emmc(emunand_boot0_path, emunand_boot1_path, emunand_rawnand_base_path) < 0) {
fatal_error("[NXBOOT]: Failed to mount emulated eMMC!\n"); fatal_error("[NXBOOT] Failed to mount emulated eMMC!\n");
} }
} }
@ -247,11 +259,11 @@ static void nxboot_configure_exosphere(uint32_t target_firmware, unsigned int ke
} }
if (ini_parse_string(get_loader_ctx()->bct0, exosphere_ini_handler, &exo_cfg) < 0) { if (ini_parse_string(get_loader_ctx()->bct0, exosphere_ini_handler, &exo_cfg) < 0) {
fatal_error("[NXBOOT]: Failed to parse BCT.ini!\n"); fatal_error("[NXBOOT] Failed to parse BCT.ini!\n");
} }
if ((exo_cfg.target_firmware < ATMOSPHERE_TARGET_FIRMWARE_MIN) || (exo_cfg.target_firmware > ATMOSPHERE_TARGET_FIRMWARE_MAX)) { if ((exo_cfg.target_firmware < ATMOSPHERE_TARGET_FIRMWARE_MIN) || (exo_cfg.target_firmware > ATMOSPHERE_TARGET_FIRMWARE_MAX)) {
fatal_error("[NXBOOT]: Invalid Exosphere target firmware!\n"); fatal_error("[NXBOOT] Invalid Exosphere target firmware!\n");
} }
*(MAILBOX_EXOSPHERE_CONFIGURATION) = exo_cfg; *(MAILBOX_EXOSPHERE_CONFIGURATION) = exo_cfg;
@ -260,7 +272,7 @@ static void nxboot_configure_exosphere(uint32_t target_firmware, unsigned int ke
static void nxboot_configure_stratosphere(uint32_t target_firmware) { static void nxboot_configure_stratosphere(uint32_t target_firmware) {
stratosphere_cfg_t strat_cfg = {0}; stratosphere_cfg_t strat_cfg = {0};
if (ini_parse_string(get_loader_ctx()->bct0, stratosphere_ini_handler, &strat_cfg) < 0) { if (ini_parse_string(get_loader_ctx()->bct0, stratosphere_ini_handler, &strat_cfg) < 0) {
fatal_error("[NXBOOT]: Failed to parse BCT.ini!\n"); fatal_error("[NXBOOT] Failed to parse BCT.ini!\n");
} }
/* Enable NOGC patches if the user requested it, or if the user is booting into 4.0.0+ with 3.0.2- fuses. */ /* Enable NOGC patches if the user requested it, or if the user is booting into 4.0.0+ with 3.0.2- fuses. */
@ -285,18 +297,18 @@ static void nxboot_set_bootreason(void *bootreason_base) {
/* Allocate memory for the BCT. */ /* Allocate memory for the BCT. */
bct = malloc(sizeof(nvboot_config_table)); bct = malloc(sizeof(nvboot_config_table));
if (bct == NULL) { if (bct == NULL) {
fatal_error("[NXBOOT]: Out of memory!\n"); fatal_error("[NXBOOT] Out of memory!\n");
} }
/* Open boot0. */ /* Open boot0. */
boot0 = fopen("boot0:/", "rb"); boot0 = fopen("boot0:/", "rb");
if (boot0 == NULL) { if (boot0 == NULL) {
fatal_error("[NXBOOT]: Failed to open boot0!\n"); fatal_error("[NXBOOT] Failed to open boot0!\n");
} }
/* Read the BCT. */ /* Read the BCT. */
if (fread(bct, sizeof(nvboot_config_table), 1, boot0) == 0) { if (fread(bct, sizeof(nvboot_config_table), 1, boot0) == 0) {
fatal_error("[NXBOOT]: Failed to read the BCT!\n"); fatal_error("[NXBOOT] Failed to read the BCT!\n");
} }
/* Close boot0. */ /* Close boot0. */
@ -343,17 +355,17 @@ static void nxboot_move_bootconfig() {
/* Allocate memory for reading BootConfig. */ /* Allocate memory for reading BootConfig. */
bootconfig = memalign(0x1000, 0x4000); bootconfig = memalign(0x1000, 0x4000);
if (bootconfig == NULL) { if (bootconfig == NULL) {
fatal_error("[NXBOOT]: Out of memory!\n"); fatal_error("[NXBOOT] Out of memory!\n");
} }
/* Get BootConfig from the Package2 partition. */ /* Get BootConfig from the Package2 partition. */
bcfile = fopen("bcpkg21:/", "rb"); bcfile = fopen("bcpkg21:/", "rb");
if (bcfile == NULL) { if (bcfile == NULL) {
fatal_error("[NXBOOT]: Failed to open BootConfig from eMMC!\n"); fatal_error("[NXBOOT] Failed to open BootConfig from eMMC!\n");
} }
if (fread(bootconfig, 0x4000, 1, bcfile) < 1) { if (fread(bootconfig, 0x4000, 1, bcfile) < 1) {
fclose(bcfile); fclose(bcfile);
fatal_error("[NXBOOT]: Failed to read BootConfig!\n"); fatal_error("[NXBOOT] Failed to read BootConfig!\n");
} }
fclose(bcfile); fclose(bcfile);
@ -396,86 +408,86 @@ uint32_t nxboot_main(void) {
/* Configure emunand or mount the real NAND. */ /* Configure emunand or mount the real NAND. */
if (!nxboot_configure_emunand()) { if (!nxboot_configure_emunand()) {
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");
} }
} }
/* Allocate memory for reading Package2. */ /* Allocate memory for reading Package2. */
package2 = memalign(0x1000, PACKAGE2_SIZE_MAX); package2 = memalign(0x1000, PACKAGE2_SIZE_MAX);
if (package2 == NULL) { if (package2 == NULL) {
fatal_error("[NXBOOT]: Out of memory!\n"); fatal_error("[NXBOOT] Out of memory!\n");
} }
/* Read Package2 from a file, otherwise from its partition(s). */ /* Read Package2 from a file, otherwise from its partition(s). */
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT]: Reading package2...\n"); print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Reading package2...\n");
if (loader_ctx->package2_path[0] != '\0') { if (loader_ctx->package2_path[0] != '\0') {
pk2file = fopen(loader_ctx->package2_path, "rb"); pk2file = fopen(loader_ctx->package2_path, "rb");
if (pk2file == NULL) { if (pk2file == NULL) {
fatal_error("[NXBOOT]: Failed to open Package2 from %s: %s!\n", loader_ctx->package2_path, strerror(errno)); fatal_error("[NXBOOT] Failed to open Package2 from %s: %s!\n", loader_ctx->package2_path, strerror(errno));
} }
} else { } else {
pk2file = fopen("bcpkg21:/", "rb"); pk2file = fopen("bcpkg21:/", "rb");
if (pk2file == NULL) { if (pk2file == NULL) {
fatal_error("[NXBOOT]: Failed to open Package2 from eMMC: %s!\n", strerror(errno)); fatal_error("[NXBOOT] Failed to open Package2 from eMMC: %s!\n", strerror(errno));
} }
if (fseek(pk2file, 0x4000, SEEK_SET) != 0) { if (fseek(pk2file, 0x4000, SEEK_SET) != 0) {
fclose(pk2file); fclose(pk2file);
fatal_error("[NXBOOT]: Failed to seek Package2 in eMMC: %s!\n", strerror(errno)); fatal_error("[NXBOOT] Failed to seek Package2 in eMMC: %s!\n", strerror(errno));
} }
} }
setvbuf(pk2file, NULL, _IONBF, 0); /* Workaround. */ setvbuf(pk2file, NULL, _IONBF, 0); /* Workaround. */
if (fread(package2, sizeof(package2_header_t), 1, pk2file) < 1) { if (fread(package2, sizeof(package2_header_t), 1, pk2file) < 1) {
fclose(pk2file); fclose(pk2file);
fatal_error("[NXBOOT]: Failed to read Package2!\n"); fatal_error("[NXBOOT] Failed to read Package2!\n");
} }
package2_size = package2_meta_get_size(&package2->metadata); package2_size = package2_meta_get_size(&package2->metadata);
if ((package2_size > PACKAGE2_SIZE_MAX) || (package2_size <= sizeof(package2_header_t))) { if ((package2_size > PACKAGE2_SIZE_MAX) || (package2_size <= sizeof(package2_header_t))) {
fclose(pk2file); fclose(pk2file);
fatal_error("[NXBOOT]: Package2 is too big or too small!\n"); fatal_error("[NXBOOT] Package2 is too big or too small!\n");
} }
if (fread(package2->data, package2_size - sizeof(package2_header_t), 1, pk2file) < 1) { if (fread(package2->data, package2_size - sizeof(package2_header_t), 1, pk2file) < 1) {
fclose(pk2file); fclose(pk2file);
fatal_error("[NXBOOT]: Failed to read Package2!\n"); fatal_error("[NXBOOT] Failed to read Package2!\n");
} }
fclose(pk2file); fclose(pk2file);
/* Read and parse boot0. */ /* Read and parse boot0. */
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT]: Reading boot0...\n"); print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Reading boot0...\n");
boot0 = fopen("boot0:/", "rb"); boot0 = fopen("boot0:/", "rb");
if ((boot0 == NULL) || (package1_read_and_parse_boot0(&package1loader, &package1loader_size, g_keyblobs, &available_revision, boot0) == -1)) { if ((boot0 == NULL) || (package1_read_and_parse_boot0(&package1loader, &package1loader_size, g_keyblobs, &available_revision, boot0) == -1)) {
fatal_error("[NXBOOT]: Couldn't parse boot0: %s!\n", strerror(errno)); fatal_error("[NXBOOT] Couldn't parse boot0: %s!\n", strerror(errno));
} }
fclose(boot0); fclose(boot0);
/* Find the system's target firmware. */ /* Find the system's target firmware. */
uint32_t target_firmware = nxboot_get_target_firmware(package1loader); uint32_t target_firmware = nxboot_get_target_firmware(package1loader);
if (!target_firmware) if (!target_firmware)
fatal_error("[NXBOOT]: Failed to detect target firmware!\n"); fatal_error("[NXBOOT] Failed to detect target firmware!\n");
else else
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT]: Detected target firmware %ld!\n", target_firmware); print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Detected target firmware %ld!\n", target_firmware);
/* Read the TSEC firmware from a file, otherwise from PK1L. */ /* Read the TSEC firmware from a file, otherwise from PK1L. */
if (loader_ctx->tsecfw_path[0] != '\0') { if (loader_ctx->tsecfw_path[0] != '\0') {
tsec_fw_size = get_file_size(loader_ctx->tsecfw_path); tsec_fw_size = get_file_size(loader_ctx->tsecfw_path);
if ((tsec_fw_size != 0) && (tsec_fw_size != 0xF00 && tsec_fw_size != 0x2900 && tsec_fw_size != 0x3000)) { if ((tsec_fw_size != 0) && (tsec_fw_size != 0xF00 && tsec_fw_size != 0x2900 && tsec_fw_size != 0x3000)) {
fatal_error("[NXBOOT]: TSEC firmware from %s has a wrong size!\n", loader_ctx->tsecfw_path); fatal_error("[NXBOOT] TSEC firmware from %s has a wrong size!\n", loader_ctx->tsecfw_path);
} else if (tsec_fw_size == 0) { } else if (tsec_fw_size == 0) {
fatal_error("[NXBOOT]: Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path); fatal_error("[NXBOOT] Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path);
} }
/* Allocate memory for the TSEC firmware. */ /* Allocate memory for the TSEC firmware. */
tsec_fw = memalign(0x100, tsec_fw_size); tsec_fw = memalign(0x100, tsec_fw_size);
if (tsec_fw == NULL) { if (tsec_fw == NULL) {
fatal_error("[NXBOOT]: Out of memory!\n"); fatal_error("[NXBOOT] Out of memory!\n");
} }
if (read_from_file(tsec_fw, tsec_fw_size, loader_ctx->tsecfw_path) != tsec_fw_size) { if (read_from_file(tsec_fw, tsec_fw_size, loader_ctx->tsecfw_path) != tsec_fw_size) {
fatal_error("[NXBOOT]: Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path); fatal_error("[NXBOOT] Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path);
} }
} else { } else {
if (!package1_get_tsec_fw(&tsec_fw, package1loader, package1loader_size)) { if (!package1_get_tsec_fw(&tsec_fw, package1loader, package1loader_size)) {
fatal_error("[NXBOOT]: Failed to read the TSEC firmware from Package1loader!\n"); fatal_error("[NXBOOT] Failed to read the TSEC firmware from Package1loader!\n");
} }
if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_700) { if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_700) {
tsec_fw_size = 0x3000; tsec_fw_size = 0x3000;
@ -486,7 +498,7 @@ uint32_t nxboot_main(void) {
} }
} }
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT]: Loaded firmware from eMMC...\n"); print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Loaded firmware from eMMC...\n");
/* Get the TSEC keys. */ /* Get the TSEC keys. */
uint8_t tsec_key[0x10] = {0}; uint8_t tsec_key[0x10] = {0};
@ -497,7 +509,7 @@ uint32_t nxboot_main(void) {
reboot_to_sept(tsec_fw, tsec_fw_size, sept_secondary_enc, sept_secondary_enc_size); reboot_to_sept(tsec_fw, tsec_fw_size, sept_secondary_enc, sept_secondary_enc_size);
} else { } else {
if (mkey_detect_revision(fuse_get_retail_type() != 0) != 0) { if (mkey_detect_revision(fuse_get_retail_type() != 0) != 0) {
fatal_error("[NXBOOT]: Sept derived incorrect keys!\n"); fatal_error("[NXBOOT] Sept derived incorrect keys!\n");
} }
} }
get_and_clear_has_run_sept(); get_and_clear_has_run_sept();
@ -513,7 +525,7 @@ uint32_t nxboot_main(void) {
} else { } else {
/* Run the TSEC payload and get the key. */ /* Run the TSEC payload and get the key. */
if (tsec_get_key(tsec_key, 1, tsec_fw, tsec_fw_size) != 0) { if (tsec_get_key(tsec_key, 1, tsec_fw, tsec_fw_size) != 0) {
fatal_error("[NXBOOT]: Failed to get TSEC key!\n"); fatal_error("[NXBOOT] Failed to get TSEC key!\n");
} }
} }
@ -525,7 +537,7 @@ uint32_t nxboot_main(void) {
unsigned int keygen_type = 0; unsigned int keygen_type = 0;
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_700) { if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_700) {
if (derive_nx_keydata(target_firmware, g_keyblobs, available_revision, tsec_key, tsec_root_keys, &keygen_type) != 0) { if (derive_nx_keydata(target_firmware, g_keyblobs, available_revision, tsec_key, tsec_root_keys, &keygen_type) != 0) {
fatal_error("[NXBOOT]: Key derivation failed!\n"); fatal_error("[NXBOOT] Key derivation failed!\n");
} }
} }
@ -534,7 +546,7 @@ uint32_t nxboot_main(void) {
/* Initialize Boot Reason on older firmware versions. */ /* Initialize Boot Reason on older firmware versions. */
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT]: Initializing Boot Reason...\n"); print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Initializing Boot Reason...\n");
nxboot_set_bootreason((void *)MAILBOX_NX_BOOTLOADER_BOOT_REASON_BASE(target_firmware)); nxboot_set_bootreason((void *)MAILBOX_NX_BOOTLOADER_BOOT_REASON_BASE(target_firmware));
} }
@ -542,17 +554,17 @@ uint32_t nxboot_main(void) {
if (loader_ctx->warmboot_path[0] != '\0') { if (loader_ctx->warmboot_path[0] != '\0') {
warmboot_fw_size = get_file_size(loader_ctx->warmboot_path); warmboot_fw_size = get_file_size(loader_ctx->warmboot_path);
if (warmboot_fw_size == 0) { if (warmboot_fw_size == 0) {
fatal_error("[NXBOOT]: Could not read the warmboot firmware from %s!\n", loader_ctx->warmboot_path); fatal_error("[NXBOOT] Could not read the warmboot firmware from %s!\n", loader_ctx->warmboot_path);
} }
/* Allocate memory for the warmboot firmware. */ /* Allocate memory for the warmboot firmware. */
warmboot_fw = malloc(warmboot_fw_size); warmboot_fw = malloc(warmboot_fw_size);
if (warmboot_fw == NULL) { if (warmboot_fw == NULL) {
fatal_error("[NXBOOT]: Out of memory!\n"); fatal_error("[NXBOOT] Out of memory!\n");
} }
if (read_from_file(warmboot_fw, warmboot_fw_size, loader_ctx->warmboot_path) != warmboot_fw_size) { if (read_from_file(warmboot_fw, warmboot_fw_size, loader_ctx->warmboot_path) != warmboot_fw_size) {
fatal_error("[NXBOOT]: Could not read the warmboot firmware from %s!\n", loader_ctx->warmboot_path); fatal_error("[NXBOOT] Could not read the warmboot firmware from %s!\n", loader_ctx->warmboot_path);
} }
} else { } else {
/* Use Atmosphere's warmboot firmware implementation. */ /* Use Atmosphere's warmboot firmware implementation. */
@ -560,13 +572,13 @@ uint32_t nxboot_main(void) {
warmboot_fw = malloc(warmboot_fw_size); warmboot_fw = malloc(warmboot_fw_size);
if (warmboot_fw == NULL) { if (warmboot_fw == NULL) {
fatal_error("[NXBOOT]: Out of memory!\n"); fatal_error("[NXBOOT] Out of memory!\n");
} }
memcpy(warmboot_fw, lp0fw_bin, warmboot_fw_size); memcpy(warmboot_fw, lp0fw_bin, warmboot_fw_size);
if (warmboot_fw_size == 0) { if (warmboot_fw_size == 0) {
fatal_error("[NXBOOT]: Could not read the warmboot firmware from Package1!\n"); fatal_error("[NXBOOT] Could not read the warmboot firmware from Package1!\n");
} }
} }
@ -595,7 +607,7 @@ uint32_t nxboot_main(void) {
warmboot_memaddr = (void *)0x4003E000; warmboot_memaddr = (void *)0x4003E000;
} }
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT]: Copying warmboot firmware...\n"); print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Copying warmboot firmware...\n");
/* Copy the warmboot firmware and set the address in PMC if necessary. */ /* Copy the warmboot firmware and set the address in PMC if necessary. */
if (warmboot_fw && (warmboot_fw_size > 0)) { if (warmboot_fw && (warmboot_fw_size > 0)) {
@ -604,17 +616,17 @@ uint32_t nxboot_main(void) {
pmc->scratch1 = (uint32_t)warmboot_memaddr; pmc->scratch1 = (uint32_t)warmboot_memaddr;
} }
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT]: Rebuilding package2...\n"); print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Rebuilding package2...\n");
/* Parse stratosphere config. */ /* Parse stratosphere config. */
nxboot_configure_stratosphere(MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware); nxboot_configure_stratosphere(MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware);
print(SCREEN_LOG_LEVEL_INFO, u8"[NXBOOT]: Configured Stratosphere...\n"); print(SCREEN_LOG_LEVEL_INFO, u8"[NXBOOT] Configured Stratosphere...\n");
/* Patch package2, adding Thermosphère + custom KIPs. */ /* Patch package2, adding Thermosphère + custom KIPs. */
package2_rebuild_and_copy(package2, MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware); package2_rebuild_and_copy(package2, MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware);
print(SCREEN_LOG_LEVEL_INFO, u8"[NXBOOT]: Reading Exosphère...\n"); print(SCREEN_LOG_LEVEL_INFO, u8"[NXBOOT] Reading Exosphère...\n");
/* Select the right address for Exosphère. */ /* Select the right address for Exosphère. */
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
@ -627,21 +639,21 @@ uint32_t nxboot_main(void) {
if (loader_ctx->exosphere_path[0] != '\0') { if (loader_ctx->exosphere_path[0] != '\0') {
size_t exosphere_size = get_file_size(loader_ctx->exosphere_path); size_t exosphere_size = get_file_size(loader_ctx->exosphere_path);
if (exosphere_size == 0) { if (exosphere_size == 0) {
fatal_error(u8"[NXBOOT]: Could not read Exosphère from %s!\n", loader_ctx->exosphere_path); fatal_error(u8"[NXBOOT] Could not read Exosphère from %s!\n", loader_ctx->exosphere_path);
} else if (exosphere_size > 0x10000) { } else if (exosphere_size > 0x10000) {
/* The maximum is actually a bit less than that. */ /* The maximum is actually a bit less than that. */
fatal_error(u8"[NXBOOT]: Exosphère from %s is too big!\n", loader_ctx->exosphere_path); fatal_error(u8"[NXBOOT] Exosphère from %s is too big!\n", loader_ctx->exosphere_path);
} }
if (read_from_file(exosphere_memaddr, exosphere_size, loader_ctx->exosphere_path) != exosphere_size) { if (read_from_file(exosphere_memaddr, exosphere_size, loader_ctx->exosphere_path) != exosphere_size) {
fatal_error(u8"[NXBOOT]: Could not read Exosphère from %s!\n", loader_ctx->exosphere_path); fatal_error(u8"[NXBOOT] Could not read Exosphère from %s!\n", loader_ctx->exosphere_path);
} }
} else { } else {
memcpy(exosphere_memaddr, exosphere_bin, exosphere_bin_size); memcpy(exosphere_memaddr, exosphere_bin, exosphere_bin_size);
} }
/* Move BootConfig. */ /* Move BootConfig. */
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT]: Moving BootConfig...\n"); print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Moving BootConfig...\n");
nxboot_move_bootconfig(); nxboot_move_bootconfig();
/* Set 3.0.0/3.0.1/3.0.2 warmboot security check. */ /* Set 3.0.0/3.0.1/3.0.2 warmboot security check. */
@ -663,7 +675,7 @@ uint32_t nxboot_main(void) {
} }
free(package2); free(package2);
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT]: Powering on the CCPLEX...\n"); print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Powering on the CCPLEX...\n");
/* Unmount everything. */ /* Unmount everything. */
nxfs_end(); nxfs_end();

View file

@ -380,21 +380,22 @@ int nxfs_mount_emmc() {
return rc; return rc;
} }
int nxfs_mount_emu_emmc(const char *emunand_path) { int nxfs_mount_emu_emmc(const char *emunand_boot0_path, const char *emunand_boot1_path, const char *emunand_rawnand_base_path) {
device_partition_t model; device_partition_t model;
int rc; int rc;
FILE *rawnand; FILE *rawnand;
bool is_exfat;
/* Setup emunand paths. */ /* Check if the SD card is EXFAT formatted. */
char emu_boot0_path[0x100]; rc = fsdev_is_exfat("sdmc");
char emu_boot1_path[0x100];
char emu_rawnand_path[0x100]; /* Failed to detect file system type. */
memset(emu_boot0_path, 0, sizeof(emu_boot0_path)); if (rc == -1) {
memset(emu_boot1_path, 0, sizeof(emu_boot1_path)); return -1;
memset(emu_rawnand_path, 0, sizeof(emu_rawnand_path)); }
snprintf(emu_boot0_path, sizeof(emu_boot0_path), "sdmc:/%s/%s", emunand_path, "boot0");
snprintf(emu_boot1_path, sizeof(emu_boot1_path), "sdmc:/%s/%s", emunand_path, "boot1"); /* Set EXFAT status. */
snprintf(emu_rawnand_path, sizeof(emu_rawnand_path), "sdmc:/%s/%s", emunand_path, "rawnand"); is_exfat = (rc == 1);
/* Setup an emulation template for boot0. */ /* Setup an emulation template for boot0. */
model = g_emummc_devpart_template; model = g_emummc_devpart_template;
@ -402,7 +403,7 @@ int nxfs_mount_emu_emmc(const char *emunand_path) {
model.num_sectors = 0x184000 / model.sector_size; model.num_sectors = 0x184000 / model.sector_size;
/* Mount emulated boot0 device. */ /* Mount emulated boot0 device. */
rc = emudev_mount_device("boot0", emu_boot0_path, &model); rc = emudev_mount_device("boot0", &model, emunand_boot0_path);
if (rc == -1) { if (rc == -1) {
return -1; return -1;
@ -421,7 +422,7 @@ int nxfs_mount_emu_emmc(const char *emunand_path) {
model.num_sectors = 0x80000 / model.sector_size; model.num_sectors = 0x80000 / model.sector_size;
/* Mount emulated boot1 device. */ /* Mount emulated boot1 device. */
rc = emudev_mount_device("boot1", emu_boot1_path, &model); rc = emudev_mount_device("boot1", &model, emunand_boot1_path);
if (rc == -1) { if (rc == -1) {
return -1; return -1;
@ -434,8 +435,11 @@ int nxfs_mount_emu_emmc(const char *emunand_path) {
model.start_sector = 0; model.start_sector = 0;
model.num_sectors = (256ull << 30) / model.sector_size; model.num_sectors = (256ull << 30) / model.sector_size;
if (!is_exfat) {
/* TODO: Use file concatenation for FAT32. */
} else {
/* Mount emulated raw NAND device. */ /* Mount emulated raw NAND device. */
rc = emudev_mount_device("rawnand", emu_rawnand_path, &model); rc = emudev_mount_device("rawnand", &model, emunand_rawnand_base_path);
if (rc == -1) { if (rc == -1) {
return -1; return -1;
@ -459,6 +463,7 @@ int nxfs_mount_emu_emmc(const char *emunand_path) {
/* Close emulated raw NAND device. */ /* Close emulated raw NAND device. */
fclose(rawnand); fclose(rawnand);
}
/* All emulated devices are ready. */ /* All emulated devices are ready. */
if (rc == 0) { if (rc == 0) {

View file

@ -26,7 +26,7 @@ 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 nxfs_mount_emu_emmc(const char *emunand_boot0_path, const char *emunand_boot1_path, const char *emunand_rawnand_base_path);
int nxfs_unmount_sd(); int nxfs_unmount_sd();
int nxfs_unmount_emmc(); int nxfs_unmount_emmc();
int nxfs_unmount_emu_emmc(); int nxfs_unmount_emu_emmc();

View file

@ -24,11 +24,11 @@
#define RAWDEV_MAX_DEVICES 16 #define RAWDEV_MAX_DEVICES 16
int rawdev_mount_device(const char *name, const device_partition_t *device, bool mount_immediately); int rawdev_mount_device(const char *name, const device_partition_t *devpart, bool initialize_immediately);
int rawdev_register_device(const char *name); int rawdev_register_device(const char *name);
int rawdev_unregister_device(const char *name); int rawdev_unregister_device(const char *name);
int rawdev_unmount_device(const char *name); /* also unregisters. */ int rawdev_unmount_device(const char *name); /* also unregisters. */
int rawdev_unmount_all(void); int rawdev_unmount_all(void);
#endif #endif