ams: revamp target firmware

This commit is contained in:
Michael Scire 2020-05-06 22:29:07 -07:00
parent 85cd2c97a0
commit 8e75a4169d
48 changed files with 863 additions and 693 deletions

View file

@ -206,7 +206,7 @@ uint32_t fuse_get_hardware_type(uint32_t target_firmware) {
uint32_t hardware_type = (((fuse_reserved_odm4 >> 7) & 2) | ((fuse_reserved_odm4 >> 2) & 1));
/* Firmware from versions 1.0.0 to 3.0.2. */
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs();
if (hardware_type >= 1) {
return (hardware_type > 2) ? 3 : hardware_type - 1;
@ -215,7 +215,7 @@ uint32_t fuse_get_hardware_type(uint32_t target_firmware) {
} else {
return 3;
}
} else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_700) { /* Firmware versions from 4.0.0 to 6.2.0. */
} else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) { /* Firmware versions from 4.0.0 to 6.2.0. */
static const uint32_t types[] = {0,1,4,3};
hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C);
hardware_type--;

View file

@ -206,7 +206,7 @@ uint32_t fuse_get_hardware_type(uint32_t target_firmware) {
uint32_t hardware_type = (((fuse_reserved_odm4 >> 7) & 2) | ((fuse_reserved_odm4 >> 2) & 1));
/* Firmware from versions 1.0.0 to 3.0.2. */
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs();
if (hardware_type >= 1) {
return (hardware_type > 2) ? 3 : hardware_type - 1;
@ -215,7 +215,7 @@ uint32_t fuse_get_hardware_type(uint32_t target_firmware) {
} else {
return 3;
}
} else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_700) { /* Firmware versions from 4.0.0 to 6.2.0. */
} else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) { /* Firmware versions from 4.0.0 to 6.2.0. */
static const uint32_t types[] = {0,1,4,3};
hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C);
hardware_type--;

View file

@ -13,7 +13,7 @@
* 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 FUSEE_DEVICE_PARTITION_H
#define FUSEE_DEVICE_PARTITION_H
@ -50,6 +50,7 @@ typedef struct device_partition_t {
device_partition_cipher_t read_cipher; /* Cipher for read operations. */
device_partition_cipher_t write_cipher; /* Cipher for write operations. */
DevicePartitionCryptoMode crypto_mode; /* Mode to use for cryptographic operations. */
size_t crypto_sector_size;
device_partition_initializer_t initializer; /* Initializer. */
device_partition_finalizer_t finalizer; /* Finalizer. */
@ -65,7 +66,7 @@ typedef struct device_partition_t {
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. */
bool initialized;
char *emu_file_path; /* Emulated device file path. */
bool emu_use_file;
} device_partition_t;

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
@ -121,7 +121,7 @@ int fsdev_mount_device(const char *name, const device_partition_t *devpart, bool
fsdev_device_t *device = fsdev_find_device(name);
FRESULT rc;
char drname[40];
if (device != NULL) {
errno = EEXIST; /* Device already exists */
return -1;
@ -170,7 +170,7 @@ int fsdev_mount_device(const char *name, const device_partition_t *devpart, bool
VolumeStr[device - g_fsdev_devices] = FKNAM;
return fsdev_convert_rc(NULL, rc);
}
device->setup = true;
device->registered = false;
@ -289,6 +289,20 @@ int fsdev_unmount_device(const char *name) {
return ret;
}
int fsdev_register_keys(const char *name, unsigned int target_firmware, BisPartition part) {
fsdev_device_t *device = fsdev_find_device(name);
if (device == NULL) {
errno = ENOENT;
return -1;
}
derive_bis_key(device->devpart.keys, part, target_firmware);
return 0;
}
int fsdev_unmount_all(void) {
for (size_t i = 0; i < FF_VOLUMES; i++) {
int ret = fsdev_unmount_device(g_fsdev_devices[i].name);
@ -403,7 +417,7 @@ static void fsdev_filinfo_to_st(struct stat *st, const FILINFO *info) {
date.tm_sec = (info->ftime << 1) & 63;
date.tm_min = (info->ftime >> 5) & 63;
date.tm_hour = (info->ftime >> 11) & 31;
date.tm_isdst = 0;
st->st_atime = st->st_mtime = st->st_ctime = mktime(&date);

View file

@ -13,7 +13,7 @@
* 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 FUSEE_FS_DEV_H
#define FUSEE_FS_DEV_H
@ -21,12 +21,15 @@
#include <stdint.h>
#include <stdbool.h>
#include "device_partition.h"
#include "key_derivation.h"
int fsdev_mount_device(const char *name, const device_partition_t *devpart, bool initialize_immediately);
int fsdev_register_device(const char *name);
int fsdev_unregister_device(const char *name);
int fsdev_unmount_device(const char *name); /* also unregisters. */
int fsdev_register_keys(const char *name, unsigned int target_firmware, BisPartition part);
int fsdev_set_attr(const char *file, int attr, int mask); /* Non-standard function to set file DOS attributes. */
int fsdev_get_attr(const char *file); /* Non-standard function to get file DOS attributes. */

View file

@ -13,10 +13,12 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <sys/stat.h>
#include "lib/fatfs/ff.h"
#include "fs_utils.h"
#include "fs_dev.h"
size_t get_file_size(const char *filename) {
struct stat st;
@ -54,7 +56,7 @@ bool is_valid_folder(const char *path) {
if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
return true;
}
return false;
}
@ -63,6 +65,29 @@ bool is_valid_file(const char *path) {
if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
return true;
}
return false;
}
bool is_valid_concatenation_file(const char *path) {
if (is_valid_file(path)) {
return true;
} else if (is_valid_folder(path)) {
/* Check if the archive bit is set. */
int rc = fsdev_get_attr(path);
/* Failed to get file DOS attributes. */
if (rc == -1) {
return false;
}
/* Check if our path is not a directory (it should be if we're in this code, though...). */
if (!(rc & AM_DIR)) {
return false;
}
return (rc & AM_ARC) != 0;
} else {
return false;
}
}

View file

@ -13,7 +13,7 @@
* 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 FUSEE_FS_UTILS_H
#define FUSEE_FS_UTILS_H
@ -25,4 +25,6 @@ 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);
bool is_valid_concatenation_file(const char *path);
#endif

View file

@ -206,7 +206,7 @@ uint32_t fuse_get_hardware_type(uint32_t target_firmware) {
uint32_t hardware_type = (((fuse_reserved_odm4 >> 7) & 2) | ((fuse_reserved_odm4 >> 2) & 1));
/* Firmware from versions 1.0.0 to 3.0.2. */
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
volatile tegra_fuse_chip_t *fuse_chip = fuse_chip_get_regs();
if (hardware_type >= 1) {
return (hardware_type > 2) ? 3 : hardware_type - 1;
@ -215,7 +215,7 @@ uint32_t fuse_get_hardware_type(uint32_t target_firmware) {
} else {
return 3;
}
} else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_700) { /* Firmware versions from 4.0.0 to 6.2.0. */
} else if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) { /* Firmware versions from 4.0.0 to 6.2.0. */
static const uint32_t types[] = {0,1,4,3};
hardware_type |= ((fuse_reserved_odm4 >> 14) & 0x3C);
hardware_type--;
@ -261,3 +261,12 @@ void fuse_get_hardware_info(void *dst) {
memcpy(dst, hw_info, 0x10);
}
/* Get the Key Generation value. */
uint32_t fuse_get_5x_key_generation(void) {
if ((fuse_get_reserved_odm(4) & 0x800) && (fuse_get_reserved_odm(0) == 0x8E61ECAE) && (fuse_get_reserved_odm(1) == 0xF2BA3BB2)) {
return (fuse_get_reserved_odm(2) & 0x1F);
} else {
return 0;
}
}

View file

@ -219,6 +219,7 @@ uint32_t fuse_get_dram_id(void);
uint32_t fuse_get_hardware_type(uint32_t target_firmware);
uint32_t fuse_get_retail_type(void);
void fuse_get_hardware_info(void *dst);
uint32_t fuse_get_5x_key_generation(void);
uint32_t fuse_hw_read(uint32_t addr);
void fuse_hw_write(uint32_t value, uint32_t addr);

View file

@ -15,6 +15,7 @@
*/
#include <stdio.h>
#include "lib/log.h"
#include "key_derivation.h"
#include "masterkey.h"
#include "se.h"
@ -143,29 +144,16 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
}
/* Do 6.2.0+ keygen. */
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_620) {
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_6_2_0) {
uint32_t desired_keyblob;
switch (target_firmware) {
case ATMOSPHERE_TARGET_FIRMWARE_620:
desired_keyblob = MASTERKEY_REVISION_620;
break;
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
desired_keyblob = MASTERKEY_REVISION_700_800;
break;
case ATMOSPHERE_TARGET_FIRMWARE_810:
desired_keyblob = MASTERKEY_REVISION_810;
/* Fallthrough */
case ATMOSPHERE_TARGET_FIRMWARE_900:
desired_keyblob = MASTERKEY_REVISION_900;
/* Fallthrough */
case ATMOSPHERE_TARGET_FIRMWARE_910:
case ATMOSPHERE_TARGET_FIRMWARE_1000:
desired_keyblob = MASTERKEY_REVISION_910_CURRENT;
break;
default:
fatal_error("Unknown target firmware: %02x!", target_firmware);
break;
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_8_1_0) {
/* NOTE: We load in the current key for all >= 8.1.0 firmwares to reduce sept binaries. */
desired_keyblob = MASTERKEY_REVISION_910_CURRENT;
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
desired_keyblob = MASTERKEY_REVISION_700_800;
} else {
desired_keyblob = MASTERKEY_REVISION_620;
}
/* Try emulation result. */
@ -213,31 +201,31 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
set_aes_keyslot(0xC, g_dec_keyblobs[available_revision].master_kek, 0x10);
/* Also set the Package1 key for the revision that is stored on the eMMC boot0 partition. */
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_620) {
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_6_2_0) {
load_package1_key(available_revision);
}
/* Derive keys for Exosphere, lock critical keyslots. */
switch (target_firmware) {
case ATMOSPHERE_TARGET_FIRMWARE_100:
case ATMOSPHERE_TARGET_FIRMWARE_200:
case ATMOSPHERE_TARGET_FIRMWARE_300:
case ATMOSPHERE_TARGET_FIRMWARE_1_0_0:
case ATMOSPHERE_TARGET_FIRMWARE_2_0_0:
case ATMOSPHERE_TARGET_FIRMWARE_3_0_0:
decrypt_data_into_keyslot(0xD, 0xF, devicekey_seed, 0x10);
decrypt_data_into_keyslot(0xC, 0xC, masterkey_seed, 0x10);
break;
case ATMOSPHERE_TARGET_FIRMWARE_400:
case ATMOSPHERE_TARGET_FIRMWARE_4_0_0:
decrypt_data_into_keyslot(0xD, 0xF, devicekey_4x_seed, 0x10);
decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
decrypt_data_into_keyslot(0xE, 0xC, masterkey_4x_seed, 0x10);
decrypt_data_into_keyslot(0xC, 0xC, masterkey_seed, 0x10);
break;
case ATMOSPHERE_TARGET_FIRMWARE_500:
case ATMOSPHERE_TARGET_FIRMWARE_600:
case ATMOSPHERE_TARGET_FIRMWARE_620:
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
case ATMOSPHERE_TARGET_FIRMWARE_810:
case ATMOSPHERE_TARGET_FIRMWARE_900:
case ATMOSPHERE_TARGET_FIRMWARE_5_0_0:
case ATMOSPHERE_TARGET_FIRMWARE_6_0_0:
case ATMOSPHERE_TARGET_FIRMWARE_6_2_0:
case ATMOSPHERE_TARGET_FIRMWARE_7_0_0:
case ATMOSPHERE_TARGET_FIRMWARE_8_0_0:
case ATMOSPHERE_TARGET_FIRMWARE_8_1_0:
case ATMOSPHERE_TARGET_FIRMWARE_9_0_0:
decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10);
decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
decrypt_data_into_keyslot(0xE, 0xC, masterkey_4x_seed, 0x10);
@ -254,11 +242,13 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
/* Sets final keyslot flags, for handover to TZ/Exosphere. Setting these will prevent the BPMP from using the device key or master key. */
void finalize_nx_keydata(uint32_t target_firmware) {
set_aes_keyslot_flags(0xC, 0xFF);
set_aes_keyslot_flags((target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_400) ? (KEYSLOT_SWITCH_4XOLDDEVICEKEY) : (KEYSLOT_SWITCH_DEVICEKEY), 0xFF);
set_aes_keyslot_flags((target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) ? (KEYSLOT_SWITCH_4XOLDDEVICEKEY) : (KEYSLOT_SWITCH_DEVICEKEY), 0xFF);
}
static void generate_specific_aes_key(void *dst, const void *wrapped_key, bool should_mask, uint32_t target_firmware) {
unsigned int keyslot = (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_400) ? (KEYSLOT_SWITCH_4XOLDDEVICEKEY) : (KEYSLOT_SWITCH_DEVICEKEY);
static void generate_specific_aes_key(void *dst, const void *wrapped_key, bool should_mask, uint32_t target_firmware, uint32_t generation) {
unsigned int keyslot = (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) ? (devkey_get_keyslot(generation)) : (KEYSLOT_SWITCH_DEVICEKEY);
if (fuse_get_bootrom_patch_version() < 0x7F) {
/* On dev units, use a fixed "all-zeroes" seed. */
/* Yes, this data really is all-zero in actual TrustZone .rodata. */
@ -281,7 +271,7 @@ static void generate_specific_aes_key(void *dst, const void *wrapped_key, bool s
}
}
static void generate_personalized_aes_key_for_bis(void *dst, const void *wrapped_kek, const void *wrapped_key, uint32_t target_firmware) {
static void generate_personalized_aes_key_for_bis(void *dst, const void *wrapped_kek, const void *wrapped_key, uint32_t target_firmware, uint32_t generation) {
static const uint8_t AL16 kek_source[0x10] = {
0x4D, 0x87, 0x09, 0x86, 0xC4, 0x5D, 0x20, 0x72, 0x2F, 0xBA, 0x10, 0x53, 0xDA, 0x92, 0xE8, 0xA9
};
@ -289,7 +279,7 @@ static void generate_personalized_aes_key_for_bis(void *dst, const void *wrapped
0x89, 0x61, 0x5E, 0xE0, 0x5C, 0x31, 0xB6, 0x80, 0x5F, 0xE5, 0x8F, 0x3D, 0xA2, 0x4F, 0x7A, 0xA8
};
unsigned int keyslot = (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_400) ? (KEYSLOT_SWITCH_4XOLDDEVICEKEY) : (KEYSLOT_SWITCH_DEVICEKEY);
unsigned int keyslot = (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) ? (devkey_get_keyslot(generation)) : (KEYSLOT_SWITCH_DEVICEKEY);
/* Derive kek. */
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, keyslot, kek_source, 0x10);
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, KEYSLOT_SWITCH_TEMPKEY, wrapped_kek, 0x10);
@ -314,16 +304,18 @@ void derive_bis_key(void *dst, BisPartition partition_id, uint32_t target_firmwa
}
};
const uint32_t bis_key_generation = fuse_get_5x_key_generation();
static const uint8_t AL16 bis_kek_source[0x10] = {0x34, 0xC1, 0xA0, 0xC4, 0x82, 0x58, 0xF8, 0xB4, 0xFA, 0x9E, 0x5E, 0x6A, 0xDA, 0xFC, 0x7E, 0x4F};
switch (partition_id) {
case BisPartition_Calibration:
generate_specific_aes_key(dst, key_source_for_bis[partition_id][0], false, target_firmware);
generate_specific_aes_key(dst + 0x10, key_source_for_bis[partition_id][1], false, target_firmware);
generate_specific_aes_key(dst, key_source_for_bis[partition_id][0], false, target_firmware, bis_key_generation);
generate_specific_aes_key(dst + 0x10, key_source_for_bis[partition_id][1], false, target_firmware, bis_key_generation);
break;
case BisPartition_Safe:
case BisPartition_UserSystem:
generate_personalized_aes_key_for_bis(dst, bis_kek_source, key_source_for_bis[partition_id][0], target_firmware);
generate_personalized_aes_key_for_bis(dst + 0x10, bis_kek_source, key_source_for_bis[partition_id][1], target_firmware);
generate_personalized_aes_key_for_bis(dst, bis_kek_source, key_source_for_bis[partition_id][0], target_firmware, bis_key_generation);
generate_personalized_aes_key_for_bis(dst + 0x10, bis_kek_source, key_source_for_bis[partition_id][1], target_firmware, bis_key_generation);
break;
default:
generic_panic();

View file

@ -91,7 +91,7 @@ static void add_prefix(ScreenLogLevel screen_log_level, const char *fmt, char *b
/**
* print - logs a message and prints it to screen based on its screen_log_level
*
*
* If the level is below g_screen_log_level it will not be shown but logged to UART
* Use SCREEN_LOG_LEVEL_NO_PREFIX if you don't want a prefix to be added
* UART is TODO

View file

@ -17,6 +17,7 @@
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <vapours/ams/ams_target_firmware.h>
#include "utils.h"
#include "masterkey.h"
@ -26,6 +27,7 @@ static unsigned int g_mkey_revision = 0;
static bool g_determined_mkey_revision = false;
static uint8_t g_old_masterkeys[MASTERKEY_REVISION_MAX][0x10];
static uint8_t g_old_devicekeys[MASTERKEY_NUM_NEW_DEVICE_KEYS - 1][0x10];
/* TODO: Extend with new vectors, as needed. */
/* Dev unit keys. */
@ -59,6 +61,39 @@ static const uint8_t mkey_vectors[MASTERKEY_REVISION_MAX][0x10] =
{0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A}, /* Master key 09 encrypted with Master key 0A. */
};
static const uint8_t new_device_key_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
{0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.x New Device Key Source. */
{0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.x New Device Key Source. */
{0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.x New Device Key Source. */
{0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 New Device Key Source. */
{0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 New Device Key Source. */
{0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 New Device Key Source. */
{0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 New Device Key Source. */
{0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 New Device Key Source. */
};
static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
{0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.x New Device Keygen Source. */
{0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.x New Device Keygen Source. */
{0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.x New Device Keygen Source. */
{0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 New Device Keygen Source. */
{0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */
{0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 New Device Keygen Source. */
{0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 New Device Keygen Source. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.1.0 New Device Keygen Source to be added on next change-of-keys. */
};
static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
{0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34}, /* 4.x New Device Keygen Source. */
{0x59, 0x2D, 0x20, 0x69, 0x33, 0xB5, 0x17, 0xBA, 0xCF, 0xB1, 0x4E, 0xFD, 0xE4, 0xC2, 0x7B, 0xA8}, /* 5.x New Device Keygen Source. */
{0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5}, /* 6.x New Device Keygen Source. */
{0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38}, /* 6.2.0 New Device Keygen Source. */
{0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 7.0.0 New Device Keygen Source. */
{0x94, 0xD6, 0xA8, 0xC0, 0x95, 0xAF, 0xD0, 0xA6, 0x27, 0x53, 0x5E, 0xE5, 0x8E, 0x70, 0x1F, 0x87}, /* 8.1.0 New Device Keygen Source. */
{0x61, 0x6A, 0x88, 0x21, 0xA3, 0x52, 0xB0, 0x19, 0x16, 0x25, 0xA4, 0xE3, 0x4C, 0x54, 0x02, 0x0F}, /* 9.0.0 New Device Keygen Source. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 9.1.0 New Device Keygen Source to be added on next change-of-keys. */
};
static bool check_mkey_revision(unsigned int revision, bool is_retail) {
uint8_t final_vector[0x10];
@ -127,3 +162,50 @@ unsigned int mkey_get_keyslot(unsigned int revision) {
return KEYSLOT_SWITCH_TEMPKEY;
}
}
void derive_new_device_keys(bool is_retail, unsigned int keygen_keyslot, unsigned int target_firmware) {
uint8_t work_buffer[0x10];
for (unsigned int revision = 0; revision < MASTERKEY_NUM_NEW_DEVICE_KEYS; revision++) {
const unsigned int relative_revision = revision + MASTERKEY_REVISION_400_410;
se_aes_ecb_decrypt_block(keygen_keyslot, work_buffer, 0x10, new_device_key_sources[revision], 0x10);
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, mkey_get_keyslot(0), is_retail ? new_device_keygen_sources[revision] : new_device_keygen_sources_dev[revision], 0x10);
if (relative_revision > mkey_get_revision()) {
break;
} else if (relative_revision == mkey_get_revision()) {
/* On 7.0.0, sept will have derived this key for us already. */
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
decrypt_data_into_keyslot(KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10);
}
} else {
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10, work_buffer, 0x10);
set_old_devkey(relative_revision, work_buffer);
}
}
set_aes_keyslot_flags(KEYSLOT_SWITCH_DEVICEKEY, 0xFF);
clear_aes_keyslot(keygen_keyslot);
}
void set_old_devkey(unsigned int revision, const uint8_t *key) {
if (revision < MASTERKEY_REVISION_400_410 || MASTERKEY_REVISION_MAX <= revision) {
generic_panic();
}
memcpy(g_old_devicekeys[revision - MASTERKEY_REVISION_400_410], key, 0x10);
}
unsigned int devkey_get_keyslot(unsigned int revision) {
if (!g_determined_mkey_revision || revision > g_mkey_revision) {
generic_panic();
}
if (revision < MASTERKEY_REVISION_400_410) {
return KEYSLOT_SWITCH_4XOLDDEVICEKEY;
} else if (revision < g_mkey_revision) {
/* Load into a temp keyslot. */
set_aes_keyslot(KEYSLOT_SWITCH_TEMPKEY, g_old_devicekeys[revision - MASTERKEY_REVISION_400_410], 0x10);
return KEYSLOT_SWITCH_TEMPKEY;
} else {
return KEYSLOT_SWITCH_DEVICEKEY;
}
}

View file

@ -41,7 +41,11 @@ int mkey_detect_revision(bool is_retail);
unsigned int mkey_get_revision(void);
unsigned int mkey_get_keyslot(unsigned int revision);
void derive_new_device_keys(bool is_retail, unsigned int keygen_keyslot, unsigned int target_firmware);
void set_old_devkey(unsigned int revision, const uint8_t *key);
unsigned int devkey_get_keyslot(unsigned int revision);
#endif

View file

@ -218,41 +218,110 @@ static int stratosphere_ini_handler(void *user, const char *section, const char
return 1;
}
static bool is_nca_present(const char *nca_name) {
char path[0x100];
snprintf(path, sizeof(path), "system:/contents/registered/%s.nca", nca_name);
return is_valid_concatenation_file(path);
}
static uint32_t nxboot_get_specific_target_firmware(uint32_t target_firmware){
#define CHECK_NCA(NCA_ID, VERSION) do { if (is_nca_present(NCA_ID)) { return ATMOSPHERE_TARGET_FIRMWARE_##VERSION; } } while(0)
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_10_0_0) {
CHECK_NCA("e951bc9dedcd54f65ffd83d4d050f9e0", 10_0_2);
CHECK_NCA("36ab1acf0c10a2beb9f7d472685f9a89", 10_0_1);
CHECK_NCA("5625cdc21d5f1ca52f6c36ba261505b9", 10_0_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_9_1_0) {
CHECK_NCA("09ef4d92bb47b33861e695ba524a2c17", 9_2_0);
CHECK_NCA("c5fbb49f2e3648c8cfca758020c53ecb", 9_1_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_9_0_0) {
CHECK_NCA("fd1ffb82dc1da76346343de22edbc97c", 9_0_1);
CHECK_NCA("a6af05b33f8f903aab90c8b0fcbcc6a4", 9_0_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_8_1_0) {
CHECK_NCA("724d9b432929ea43e787ad81bf09ae65", 8_1_1); /* 8.1.1-100 from Lite */
CHECK_NCA("e9bb0602e939270a9348bddd9b78827b", 8_1_1); /* 8.1.1-12 from chinese gamecard */
CHECK_NCA("7eedb7006ad855ec567114be601b2a9d", 8_1_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_8_0_0) {
CHECK_NCA("6c5426d27c40288302ad616307867eba", 8_0_1);
CHECK_NCA("4fe7b4abcea4a0bcc50975c1a926efcb", 8_0_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
CHECK_NCA("e6b22c40bb4fa66a151f1dc8db5a7b5c", 7_0_1);
CHECK_NCA("c613bd9660478de69bc8d0e2e7ea9949", 7_0_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_6_2_0) {
CHECK_NCA("6dfaaf1a3cebda6307aa770d9303d9b6", 6_2_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
CHECK_NCA("1d21680af5a034d626693674faf81b02", 6_1_0);
CHECK_NCA("663e74e45ffc86fbbaeb98045feea315", 6_0_1);
CHECK_NCA("258c1786b0f6844250f34d9c6f66095b", 6_0_0); /* Release 6.0.0-5.0 */
CHECK_NCA("286e30bafd7e4197df6551ad802dd815", 6_0_0); /* Pre-Release 6.0.0-4.0 */
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
CHECK_NCA("fce3b0ea366f9c95fe6498b69274b0e7", 5_1_0);
CHECK_NCA("c5758b0cb8c6512e8967e38842d35016", 5_0_2);
CHECK_NCA("53eb605d4620e8fd50064b24fd57783a", 5_0_1);
CHECK_NCA("09a2f9c16ce1c121ae6d231b35d17515", 5_0_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
CHECK_NCA("77e1ae7661ad8a718b9b13b70304aeea", 4_1_0);
CHECK_NCA("d0e5d20e3260f3083bcc067483b71274", 4_0_1);
CHECK_NCA("483a24ee3fd7149f9112d1931166a678", 4_0_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_3_0_0) {
CHECK_NCA("704129fc89e1fcb85c37b3112e51b0fc", 3_0_2);
CHECK_NCA("1fb00543307337d523ccefa9923e0c50", 3_0_1);
CHECK_NCA("6ebd3447473bade18badbeb5032af87d", 3_0_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_2_0_0) {
CHECK_NCA("d1c991c53a8a9038f8c3157a553d876d", 2_3_0);
CHECK_NCA("7f90353dff2d7ce69e19e07ebc0d5489", 2_2_0);
CHECK_NCA("e9b3e75fce00e52fe646156634d229b4", 2_1_0);
CHECK_NCA("7a1f79f8184d4b9bae1755090278f52c", 2_0_0);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_1_0_0) {
CHECK_NCA("a1b287e07f8455e8192f13d0e45a2aaf", 1_0_0); /* 1.0.0 from Factory */
CHECK_NCA("117f7b9c7da3e8cef02340596af206b3", 1_0_0); /* 1.0.0 from Gamecard */
} else {
fatal_error("[NXBOOT] Unknown Target Firmware!");
}
#undef CHECK_NCA
/* If we didn't find a more specific firmware, return our package1 approximation. */
return target_firmware;
}
static uint32_t nxboot_get_target_firmware(const void *package1loader) {
const package1loader_header_t *package1loader_header = (const package1loader_header_t *)package1loader;
switch (package1loader_header->version) {
case 0x01: /* 1.0.0 */
return ATMOSPHERE_TARGET_FIRMWARE_100;
return ATMOSPHERE_TARGET_FIRMWARE_1_0_0;
case 0x02: /* 2.0.0 - 2.3.0 */
return ATMOSPHERE_TARGET_FIRMWARE_200;
return ATMOSPHERE_TARGET_FIRMWARE_2_0_0;
case 0x04: /* 3.0.0 and 3.0.1 - 3.0.2 */
return ATMOSPHERE_TARGET_FIRMWARE_300;
return ATMOSPHERE_TARGET_FIRMWARE_3_0_0;
case 0x07: /* 4.0.0 - 4.1.0 */
return ATMOSPHERE_TARGET_FIRMWARE_400;
return ATMOSPHERE_TARGET_FIRMWARE_4_0_0;
case 0x0B: /* 5.0.0 - 5.1.0 */
return ATMOSPHERE_TARGET_FIRMWARE_500;
return ATMOSPHERE_TARGET_FIRMWARE_5_0_0;
case 0x0E: { /* 6.0.0 - 6.2.0 */
if (memcmp(package1loader_header->build_timestamp, "20180802", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_600;
return ATMOSPHERE_TARGET_FIRMWARE_6_0_0;
} else if (memcmp(package1loader_header->build_timestamp, "20181107", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_620;
return ATMOSPHERE_TARGET_FIRMWARE_6_2_0;
} else {
fatal_error("[NXBOOT] Unable to identify package1!\n");
}
}
case 0x0F: /* 7.0.0 - 7.0.1 */
return ATMOSPHERE_TARGET_FIRMWARE_700;
return ATMOSPHERE_TARGET_FIRMWARE_7_0_0;
case 0x10: { /* 8.0.0 - 9.0.0 */
if (memcmp(package1loader_header->build_timestamp, "20190314", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_800;
return ATMOSPHERE_TARGET_FIRMWARE_8_0_0;
} else if (memcmp(package1loader_header->build_timestamp, "20190531", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_810;
return ATMOSPHERE_TARGET_FIRMWARE_8_1_0;
} else if (memcmp(package1loader_header->build_timestamp, "20190809", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_900;
return ATMOSPHERE_TARGET_FIRMWARE_9_0_0;
} else if (memcmp(package1loader_header->build_timestamp, "20191021", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_910;
return ATMOSPHERE_TARGET_FIRMWARE_9_1_0;
} else if (memcmp(package1loader_header->build_timestamp, "20200303", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_1000;
return ATMOSPHERE_TARGET_FIRMWARE_10_0_0;
} else {
fatal_error("[NXBOOT] Unable to identify package1!\n");
}
@ -424,11 +493,11 @@ static void nxboot_configure_stratosphere(uint32_t target_firmware) {
}
} else {
/* Check if fuses are < 4.0.0, but firmware is >= 4.0.0 */
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_400 && !(fuse_get_reserved_odm(7) & ~0x0000000F)) {
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0 && !(fuse_get_reserved_odm(7) & ~0x0000000F)) {
kip_patches_set_enable_nogc();
}
/* Check if the fuses are < 9.0.0, but firmware is >= 9.0.0 */
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_900 && !(fuse_get_reserved_odm(7) & ~0x000003FF)) {
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_9_0_0 && !(fuse_get_reserved_odm(7) & ~0x000003FF)) {
kip_patches_set_enable_nogc();
}
}
@ -516,8 +585,8 @@ static void nxboot_move_bootconfig() {
fclose(bcfile);
/* Select the actual BootConfig size and destination address. */
bootconfig_addr = (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_600) ? 0x4003D000 : 0x4003F800;
bootconfig_size = (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) ? 0x3000 : 0x1000;
bootconfig_addr = (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_6_0_0) ? 0x4003D000 : 0x4003F800;
bootconfig_size = (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) ? 0x3000 : 0x1000;
/* Copy the BootConfig into IRAM. */
memset((void *)bootconfig_addr, 0, bootconfig_size);
@ -638,6 +707,7 @@ uint32_t nxboot_main(void) {
/* Find the system's target firmware. */
uint32_t target_firmware = nxboot_get_target_firmware(package1loader);
if (!target_firmware)
fatal_error("[NXBOOT] Failed to detect target firmware!\n");
else
@ -685,7 +755,7 @@ uint32_t nxboot_main(void) {
if (!package1_get_tsec_fw(&tsec_fw, package1loader, package1loader_size)) {
fatal_error("[NXBOOT] Failed to read the TSEC firmware from Package1loader!\n");
}
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_810) {
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_8_1_0) {
if (fuse_get_retail_type() != 0) {
sept_secondary_enc = sept_secondary_01_enc;
sept_secondary_enc_size = sept_secondary_01_enc_size;
@ -694,7 +764,7 @@ uint32_t nxboot_main(void) {
sept_secondary_enc_size = sept_secondary_dev_01_enc_size;
}
tsec_fw_size = 0x3300;
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_700) {
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
if (fuse_get_retail_type() != 0) {
sept_secondary_enc = sept_secondary_00_enc;
sept_secondary_enc_size = sept_secondary_00_enc_size;
@ -703,7 +773,7 @@ uint32_t nxboot_main(void) {
sept_secondary_enc_size = sept_secondary_dev_00_enc_size;
}
tsec_fw_size = 0x3000;
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) {
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_6_2_0) {
tsec_fw_size = 0x2900;
} else {
tsec_fw_size = 0xF00;
@ -715,7 +785,7 @@ uint32_t nxboot_main(void) {
/* Get the TSEC keys. */
uint8_t tsec_key[0x10] = {0};
uint8_t tsec_root_keys[0x20][0x10] = {0};
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_700) {
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
/* Detect whether we need to run sept-secondary in order to derive keys. */
if (!get_and_clear_has_run_sept()) {
reboot_to_sept(tsec_fw, tsec_fw_size, sept_secondary_enc, sept_secondary_enc_size);
@ -725,7 +795,7 @@ uint32_t nxboot_main(void) {
}
}
get_and_clear_has_run_sept();
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) {
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_6_2_0) {
uint8_t tsec_keys[0x20] = {0};
/* Emulate the TSEC payload on 6.2.0+. */
@ -746,17 +816,46 @@ uint32_t nxboot_main(void) {
/* Derive keydata. If on 7.0.0+, sept has already derived keys for us. */
unsigned int keygen_type = 0;
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_700) {
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_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");
}
}
/* Derive new device keys. */
{
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_5_0_0) {
derive_new_device_keys(fuse_get_retail_type() != 0, KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY, target_firmware);
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
derive_new_device_keys(fuse_get_retail_type() != 0, KEYSLOT_SWITCH_4XNEWDEVICEKEYGENKEY, target_firmware);
} else {
/* No new keys to derive */
}
}
/* Set the system partition's keys. */
if (fsdev_register_keys("system", target_firmware, BisPartition_UserSystem) != 0) {
fatal_error("[NXBOOT] Failed to set SYSTEM partition keys!\n");
}
/* Mount the system partition. */
if (fsdev_register_device("system") != 0) {
fatal_error("[NXBOOT] Failed to register SYSTEM partition!\n");
}
/* Lightly validate the system partition. */
if (!is_valid_folder("system:/Contents")) {
fatal_error("[NXBOOT] SYSTEM partition seems corrupted!\n");
}
/* Make the target firmware more specific. */
target_firmware = nxboot_get_specific_target_firmware(target_firmware);
/* Setup boot configuration for Exosphère. */
nxboot_configure_exosphere(target_firmware, keygen_type, &exo_emummc_cfg);
/* Initialize Boot Reason on older firmware versions. */
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Initializing Boot Reason...\n");
nxboot_set_bootreason((void *)MAILBOX_NX_BOOTLOADER_BOOT_REASON_BASE(target_firmware));
}
@ -807,11 +906,11 @@ uint32_t nxboot_main(void) {
}
/* Select the right address for the warmboot firmware. */
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
warmboot_memaddr = (void *)0x8000D000;
} else if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_600) {
} else if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_6_0_0) {
warmboot_memaddr = (void *)0x4003B000;
} else if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_700) {
} else if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_7_0_0) {
warmboot_memaddr = (void *)0x4003D800;
} else {
warmboot_memaddr = (void *)0x4003E000;
@ -822,7 +921,7 @@ uint32_t nxboot_main(void) {
/* Copy the warmboot firmware and set the address in PMC if necessary. */
if (warmboot_fw && (warmboot_fw_size > 0)) {
memcpy(warmboot_memaddr, warmboot_fw, warmboot_fw_size);
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400)
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0)
pmc->scratch1 = (uint32_t)warmboot_memaddr;
}
@ -842,7 +941,7 @@ uint32_t nxboot_main(void) {
print(SCREEN_LOG_LEVEL_INFO, u8"[NXBOOT] Reading Exosphère...\n");
/* 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_4_0_0) {
exosphere_memaddr = (void *)0x4002D000;
} else {
exosphere_memaddr = (void *)0x4002B000;
@ -870,7 +969,7 @@ uint32_t nxboot_main(void) {
nxboot_move_bootconfig();
/* Set 3.0.0/3.0.1/3.0.2 warmboot security check. */
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware == ATMOSPHERE_TARGET_FIRMWARE_300) {
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware == ATMOSPHERE_TARGET_FIRMWARE_3_0_0) {
const package1loader_header_t *package1loader_header = (const package1loader_header_t *)package1loader;
if (!strcmp(package1loader_header->build_timestamp, "20170519101410"))
pmc->secure_scratch32 = 0xE3; /* Warmboot 3.0.0 security check.*/

View file

@ -13,7 +13,7 @@
* 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 FUSEE_NX_BOOT_H
#define FUSEE_NX_BOOT_H
@ -35,7 +35,7 @@ typedef struct {
#define MAILBOX_NX_BOOTLOADER_BASE_100_620 0x40002E00
#define MAILBOX_NX_BOOTLOADER_BASE_700 0x40000000
#define MAILBOX_NX_BOOTLOADER_BASE(targetfw) ((targetfw >= ATMOSPHERE_TARGET_FIRMWARE_700) ? (MAILBOX_NX_BOOTLOADER_BASE_700) : (MAILBOX_NX_BOOTLOADER_BASE_100_620))
#define MAILBOX_NX_BOOTLOADER_BASE(targetfw) ((targetfw >= ATMOSPHERE_TARGET_FIRMWARE_7_0_0) ? (MAILBOX_NX_BOOTLOADER_BASE_700) : (MAILBOX_NX_BOOTLOADER_BASE_100_620))
#define MAKE_MAILBOX_NX_BOOTLOADER_REG(targetfw, n) MAKE_REG32(MAILBOX_NX_BOOTLOADER_BASE(targetfw) + n)
#define MAILBOX_NX_BOOTLOADER_BOOT_REASON_BASE(targetfw) (MAILBOX_NX_BOOTLOADER_BASE(targetfw) + 0x10)

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "cluster.h"
@ -30,40 +30,40 @@
void nxboot_finish(uint32_t boot_memaddr) {
uint32_t target_firmware = MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware;
volatile tegra_se_t *se = se_get_regs();
/* Clear used keyslots. */
clear_aes_keyslot(KEYSLOT_SWITCH_PACKAGE2KEY);
clear_aes_keyslot(KEYSLOT_SWITCH_RNGKEY);
/* Lock keyslots. */
set_aes_keyslot_flags(KEYSLOT_SWITCH_MASTERKEY, 0xFF);
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
set_aes_keyslot_flags(KEYSLOT_SWITCH_DEVICEKEY, 0xFF);
} else {
set_aes_keyslot_flags(KEYSLOT_SWITCH_4XOLDDEVICEKEY, 0xFF);
}
/* Finalize the GPU UCODE carveout. */
/* NOTE: [4.0.0+] This is now done in the Secure Monitor. */
/* mc_config_carveout_finalize(); */
/* Lock AES keyslots. */
for (uint32_t i = 0; i < 16; i++)
set_aes_keyslot_flags(i, 0x15);
/* Lock RSA keyslots. */
for (uint32_t i = 0; i < 2; i++)
set_rsa_keyslot_flags(i, 1);
/* Lock the Security Engine. */
se->SE_TZRAM_SECURITY = 0;
se->SE_CRYPTO_SECURITY_PERKEY = 0;
se->SE_RSA_SECURITY_PERKEY = 0;
se->SE_SE_SECURITY &= 0xFFFFFFFB;
/* Boot up Exosphère. */
MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE(target_firmware) = 0;
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_LOADED_PACKAGE2;
} else {
MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_DRAM_INITIALIZED_4X;
@ -71,30 +71,30 @@ void nxboot_finish(uint32_t boot_memaddr) {
/* Terminate the display. */
display_end();
/* Check if SMMU emulation has been used. */
uint32_t smmu_magic = *(uint32_t *)(SMMU_AARCH64_PAYLOAD_ADDR + 0xFC);
if (smmu_magic == 0xDEADC0DE) {
/* Clear the magic. */
*(uint32_t *)(SMMU_AARCH64_PAYLOAD_ADDR + 0xFC) = 0;
/* Pass the boot address to the already running payload. */
*(uint32_t *)(SMMU_AARCH64_PAYLOAD_ADDR + 0xF0) = boot_memaddr;
/* Wait a while. */
mdelay(500);
} else {
/* Boot CPU0. */
cluster_boot_cpu0(boot_memaddr);
}
/* Wait for Exosphère to wake up. */
while (MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE(target_firmware) == 0) {
udelay(1);
}
/* Signal Exosphère. */
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_4_0_0) {
MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_FINISHED;
} else {
MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_FINISHED_4X;

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
@ -24,8 +24,10 @@
#include "gpt.h"
#include "se.h"
#include "utils.h"
#include "fs_utils.h"
#include "sdmmc/sdmmc.h"
#include "lib/log.h"
#include "lib/fatfs/ff.h"
static bool g_ahb_redirect_enabled = false;
@ -59,7 +61,7 @@ SdmmcPartitionNum g_current_emmc_partition = SDMMC_PARTITION_INVALID;
static int mmc_partition_initialize(device_partition_t *devpart) {
mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct;
/* Allocate the crypto work buffer. */
if ((devpart->read_cipher != NULL) || (devpart->write_cipher != NULL)) {
devpart->crypto_work_buffer = memalign(16, devpart->sector_size * 16);
@ -105,7 +107,7 @@ static int mmc_partition_initialize(device_partition_t *devpart) {
static void mmc_partition_finalize(device_partition_t *devpart) {
mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct;
/* Finalize hardware. */
if (mmcpart->device == &g_sd_device) {
if (g_is_emummc) {
@ -123,13 +125,13 @@ static void mmc_partition_finalize(device_partition_t *devpart) {
}
devpart->initialized = false;
}
/* Disable AHB redirection if necessary. */
if (g_ahb_redirect_enabled) {
mc_disable_ahb_redirect();
g_ahb_redirect_enabled = false;
}
/* Free the crypto work buffer. */
if (devpart->crypto_work_buffer != NULL) {
free(devpart->crypto_work_buffer);
@ -138,19 +140,19 @@ static void mmc_partition_finalize(device_partition_t *devpart) {
static int mmc_partition_read(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors) {
mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct;
if ((mmcpart->device == &g_emmc_device) && (g_current_emmc_partition != mmcpart->partition)) {
if (!sdmmc_mmc_select_partition(mmcpart->device, mmcpart->partition))
return EIO;
g_current_emmc_partition = mmcpart->partition;
}
return sdmmc_device_read(mmcpart->device, (uint32_t)(devpart->start_sector + sector), (uint32_t)num_sectors, dst) ? 0 : EIO;
}
static int mmc_partition_write(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors) {
mmc_partition_info_t *mmcpart = (mmc_partition_info_t *)devpart->device_struct;
if ((mmcpart->device == &g_emmc_device) && (g_current_emmc_partition != mmcpart->partition)) {
if (!sdmmc_mmc_select_partition(mmcpart->device, mmcpart->partition))
return EIO;
@ -174,11 +176,11 @@ static int emummc_partition_initialize(device_partition_t *devpart) {
devpart->crypto_work_buffer_num_sectors = 0;
}
devpart->initialized = true;
return 0;
}
static void emummc_partition_finalize(device_partition_t *devpart) {
static void emummc_partition_finalize(device_partition_t *devpart) {
/* Free the crypto work buffer. */
if (devpart->crypto_work_buffer != NULL) {
free(devpart->crypto_work_buffer);
@ -194,10 +196,10 @@ 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;
}
}
}
static int emummc_partition_write(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors) {
@ -212,7 +214,7 @@ static int emummc_partition_write(device_partition_t *devpart, const void *src,
} 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) {
@ -227,7 +229,7 @@ static int nxfs_bis_crypto_decrypt(device_partition_t *devpart, uint64_t sector,
case DevicePartitionCryptoMode_Xts:
set_aes_keyslot(keyslot_a, devpart->keys[0], 0x10);
set_aes_keyslot(keyslot_b, devpart->keys[1], 0x10);
se_aes_128_xts_nintendo_decrypt(keyslot_a, keyslot_b, sector, devpart->crypto_work_buffer, devpart->crypto_work_buffer, size, devpart->sector_size);
se_aes_128_xts_nintendo_decrypt(keyslot_a, keyslot_b, sector, devpart->crypto_work_buffer, devpart->crypto_work_buffer, size, devpart->sector_size, devpart->crypto_sector_size);
return 0;
case DevicePartitionCryptoMode_None:
default:
@ -247,7 +249,7 @@ static int nxfs_bis_crypto_encrypt(device_partition_t *devpart, uint64_t sector,
case DevicePartitionCryptoMode_Xts:
set_aes_keyslot(keyslot_a, devpart->keys[0], 0x10);
set_aes_keyslot(keyslot_b, devpart->keys[1], 0x10);
se_aes_128_xts_nintendo_encrypt(keyslot_a, keyslot_b, sector, devpart->crypto_work_buffer, devpart->crypto_work_buffer, size, devpart->sector_size);
se_aes_128_xts_nintendo_encrypt(keyslot_a, keyslot_b, sector, devpart->crypto_work_buffer, devpart->crypto_work_buffer, size, devpart->sector_size, devpart->crypto_sector_size);
return 0;
case DevicePartitionCryptoMode_None:
default:
@ -256,6 +258,7 @@ static int nxfs_bis_crypto_encrypt(device_partition_t *devpart, uint64_t sector,
}
static const device_partition_t g_mmc_devpart_template = {
.crypto_sector_size = 0x4000,
.sector_size = 512,
.initializer = mmc_partition_initialize,
.finalizer = mmc_partition_finalize,
@ -264,6 +267,7 @@ static const device_partition_t g_mmc_devpart_template = {
};
static const device_partition_t g_emummc_devpart_template = {
.crypto_sector_size = 0x4000,
.sector_size = 512,
.initializer = emummc_partition_initialize,
.finalizer = emummc_partition_finalize,
@ -378,7 +382,7 @@ static int nxfs_mount_emu_partition_gpt_callback(const efi_entry_t *entry, void
{"BCPKG2-5-Repair-Main", "bcpkg25", false, false, false},
{"BCPKG2-6-Repair-Sub", "bcpkg26", false, false, false},
{"SAFE", "safe", true, true, false},
{"SYSTEM", "system", true, true, false},
{"SYSTEM", "system", true, true, true},
{"USER", "user", true, true, false},
};
@ -442,26 +446,26 @@ int nxfs_mount_sd() {
model.device_struct = &g_sd_mmcpart;
model.start_sector = 0;
model.num_sectors = 1u << 30; /* arbitrary numbers of sectors. TODO: find the size of the SD in sectors. */
/* Mount the SD card device. */
rc = fsdev_mount_device("sdmc", &model, true);
if (rc == -1) {
return -1;
}
/* Register the SD card device. */
rc = fsdev_register_device("sdmc");
if (rc == -1) {
return -1;
}
/* All fs devices are ready. */
if (rc == 0) {
g_fsdev_ready = true;
}
return rc;
}
@ -469,36 +473,36 @@ int nxfs_mount_emmc() {
device_partition_t model;
int rc;
FILE *rawnand;
/* Setup a template for boot0. */
model = g_mmc_devpart_template;
model.device_struct = &g_emmc_boot0_mmcpart;
model.start_sector = 0;
model.num_sectors = 0x184000 / model.sector_size;
/* Mount boot0 device. */
rc = rawdev_mount_device("boot0", &model, true);
if (rc == -1) {
return -1;
}
/* Register boot0 device. */
rc = rawdev_register_device("boot0");
if (rc == -1) {
return -1;
}
/* Setup a template for boot1. */
model = g_mmc_devpart_template;
model.device_struct = &g_emmc_boot1_mmcpart;
model.start_sector = 0;
model.num_sectors = 0x80000 / model.sector_size;
/* Mount boot1 device. */
rc = rawdev_mount_device("boot1", &model, false);
if (rc == -1) {
return -1;
}
@ -510,38 +514,38 @@ int nxfs_mount_emmc() {
model.device_struct = &g_emmc_user_mmcpart;
model.start_sector = 0;
model.num_sectors = (256ull << 30) / model.sector_size;
/* Mount raw NAND device. */
rc = rawdev_mount_device("rawnand", &model, false);
if (rc == -1) {
return -1;
}
/* Register raw NAND device. */
rc = rawdev_register_device("rawnand");
if (rc == -1) {
return -1;
}
/* Open raw NAND device. */
rawnand = fopen("rawnand:/", "rb");
if (rawnand == NULL) {
return -1;
}
/* Iterate the GPT and mount each raw NAND partition. */
rc = gpt_iterate_through_entries(rawnand, model.sector_size, nxfs_mount_partition_gpt_callback, &model);
/* Close raw NAND device. */
fclose(rawnand);
/* All raw devices are ready. */
if (rc == 0) {
g_rawdev_ready = true;
}
return rc;
}
@ -549,7 +553,7 @@ 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 + (0x400000 * 0 / model.sector_size);
@ -558,20 +562,20 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
/* Mount emulated boot0 device. */
rc = emudev_mount_device("boot0", &model, NULL, 0, 0);
/* 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 -2;
}
/* Setup an emulation template for boot1. */
model = g_emummc_devpart_template;
model.start_sector = emummc_start_sector + (0x400000 * 1 / model.sector_size);
@ -580,7 +584,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
/* Mount emulated boot1 device. */
rc = emudev_mount_device("boot1", &model, NULL, 0, 0);
/* Failed to mount boot1. */
if (rc == -1) {
return -3;
@ -593,43 +597,43 @@ 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, 0, 0);
/* Failed to mount raw NAND. */
if (rc == -1) {
return -4;
}
/* Register emulated raw NAND device. */
rc = emudev_register_device("rawnand");
/* Failed to register raw NAND device. */
if (rc == -1) {
return -5;
}
/* Open emulated raw NAND device. */
rawnand = fopen("rawnand:/", "rb");
/* Failed to open emulated raw NAND device. */
if (rawnand == NULL) {
return -6;
}
/* 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, 0, 0);
/* Close emulated raw NAND device. */
fclose(rawnand);
/* All emulated devices are ready. */
if (rc == 0) {
g_emudev_ready = true;
g_is_emummc = true;
}
return rc;
}
@ -640,85 +644,85 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
bool is_exfat;
char emummc_boot0_path[0x300 + 1] = {0};
char emummc_boot1_path[0x300 + 1] = {0};
/* Check if the SD card is EXFAT formatted. */
rc = fsdev_is_exfat("sdmc");
/* Failed to detect file system type. */
if (rc == -1) {
return -1;
}
/* Set EXFAT status. */
is_exfat = (rc == 1);
/* Reject single part in FAT32. */
/* NOTE: This check has no effect in the current design. */
if (!is_exfat && (num_parts < 1)) {
return -2;
}
/* We want a folder with the archive bit set. */
rc = fsdev_get_attr(emummc_path);
/* Failed to get file DOS attributes. */
if (rc == -1) {
return -3;
}
/* Our path is not a directory. */
if (!(rc & AM_DIR)) {
return -4;
}
/* Check if the archive bit is not set. */
if (!(rc & AM_ARC)) {
/* Try to set the archive bit. */
rc = fsdev_set_attr(emummc_path, AM_ARC, AM_ARC);
/* Failed to set file DOS attributes. */
if (rc == -1) {
return -5;
}
}
/* Setup an emulation template for boot0. */
model = g_emummc_devpart_template;
model.start_sector = 0;
model.num_sectors = 0x400000 / model.sector_size;
model.emu_use_file = true;
/* Prepare boot0 file path. */
snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "%s/%s", emummc_path, "boot0");
/* Mount emulated boot0 device. */
rc = emudev_mount_device("boot0", &model, emummc_boot0_path, 0, 0);
/* Failed to mount boot0 device. */
if (rc == -1) {
return -6;
}
/* Register emulated boot0 device. */
rc = emudev_register_device("boot0");
/* Failed to register boot0 device. */
if (rc == -1) {
return -7;
}
/* Setup an emulation template for boot1. */
model = g_emummc_devpart_template;
model.start_sector = 0;
model.num_sectors = 0x400000 / model.sector_size;
model.emu_use_file = true;
/* Prepare boot1 file path. */
snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "%s/%s", emummc_path, "boot1");
/* Mount emulated boot1 device. */
rc = emudev_mount_device("boot1", &model, emummc_boot1_path, 0, 0);
/* Failed to mount boot1. */
if (rc == -1) {
return -8;
@ -726,7 +730,7 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
/* Register emulated boot1 device. */
rc = emudev_register_device("boot1");
/* Failed to register boot1 device. */
if (rc == -1) {
return -9;
@ -737,93 +741,93 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
model.start_sector = 0;
model.num_sectors = (256ull << 30) / model.sector_size;
model.emu_use_file = true;
/* Mount emulated raw NAND device from single or multiple parts. */
rc = emudev_mount_device("rawnand", &model, emummc_path, num_parts, part_limit);
/* Failed to mount raw NAND. */
if (rc == -1) {
return -10;
}
/* Register emulated raw NAND device. */
rc = emudev_register_device("rawnand");
/* Failed to register raw NAND device. */
if (rc == -1) {
return -11;
}
/* Open emulated raw NAND device. */
rawnand = fopen("rawnand:/", "rb");
/* Failed to open emulated raw NAND device. */
if (rawnand == NULL) {
return -12;
}
/* 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, emummc_path, num_parts, part_limit);
/* Close emulated raw NAND device. */
fclose(rawnand);
/* All emulated devices are ready. */
if (rc == 0) {
g_emudev_ready = true;
g_is_emummc = true;
}
return rc;
}
int nxfs_unmount_sd() {
int rc = 0;
/* Unmount all fs devices. */
if (g_fsdev_ready) {
rc = fsdev_unmount_all();
g_fsdev_ready = false;
}
return rc;
}
int nxfs_unmount_emmc() {
int rc = 0;
/* Unmount all raw devices. */
if (g_rawdev_ready) {
rc = rawdev_unmount_all();
g_rawdev_ready = false;
}
return rc;
}
int nxfs_unmount_emummc() {
int rc = 0;
/* Unmount all emulated devices. */
if (g_emudev_ready) {
rc = emudev_unmount_all();
g_emudev_ready = false;
}
return rc;
}
int nxfs_init() {
int rc;
/* Mount and register the SD card. */
rc = nxfs_mount_sd();
/* Set the SD card as the default file system device. */
if (rc == 0) {
rc = fsdev_set_default_device("sdmc");
}
return rc;
}

View file

@ -90,13 +90,13 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm
package2_patch_kernel(kernel, &kernel_size, is_sd_kernel, (void *)&orig_ini1, target_firmware);
/* Ensure we know where embedded INI is if present, and we don't if not. */
if ((target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 != NULL) ||
(target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 == NULL)) {
if ((target_firmware < ATMOSPHERE_TARGET_FIRMWARE_8_0_0 && orig_ini1 != NULL) ||
(target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_8_0_0 && orig_ini1 == NULL)) {
fatal_error("Error: inappropriate kernel embedded ini context");
}
print(SCREEN_LOG_LEVEL_DEBUG, "Rebuilding the INI1 section...\n");
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800) {
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_8_0_0) {
package2_get_src_section((void *)&orig_ini1, package2, PACKAGE2_SECTION_INI1);
} else {
/* On 8.0.0, place INI1 right after kernelldr for our sanity. */

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "utils.h"
@ -60,7 +60,7 @@ void se_verify_flags_cleared(void) {
/* Set the flags for an AES keyslot. */
void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
@ -79,7 +79,7 @@ void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
/* Set the flags for an RSA keyslot. */
void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_RSA_MAX) {
generic_panic();
}
@ -98,7 +98,7 @@ void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) {
void clear_aes_keyslot(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
@ -112,7 +112,7 @@ void clear_aes_keyslot(unsigned int keyslot) {
void clear_rsa_keyslot(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_RSA_MAX) {
generic_panic();
}
@ -132,7 +132,7 @@ void clear_rsa_keyslot(unsigned int keyslot) {
void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || key_size > KEYSIZE_AES_MAX) {
generic_panic();
}
@ -145,7 +145,7 @@ void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size) {
void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_size, const void *exponent, size_t exp_size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_RSA_MAX || modulus_size > KEYSIZE_RSA_MAX || exp_size > KEYSIZE_RSA_MAX) {
generic_panic();
}
@ -166,7 +166,7 @@ void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_
void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || iv_size > 0x10) {
generic_panic();
}
@ -179,7 +179,7 @@ void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size) {
void clear_aes_keyslot_iv(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
@ -198,7 +198,7 @@ void set_se_ctr(const void *ctr) {
void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot_dst >= KEYSLOT_AES_MAX || keyslot_src >= KEYSLOT_AES_MAX || wrapped_key_size > KEYSIZE_AES_MAX) {
generic_panic();
}
@ -235,7 +235,7 @@ void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, co
void se_get_exp_mod_output(void *buf, size_t size) {
size_t num_dwords = (size >> 2);
if (num_dwords < 1) {
return;
}
@ -351,7 +351,7 @@ void se_perform_aes_block_operation(void *dst, size_t dst_size, const void *src,
void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || ctr_size != 0x10) {
generic_panic();
}
@ -382,7 +382,7 @@ void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const vo
void se_aes_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, unsigned int config_high) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
generic_panic();
}
@ -403,7 +403,7 @@ void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_si
void se_aes_ecb_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
generic_panic();
}
@ -444,14 +444,24 @@ void aes_128_xts_nintendo_get_tweak(uint8_t *tweak, size_t sector) {
}
}
void aes_128_xts_nintendo_xor_with_tweak(unsigned int keyslot, size_t sector, uint8_t *dst, const uint8_t *src, size_t size) {
void aes_128_xts_nintendo_xor_with_tweak(unsigned int keyslot, size_t sector, uint8_t *dst, const uint8_t *src, size_t size, size_t crypto_sector_size) {
if ((size & 0xF) || size == 0) {
generic_panic();
}
unsigned int sector_scale = crypto_sector_size / size;
unsigned int real_sector = sector / sector_scale;
uint8_t tweak[0x10];
aes_128_xts_nintendo_get_tweak(tweak, sector);
aes_128_xts_nintendo_get_tweak(tweak, real_sector);
se_aes_128_ecb_encrypt_block(keyslot, tweak, sizeof(tweak), tweak, sizeof(tweak));
unsigned int num_pre_blocks = ((sector % sector_scale) * size) / 0x10;
for (unsigned int pre = 0; pre < num_pre_blocks; pre++) {
shift_left_xor_rb_le(tweak);
}
for (unsigned int block = 0; block < (size >> 4); block++) {
for (unsigned int i = 0; i < 0x10; i++) {
dst[(block << 4) | i] = src[(block << 4) | i] ^ tweak[i];
@ -460,16 +470,16 @@ void aes_128_xts_nintendo_xor_with_tweak(unsigned int keyslot, size_t sector, ui
}
}
void aes_128_xts_nintendo_crypt_sector(unsigned int keyslot_1, unsigned int keyslot_2, size_t sector, bool encrypt, void *dst, const void *src, size_t size) {
void aes_128_xts_nintendo_crypt_sector(unsigned int keyslot_1, unsigned int keyslot_2, size_t sector, bool encrypt, void *dst, const void *src, size_t size, size_t crypto_sector_size) {
volatile tegra_se_t *se = se_get_regs();
if ((size & 0xF) || size == 0) {
if ((size & 0xF) || size == 0 || crypto_sector_size < size || (crypto_sector_size % size) != 0) {
generic_panic();
}
/* XOR. */
aes_128_xts_nintendo_xor_with_tweak(keyslot_2, sector, dst, src, size);
aes_128_xts_nintendo_xor_with_tweak(keyslot_2, sector, dst, src, size, crypto_sector_size);
/* Encrypt/Decrypt. */
if (encrypt) {
se->SE_CONFIG = (ALG_AES_ENC | DST_MEMORY);
@ -480,38 +490,39 @@ void aes_128_xts_nintendo_crypt_sector(unsigned int keyslot_1, unsigned int keys
}
se->SE_CRYPTO_LAST_BLOCK = (size >> 4) - 1;
trigger_se_blocking_op(OP_START, dst, size, src, size);
/* XOR. */
aes_128_xts_nintendo_xor_with_tweak(keyslot_2, sector, dst, dst, size);
aes_128_xts_nintendo_xor_with_tweak(keyslot_2, sector, dst, dst, size, crypto_sector_size);
}
/* Encrypt with AES-XTS (Nintendo's custom tweak). */
void se_aes_128_xts_nintendo_encrypt(unsigned int keyslot_1, unsigned int keyslot_2, size_t base_sector, void *dst, const void *src, size_t size, unsigned int sector_size) {
if ((size & 0xF) || size == 0) {
void se_aes_128_xts_nintendo_encrypt(unsigned int keyslot_1, unsigned int keyslot_2, size_t base_sector, void *dst, const void *src, size_t size, unsigned int sector_size, unsigned int crypto_sector_size) {
if ((size & 0xF) || size == 0 || crypto_sector_size < sector_size || (crypto_sector_size % sector_size) != 0) {
generic_panic();
}
size_t sector = base_sector;
for (size_t ofs = 0; ofs < size; ofs += sector_size) {
aes_128_xts_nintendo_crypt_sector(keyslot_1, keyslot_2, sector, true, dst + ofs, src + ofs, sector_size);
aes_128_xts_nintendo_crypt_sector(keyslot_1, keyslot_2, sector, true, dst + ofs, src + ofs, sector_size, crypto_sector_size);
sector++;
}
}
/* Decrypt with AES-XTS (Nintendo's custom tweak). */
void se_aes_128_xts_nintendo_decrypt(unsigned int keyslot_1, unsigned int keyslot_2, size_t base_sector, void *dst, const void *src, size_t size, unsigned int sector_size) {
if ((size & 0xF) || size == 0) {
void se_aes_128_xts_nintendo_decrypt(unsigned int keyslot_1, unsigned int keyslot_2, size_t base_sector, void *dst, const void *src, size_t size, unsigned int sector_size, unsigned int crypto_sector_size) {
if ((size & 0xF) || size == 0 || crypto_sector_size < sector_size || (crypto_sector_size % sector_size) != 0) {
generic_panic();
}
size_t sector = base_sector;
for (size_t ofs = 0; ofs < size; ofs += sector_size) {
aes_128_xts_nintendo_crypt_sector(keyslot_1, keyslot_2, sector, false, dst + ofs, src + ofs, sector_size);
aes_128_xts_nintendo_crypt_sector(keyslot_1, keyslot_2, sector, false, dst + ofs, src + ofs, sector_size, crypto_sector_size);
sector++;
}
}
void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size, unsigned int config_high) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
@ -568,7 +579,7 @@ void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size,
void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) {
generic_panic();
}
@ -583,7 +594,7 @@ void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, co
/* SHA256 Implementation. */
void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
volatile tegra_se_t *se = se_get_regs();
/* Setup config for SHA256, size = BITS(src_size) */
se->SE_CONFIG = (ENCMODE_SHA256 | ALG_SHA | DST_HASHREG);
se->SE_SHA_CONFIG = 1;
@ -608,7 +619,7 @@ void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
/* RNG API */
void se_initialize_rng(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
@ -628,7 +639,7 @@ void se_initialize_rng(unsigned int keyslot) {
void se_generate_random(unsigned int keyslot, void *dst, size_t size) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}

View file

@ -13,7 +13,7 @@
* 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 FUSEE_SE_H
#define FUSEE_SE_H
@ -182,8 +182,8 @@ void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size);
void set_se_ctr(const void *ctr);
/* Secure AES API */
void se_aes_128_xts_nintendo_decrypt(unsigned int keyslot_1, unsigned int keyslot_2, unsigned int base_sector, void *dst, const void *src, size_t size, unsigned int sector_size);
void se_aes_128_xts_nintendo_encrypt(unsigned int keyslot_1, unsigned int keyslot_2, unsigned int base_sector, void *dst, const void *src, size_t size, unsigned int sector_size);
void se_aes_128_xts_nintendo_decrypt(unsigned int keyslot_1, unsigned int keyslot_2, unsigned int base_sector, void *dst, const void *src, size_t size, unsigned int sector_size, unsigned int crypto_sector_size);
void se_aes_128_xts_nintendo_encrypt(unsigned int keyslot_1, unsigned int keyslot_2, unsigned int base_sector, void *dst, const void *src, size_t size, unsigned int sector_size, unsigned int crypto_sector_size);
void se_compute_aes_128_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size);
void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size);
void se_aes_128_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);