mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +00:00
fusee: add automatic emummc injection support
This commit is contained in:
parent
4f8ab5c599
commit
8bd79e8299
14 changed files with 315 additions and 37 deletions
|
@ -59,6 +59,7 @@ typedef struct {
|
|||
emummc_partition_config_t partition_cfg;
|
||||
emummc_file_config_t file_cfg;
|
||||
};
|
||||
//char emu_dir_path[EMUMMC_FILE_PATH_MAX];
|
||||
} exo_emummc_config_t;
|
||||
|
||||
_Static_assert(sizeof(exo_emummc_config_t) == 0x90, "exo_emummc_config_t definition!");
|
||||
|
|
|
@ -77,7 +77,7 @@ int device_partition_write_data(device_partition_t *devpart, const void *src, ui
|
|||
int emu_device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors, const char *origin_path, int num_parts, uint64_t part_limit)
|
||||
{
|
||||
int rc = 0;
|
||||
uint64_t target_sector = 0;
|
||||
uint64_t target_sector = sector;
|
||||
char target_path[0x300 + 1] = {0};
|
||||
|
||||
/* Perform initialization steps, if necessary. */
|
||||
|
@ -150,7 +150,7 @@ int emu_device_partition_read_data(device_partition_t *devpart, void *dst, uint6
|
|||
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 num_parts, uint64_t part_limit)
|
||||
{
|
||||
int rc = 0;
|
||||
uint64_t target_sector = 0;
|
||||
uint64_t target_sector = sector;
|
||||
char target_path[0x300 + 1] = {0};
|
||||
|
||||
/* Perform initialization steps, if necessary. */
|
||||
|
@ -214,7 +214,7 @@ int emu_device_partition_write_data(device_partition_t *devpart, const void *src
|
|||
}
|
||||
} else {
|
||||
/* Write partition data. */
|
||||
rc = devpart->writer(devpart, src, sector, num_sectors);
|
||||
rc = devpart->writer(devpart, src, target_sector, num_sectors);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "emu_dev.h"
|
||||
#include "utils.h"
|
||||
|
||||
static int emudev_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode);
|
||||
static int emudev_close(struct _reent *r, void *fd);
|
||||
|
|
106
fusee/fusee-secondary/src/emummc_cfg.h
Normal file
106
fusee/fusee-secondary/src/emummc_cfg.h
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EXOSPHERE_EMUMMC_CONFIG_H
|
||||
#define EXOSPHERE_EMUMMC_CONFIG_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <atmosphere.h>
|
||||
|
||||
/* "EFS0" */
|
||||
#define MAGIC_EMUMMC_CONFIG (0x30534645)
|
||||
|
||||
#define EMUMMC_FILE_PATH_MAX (0x80)
|
||||
|
||||
typedef enum {
|
||||
EMUMMC_TYPE_NONE = 0,
|
||||
EMUMMC_TYPE_PARTITION = 1,
|
||||
EMUMMC_TYPE_FILES = 2,
|
||||
} emummc_type_t;
|
||||
|
||||
typedef enum {
|
||||
EMUMMC_MMC_NAND = 0,
|
||||
EMUMMC_MMC_SD = 1,
|
||||
EMUMMC_MMC_GC = 2,
|
||||
} emummc_mmc_t;
|
||||
|
||||
typedef enum {
|
||||
FS_VER_1_0_0 = 0,
|
||||
|
||||
FS_VER_2_0_0,
|
||||
FS_VER_2_0_0_EXFAT,
|
||||
|
||||
FS_VER_2_1_0,
|
||||
FS_VER_2_1_0_EXFAT,
|
||||
|
||||
FS_VER_3_0_0,
|
||||
FS_VER_3_0_0_EXFAT,
|
||||
|
||||
FS_VER_3_0_1,
|
||||
FS_VER_3_0_1_EXFAT,
|
||||
|
||||
FS_VER_4_0_0,
|
||||
FS_VER_4_0_0_EXFAT,
|
||||
|
||||
FS_VER_4_1_0,
|
||||
FS_VER_4_1_0_EXFAT,
|
||||
|
||||
FS_VER_5_0_0,
|
||||
FS_VER_5_0_0_EXFAT,
|
||||
|
||||
FS_VER_5_1_0,
|
||||
FS_VER_5_1_0_EXFAT,
|
||||
|
||||
FS_VER_6_0_0,
|
||||
FS_VER_6_0_0_EXFAT,
|
||||
|
||||
FS_VER_7_0_0,
|
||||
FS_VER_7_0_0_EXFAT,
|
||||
|
||||
FS_VER_8_0_0,
|
||||
FS_VER_8_0_0_EXFAT,
|
||||
|
||||
FS_VER_MAX,
|
||||
} emummc_fs_ver_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t magic;
|
||||
uint32_t type;
|
||||
uint32_t id;
|
||||
uint32_t fs_version;
|
||||
} emummc_base_config_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t start_sector;
|
||||
} emummc_partition_config_t;
|
||||
|
||||
typedef struct {
|
||||
char path[EMUMMC_FILE_PATH_MAX];
|
||||
} emummc_file_config_t;
|
||||
|
||||
typedef struct {
|
||||
emummc_base_config_t base_cfg;
|
||||
union {
|
||||
emummc_partition_config_t partition_cfg;
|
||||
emummc_file_config_t file_cfg;
|
||||
};
|
||||
//char emu_dir_path[EMUMMC_FILE_PATH_MAX];
|
||||
} exo_emummc_config_t;
|
||||
|
||||
_Static_assert(sizeof(exo_emummc_config_t) == 0x90, "exo_emummc_config_t definition!");
|
||||
|
||||
#endif
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <atmosphere.h>
|
||||
#include "emummc_cfg.h"
|
||||
|
||||
/* This serves to set configuration for *exosphere itself*, separate from the SecMon Exosphere mimics. */
|
||||
|
||||
|
@ -35,11 +36,11 @@ typedef struct {
|
|||
uint32_t magic;
|
||||
uint32_t target_firmware;
|
||||
uint32_t flags;
|
||||
uint32_t reserved;
|
||||
uint64_t emunand_config;
|
||||
uint32_t reserved[5];
|
||||
exo_emummc_config_t emummc_cfg;
|
||||
} exosphere_config_t;
|
||||
|
||||
_Static_assert(sizeof(exosphere_config_t) == 0x18, "exosphere config definition");
|
||||
_Static_assert(sizeof(exosphere_config_t) == 0x20 + sizeof(exo_emummc_config_t), "exosphere config definition");
|
||||
|
||||
#define MAILBOX_EXOSPHERE_CONFIGURATION ((volatile exosphere_config_t *)(0x8000F000ull))
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "utils.h"
|
||||
#include "exocfg.h"
|
||||
#include "se.h"
|
||||
#include "lib/log.h"
|
||||
#include "ips.h"
|
||||
|
@ -343,7 +344,7 @@ static void kip1_blz_uncompress(void *hdr_end) {
|
|||
}
|
||||
}
|
||||
|
||||
static kip1_header_t *kip1_uncompress(kip1_header_t *kip, size_t *size) {
|
||||
kip1_header_t *kip1_uncompress(kip1_header_t *kip, size_t *size) {
|
||||
kip1_header_t new_header = *kip;
|
||||
for (unsigned int i = 0; i < 3; i++) {
|
||||
new_header.section_headers[i].compressed_size = new_header.section_headers[i].out_size;
|
||||
|
@ -372,10 +373,60 @@ static kip1_header_t *kip1_uncompress(kip1_header_t *kip, size_t *size) {
|
|||
return (kip1_header_t *)new_kip;
|
||||
}
|
||||
|
||||
kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size) {
|
||||
static const uint8_t g_fs_hashes[FS_VER_MAX][0x8] = {
|
||||
"\xde\x9f\xdd\xa4\x08\x5d\xd5\xfe", /* FS_VER_1_0_0 */
|
||||
|
||||
"\xcd\x7b\xbe\x18\xd6\x13\x0b\x28", /* FS_VER_2_0_0 */
|
||||
"\xe7\x66\x92\xdf\xaa\x04\x20\xe9", /* FS_VER_2_0_0_EXFAT */
|
||||
|
||||
"\x0d\x70\x05\x62\x7b\x07\x76\x7c", /* FS_VER_2_1_0 */
|
||||
"\xdb\xd8\x5f\xca\xcc\x19\x3d\xa8", /* FS_VER_2_1_0_EXFAT */
|
||||
|
||||
"\xa8\x6d\xa5\xe8\x7e\xf1\x09\x7b", /* FS_VER_3_0_0 */
|
||||
"\x98\x1c\x57\xe7\xf0\x2f\x70\xf7", /* FS_VER_3_0_0_EXFAT */
|
||||
|
||||
"\x57\x39\x7c\x06\x3f\x10\xb6\x31", /* FS_VER_3_0_1 */
|
||||
"\x07\x30\x99\xd7\xc6\xad\x7d\x89", /* FS_VER_3_0_1_EXFAT */
|
||||
|
||||
"\x06\xe9\x07\x19\x59\x5a\x01\x0c", /* FS_VER_4_0_0 */
|
||||
"\x54\x9b\x0f\x8d\x6f\x72\xc4\xe9", /* FS_VER_4_0_0_EXFAT */
|
||||
|
||||
"\x80\x96\xaf\x7c\x6a\x35\xaa\x82", /* FS_VER_4_1_0 */
|
||||
"\x02\xd5\xab\xaa\xfd\x20\xc8\xb0", /* FS_VER_4_1_0_EXFAT */
|
||||
|
||||
"\xa6\xf2\x7a\xd9\xac\x7c\x73\xad", /* FS_VER_5_0_0 */
|
||||
"\xce\x3e\xcb\xa2\xf2\xf0\x62\xf5", /* FS_VER_5_0_0_EXFAT */
|
||||
|
||||
"\x76\xf8\x74\x02\xc9\x38\x7c\x0f", /* FS_VER_5_1_0 */
|
||||
"\x10\xb2\xd8\x16\x05\x48\x85\x99", /* FS_VER_5_1_0_EXFAT */
|
||||
|
||||
"\x3a\x57\x4d\x43\x61\x86\x19\x1d", /* FS_VER_6_0_0 */
|
||||
"\x33\x05\x53\xf6\xb5\xfb\x55\xc4", /* FS_VER_6_0_0_EXFAT */
|
||||
|
||||
"\x2A\xDB\xE9\x7E\x9B\x5F\x41\x77", /* FS_VER_7_0_0 */
|
||||
"\x2C\xCE\x65\x9C\xEC\x53\x6A\x8E", /* FS_VER_7_0_0_EXFAT */
|
||||
|
||||
"\xB2\xF5\x17\x6B\x35\x48\x36\x4D", /* FS_VER_8_0_0 */
|
||||
"\xDB\xD9\x41\xC0\xC5\x3C\x52\xCC", /* FS_VER_8_0_0_EXFAT */
|
||||
};
|
||||
|
||||
kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size, emummc_fs_ver_t *out_fs_ver) {
|
||||
uint8_t hash[0x20];
|
||||
se_calculate_sha256(hash, kip, kip_size);
|
||||
|
||||
if (kip->title_id == FS_TITLE_ID) {
|
||||
bool found = false;
|
||||
for (size_t i = 0; i < FS_VER_MAX; i++) {
|
||||
if (memcmp(hash, g_fs_hashes[i], 0x8) == 0) {
|
||||
found = true;
|
||||
*out_fs_ver = (emummc_fs_ver_t)i;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
fatal_error("[NXBOOT]: Failed to identify FS version...");
|
||||
}
|
||||
}
|
||||
|
||||
if (!has_needed_default_kip_patches(kip->title_id, hash, sizeof(hash))) {
|
||||
fatal_error("[NXBOOT]: Missing default patch for KIP %08x%08x...\n", (uint32_t)(kip->title_id >> 32), (uint32_t)kip->title_id);
|
||||
}
|
||||
|
|
|
@ -17,12 +17,16 @@
|
|||
#ifndef FUSEE_IPS_H
|
||||
#define FUSEE_IPS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "utils.h"
|
||||
#include "kip.h"
|
||||
#include <stdint.h>
|
||||
#include "exocfg.h"
|
||||
|
||||
#define FS_TITLE_ID 0x0100000000000000ull
|
||||
|
||||
void apply_kernel_ips_patches(void *kernel, size_t kernel_size);
|
||||
kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size);
|
||||
kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size, emummc_fs_ver_t *out_fs_ver);
|
||||
kip1_header_t *kip1_uncompress(kip1_header_t *kip, size_t *size);
|
||||
|
||||
void kip_patches_set_enable_nogc(void);
|
||||
|
||||
|
|
|
@ -109,8 +109,8 @@ static int emummc_ini_handler(void *user, const char *section, const char *name,
|
|||
emummc_cfg->enabled = (tmp != 0);
|
||||
}
|
||||
if (strcmp(name, EMUMMC_SECTOR_KEY) == 0) {
|
||||
uint64_t sector = 0;
|
||||
sscanf(value, "%llu", §or);
|
||||
uintptr_t sector = 0;
|
||||
sscanf(value, "%x", §or);
|
||||
emummc_cfg->sector = sector;
|
||||
} else if (strcmp(name, EMUMMC_PATH_KEY) == 0) {
|
||||
strncpy(emummc_cfg->path, value, sizeof(emummc_cfg->path) - 1);
|
||||
|
@ -208,7 +208,7 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool nxboot_configure_emummc() {
|
||||
static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
|
||||
emummc_config_t emummc_cfg = {.enabled = false, .sector = -1, .path = ""};
|
||||
|
||||
/* Load emummc settings from BCT.ini file. */
|
||||
|
@ -216,13 +216,25 @@ static bool nxboot_configure_emummc() {
|
|||
fatal_error("[NXBOOT] Failed to parse BCT.ini!\n");
|
||||
}
|
||||
|
||||
memset(exo_emummc_config, 0, sizeof(*exo_emummc_config));
|
||||
exo_emummc_config->base_cfg.magic = MAGIC_EMUMMC_CONFIG;
|
||||
exo_emummc_config->base_cfg.type = EMUMMC_TYPE_NONE;
|
||||
exo_emummc_config->base_cfg.id = 0; /* TODO: Multiple ID support. */
|
||||
exo_emummc_config->base_cfg.fs_version = FS_VER_1_0_0; /* Will be filled out later. */
|
||||
|
||||
if (emummc_cfg.enabled) {
|
||||
if (emummc_cfg.sector >= 0) {
|
||||
exo_emummc_config->base_cfg.type = EMUMMC_TYPE_PARTITION;
|
||||
exo_emummc_config->partition_cfg.start_sector = emummc_cfg.sector;
|
||||
|
||||
/* Mount emulated NAND from SD card partition. */
|
||||
if (nxfs_mount_emummc_partition(emummc_cfg.sector) < 0) {
|
||||
fatal_error("[NXBOOT] Failed to mount EmuMMC from SD card partition!\n");
|
||||
}
|
||||
} else if (is_valid_folder(emummc_cfg.path)) {
|
||||
exo_emummc_config->base_cfg.type = EMUMMC_TYPE_FILES;
|
||||
strncpy(exo_emummc_config->file_cfg.path, emummc_cfg.path, sizeof(exo_emummc_config->file_cfg.path) - 1);
|
||||
|
||||
int num_parts = 0;
|
||||
uint64_t part_limit = 0;
|
||||
char emummc_boot0_path[0x300 + 1] = {0};
|
||||
|
@ -267,11 +279,13 @@ static bool nxboot_configure_emummc() {
|
|||
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, exo_emummc_config_t *exo_emummc_cfg) {
|
||||
exosphere_config_t exo_cfg = {0};
|
||||
|
||||
exo_cfg.magic = MAGIC_EXOSPHERE_CONFIG;
|
||||
exo_cfg.target_firmware = target_firmware;
|
||||
memcpy(&exo_cfg.emummc_cfg, exo_emummc_cfg, sizeof(*exo_emummc_cfg));
|
||||
|
||||
if (keygen_type) {
|
||||
exo_cfg.flags = EXOSPHERE_FLAGS_DEFAULT | EXOSPHERE_FLAG_PERFORM_620_KEYGEN;
|
||||
} else {
|
||||
|
@ -421,15 +435,35 @@ uint32_t nxboot_main(void) {
|
|||
void *warmboot_memaddr;
|
||||
void *package1loader;
|
||||
size_t package1loader_size;
|
||||
void *emummc_kip;
|
||||
size_t emummc_kip_size;
|
||||
uint32_t available_revision;
|
||||
FILE *boot0, *pk2file;
|
||||
void *exosphere_memaddr;
|
||||
exo_emummc_config_t exo_emummc_cfg;
|
||||
|
||||
/* Configure emummc or mount the real NAND. */
|
||||
if (!nxboot_configure_emummc()) {
|
||||
if (!nxboot_configure_emummc(&exo_emummc_cfg)) {
|
||||
emummc_kip = NULL;
|
||||
emummc_kip_size = 0;
|
||||
if (nxfs_mount_emmc() < 0) {
|
||||
fatal_error("[NXBOOT] Failed to mount eMMC!\n");
|
||||
}
|
||||
} else {
|
||||
emummc_kip_size = get_file_size("atmosphere/emummc.kip");
|
||||
if (emummc_kip_size == 0) {
|
||||
fatal_error("[NXBOOT] Could not read emummc kip!\n");
|
||||
}
|
||||
|
||||
/* Allocate memory for the TSEC firmware. */
|
||||
emummc_kip = memalign(0x100, emummc_kip_size);
|
||||
|
||||
if (emummc_kip == NULL) {
|
||||
fatal_error("[NXBOOT] Out of memory!\n");
|
||||
}
|
||||
if (read_from_file(emummc_kip, emummc_kip_size, "atmosphere/emummc.kip") != emummc_kip_size) {
|
||||
fatal_error("[NXBOOT] Could not read the emummc kip!\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate memory for reading Package2. */
|
||||
|
@ -562,7 +596,7 @@ uint32_t nxboot_main(void) {
|
|||
}
|
||||
|
||||
/* Setup boot configuration for Exosphère. */
|
||||
nxboot_configure_exosphere(target_firmware, keygen_type);
|
||||
nxboot_configure_exosphere(target_firmware, keygen_type, &exo_emummc_cfg);
|
||||
|
||||
/* Initialize Boot Reason on older firmware versions. */
|
||||
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
|
||||
|
@ -644,7 +678,10 @@ uint32_t nxboot_main(void) {
|
|||
print(SCREEN_LOG_LEVEL_INFO, u8"[NXBOOT] Configured Stratosphere...\n");
|
||||
|
||||
/* 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, emummc_kip, emummc_kip_size);
|
||||
|
||||
/* Set detected FS version. */
|
||||
MAILBOX_EXOSPHERE_CONFIGURATION->emummc_cfg.base_cfg.fs_version = stratosphere_get_fs_version();
|
||||
|
||||
print(SCREEN_LOG_LEVEL_INFO, u8"[NXBOOT] Reading Exosphère...\n");
|
||||
|
||||
|
|
|
@ -36,6 +36,8 @@ static bool g_fsdev_ready = false;
|
|||
static bool g_rawdev_ready = false;
|
||||
static bool g_emudev_ready = false;
|
||||
|
||||
static bool g_is_emummc = false;
|
||||
|
||||
static sdmmc_t g_sd_sdmmc = {0};
|
||||
static sdmmc_t g_emmc_sdmmc = {0};
|
||||
|
||||
|
@ -106,6 +108,9 @@ static void mmc_partition_finalize(device_partition_t *devpart) {
|
|||
|
||||
/* Finalize hardware. */
|
||||
if (mmcpart->device == &g_sd_device) {
|
||||
if (g_is_emummc) {
|
||||
return;
|
||||
}
|
||||
if (g_sd_device_initialized) {
|
||||
sdmmc_device_finish(&g_sd_device);
|
||||
g_sd_device_initialized = false;
|
||||
|
@ -189,7 +194,7 @@ static int emummc_partition_read(device_partition_t *devpart, void *dst, uint64_
|
|||
rc = (fread(dst, devpart->sector_size, num_sectors, emummc_file) > 0) ? 0 : -1;
|
||||
fclose(emummc_file);
|
||||
return rc;
|
||||
} else {
|
||||
} 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;
|
||||
}
|
||||
|
@ -571,7 +576,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
|
|||
|
||||
/* Failed to register boot0 device. */
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* Setup an emulation template for boot1. */
|
||||
|
@ -585,7 +590,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
|
|||
|
||||
/* Failed to mount boot1. */
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
return -3;
|
||||
}
|
||||
|
||||
/* Don't register emulated boot1 for now. */
|
||||
|
@ -595,13 +600,13 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
|
|||
model.start_sector = emummc_start_sector + (0x400000 * 2 / model.sector_size);
|
||||
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;
|
||||
return -4;
|
||||
}
|
||||
|
||||
/* Register emulated raw NAND device. */
|
||||
|
@ -609,7 +614,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
|
|||
|
||||
/* Failed to register raw NAND device. */
|
||||
if (rc == -1) {
|
||||
return -1;
|
||||
return -5;
|
||||
}
|
||||
|
||||
/* Open emulated raw NAND device. */
|
||||
|
@ -617,7 +622,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
|
|||
|
||||
/* Failed to open emulated raw NAND device. */
|
||||
if (rawnand == NULL) {
|
||||
return -1;
|
||||
return -6;
|
||||
}
|
||||
|
||||
/* Iterate the GPT and mount each emulated raw NAND partition. */
|
||||
|
@ -629,6 +634,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
|
|||
/* All emulated devices are ready. */
|
||||
if (rc == 0) {
|
||||
g_emudev_ready = true;
|
||||
g_is_emummc = true;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
@ -772,6 +778,7 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
|
|||
/* All emulated devices are ready. */
|
||||
if (rc == 0) {
|
||||
g_emudev_ready = true;
|
||||
g_is_emummc = true;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
static void package2_decrypt(package2_header_t *package2);
|
||||
static size_t package2_get_src_section(void **section, package2_header_t *package2, unsigned int id);
|
||||
static size_t package2_get_thermosphere(void **thermosphere);
|
||||
static ini1_header_t *package2_rebuild_ini1(ini1_header_t *ini1, uint32_t target_firmware);
|
||||
static ini1_header_t *package2_rebuild_ini1(ini1_header_t *ini1, uint32_t target_firmware, void *emummc, size_t emummc_size);
|
||||
static void package2_append_section(unsigned int id, package2_header_t *package2, void *data, size_t size);
|
||||
static void package2_fixup_header_and_section_hashes(package2_header_t *package2, size_t size);
|
||||
|
||||
|
@ -44,7 +44,7 @@ static inline size_t align_to_4(size_t s) {
|
|||
return ((s + 3) >> 2) << 2;
|
||||
}
|
||||
|
||||
void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firmware) {
|
||||
void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firmware, void *emummc, size_t emummc_size) {
|
||||
package2_header_t *rebuilt_package2;
|
||||
size_t rebuilt_package2_size;
|
||||
void *kernel;
|
||||
|
@ -104,7 +104,7 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm
|
|||
}
|
||||
|
||||
/* Perform any patches to the INI1, rebuilding it (This is where our built-in sysmodules will be added.) */
|
||||
rebuilt_ini1 = package2_rebuild_ini1(orig_ini1, target_firmware);
|
||||
rebuilt_ini1 = package2_rebuild_ini1(orig_ini1, target_firmware, emummc, emummc_size);
|
||||
print(SCREEN_LOG_LEVEL_DEBUG, "Rebuilt INI1...\n");
|
||||
|
||||
/* Allocate the rebuilt package2. */
|
||||
|
@ -317,7 +317,7 @@ static size_t package2_get_thermosphere(void **thermosphere) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static ini1_header_t *package2_rebuild_ini1(ini1_header_t *ini1, uint32_t target_firmware) {
|
||||
static ini1_header_t *package2_rebuild_ini1(ini1_header_t *ini1, uint32_t target_firmware, void *emummc, size_t emummc_size) {
|
||||
/* TODO: Do we want to support loading another INI from sd:/whatever/INI1.bin? */
|
||||
ini1_header_t *inis_to_merge[STRATOSPHERE_INI1_MAX] = {0};
|
||||
ini1_header_t *merged;
|
||||
|
@ -327,7 +327,7 @@ static ini1_header_t *package2_rebuild_ini1(ini1_header_t *ini1, uint32_t target
|
|||
inis_to_merge[STRATOSPHERE_INI1_PACKAGE2] = ini1;
|
||||
|
||||
/* Merge all of the INI1s. */
|
||||
merged = stratosphere_merge_inis(inis_to_merge, STRATOSPHERE_INI1_MAX);
|
||||
merged = stratosphere_merge_inis(inis_to_merge, STRATOSPHERE_INI1_MAX, emummc, emummc_size);
|
||||
|
||||
/* Free temporary buffer. */
|
||||
stratosphere_free_ini1();
|
||||
|
|
|
@ -86,6 +86,6 @@ static inline uint8_t package2_meta_get_header_version(const package2_meta_t *me
|
|||
return (uint8_t)((metadata->ctr_dwords[1] ^ (metadata->ctr_dwords[1] >> 16) ^ (metadata->ctr_dwords[1] >> 24)) & 0xFF);
|
||||
}
|
||||
|
||||
void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firmware);
|
||||
void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firmware, void *emummc, size_t emummc_size);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -494,7 +494,7 @@ static int sdmmc_sd_send_op_cond(sdmmc_device_t *device, bool is_sd_ver2, bool i
|
|||
device->is_block_sdhc = true;
|
||||
|
||||
/* We asked for low voltage support and the card accepted. */
|
||||
if (is_uhs_en && (resp & SD_ROCR_S18A))
|
||||
if (false && is_uhs_en && (resp & SD_ROCR_S18A))
|
||||
{
|
||||
/* Voltage switching is only valid for SDMMC1. */
|
||||
if (device->sdmmc->controller == SDMMC_1)
|
||||
|
|
|
@ -51,6 +51,12 @@ static bool g_stratosphere_boot_enabled = true;
|
|||
extern const uint8_t loader_kip[], pm_kip[], sm_kip[], spl_kip[], boot_kip[], ams_mitm_kip[];
|
||||
extern const uint32_t loader_kip_size, pm_kip_size, sm_kip_size, spl_kip_size, boot_kip_size, ams_mitm_kip_size;
|
||||
|
||||
static emummc_fs_ver_t g_fs_ver = FS_VER_1_0_0;
|
||||
|
||||
emummc_fs_ver_t stratosphere_get_fs_version(void) {
|
||||
return g_fs_ver;
|
||||
}
|
||||
|
||||
/* GCC doesn't consider the size as const... we have to write it ourselves. */
|
||||
|
||||
ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware) {
|
||||
|
@ -152,8 +158,6 @@ void stratosphere_free_ini1(void) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void try_add_sd_kip(ini1_header_t *ini1, const char *kip_path) {
|
||||
size_t file_size = get_file_size(kip_path);
|
||||
|
||||
|
@ -180,6 +184,60 @@ static void try_add_sd_kip(ini1_header_t *ini1, const char *kip_path) {
|
|||
ini1->num_processes++;
|
||||
}
|
||||
|
||||
static kip1_header_t *inject_emummc_kip(kip1_header_t *fs_kip, kip1_header_t *emummc_kip) {
|
||||
/* Ensure KIPs are uncompressed. */
|
||||
size_t fs_kip_size, emummc_kip_size;
|
||||
fs_kip = kip1_uncompress(fs_kip, &fs_kip_size);
|
||||
emummc_kip = kip1_uncompress(emummc_kip, &emummc_kip_size);
|
||||
|
||||
/* Allocate kip. */
|
||||
kip1_header_t *injected_kip = calloc(1, fs_kip_size + emummc_kip_size);
|
||||
if (injected_kip == NULL) {
|
||||
fatal_error("Failed to allocate memory for emummc kip injection!");
|
||||
}
|
||||
memcpy(injected_kip, fs_kip, sizeof(*fs_kip));
|
||||
|
||||
const size_t fs_contents_size = kip1_get_size_from_header(fs_kip) - sizeof(kip1_header_t);
|
||||
|
||||
const size_t emummc_data_size = emummc_kip->section_headers[3].out_offset + emummc_kip->section_headers[3].out_size;
|
||||
if (emummc_data_size & 0xFFF) {
|
||||
fatal_error("Invalid emummc kip!");
|
||||
}
|
||||
|
||||
/* Copy over capabilities. */
|
||||
memcpy(injected_kip->capabilities, emummc_kip->capabilities, sizeof(emummc_kip->capabilities));
|
||||
|
||||
/* Add extra cap for 1.0.0 */
|
||||
if (stratosphere_get_fs_version() == FS_VER_1_0_0) {
|
||||
for (size_t i = 0; i < 0x20; i++) {
|
||||
if (injected_kip->capabilities[i] = 0xFFFFFFFF) {
|
||||
/* Map PMC registers in. */
|
||||
injected_kip->capabilities[i] = 0x07000E7F;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Update sections. */
|
||||
injected_kip->section_headers[0].out_size += emummc_data_size;
|
||||
injected_kip->section_headers[0].compressed_size += emummc_data_size;
|
||||
for (size_t i = 1; i < 4; i++) {
|
||||
injected_kip->section_headers[i].out_offset += emummc_data_size;
|
||||
}
|
||||
|
||||
/* Copy data. */
|
||||
{
|
||||
size_t ofs = 0;
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
memcpy(injected_kip->data + emummc_kip->section_headers[i].out_offset, emummc_kip->data + ofs, emummc_kip->section_headers[i].compressed_size);
|
||||
ofs += emummc_kip->section_headers[i].compressed_size;
|
||||
}
|
||||
}
|
||||
memcpy(injected_kip->data + emummc_data_size, fs_kip->data, fs_contents_size);
|
||||
|
||||
return injected_kip;
|
||||
}
|
||||
|
||||
ini1_header_t *stratosphere_get_sd_files_ini1(void) {
|
||||
if (g_sd_files_ini1 != NULL) {
|
||||
return g_sd_files_ini1;
|
||||
|
@ -246,7 +304,7 @@ ini1_header_t *stratosphere_get_sd_files_ini1(void) {
|
|||
}
|
||||
|
||||
/* Merges some number of INI1s into a single INI1. It's assumed that the INIs are in order of preference. */
|
||||
ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, size_t num_inis) {
|
||||
ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, size_t num_inis, void *emummc, size_t emummc_size) {
|
||||
uint32_t total_num_processes = 0;
|
||||
|
||||
/* Validate all ini headers. */
|
||||
|
@ -305,11 +363,17 @@ ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, size_t num_inis) {
|
|||
fatal_error("Not enough space for all the KIP1s!\n");
|
||||
}
|
||||
|
||||
kip1_header_t *patched_kip = apply_kip_ips_patches(current_kip, current_kip_size);
|
||||
kip1_header_t *patched_kip = apply_kip_ips_patches(current_kip, current_kip_size, &g_fs_ver);
|
||||
|
||||
if (current_kip->title_id == FS_TITLE_ID && emummc != NULL) {
|
||||
patched_kip = inject_emummc_kip(patched_kip != NULL ? patched_kip : current_kip, (kip1_header_t *)emummc);
|
||||
dump_to_file(patched_kip, kip1_get_size_from_header(patched_kip), "DEBUG_EMUMMC.kip");
|
||||
}
|
||||
|
||||
if (patched_kip != NULL) {
|
||||
size_t patched_kip_size = kip1_get_size_from_header(patched_kip);
|
||||
if (patched_kip_size > remaining_size) {
|
||||
fatal_error("Not enough space for all the KIP1s!\n");
|
||||
fatal_error("Not enough space for all the KIP1s! %08x %08x\n", remaining_size, patched_kip_size);
|
||||
}
|
||||
memcpy(current_dst_kip, patched_kip, patched_kip_size);
|
||||
remaining_size -= patched_kip_size;
|
||||
|
@ -326,6 +390,9 @@ ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, size_t num_inis) {
|
|||
}
|
||||
}
|
||||
merged->size = sizeof(ini1_header_t) + (uint32_t)(current_dst_kip - merged->kip_data);
|
||||
if (merged->size & 3) {
|
||||
merged->size = (merged->size + 3) & ~3;
|
||||
}
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "utils.h"
|
||||
#include "kip.h"
|
||||
#include "exocfg.h"
|
||||
|
||||
#define STRATOSPHERE_INI1_SDFILES 0x0
|
||||
#define STRATOSPHERE_INI1_EMBEDDED 0x1
|
||||
|
@ -29,7 +30,9 @@ ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware);
|
|||
ini1_header_t *stratosphere_get_sd_files_ini1(void);
|
||||
void stratosphere_free_ini1(void);
|
||||
|
||||
ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, unsigned int num_inis);
|
||||
emummc_fs_ver_t stratosphere_get_fs_version(void);
|
||||
|
||||
ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, unsigned int num_inis, void *emummc, size_t emummc_size);
|
||||
|
||||
typedef struct {
|
||||
bool has_nogc_config;
|
||||
|
|
Loading…
Reference in a new issue