Merge pull request #577 from Atmosphere-NX/810_support

Implement support for 8.1.0
This commit is contained in:
SciresM 2019-06-19 12:59:30 -07:00 committed by GitHub
commit f2086fe054
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
57 changed files with 3032 additions and 481 deletions

View file

@ -61,7 +61,8 @@ dist: all
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/sept/payload.bin
cp sept/sept-primary/sept-primary.bin atmosphere-$(AMSVER)/sept/sept-primary.bin
cp sept/sept-secondary/sept-secondary.bin atmosphere-$(AMSVER)/sept/sept-secondary.bin
cp sept/sept-secondary/sept-secondary.enc atmosphere-$(AMSVER)/sept/sept-secondary.enc
cp sept/sept-secondary/sept-secondary_00.enc atmosphere-$(AMSVER)/sept/sept-secondary_00.enc
cp sept/sept-secondary/sept-secondary_01.enc atmosphere-$(AMSVER)/sept/sept-secondary_01.enc
cp common/defaults/BCT.ini atmosphere-$(AMSVER)/atmosphere/BCT.ini
cp common/defaults/loader.ini atmosphere-$(AMSVER)/atmosphere/loader.ini
cp common/defaults/system_settings.ini atmosphere-$(AMSVER)/atmosphere/system_settings.ini

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 ATMOSPHERE_TARGET_FIRMWARE_H
#define ATMOSPHERE_TARGET_FIRMWARE_H
@ -26,11 +26,12 @@
#define ATMOSPHERE_TARGET_FIRMWARE_620 7
#define ATMOSPHERE_TARGET_FIRMWARE_700 8
#define ATMOSPHERE_TARGET_FIRMWARE_800 9
#define ATMOSPHERE_TARGET_FIRMWARE_810 10
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_800
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_810
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE_100
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_800
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_810
/* TODO: What should this be, for release? */
#define ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG ATMOSPHERE_TARGET_FIRMWARE_CURRENT

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 ATMOSPHERE_VERSION_H
#define ATMOSPHERE_VERSION_H
@ -22,7 +22,7 @@
#define ATMOSPHERE_RELEASE_VERSION_MICRO 0
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 8
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 0
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 1
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 1
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0
#endif

View file

@ -39,6 +39,8 @@
#include "offsets/700_exfat.h"
#include "offsets/800.h"
#include "offsets/800_exfat.h"
#include "offsets/810.h"
#include "offsets/810_exfat.h"
#include "../utils/fatal.h"
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
@ -88,6 +90,8 @@ DEFINE_OFFSET_STRUCT(_700);
DEFINE_OFFSET_STRUCT(_700_EXFAT);
DEFINE_OFFSET_STRUCT(_800);
DEFINE_OFFSET_STRUCT(_800_EXFAT);
DEFINE_OFFSET_STRUCT(_810);
DEFINE_OFFSET_STRUCT(_810_EXFAT);
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
switch (version) {
@ -137,6 +141,10 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
return &(GET_OFFSET_STRUCT_NAME(_800));
case FS_VER_8_0_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_800_EXFAT));
case FS_VER_8_1_0:
return &(GET_OFFSET_STRUCT_NAME(_810));
case FS_VER_8_1_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_810_EXFAT));
default:
fatal_abort(Fatal_UnknownVersion);
}

View file

@ -56,6 +56,9 @@ enum FS_VER
FS_VER_8_0_0,
FS_VER_8_0_0_EXFAT,
FS_VER_8_1_0,
FS_VER_8_1_0_EXFAT,
FS_VER_MAX,
};

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
* Copyright (c) 2019 Atmosphere-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 __FS_810_H__
#define __FS_810_H__
// Accessor vtable getters
#define FS_OFFSET_810_SDMMC_ACCESSOR_GC 0x15EA20
#define FS_OFFSET_810_SDMMC_ACCESSOR_SD 0x15E790
#define FS_OFFSET_810_SDMMC_ACCESSOR_NAND 0x15AC80
// Hooks
#define FS_OFFSET_810_SDMMC_WRAPPER_READ 0x152A80
#define FS_OFFSET_810_SDMMC_WRAPPER_WRITE 0x152B60
#define FS_OFFSET_810_RTLD 0x5B4
#define FS_OFFSET_810_RTLD_DESTINATION 0x9C
#define FS_OFFSET_810_CLKRST_SET_MIN_V_CLK_RATE 0x16F370
// Misc funcs
#define FS_OFFSET_810_LOCK_MUTEX 0x14B6D0
#define FS_OFFSET_810_UNLOCK_MUTEX 0x14B720
// Misc Data
#define FS_OFFSET_810_SD_MUTEX 0xF1A3E8
#define FS_OFFSET_810_NAND_MUTEX 0xF15BE8
#define FS_OFFSET_810_ACTIVE_PARTITION 0xF15C28
#define FS_OFFSET_810_SDMMC_DAS_HANDLE 0xE167C0
// NOPs
#define FS_OFFSET_810_SHUTDOWN_SD 0xBAF6C
#define FS_OFFSET_810_SD_DAS_INIT 0x87D58
// Nintendo Paths
#define FS_OFFSET_810_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x0007F5F0, .add_rel_offset = 4}, \
{.opcode_reg = 3, .adrp_offset = 0x00081084, .add_rel_offset = 4}, \
{.opcode_reg = 3, .adrp_offset = 0x00081278, .add_rel_offset = 4}, \
{.opcode_reg = 3, .adrp_offset = 0x00081654, .add_rel_offset = 4}, \
{.opcode_reg = 4, .adrp_offset = 0x00081818, .add_rel_offset = 4}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0} \
}
#endif // __FS_810_H__

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
* Copyright (c) 2019 Atmosphere-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 __FS_810_EXFAT_H__
#define __FS_810_EXFAT_H__
// Accessor vtable getters
#define FS_OFFSET_810_EXFAT_SDMMC_ACCESSOR_GC 0x169FD0
#define FS_OFFSET_810_EXFAT_SDMMC_ACCESSOR_SD 0x169D40
#define FS_OFFSET_810_EXFAT_SDMMC_ACCESSOR_NAND 0x166230
// Hooks
#define FS_OFFSET_810_EXFAT_SDMMC_WRAPPER_READ 0x15E030
#define FS_OFFSET_810_EXFAT_SDMMC_WRAPPER_WRITE 0x15E110
#define FS_OFFSET_810_EXFAT_RTLD 0x5B4
#define FS_OFFSET_810_EXFAT_RTLD_DESTINATION 0x9C
#define FS_OFFSET_810_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x17A920
// Misc funcs
#define FS_OFFSET_810_EXFAT_LOCK_MUTEX 0x156C80
#define FS_OFFSET_810_EXFAT_UNLOCK_MUTEX 0x156CD0
// Misc Data
#define FS_OFFSET_810_EXFAT_SD_MUTEX 0xFFE3E8
#define FS_OFFSET_810_EXFAT_NAND_MUTEX 0xFF9BE8
#define FS_OFFSET_810_EXFAT_ACTIVE_PARTITION 0xFF9C28
#define FS_OFFSET_810_EXFAT_SDMMC_DAS_HANDLE 0xEFAA20
// NOPs
#define FS_OFFSET_810_EXFAT_SHUTDOWN_SD 0xC651C
#define FS_OFFSET_810_EXFAT_SD_DAS_INIT 0x93308
// Nintendo Paths
#define FS_OFFSET_810_EXFAT_NINTENDO_PATHS \
{ \
{.opcode_reg = 3, .adrp_offset = 0x0008ABA0, .add_rel_offset = 4}, \
{.opcode_reg = 3, .adrp_offset = 0x0008C634, .add_rel_offset = 4}, \
{.opcode_reg = 3, .adrp_offset = 0x0008C828, .add_rel_offset = 4}, \
{.opcode_reg = 3, .adrp_offset = 0x0008CC04, .add_rel_offset = 4}, \
{.opcode_reg = 4, .adrp_offset = 0x0008CDC8, .add_rel_offset = 4}, \
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0} \
}
#endif // __FS_810_EXFAT_H__

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 <stdint.h>
#include <stdbool.h>
@ -34,13 +34,13 @@ unsigned int exosphere_load_config(void) {
generic_panic();
}
g_has_loaded_config = true;
const unsigned int magic = MAILBOX_EXOSPHERE_CONFIG.magic;
if (magic == MAGIC_EXOSPHERE_CONFIG) {
g_exosphere_cfg = MAILBOX_EXOSPHERE_CONFIG;
}
return g_exosphere_cfg.target_firmware;
}
@ -48,7 +48,7 @@ unsigned int exosphere_get_target_firmware(void) {
if (!g_has_loaded_config) {
generic_panic();
}
return g_exosphere_cfg.target_firmware;
}
@ -56,15 +56,15 @@ unsigned int exosphere_should_perform_620_keygen(void) {
if (!g_has_loaded_config) {
generic_panic();
}
return g_exosphere_cfg.target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_620 && EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_PERFORM_620_KEYGEN);
return false;
}
unsigned int exosphere_should_override_debugmode_priv(void) {
if (!g_has_loaded_config) {
generic_panic();
}
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV);
}
@ -72,7 +72,7 @@ unsigned int exosphere_should_override_debugmode_user(void) {
if (!g_has_loaded_config) {
generic_panic();
}
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_IS_DEBUGMODE_USER);
}
@ -80,7 +80,7 @@ unsigned int exosphere_should_disable_usermode_exception_handlers(void) {
if (!g_has_loaded_config) {
generic_panic();
}
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS);
}

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 EXOSPHERE_EXOSPHERE_CONFIG_H
#define EXOSPHERE_EXOSPHERE_CONFIG_H
@ -36,7 +36,7 @@
/* Exosphere config in DRAM shares physical/virtual mapping. */
#define MAILBOX_EXOSPHERE_CONFIG_PHYS MAILBOX_EXOSPHERE_CONFIG
#define EXOSPHERE_FLAG_PERFORM_620_KEYGEN (1 << 0u)
#define EXOSPHERE_FLAG_PERFORM_620_KEYGEN_DEPRECATED (1 << 0u)
#define EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV (1 << 1u)
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
#define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u)

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 <stdbool.h>
#include <stdint.h>
#include <string.h>
@ -42,6 +42,7 @@ static const uint8_t mkey_vectors_dev[MASTERKEY_REVISION_MAX][0x10] =
{0x78, 0xD5, 0xF1, 0x20, 0x3D, 0x16, 0xE9, 0x30, 0x32, 0x27, 0x34, 0x6F, 0xCF, 0xE0, 0x27, 0xDC}, /* Master key 04 encrypted with Master key 05. */
{0x6F, 0xD2, 0x84, 0x1D, 0x05, 0xEC, 0x40, 0x94, 0x5F, 0x18, 0xB3, 0x81, 0x09, 0x98, 0x8D, 0x4E}, /* Master key 05 encrypted with Master key 06. */
{0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19}, /* Master key 06 encrypted with Master key 07. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: Master key 07 encrypted with Master key 08. */
};
/* Retail unit keys. */
@ -55,6 +56,7 @@ static const uint8_t mkey_vectors[MASTERKEY_REVISION_MAX][0x10] =
{0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */
{0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */
{0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */
{0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */
};
bool check_mkey_revision(unsigned int revision, bool is_retail) {
@ -83,7 +85,7 @@ void mkey_detect_revision(void) {
if (g_determined_mkey_revision) {
generic_panic();
}
for (unsigned int rev = 0; rev < MASTERKEY_REVISION_MAX; rev++) {
if (check_mkey_revision(rev, configitem_is_retail())) {
g_determined_mkey_revision = true;
@ -91,7 +93,7 @@ void mkey_detect_revision(void) {
break;
}
}
/* We must have determined the master key, or we're not running on a Switch. */
if (!g_determined_mkey_revision) {
/* Panic in bright red. */
@ -125,7 +127,6 @@ unsigned int mkey_get_keyslot(unsigned int revision) {
}
}
void set_old_devkey(unsigned int revision, const uint8_t *key) {
if (revision < MASTERKEY_REVISION_400_410 || MASTERKEY_REVISION_MAX <= revision) {
generic_panic();
@ -135,23 +136,17 @@ void set_old_devkey(unsigned int revision, const uint8_t *key) {
}
unsigned int devkey_get_keyslot(unsigned int revision) {
if (!g_determined_mkey_revision || revision >= MASTERKEY_REVISION_MAX) {
if (!g_determined_mkey_revision || revision > g_mkey_revision) {
generic_panic();
}
if (revision > g_mkey_revision) {
generic_panic();
}
if (revision >= 1) {
if (revision == MASTERKEY_REVISION_MAX) {
return KEYSLOT_SWITCH_DEVICEKEY;
} else {
/* 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 {
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

@ -13,14 +13,14 @@
* 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_MASTERKEY_H
#define EXOSPHERE_MASTERKEY_H
/* This is glue code to enable master key support across versions. */
/* TODO: Update to 0x9 on release of new master key. */
#define MASTERKEY_REVISION_MAX 0x8
/* TODO: Update to 0xA on release of new master key. */
#define MASTERKEY_REVISION_MAX 0x9
#define MASTERKEY_REVISION_100_230 0x00
#define MASTERKEY_REVISION_300 0x01
@ -29,7 +29,8 @@
#define MASTERKEY_REVISION_500_510 0x04
#define MASTERKEY_REVISION_600_610 0x05
#define MASTERKEY_REVISION_620 0x06
#define MASTERKEY_REVISION_700_CURRENT 0x07
#define MASTERKEY_REVISION_700_800 0x07
#define MASTERKEY_REVISION_810_CURRENT 0x08
#define MASTERKEY_NUM_NEW_DEVICE_KEYS (MASTERKEY_REVISION_MAX - MASTERKEY_REVISION_400_410)

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 <stdint.h>
#include "memory_map.h"
@ -28,7 +28,7 @@ typedef struct {
static saved_carveout_info_t g_saved_carveouts[2] = {
{0x80060000ull, KERNEL_CARVEOUT_SIZE_MAX},
{0x00000000ull, 0x00000000ull}
};
};
volatile security_carveout_t *get_carveout_by_id(unsigned int carveout) {
if (CARVEOUT_ID_MIN <= carveout && carveout <= CARVEOUT_ID_MAX) {
@ -130,7 +130,7 @@ void configure_kernel_carveout(unsigned int carveout_id, uint64_t address, uint6
if (carveout_id != 4 && carveout_id != 5) {
generic_panic();
}
g_saved_carveouts[carveout_id-4].address = address;
g_saved_carveouts[carveout_id-4].size = size;
@ -140,8 +140,12 @@ void configure_kernel_carveout(unsigned int carveout_id, uint64_t address, uint6
carveout->size_big_pages = (uint32_t)(size >> 17);
carveout->client_access_0 = (BIT(CSR_PTCR) | BIT(CSR_DISPLAY0A) | BIT(CSR_DISPLAY0AB) | BIT(CSR_DISPLAY0B) | BIT(CSR_DISPLAY0BB) | BIT(CSR_DISPLAY0C) | BIT(CSR_DISPLAY0CB) | BIT(CSR_AFIR) | BIT(CSR_DISPLAYHC) | BIT(CSR_DISPLAYHCB) | BIT(CSR_HDAR) | BIT(CSR_HOST1XDMAR) | BIT(CSR_HOST1XR) | BIT(CSR_NVENCSRD) | BIT(CSR_PPCSAHBDMAR) | BIT(CSR_PPCSAHBSLVR));
carveout->client_access_1 = (BIT(CSR_MPCORER) | BIT(CSW_NVENCSWR) | BIT(CSW_AFIW) | BIT(CSW_HDAW) | BIT(CSW_HOST1XW) | BIT(CSW_MPCOREW) | BIT(CSW_PPCSAHBDMAW) | BIT(CSW_PPCSAHBSLVW));
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_800) {
carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW));
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_810) {
carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW));
carveout->client_access_3 = (BIT(CSR_SDMMCRA) | BIT(CSR_SDMMCRAA) | BIT(CSR_SDMMCRAB) | BIT(CSW_SDMMCWA) | BIT(CSW_SDMMCWAA) | BIT(CSW_SDMMCWAB) | BIT(CSR_VICSRD) | BIT(CSW_VICSWR) | BIT(CSR_DISPLAYD) | BIT(CSR_APER) | BIT(CSW_APEW) | BIT(CSR_NVJPGSRD) | BIT(CSW_NVJPGSWR));
carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR));
} else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_800) {
carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW));
carveout->client_access_3 = (BIT(CSR_SDMMCRA) | BIT(CSR_SDMMCRAA) | BIT(CSR_SDMMCRAB) | BIT(CSW_SDMMCWA) | BIT(CSW_SDMMCWAA) | BIT(CSW_SDMMCWAB) | BIT(CSR_VICSRD) | BIT(CSW_VICSWR) | BIT(CSR_DISPLAYD) | BIT(CSR_NVDECSRD) | BIT(CSW_NVDECSWR) | BIT(CSR_APER) | BIT(CSW_APEW) | BIT(CSR_NVJPGSRD) | BIT(CSW_NVJPGSWR));
carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR) | BIT(CSR_TSECSRDB) | BIT(CSW_TSECSWRB));
} else {

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"
@ -43,6 +43,7 @@ static const uint8_t new_device_key_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10]
{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. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */
};
static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
@ -51,6 +52,7 @@ static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x
{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. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */
};
static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
@ -58,45 +60,28 @@ static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS
{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}, /* 6.2.0 New Device Keygen Source. */
};
static const uint8_t new_master_kek_sources[MASTERKEY_REVISION_700_CURRENT - MASTERKEY_REVISION_600_610][0x10] = {
{0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, /* 6.2.0 Master Kek Source. */
{0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, /* 7.0.0 Master Kek Source. */
};
static const uint8_t keyblob_key_seed_00[0x10] = {
0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3
};
static const uint8_t devicekey_seed[0x10] = {
0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78
};
static const uint8_t devicekey_4x_seed[0x10] = {
0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28
};
static const uint8_t masterkey_seed[0x10] = {
0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C
};
static const uint8_t devicekek_4x_seed[0x10] = {
0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66
{0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 7.0.0 New Device Keygen Source. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */
};
static void derive_new_device_keys(unsigned int keygen_keyslot) {
uint8_t work_buffer[0x10];
bool is_retail = configitem_is_retail();
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 (revision < MASTERKEY_NUM_NEW_DEVICE_KEYS - 1) {
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10, work_buffer, 0x10);
set_old_devkey(revision + MASTERKEY_REVISION_400_410, work_buffer);
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 (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_700) {
decrypt_data_into_keyslot(KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10);
}
} else {
decrypt_data_into_keyslot(KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10);
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);
@ -118,7 +103,8 @@ static void setup_se(void) {
se->_0x0 &= 0xFFFEFFFF; /* Clear bit 16. */
(void)(se->FLAGS_REG);
__dsb_sy();
/* NOTE: On 8.1.0+, Nintendo does not make keyslots 0-5 unreadable. */
se->_0x4 = 0;
se->AES_KEY_READ_DISABLE_REG = 0;
se->RSA_KEY_READ_DISABLE_REG = 0;
@ -136,33 +122,6 @@ static void setup_se(void) {
for (unsigned int i = 0; i < KEYSLOT_RSA_MAX; i++) {
set_rsa_keyslot_flags(i, 0x41);
}
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_620 && exosphere_should_perform_620_keygen()) {
unsigned int master_kek_source_ind;
switch (exosphere_get_target_firmware()) {
case ATMOSPHERE_TARGET_FIRMWARE_620:
master_kek_source_ind = MASTERKEY_REVISION_620 - MASTERKEY_REVISION_620;
break;
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
master_kek_source_ind = MASTERKEY_REVISION_700_CURRENT - MASTERKEY_REVISION_620;
break;
default:
generic_panic();
break;
}
/* Start by generating device keys. */
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_6XTSECKEY, work_buffer, 0x10, keyblob_key_seed_00, 0x10);
decrypt_data_into_keyslot(KEYSLOT_SWITCH_4XOLDDEVICEKEY, KEYSLOT_SWITCH_6XSBK, work_buffer, 0x10);
decrypt_data_into_keyslot(KEYSLOT_SWITCH_4XNEWCONSOLEKEYGENKEY, KEYSLOT_SWITCH_4XOLDDEVICEKEY, devicekey_4x_seed, 0x10);
decrypt_data_into_keyslot(KEYSLOT_SWITCH_4XOLDDEVICEKEY, KEYSLOT_SWITCH_4XOLDDEVICEKEY, devicekey_seed, 0x10);
/* Next, generate the master kek, and from there master key/device kek. We use different keyslots than Nintendo, here. */
decrypt_data_into_keyslot(KEYSLOT_SWITCH_6XTSECROOTKEY, KEYSLOT_SWITCH_6XTSECROOTKEY, new_master_kek_sources[master_kek_source_ind], 0x10);
decrypt_data_into_keyslot(KEYSLOT_SWITCH_MASTERKEY, KEYSLOT_SWITCH_6XTSECROOTKEY, masterkey_seed, 0x10);
decrypt_data_into_keyslot(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY, KEYSLOT_SWITCH_6XTSECROOTKEY, devicekek_4x_seed, 0x10);
clear_aes_keyslot(KEYSLOT_SWITCH_6XTSECROOTKEY);
}
/* Detect Master Key revision. */
mkey_detect_revision();
@ -181,6 +140,7 @@ static void setup_se(void) {
case ATMOSPHERE_TARGET_FIRMWARE_620:
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
case ATMOSPHERE_TARGET_FIRMWARE_810:
derive_new_device_keys(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY);
break;
}
@ -198,7 +158,7 @@ static void setup_se(void) {
set_aes_keyslot_flags(KEYSLOT_SWITCH_SESSIONKEY, 0xFF);
/* Generate test vector for our keys. */
se_generate_stored_vector();
se_generate_stored_vector();
}
static void setup_boot_config(void) {
@ -287,7 +247,7 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
if (metadata->magic != MAGIC_PK21) {
return false;
}
/* Package2 size, version number is stored XORed in header CTR. */
/* Nintendo, what the fuck? */
@ -370,7 +330,7 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
/* Perform version checks. */
/* We will be compatible with all package2s released before current, but not newer ones. */
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_700_CURRENT) {
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_810_CURRENT) {
return true;
}
@ -495,21 +455,22 @@ static void copy_warmboot_bin_to_dram() {
break;
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
case ATMOSPHERE_TARGET_FIRMWARE_810:
warmboot_src = (uint8_t *)0x4003E000;
break;
}
uint8_t *warmboot_dst = (uint8_t *)0x8000D000;
const size_t warmboot_size = 0x2000;
/* Flush cache, to ensure warmboot is where we need it to be. */
flush_dcache_range(warmboot_src, warmboot_src + warmboot_size);
__dsb_sy();
/* Copy warmboot. */
for (size_t i = 0; i < warmboot_size; i += sizeof(uint32_t)) {
write32le(warmboot_dst, i, read32le(warmboot_src, i));
}
/* Flush cache, to ensure warmboot is where we need it to be. */
flush_dcache_range(warmboot_dst, warmboot_dst + warmboot_size);
__dsb_sy();
@ -544,12 +505,12 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Setup the Security Engine. */
setup_se();
/* Perform initial PMC register writes, if relevant. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) {
MAKE_REG32(PMC_BASE + 0x054) = 0x8000D000;
MAKE_REG32(PMC_BASE + 0x0A0) &= 0xFFF3FFFF;
MAKE_REG32(PMC_BASE + 0x818) &= 0xFFFFFFFE;
MAKE_REG32(PMC_BASE + 0x054) = 0x8000D000;
MAKE_REG32(PMC_BASE + 0x0A0) &= 0xFFF3FFFF;
MAKE_REG32(PMC_BASE + 0x818) &= 0xFFFFFFFE;
MAKE_REG32(PMC_BASE + 0x334) |= 0x10;
switch (exosphere_get_target_firmware()) {
case ATMOSPHERE_TARGET_FIRMWARE_400:
@ -568,6 +529,9 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
case ATMOSPHERE_TARGET_FIRMWARE_800:
MAKE_REG32(PMC_BASE + 0x360) = 0x129;
break;
case ATMOSPHERE_TARGET_FIRMWARE_810:
MAKE_REG32(PMC_BASE + 0x360) = 0x14A;
break;
}
}
@ -585,7 +549,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* memclear the initial copy of Exosphere running in IRAM (relocated to TZRAM by earlier code). */
/* memset((void *)reloc_list->reloc_base, 0, reloc_list->loaded_bin_size); */
/* Let NX Bootloader know that we're running. */
MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE(exosphere_get_target_firmware()) = 1;
@ -597,7 +561,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Load Boot Config into global. */
setup_boot_config();
/* Set sysctr0 registers based on bootconfig. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) {
uint64_t sysctr0_val = bootconfig_get_value_for_sysctr0();
@ -620,7 +584,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Make PMC (2.x+), MC (4.x+) registers secure-only */
secure_additional_devices();
/* Remove the identity mapping for iRAM-C+D & TZRAM */
/* For our crt0 to work, this doesn't actually unmap TZRAM */
identity_unmap_iram_cd_tzram();
@ -630,7 +594,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
flush_dcache_range((uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, (uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS + sizeof(header));
memcpy(&header, NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, sizeof(header));
flush_dcache_range((uint8_t *)&header, (uint8_t *)&header + sizeof(header));
/* Perform signature checks. */
/* Special exosphere patching enable: All-zeroes signature + decrypted header implies unsigned and decrypted package2. */
if (header.signature[0] == 0 && memcmp(header.signature, header.signature + 1, sizeof(header.signature) - 1) == 0 && header.metadata.magic == MAGIC_PK21) {
@ -641,7 +605,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Decrypt header, get key revision required. */
uint32_t package2_mkey_rev = decrypt_and_validate_header(&header);
/* Copy hash, if necessary. */
if (bootconfig_is_recovery_boot()) {
bootconfig_set_package2_hash_for_recovery(NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, get_package2_size(&header.metadata));
@ -649,7 +613,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Load Package2 Sections. */
load_package2_sections(&header.metadata, package2_mkey_rev);
/* Clean up cache. */
flush_dcache_all();
invalidate_icache_all(); /* non-broadcasting */
@ -660,7 +624,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Remove the DRAM identity mapping. */
if (0) {
identity_unmap_dram();
}
}
/* Synchronize with NX BOOTLOADER. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) {

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 EXOSPHERE_PACKAGE2_H
#define EXOSPHERE_PACKAGE2_H
@ -70,7 +70,8 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(unsigned int targetfw) {
#define PACKAGE2_MAXVER_500_510 0x7
#define PACKAGE2_MAXVER_600_610 0x8
#define PACKAGE2_MAXVER_620 0x9
#define PACKAGE2_MAXVER_700_CURRENT 0xA
#define PACKAGE2_MAXVER_700_800 0xA
#define PACKAGE2_MAXVER_810_CURRENT 0xB
#define PACKAGE2_MINVER_100 0x3
#define PACKAGE2_MINVER_200 0x4
@ -80,7 +81,8 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(unsigned int targetfw) {
#define PACKAGE2_MINVER_500_510 0x8
#define PACKAGE2_MINVER_600_610 0x9
#define PACKAGE2_MINVER_620 0xA
#define PACKAGE2_MINVER_700_CURRENT 0xB
#define PACKAGE2_MINVER_700_800 0xB
#define PACKAGE2_MINVER_810_CURRENT 0xC
typedef struct {
union {

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 <stdatomic.h>
#include <stdint.h>
@ -185,6 +185,7 @@ void set_version_specific_smcs(void) {
case ATMOSPHERE_TARGET_FIRMWARE_620:
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
case ATMOSPHERE_TARGET_FIRMWARE_810:
/* No more LoadSecureExpModKey. */
g_smc_user_table[0xE].handler = NULL;
g_smc_user_table[0xC].id = 0xC300D60C;
@ -256,7 +257,7 @@ void call_smc_handler(uint32_t handler_id, smc_args_t *args) {
unsigned char smc_id, call_range;
unsigned int result;
unsigned int (*smc_handler)(smc_args_t *args);
/* Validate top-level handler. */
if (handler_id >= SMC_HANDLER_COUNT) {
generic_panic();
@ -288,17 +289,17 @@ void call_smc_handler(uint32_t handler_id, smc_args_t *args) {
if ((smc_handler = g_smc_tables[handler_id].handlers[smc_id].handler) == NULL) {
generic_panic();
}
bool is_aes_kek = handler_id == SMC_HANDLER_USER && args->X[0] == 0xC3000007;
#if DEBUG_LOG_SMCS
uint64_t num;
#if DEBUG_LOG_SMCS
uint64_t num;
if (handler_id == SMC_HANDLER_USER) {
num = atomic_fetch_add(&num_smcs_called, 1);
*(volatile smc_args_t *)(get_iram_address_for_debug() + 0x100 + ((0x80 * num) & 0x3FFF)) = *args;
}
#endif
/* Call function. */
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_800 ||
(g_smc_tables[handler_id].handlers[smc_id].blacklist_mask & g_smc_blacklist_mask) == 0) {
@ -307,15 +308,15 @@ void call_smc_handler(uint32_t handler_id, smc_args_t *args) {
/* Call not allowed due to current boot conditions. */
args->X[0] = 6;
}
#if DEBUG_LOG_SMCS
#if DEBUG_LOG_SMCS
if (handler_id == SMC_HANDLER_USER) {
*(volatile smc_args_t *)(get_iram_address_for_debug() + 0x100 + ((0x80 * num + 0x40) & 0x3FFF)) = *args;
}
#endif
#if DEBUG_PANIC_ON_FAILURE
if (args->X[0] && (!is_aes_kek || args->X[3] <= ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG))
if (args->X[0] && (!is_aes_kek || args->X[3] <= ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG))
{
MAKE_REG32(get_iram_address_for_debug() + 0x4FF0) = handler_id;
MAKE_REG32(get_iram_address_for_debug() + 0x4FF4) = smc_id;
@ -695,14 +696,14 @@ uint32_t smc_configure_carveout(smc_args_t *args) {
if (size > KERNEL_CARVEOUT_SIZE_MAX) {
return 2;
}
/* Ensure validity of carveout index. */
if (carveout_id > 1) {
return 2;
}
/* Configuration is one-shot, and cannot be done multiple times. */
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_300) {
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_300) {
if (g_configured_carveouts[carveout_id]) {
return 2;
}

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 <stdbool.h>
#include <stdint.h>
#include <string.h>
@ -52,6 +52,7 @@ static bool is_user_keyslot_valid(unsigned int keyslot) {
case ATMOSPHERE_TARGET_FIRMWARE_620:
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
case ATMOSPHERE_TARGET_FIRMWARE_810:
default:
return keyslot <= 5;
}
@ -165,7 +166,7 @@ uint32_t user_generate_aes_kek(smc_args_t *args) {
bool is_personalized = (int)(packed_options & 1);
bool is_recovery_boot = configitem_is_recovery_boot();
/* 5.0.0+ Bounds checking. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) {
if (is_personalized) {
@ -295,7 +296,7 @@ uint32_t crypt_aes_done_handler(void) {
uint32_t user_crypt_aes(smc_args_t *args) {
uint32_t keyslot = args->X[1] & 3;
uint32_t mode = (args->X[1] >> 4) & 3;
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_600) {
keyslot = args->X[1] & 7;
}
@ -791,7 +792,7 @@ uint32_t user_encrypt_rsa_key_for_import(smc_args_t *args) {
if (usecase > CRYPTOUSECASE_RSAIMPORT) {
return 2;
}
}
if (usecase == 0) {
if (size < 0x31 || size > 0x240) {
return 2;
@ -823,7 +824,7 @@ uint32_t user_encrypt_rsa_key_for_import(smc_args_t *args) {
if (secure_copy_to_user(&page_ref, user_address, user_data, size) == 0) {
return 2;
}
}
return 0;
}
@ -854,7 +855,7 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args) {
if (usecase > CRYPTOUSECASE_RSAIMPORT) {
return 2;
}
}
if (usecase == 0) {
if (size < 0x31 || size > 0x240) {
return 2;
@ -881,7 +882,7 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args) {
case 0:
if (secure_copy_to_user(&page_ref, user_address, user_data, size) == 0) {
return 2;
}
}
return 0;
case 1:
exponent_id = 1;

View file

@ -99,7 +99,7 @@ SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
KIPFILES := loader.kip pm.kip sm.kip ams_mitm.kip spl.kip boot.kip
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) fusee-primary.bin \
exosphere.bin lp0fw.bin rebootstub.bin thermosphere.bin splash_screen.bmp \
sept-primary.bin sept-secondary.enc emummc.kip \
sept-primary.bin sept-secondary_00.enc sept-secondary_01.enc emummc.kip \
$(KIPFILES)
#---------------------------------------------------------------------------------
@ -198,22 +198,27 @@ fusee_primary.bin.o fusee_primary_bin.h: fusee-primary.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(_bin2o)
sept_primary.bin.o sept_primary_bin.h: sept-primary.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(_bin2o)
sept_secondary.enc.o sept_secondary_enc.h: sept-secondary.enc
sept_secondary_00.enc.o sept_secondary_00.h: sept-secondary_00.enc
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(_bin2o)
sept_secondary_01.enc.o sept_secondary_01_enc.h: sept-secondary_01.enc
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(_bin2o)
%.bin.o %_bin.h: %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
%.bmp.o %_bmp.h: %.bmp
#---------------------------------------------------------------------------------
@echo $(notdir $<)

View file

@ -55,7 +55,7 @@ SECTIONS
. = ALIGN(32);
PROVIDE (__chainloader_end__ = ABSOLUTE(.));
} >low_iram :NONE
.nxboot_loadable :
{
. = ALIGN(32);
@ -157,7 +157,7 @@ SECTIONS
CONSTRUCTORS
. = ALIGN(32);
} >main
__data_end__ = ABSOLUTE(.);
PROVIDE (__total_size__ = (__data_end__ - __start__));
@ -236,8 +236,10 @@ SECTIONS
PROVIDE(__rebootstub_bin_size__ = rebootstub_bin_end - rebootstub_bin);
PROVIDE(__sept_primary_bin_start__ = sept_primary_bin - __start__);
PROVIDE(__sept_primary_bin_size__ = sept_primary_bin_end - sept_primary_bin);
PROVIDE(__sept_secondary_enc_start__ = sept_secondary_enc - __start__);
PROVIDE(__sept_secondary_enc_size__ = sept_secondary_enc_end - sept_secondary_enc);
PROVIDE(__sept_secondary_00_enc_start__ = sept_secondary_00_enc - __start__);
PROVIDE(__sept_secondary_00_enc_size__ = sept_secondary_00_enc_end - sept_secondary_00_enc);
PROVIDE(__sept_secondary_01_enc_start__ = sept_secondary_01_enc - __start__);
PROVIDE(__sept_secondary_01_enc_size__ = sept_secondary_01_enc_end - sept_secondary_01_enc);
PROVIDE(__sm_kip_start__ = sm_kip - __start__);
PROVIDE(__sm_kip_size__ = sm_kip_end - sm_kip);
PROVIDE(__spl_kip_start__ = spl_kip - __start__);

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 EXOSPHERE_EMUMMC_CONFIG_H
#define EXOSPHERE_EMUMMC_CONFIG_H
@ -73,6 +73,9 @@ typedef enum {
FS_VER_8_0_0,
FS_VER_8_0_0_EXFAT,
FS_VER_8_1_0,
FS_VER_8_1_0_EXFAT,
FS_VER_MAX,
} emummc_fs_ver_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 <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@ -46,7 +46,7 @@ static bool should_ignore_default_patch(const char *patch_dir) {
if (!g_enable_nogc_patches && strcmp(patch_dir, NOGC_PATCH_DIR) == 0) {
return true;
}
return false;
}
@ -64,7 +64,7 @@ static bool has_patch(const char *dir, const char *subdir, const void *hash, siz
if (cur_len >= sizeof(path)) {
return false;
}
FILE *f = fopen(path, "rb");
if (f != NULL) {
fclose(f);
@ -77,7 +77,7 @@ static bool has_needed_default_kip_patches(uint64_t title_id, const void *hash,
if (title_id == 0x0100000000000000ULL && g_enable_nogc_patches) {
return has_patch("atmosphere/kip_patches", NOGC_PATCH_DIR, hash, hash_size);
}
return true;
}
@ -90,7 +90,7 @@ static void apply_ips_patch(uint8_t *mem, size_t mem_size, size_t prot_size, boo
} else if (!is_ips32 && memcmp(buffer, IPS_TAIL, 3) == 0) {
break;
}
/* Offset of patch. */
uint32_t patch_offset;
if (is_ips32) {
@ -98,27 +98,27 @@ static void apply_ips_patch(uint8_t *mem, size_t mem_size, size_t prot_size, boo
} else {
patch_offset = (buffer[0] << 16) | (buffer[1] << 8) | (buffer[2]);
}
/* Size of patch. */
if (fread(buffer, 2, 1, f_ips) != 1) {
break;
}
uint32_t patch_size = (buffer[0] << 8) | (buffer[1]);
/* Check for RLE encoding. */
if (patch_size == 0) {
/* Size of RLE. */
if (fread(buffer, 2, 1, f_ips) != 1) {
break;
}
uint32_t rle_size = (buffer[0] << 8) | (buffer[1]);
/* Value for RLE. */
if (fread(buffer, 1, 1, f_ips) != 1) {
break;
}
if (patch_offset < prot_size) {
if (patch_offset + rle_size > prot_size) {
uint32_t diff = prot_size - patch_offset;
@ -187,7 +187,7 @@ static bool name_matches_hash(const char *name, size_t name_len, const void *has
hash_from_name[id_ofs] |= hex_nybble_to_u8(name[name_ofs++]) << 4;
hash_from_name[id_ofs] |= hex_nybble_to_u8(name[name_ofs++]);
}
return memcmp(hash, hash_from_name, hash_size) == 0;
}
@ -204,11 +204,11 @@ static bool has_ips_patches(const char *dir, const void *hash, size_t hash_size)
if (strcmp(pdir_ent->d_name, ".") == 0 || strcmp(pdir_ent->d_name, "..") == 0) {
continue;
}
if (should_ignore_default_patch(pdir_ent->d_name)) {
continue;
}
snprintf(path, sizeof(path) - 1, "%s/%s", dir, pdir_ent->d_name);
DIR *patch_dir = opendir(path);
struct dirent *ent;
@ -218,7 +218,7 @@ static bool has_ips_patches(const char *dir, const void *hash, size_t hash_size)
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
continue;
}
size_t name_len = strlen(ent->d_name);
if ((4 < name_len && name_len <= 0x44) && ((name_len & 1) == 0) && strcmp(ent->d_name + name_len - 4, ".ips") == 0 && name_matches_hash(ent->d_name, name_len, hash, hash_size)) {
snprintf(path, sizeof(path) - 1, "%s/%s/%s", dir, pdir_ent->d_name, ent->d_name);
@ -254,11 +254,11 @@ static void apply_ips_patches(const char *dir, void *mem, size_t mem_size, size_
if (strcmp(pdir_ent->d_name, ".") == 0 || strcmp(pdir_ent->d_name, "..") == 0) {
continue;
}
if (should_ignore_default_patch(pdir_ent->d_name)) {
continue;
}
snprintf(path, sizeof(path) - 1, "%s/%s", dir, pdir_ent->d_name);
DIR *patch_dir = opendir(path);
struct dirent *ent;
@ -268,7 +268,7 @@ static void apply_ips_patches(const char *dir, void *mem, size_t mem_size, size_
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
continue;
}
size_t name_len = strlen(ent->d_name);
if ((4 < name_len && name_len <= 0x44) && ((name_len & 1) == 0) && strcmp(ent->d_name + name_len - 4, ".ips") == 0 && name_matches_hash(ent->d_name, name_len, hash, hash_size)) {
snprintf(path, sizeof(path) - 1, "%s/%s/%s", dir, pdir_ent->d_name, ent->d_name);
@ -291,7 +291,7 @@ static void apply_ips_patches(const char *dir, void *mem, size_t mem_size, size_
}
closedir(patches_dir);
}
}
}
void apply_kernel_ips_patches(void *kernel, size_t kernel_size) {
uint8_t hash[0x20];
@ -304,16 +304,16 @@ static void kip1_blz_uncompress(void *hdr_end) {
uint32_t addl_size = ((u8_hdr_end[-4]) << 0) | ((u8_hdr_end[-3]) << 8) | ((u8_hdr_end[-2]) << 16) | ((u8_hdr_end[-1]) << 24);
uint32_t header_size = ((u8_hdr_end[-8]) << 0) | ((u8_hdr_end[-7]) << 8) | ((u8_hdr_end[-6]) << 16) | ((u8_hdr_end[-5]) << 24);
uint32_t cmp_and_hdr_size = ((u8_hdr_end[-12]) << 0) | ((u8_hdr_end[-11]) << 8) | ((u8_hdr_end[-10]) << 16) | ((u8_hdr_end[-9]) << 24);
unsigned char *cmp_start = (unsigned char *)(((uintptr_t)hdr_end) - cmp_and_hdr_size);
uint32_t cmp_ofs = cmp_and_hdr_size - header_size;
uint32_t out_ofs = cmp_and_hdr_size + addl_size;
while (out_ofs) {
unsigned char control = cmp_start[--cmp_ofs];
for (unsigned int i = 0; i < 8; i++) {
if (control & 0x80) {
if (cmp_ofs < 2) {
if (cmp_ofs < 2) {
fatal_error("KIP1 decompression out of bounds!\n");
}
cmp_ofs -= 2;
@ -325,7 +325,7 @@ static void kip1_blz_uncompress(void *hdr_end) {
seg_size = out_ofs;
}
out_ofs -= seg_size;
for (unsigned int j = 0; j < seg_size; j++) {
cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs];
}
@ -350,15 +350,15 @@ kip1_header_t *kip1_uncompress(kip1_header_t *kip, size_t *size) {
new_header.section_headers[i].compressed_size = new_header.section_headers[i].out_size;
}
new_header.flags &= 0xF8;
*size = kip1_get_size_from_header(&new_header);
unsigned char *new_kip = calloc(1, *size);
if (new_kip == NULL) {
return NULL;
}
*((kip1_header_t *)new_kip) = new_header;
size_t new_offset = 0x100;
size_t old_offset = 0x100;
for (unsigned int i = 0; i < 3; i++) {
@ -369,7 +369,7 @@ kip1_header_t *kip1_uncompress(kip1_header_t *kip, size_t *size) {
new_offset += kip->section_headers[i].out_size;
old_offset += kip->section_headers[i].compressed_size;
}
return (kip1_header_t *)new_kip;
}
@ -408,12 +408,15 @@ static const uint8_t g_fs_hashes[FS_VER_MAX][0x8] = {
"\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 */
"\x6B\x09\xB6\x7B\x29\xC0\x20\x24", /* FS_VER_8_1_0 */
"\xB4\xCA\xE1\xF2\x49\x65\xD9\x2E", /* FS_VER_8_1_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++) {
@ -426,24 +429,24 @@ kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size, emummc
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);
}
if (!has_ips_patches("atmosphere/kip_patches", hash, sizeof(hash))) {
return NULL;
}
print(SCREEN_LOG_LEVEL_MANDATORY, "[NXBOOT]: Patching KIP %08x%08x...\n", (uint32_t)(kip->title_id >> 32), (uint32_t)kip->title_id);
size_t uncompressed_kip_size;
kip1_header_t *uncompressed_kip = kip1_uncompress(kip, &uncompressed_kip_size);
if (uncompressed_kip == NULL) {
if (uncompressed_kip == NULL) {
return NULL;
}
apply_ips_patches("atmosphere/kip_patches", uncompressed_kip, uncompressed_kip_size, 0x100, hash, sizeof(hash));
return uncompressed_kip;
}

View file

@ -54,7 +54,8 @@ static const uint8_t AL16 masterkey_4x_seed[0x10] = {
0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66
};
static const uint8_t AL16 new_master_kek_seeds[MASTERKEY_REVISION_700_CURRENT - MASTERKEY_REVISION_600_610][0x10] = {
/* TODO: Bother adding 8.1.0 here? We'll never call into here... */
static const uint8_t AL16 new_master_kek_seeds[MASTERKEY_REVISION_700_800 - MASTERKEY_REVISION_600_610][0x10] = {
{0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, /* MasterKek seed 06. */
{0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, /* MasterKek seed 07. */
};
@ -93,17 +94,17 @@ static int decrypt_keyblob(const nx_keyblob_t *keyblobs, uint32_t revision, uint
if (get_keyblob(&keyblob, revision, keyblobs, available_revision) != 0) {
return -1;
}
se_aes_ecb_decrypt_block(0xD, work_buffer, 0x10, keyblob_seeds[revision], 0x10);
decrypt_data_into_keyslot(keyslot, 0xE, work_buffer, 0x10);
decrypt_data_into_keyslot(0xB, keyslot, keyblob_mac_seed, 0x10);
/* Validate keyblob. */
se_compute_aes_128_cmac(0xB, work_buffer, 0x10, keyblob.mac + sizeof(keyblob.mac), sizeof(keyblob) - sizeof(keyblob.mac));
if (safe_memcmp(keyblob.mac, work_buffer, 0x10)) {
return -1;
}
/* Decrypt keyblob. */
se_aes_ctr_crypt(keyslot, &g_dec_keyblobs[revision], sizeof(g_dec_keyblobs[revision]), keyblob.data, sizeof(keyblob.data), keyblob.ctr, sizeof(keyblob.ctr));
return 0;
@ -113,7 +114,7 @@ int load_package1_key(uint32_t revision) {
if (revision > MASTERKEY_REVISION_600_610) {
return -1;
}
set_aes_keyslot(0xB, g_dec_keyblobs[revision].package1_key, 0x10);
return 0;
}
@ -122,17 +123,17 @@ int load_package1_key(uint32_t revision) {
int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, uint32_t available_revision, const void *tsec_key, void *tsec_root_keys, unsigned int *out_keygen_type) {
uint8_t AL16 work_buffer[0x10];
uint8_t AL16 zeroes[0x10] = {0};
/* Initialize keygen type. */
*out_keygen_type = 0;
/* TODO: Set keyslot flags properly in preparation of derivation. */
set_aes_keyslot_flags(0xE, 0x15);
set_aes_keyslot_flags(0xD, 0x15);
/* Set the TSEC key. */
set_aes_keyslot(0xD, tsec_key, 0x10);
/* Decrypt all keyblobs, setting keyslot 0xF correctly. */
for (unsigned int rev = 0; rev <= MASTERKEY_REVISION_600_610; rev++) {
int ret = decrypt_keyblob(keyblobs, rev, available_revision);
@ -150,13 +151,16 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
break;
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
desired_keyblob = MASTERKEY_REVISION_700_CURRENT;
desired_keyblob = MASTERKEY_REVISION_700_800;
break;
case ATMOSPHERE_TARGET_FIRMWARE_810:
desired_keyblob = MASTERKEY_REVISION_810_CURRENT;
break;
default:
fatal_error("Unknown target firmware: %02x!", target_firmware);
break;
}
/* Try emulation result. */
for (unsigned int rev = MASTERKEY_REVISION_620; rev < MASTERKEY_REVISION_MAX; rev++) {
void *tsec_root_key = (void *)((uintptr_t)tsec_root_keys + 0x10 * (rev - MASTERKEY_REVISION_620));
@ -167,7 +171,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
memcpy(g_dec_keyblobs[rev].master_kek, work_buffer, 0x10);
}
}
if (memcmp(g_dec_keyblobs[desired_keyblob].master_kek, zeroes, 0x10) == 0) {
/* Try reading the keys from a file. */
const char *keyfile = fuse_get_retail_type() != 0 ? "atmosphere/prod.keys" : "atmosphere/dev.keys";
@ -188,13 +192,13 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
}
}
}
if (memcmp(g_dec_keyblobs[available_revision].master_kek, zeroes, 0x10) == 0) {
fatal_error("Error: failed to derive master_kek_%02x!", available_revision);
}
}
/* Clear the SBK. */
clear_aes_keyslot(0xE);
@ -225,6 +229,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
case ATMOSPHERE_TARGET_FIRMWARE_620:
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
case ATMOSPHERE_TARGET_FIRMWARE_810:
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);

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 <stdbool.h>
#include <stdint.h>
#include <string.h>
@ -39,6 +39,7 @@ static const uint8_t mkey_vectors_dev[MASTERKEY_REVISION_MAX][0x10] =
{0x78, 0xD5, 0xF1, 0x20, 0x3D, 0x16, 0xE9, 0x30, 0x32, 0x27, 0x34, 0x6F, 0xCF, 0xE0, 0x27, 0xDC}, /* Master key 04 encrypted with Master key 05. */
{0x6F, 0xD2, 0x84, 0x1D, 0x05, 0xEC, 0x40, 0x94, 0x5F, 0x18, 0xB3, 0x81, 0x09, 0x98, 0x8D, 0x4E}, /* Master key 05 encrypted with Master key 06. */
{0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19}, /* Master key 06 encrypted with Master key 07. */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: Master key 07 encrypted with Master key 08. */
};
/* Retail unit keys. */
@ -52,6 +53,7 @@ static const uint8_t mkey_vectors[MASTERKEY_REVISION_MAX][0x10] =
{0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */
{0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */
{0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */
{0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */
};
static bool check_mkey_revision(unsigned int revision, bool is_retail) {
@ -80,7 +82,7 @@ int mkey_detect_revision(bool is_retail) {
if (g_determined_mkey_revision) {
generic_panic();
}
for (unsigned int rev = 0; rev < MASTERKEY_REVISION_MAX; rev++) {
if (check_mkey_revision(rev, is_retail)) {
g_determined_mkey_revision = true;
@ -88,7 +90,7 @@ int mkey_detect_revision(bool is_retail) {
break;
}
}
/* We must have determined the master key, or we're not running on a Switch. */
if (!g_determined_mkey_revision) {
return -1;

View file

@ -13,14 +13,14 @@
* 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_MASTERKEY_H
#define FUSEE_MASTERKEY_H
/* This is glue code to enable master key support across versions. */
/* TODO: Update to 0x8 on release of new master key. */
#define MASTERKEY_REVISION_MAX 0x8
/* TODO: Update to 0xA on release of new master key. */
#define MASTERKEY_REVISION_MAX 0x9
#define MASTERKEY_REVISION_100_230 0x00
#define MASTERKEY_REVISION_300 0x01
@ -29,7 +29,8 @@
#define MASTERKEY_REVISION_500_510 0x04
#define MASTERKEY_REVISION_600_610 0x05
#define MASTERKEY_REVISION_620 0x06
#define MASTERKEY_REVISION_700_CURRENT 0x07
#define MASTERKEY_REVISION_700_800 0x07
#define MASTERKEY_REVISION_810_CURRENT 0x08
#define MASTERKEY_NUM_NEW_DEVICE_KEYS (MASTERKEY_REVISION_MAX - MASTERKEY_REVISION_400_410)

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 <string.h>
#include <errno.h>
@ -53,7 +53,8 @@
#define u8 uint8_t
#define u32 uint32_t
#include "exosphere_bin.h"
#include "sept_secondary_enc.h"
#include "sept_secondary_00_enc.h"
#include "sept_secondary_01_enc.h"
#include "lp0fw_bin.h"
#include "emummc_kip.h"
#include "lib/log.h"
@ -207,8 +208,15 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
}
case 0x0F: /* 7.0.0 - 7.0.1 */
return ATMOSPHERE_TARGET_FIRMWARE_700;
case 0x10: /* 8.0.0 */
return ATMOSPHERE_TARGET_FIRMWARE_800;
case 0x10: { /* 8.0.0 - 8.1.0 */
if (memcmp(package1loader_header->build_timestamp, "20190314", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_800;
} else if (memcmp(package1loader_header->build_timestamp, "20190531", 8) == 0) {
return ATMOSPHERE_TARGET_FIRMWARE_810;
} else {
fatal_error("[NXBOOT] Unable to identify package1!\n");
}
}
default:
fatal_error("[NXBOOT] Unable to identify package1!\n");
}
@ -216,7 +224,7 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
emummc_config_t emummc_cfg = {.enabled = false, .id = 0, .sector = -1, .path = "", .nintendo_path = ""};
char *emummc_ini = calloc(1, 0x10000);
if (!read_from_file(emummc_ini, 0xFFFF, "emummc/emummc.ini")) {
free(emummc_ini);
@ -237,12 +245,12 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
exo_emummc_config->base_cfg.fs_version = FS_VER_1_0_0; /* Will be filled out later. */
strncpy(exo_emummc_config->emu_dir_path, emummc_cfg.nintendo_path, sizeof(exo_emummc_config->emu_dir_path));
exo_emummc_config->emu_dir_path[sizeof(exo_emummc_config->emu_dir_path) - 1] = '\0';
if (emummc_cfg.enabled) {
if (emummc_cfg.sector != -1) {
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");
@ -258,24 +266,24 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
char emummc_boot0_path[0x300 + 1] = {0};
char emummc_boot1_path[0x300 + 1] = {0};
char emummc_rawnand_path[0x300 + 1] = {0};
/* Prepare base folder path. */
snprintf(emummc_path, sizeof(emummc_path) - 1, "%s/%s", emummc_cfg.path, "eMMC");
/* Check if eMMC folder is present. */
if (!is_valid_folder(emummc_path)) {
fatal_error("[NXBOOT] Failed to find EmuMMC eMMC folder!\n");
}
/* Prepare expected file paths. */
snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "%s/%s", emummc_path, "boot0");
snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "%s/%s", emummc_path, "boot1");
/* Check if boot0 and boot1 image files are present. */
if (!is_valid_file(emummc_boot0_path) || !is_valid_file(emummc_boot1_path)) {
fatal_error("[NXBOOT] Failed to find EmuMMC boot0/boot1 image files!\n");
}
/* Find raw image files (single or multi part). */
for (int i = 0; i < 64; i++) {
snprintf(emummc_rawnand_path, sizeof(emummc_rawnand_path) - 1, "%s/%02d", emummc_path, i);
@ -295,7 +303,7 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
if ((num_parts == 0) || (part_limit == 0)) {
fatal_error("[NXBOOT] Failed to find EmuMMC raw image files!\n");
}
/* Mount emulated NAND from files. */
if (nxfs_mount_emummc_file(emummc_path, num_parts, part_limit) < 0) {
fatal_error("[NXBOOT] Failed to mount EmuMMC from files!\n");
@ -304,7 +312,7 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
fatal_error("[NXBOOT] Invalid EmuMMC setting!\n");
}
}
return emummc_cfg.enabled;
}
@ -337,7 +345,7 @@ static void nxboot_configure_stratosphere(uint32_t target_firmware) {
if (ini_parse_string(get_loader_ctx()->bct0, stratosphere_ini_handler, &strat_cfg) < 0) {
fatal_error("[NXBOOT] Failed to parse BCT.ini!\n");
}
/* Enable NOGC patches if the user requested it, or if the user is booting into 4.0.0+ with 3.0.2- fuses. */
if (strat_cfg.has_nogc_config) {
if (strat_cfg.enable_nogc) {
@ -353,7 +361,7 @@ static void nxboot_configure_stratosphere(uint32_t target_firmware) {
static void nxboot_set_bootreason(void *bootreason_base) {
boot_reason_t boot_reason = {0};
FILE *boot0;
FILE *boot0;
nvboot_config_table *bct;
nv_bootloader_info *bootloader_info;
@ -362,7 +370,7 @@ static void nxboot_set_bootreason(void *bootreason_base) {
if (bct == NULL) {
fatal_error("[NXBOOT] Out of memory!\n");
}
/* Open boot0. */
boot0 = fopen("boot0:/", "rb");
if (boot0 == NULL) {
@ -373,25 +381,25 @@ static void nxboot_set_bootreason(void *bootreason_base) {
if (fread(bct, sizeof(nvboot_config_table), 1, boot0) == 0) {
fatal_error("[NXBOOT] Failed to read the BCT!\n");
}
/* Close boot0. */
fclose(boot0);
/* Populate bootloader parameters. */
bootloader_info = &bct->bootloader[0];
boot_reason.bootloader_version = bootloader_info->version;
boot_reason.bootloader_start_block = bootloader_info->start_blk;
boot_reason.bootloader_start_page = bootloader_info->start_page;
boot_reason.bootloader_attribute = bootloader_info->attribute;
uint8_t power_key_intr = 0;
uint8_t rtc_intr = 0;
i2c_query(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_ONOFFIRQ, &power_key_intr, 1);
i2c_query(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_REG_RTCINT, &rtc_intr, 1);
/* Set PMIC value. */
boot_reason.boot_reason_value = ((rtc_intr << 0x08) | power_key_intr);
/* TODO: Find out what these mean. */
if (power_key_intr & 0x80)
boot_reason.boot_reason_state = 0x01;
@ -401,10 +409,10 @@ static void nxboot_set_bootreason(void *bootreason_base) {
boot_reason.boot_reason_state = 0x03;
else if (rtc_intr & 0x04)
boot_reason.boot_reason_state = 0x04;
/* Set in memory. */
memcpy(bootreason_base, &boot_reason, sizeof(boot_reason));
/* Clean up. */
free(bct);
}
@ -414,13 +422,13 @@ static void nxboot_move_bootconfig() {
void *bootconfig;
uint32_t bootconfig_addr;
uint32_t bootconfig_size;
/* Allocate memory for reading BootConfig. */
bootconfig = memalign(0x1000, 0x4000);
if (bootconfig == NULL) {
fatal_error("[NXBOOT] Out of memory!\n");
}
/* Get BootConfig from the Package2 partition. */
bcfile = fopen("bcpkg21:/", "rb");
if (bcfile == NULL) {
@ -431,15 +439,15 @@ static void nxboot_move_bootconfig() {
fatal_error("[NXBOOT] Failed to read BootConfig!\n");
}
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;
/* Copy the BootConfig into IRAM. */
memset((void *)bootconfig_addr, 0, bootconfig_size);
memcpy((void *)bootconfig_addr, bootconfig, bootconfig_size);
/* Clean up. */
free(bootconfig);
}
@ -459,6 +467,8 @@ uint32_t nxboot_main(void) {
size_t package2_size;
void *tsec_fw;
size_t tsec_fw_size;
const void *sept_secondary_enc = NULL;
size_t sept_secondary_enc_size = 0;
void *warmboot_fw;
size_t warmboot_fw_size;
void *warmboot_memaddr;
@ -470,7 +480,7 @@ uint32_t nxboot_main(void) {
FILE *boot0, *pk2file;
void *exosphere_memaddr;
exo_emummc_config_t exo_emummc_cfg;
/* Configure emummc or mount the real NAND. */
if (!nxboot_configure_emummc(&exo_emummc_cfg)) {
emummc = NULL;
@ -542,7 +552,7 @@ uint32_t nxboot_main(void) {
fatal_error("[NXBOOT] Failed to read Package2!\n");
}
fclose(pk2file);
/* Read and parse boot0. */
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Reading boot0...\n");
boot0 = fopen("boot0:/", "rb");
@ -550,7 +560,7 @@ uint32_t nxboot_main(void) {
fatal_error("[NXBOOT] Couldn't parse boot0: %s!\n", strerror(errno));
}
fclose(boot0);
/* Find the system's target firmware. */
uint32_t target_firmware = nxboot_get_target_firmware(package1loader);
if (!target_firmware)
@ -561,26 +571,42 @@ uint32_t nxboot_main(void) {
/* Read the TSEC firmware from a file, otherwise from PK1L. */
if (loader_ctx->tsecfw_path[0] != '\0') {
tsec_fw_size = get_file_size(loader_ctx->tsecfw_path);
if ((tsec_fw_size != 0) && (tsec_fw_size != 0xF00 && tsec_fw_size != 0x2900 && tsec_fw_size != 0x3000)) {
if ((tsec_fw_size != 0) && (tsec_fw_size != 0xF00 && tsec_fw_size != 0x2900 && tsec_fw_size != 0x3000 && tsec_fw_size != 0x3300)) {
fatal_error("[NXBOOT] TSEC firmware from %s has a wrong size!\n", loader_ctx->tsecfw_path);
} else if (tsec_fw_size == 0) {
fatal_error("[NXBOOT] Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path);
}
/* Allocate memory for the TSEC firmware. */
tsec_fw = memalign(0x100, tsec_fw_size);
if (tsec_fw == NULL) {
fatal_error("[NXBOOT] Out of memory!\n");
}
if (read_from_file(tsec_fw, tsec_fw_size, loader_ctx->tsecfw_path) != tsec_fw_size) {
fatal_error("[NXBOOT] Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path);
}
if (tsec_fw_size == 0x3000) {
sept_secondary_enc = sept_secondary_00_enc;
sept_secondary_enc_size = sept_secondary_00_enc_size;
} else if (tsec_fw_size == 0x3300) {
sept_secondary_enc = sept_secondary_01_enc;
sept_secondary_enc_size = sept_secondary_01_enc_size;
} else {
fatal_error("[NXBOOT] Unable to identify sept revision to run.");
}
} else {
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_700) {
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_810) {
sept_secondary_enc = sept_secondary_01_enc;
sept_secondary_enc_size = sept_secondary_01_enc_size;
tsec_fw_size = 0x3300;
} else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_700) {
sept_secondary_enc = sept_secondary_00_enc;
sept_secondary_enc_size = sept_secondary_00_enc_size;
tsec_fw_size = 0x3000;
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) {
tsec_fw_size = 0x2900;
@ -606,10 +632,10 @@ uint32_t nxboot_main(void) {
get_and_clear_has_run_sept();
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) {
uint8_t tsec_keys[0x20] = {0};
/* Emulate the TSEC payload on 6.2.0+. */
smmu_emulate_tsec((void *)tsec_keys, package1loader, package1loader_size, package1loader);
/* Copy back the keys. */
memcpy((void *)tsec_key, (void *)tsec_keys, 0x10);
memcpy((void *)tsec_root_keys, (void *)tsec_keys + 0x10, 0x10);
@ -619,11 +645,11 @@ uint32_t nxboot_main(void) {
fatal_error("[NXBOOT] Failed to get TSEC key!\n");
}
}
//fatal_error("Ran sept!");
/* Display splash screen. */
display_splash_screen_bmp(loader_ctx->custom_splash_path, (void *)0xC0000000);
/* 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) {
@ -665,27 +691,27 @@ uint32_t nxboot_main(void) {
if (warmboot_fw == NULL) {
fatal_error("[NXBOOT] Out of memory!\n");
}
memcpy(warmboot_fw, lp0fw_bin, warmboot_fw_size);
if (warmboot_fw_size == 0) {
fatal_error("[NXBOOT] Could not read the warmboot firmware from Package1!\n");
}
}
/* Patch warmboot firmware for atmosphere. */
if (warmboot_fw != NULL && warmboot_fw_size >= sizeof(warmboot_ams_header_t)) {
warmboot_ams_header_t *ams_header = (warmboot_ams_header_t *)warmboot_fw;
if (ams_header->ams_metadata.magic == WARMBOOT_MAGIC) {
/* Set target firmware */
ams_header->ams_metadata.target_firmware = target_firmware;
/* Set RSA modulus */
const uint8_t *pkc_modulus = fuse_get_retail_type() != 0 ? retail_pkc_modulus : dev_pkc_modulus;
memcpy(ams_header->rsa_modulus, pkc_modulus, sizeof(ams_header->rsa_modulus));
}
}
/* Select the right address for the warmboot firmware. */
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
@ -708,7 +734,7 @@ uint32_t nxboot_main(void) {
}
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Rebuilding package2...\n");
/* Parse stratosphere config. */
nxboot_configure_stratosphere(MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware);
@ -770,10 +796,10 @@ uint32_t nxboot_main(void) {
free(package2);
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Powering on the CCPLEX...\n");
/* Unmount everything. */
nxfs_end();
/* Return the memory address for booting CPU0. */
return (uint32_t)exosphere_memaddr;
}

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 <atmosphere.h>
@ -66,7 +66,7 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm
if (thermosphere_size != 0 && package2->metadata.section_sizes[PACKAGE2_SECTION_UNUSED] != 0) {
fatal_error(u8"Error: Package2 has no unused section for Thermosphère!\n");
}
/* Load Kernel from SD, if possible. */
{
size_t sd_kernel_size = get_file_size("atmosphere/kernel.bin");
@ -88,13 +88,13 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm
/* Perform any patches we want to the NX kernel. */
package2_patch_kernel(kernel, kernel_size, is_sd_kernel, (void *)&orig_ini1);
/* 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) ||
if ((target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 != NULL) ||
(target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_800 && 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) {
package2_get_src_section((void *)&orig_ini1, package2, PACKAGE2_SECTION_INI1);
@ -232,7 +232,7 @@ static bool package2_validate_metadata(package2_meta_t *metadata, uint8_t data[]
/* Perform version checks. */
/* We will be compatible with all package2s released before current, but not newer ones. */
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_700_CURRENT) {
if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_810_CURRENT) {
return true;
}

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_PACKAGE2_H
#define FUSEE_PACKAGE2_H
@ -36,7 +36,8 @@
#define PACKAGE2_MAXVER_500_510 0x7
#define PACKAGE2_MAXVER_600_610 0x8
#define PACKAGE2_MAXVER_620 0x9
#define PACKAGE2_MAXVER_700_CURRENT 0xA
#define PACKAGE2_MAXVER_700_800 0xA
#define PACKAGE2_MAXVER_810_CURRENT 0xB
#define PACKAGE2_MINVER_100 0x3
#define PACKAGE2_MINVER_200 0x4
@ -46,7 +47,8 @@
#define PACKAGE2_MINVER_500_510 0x8
#define PACKAGE2_MINVER_600_610 0x9
#define PACKAGE2_MINVER_620 0xA
#define PACKAGE2_MINVER_700_CURRENT 0xB
#define PACKAGE2_MINVER_700_800 0xB
#define PACKAGE2_MINVER_810_CURRENT 0xC
#define NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS ((void *)(0xA9800000ull))
@ -79,7 +81,7 @@ typedef struct {
/* Package2 can be encrypted or unencrypted for these functions: */
static inline size_t package2_meta_get_size(const package2_meta_t *metadata) {
return metadata->ctr_dwords[0] ^ metadata->ctr_dwords[2] ^ metadata->ctr_dwords[3];
return metadata->ctr_dwords[0] ^ metadata->ctr_dwords[2] ^ metadata->ctr_dwords[3];
}
static inline uint8_t package2_meta_get_header_version(const package2_meta_t *metadata) {

View file

@ -14,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <atmosphere/version.h>
.macro CLEAR_GPR_REG_ITER
mov r\@, #0
.endm
@ -27,7 +27,7 @@
.type _start, %function
_start:
b _crt0
.word (_metadata - _start)
_crt0:
@ -67,7 +67,7 @@ _crt0:
ldr r0, [r0]
ldr r1, [r1]
b main
/* Fusee-secondary header. */
.align 5
_metadata:
@ -168,12 +168,20 @@ _content_headers:
.asciz "sept_primary"
.align 5
/* sept_secondary content header */
.word __sept_secondary_enc_start__
.word __sept_secondary_enc_size__
/* sept_secondary 00 content header */
.word __sept_secondary_00_enc_start__
.word __sept_secondary_00_enc_size__
.word CONTENT_TYPE_SP2
.word 0xCCCCCCCC
.asciz "sept_secondary"
.asciz "sept_secondary_00"
.align 5
/* sept_secondary 01 content header */
.word __sept_secondary_01_enc_start__
.word __sept_secondary_01_enc_size__
.word CONTENT_TYPE_SP2
.word 0xCCCCCCCC
.asciz "sept_secondary_01"
.align 5
/* sm content header */

View file

@ -1,7 +1,20 @@
HOVI_ENC_KEY_PRD = bytearray.fromhex('00000000000000000000000000000000')
HOVI_ENC_KEY_DEV = bytearray.fromhex('00000000000000000000000000000000')
HOVI_SIG_KEY_PRD = bytearray.fromhex('00000000000000000000000000000000')
HOVI_SIG_KEY_DEV = bytearray.fromhex('00000000000000000000000000000000')
HOVI_KEK_KEY_PRD = bytearray.fromhex('00000000000000000000000000000000')
HOVI_KEK_KEY_DEV = bytearray.fromhex('00000000000000000000000000000000')
IV = bytearray.fromhex('00000000000000000000000000000000')
NUM_KEYS = 2
HOVI_ENC_KEY_PRD = [
bytearray.fromhex('00000000000000000000000000000000'),
bytearray.fromhex('00000000000000000000000000000000'),
]
HOVI_SIG_KEY_PRD = [
bytearray.fromhex('00000000000000000000000000000000'),
bytearray.fromhex('00000000000000000000000000000000'),
]
IV = [
bytearray.fromhex('00000000000000000000000000000000'),
bytearray.fromhex('00000000000000000000000000000000'),
]
assert len(HOVI_ENC_KEY_PRD) == NUM_KEYS
assert len(HOVI_SIG_KEY_PRD) == NUM_KEYS
assert len(IV) == NUM_KEYS

View file

@ -77,14 +77,15 @@ export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
$(AMS)/exosphere/rebootstub
$(AMS)/exosphere/rebootstub \
$(TOPDIR)/key_derivation
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) rebootstub.bin
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) rebootstub.bin key_derivation.bin
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
@ -111,33 +112,38 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean all check_rebootstub
.PHONY: $(BUILD) clean all check_rebootstub check_key_derivation
#---------------------------------------------------------------------------------
all: check_rebootstub $(BUILD)
all: check_rebootstub check_key_derivation $(BUILD)
check_rebootstub:
@$(MAKE) -C $(AMS)/exosphere/rebootstub all
$(BUILD):
ifeq ($(strip $(SEPT_ENC_PATH)),)
check_key_derivation:
@$(MAKE) -C key_derivation
$(BUILD): check_rebootstub check_key_derivation
ifeq ($(strip $(SEPT_00_ENC_PATH)),)
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
else
@touch $(TOPDIR)/$(TARGET).bin
@cp $(SEPT_ENC_PATH) $(TOPDIR)/$(TARGET).enc
@cp $(SEPT_00_ENC_PATH) $(TOPDIR)/$(TARGET)_00.enc
@cp $(SEPT_01_ENC_PATH) $(TOPDIR)/$(TARGET)_01.enc
endif
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@$(MAKE) -C $(AMS)/exosphere/rebootstub clean
@rm -fr $(BUILD) $(TARGET).bin $(TARGET).enc $(TARGET).elf
@$(MAKE) -C key_derivation clean
@rm -fr $(BUILD) $(TARGET).bin $(TARGET)_*.enc $(TARGET).elf
#---------------------------------------------------------------------------------
else
.PHONY: all
.PHONY: all $(OUTPUT).bin
DEPENDS := $(OFILES:.o=.d)

View file

@ -0,0 +1,154 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif
TOPDIR ?= $(CURDIR)
include $(DEVKITPRO)/devkitA64/base_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := src
DATA := data
INCLUDES := include
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv8-a -mtune=cortex-a57 -mgeneral-regs-only #<- important
CFLAGS := \
-g \
-Os \
-ffunction-sections \
-fdata-sections \
-fomit-frame-pointer \
-fno-inline \
-std=gnu11 \
-Werror \
-Wall \
$(ARCH) $(DEFINES)
CFLAGS += $(INCLUDE)
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=$(TOPDIR)/linker.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS :=
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS :=
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).bin $(TARGET).elf
#---------------------------------------------------------------------------------
else
.PHONY: all
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
all : $(OUTPUT).bin
$(OUTPUT).bin : $(OUTPUT).elf
$(OBJCOPY) -S -O binary $< $@
@echo built ... $(notdir $@)
$(OUTPUT).elf : $(OFILES)
%.elf: $(OFILES)
@echo linking $(notdir $@)
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
@$(NM) -CSn $@ > $(notdir $*.lst)
$(OFILES_SRC) : $(HFILES_BIN)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View file

@ -0,0 +1,17 @@
OUTPUT_ARCH(aarch64)
ENTRY(_start)
SECTIONS
{
. = 0x4003D000;
__start__ = ABSOLUTE(.);
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
.bss : ALIGN(8) { __bss_start__ = .; *(.bss* COMMON); . = ALIGN(8); __bss_end__ = .; }
. = ALIGN(4);
__end__ = ABSOLUTE(.);
}

View file

@ -0,0 +1,7 @@
%rename link old_link
*link:
%(old_link) -T %:getenv(TOPDIR /linker.ld) --nmagic --gc-sections
*startfile:
crti%O%s crtbegin%O%s

View file

@ -0,0 +1,142 @@
/*
* 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/>.
*/
#include <string.h>
#include "pmc.h"
#include "se.h"
#include "utils.h"
#define AL16 __attribute__((aligned(16)))
#define DERIVATION_ID_MAX 2
static const uint8_t AL16 keyblob_seed_00[0x10] = {
0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3
};
static const uint8_t AL16 masterkey_seed[0x10] = {
0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C
};
static const uint8_t AL16 devicekey_seed[0x10] = {
0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78
};
static const uint8_t AL16 devicekey_4x_seed[0x10] = {
0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28
};
static const uint8_t AL16 masterkey_4x_seed[0x10] = {
0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66
};
static const uint8_t AL16 zeroes[0x10] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const uint8_t AL16 master_kek_seeds[DERIVATION_ID_MAX][0x10] = {
{0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C},
{0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41},
};
static const uint8_t AL16 master_devkey_seeds[DERIVATION_ID_MAX][0x10] = {
{0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D},
{0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE},
};
static const uint8_t AL16 master_devkey_vectors[DERIVATION_ID_MAX][0x10] = {
{0xD8, 0xD3, 0x67, 0x4F, 0xF3, 0xA2, 0xA4, 0x4E, 0xE4, 0x04, 0x37, 0xC2, 0xD9, 0xCF, 0x41, 0x6F},
{0x72, 0xD0, 0xAD, 0xEB, 0xE1, 0xF6, 0x35, 0x90, 0xB4, 0x43, 0xCC, 0x4B, 0xC4, 0xDC, 0x88, 0x0A},
};
void derive_keys(void) {
/* Set mailbox. */
volatile uint32_t *mailbox = (volatile uint32_t *)0x4003FF00;
const uint32_t derivation_id = *((volatile uint32_t *)0x4003E800);
if (derivation_id < DERIVATION_ID_MAX) {
uint8_t *enc_se_state = (uint8_t *)0x4003E000;
uint32_t AL16 work_buffer[4];
/* Derive Keyblob Key 00. */
se_aes_ecb_decrypt_block(0xC, work_buffer, 0x10, keyblob_seed_00, 0x10);
decrypt_data_into_keyslot(0xF, 0xE, work_buffer, 0x10);
/* Derive master kek. */
decrypt_data_into_keyslot(0xE, 0xD, master_kek_seeds[derivation_id], 0x10);
/* Clear the copy of the root key inside the SE. */
clear_aes_keyslot(0xD);
/* Derive master key, device master key. */
decrypt_data_into_keyslot(0xC, 0xE, masterkey_seed, 0x10);
decrypt_data_into_keyslot(0xE, 0xE, masterkey_4x_seed, 0x10);
clear_aes_keyslot(0xD);
/* Derive device keys. */
decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10);
decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
clear_aes_keyslot(0xD);
/* Derive firmware specific device key. */
se_aes_ecb_decrypt_block(0xA, work_buffer, 0x10, master_devkey_seeds[derivation_id], 0x10);
decrypt_data_into_keyslot(0xE, 0xE, work_buffer, 0x10);
clear_aes_keyslot(0xD);
/* Test against a vector. */
for (size_t i = 0; i < 4; i++) {
work_buffer[i] = 0;
}
if (memcmp(work_buffer, zeroes, 0x10) != 0) {
clear_aes_keyslot(0xE);
clear_aes_keyslot(0xD);
clear_aes_keyslot(0xC);
clear_aes_keyslot(0xA);
clear_aes_keyslot(0xF);
generic_panic();
}
se_aes_ecb_decrypt_block(0xE, work_buffer, 0x10, master_devkey_vectors[derivation_id], 0x10);
if (memcmp(work_buffer, zeroes, 0x10) == 0) {
clear_aes_keyslot(0xE);
clear_aes_keyslot(0xD);
clear_aes_keyslot(0xC);
clear_aes_keyslot(0xA);
clear_aes_keyslot(0xF);
generic_panic();
}
/* Clear work buffer. */
for (size_t i = 0; i < 4; i++) {
work_buffer[i] = 0xCCCCCCCC;
}
/* Save context for real. */
se_set_in_context_save_mode(true);
se_save_context(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY, enc_se_state);
se_set_in_context_save_mode(false);
}
/* Clear all keyslots. */
for (size_t i = 0; i < 0x10; i++) {
clear_aes_keyslot(i);
}
*mailbox = 7;
while (1) { /* Wait for sept to handle the rest. */ }
}

View file

@ -0,0 +1,26 @@
/*
* 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 SEPT_KEYDERIVATION_H
#define SEPT_KEYDERIVATION_H
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
void derive_keys(void);
#endif

View file

@ -0,0 +1,626 @@
/*
* 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 FUSEE_PMC_H
#define FUSEE_PMC_H
#include <stdint.h>
#define PMC_BASE 0x7000E400
#define MAKE_PMC_REG(n) MAKE_REG32(PMC_BASE + n)
#define PMC_CONTROL_SDMMC1 (1 << 12)
#define PMC_CONTROL_SDMMC3 (1 << 13)
#define PMC_CONTROL_SDMMC4 (1 << 14)
#define APBDEV_PMC_CONTROL MAKE_PMC_REG(0x00)
#define APBDEV_PM_0 MAKE_PMC_REG(0x14)
#define APBDEV_PMC_DPD_ENABLE_0 MAKE_PMC_REG(0x24)
#define APBDEV_PMC_PWRGATE_TOGGLE_0 MAKE_PMC_REG(0x30)
#define APBDEV_PMC_PWRGATE_STATUS_0 MAKE_PMC_REG(0x38)
#define APBDEV_PMC_NO_IOPOWER_0 MAKE_PMC_REG(0x44)
#define APBDEV_PMC_SCRATCH0_0 MAKE_PMC_REG(0x50)
#define APBDEV_PMC_SCRATCH1_0 MAKE_PMC_REG(0x54)
#define APBDEV_PMC_SCRATCH20_0 MAKE_PMC_REG(0xA0)
#define APBDEV_PMC_PWR_DET_VAL_0 MAKE_PMC_REG(0xE4)
#define APBDEV_PMC_DDR_PWR_0 MAKE_PMC_REG(0xE8)
#define APBDEV_PMC_CRYPTO_OP_0 MAKE_PMC_REG(0xF4)
#define APBDEV_PMC_WAKE2_STATUS_0 MAKE_PMC_REG(0x168)
#define APBDEV_PMC_OSC_EDPD_OVER_0 MAKE_PMC_REG(0x1A4)
#define APBDEV_PMC_RST_STATUS_0 MAKE_PMC_REG(0x1B4)
#define APBDEV_PMC_IO_DPD_REQ_0 MAKE_PMC_REG(0x1B8)
#define APBDEV_PMC_IO_DPD2_REQ_0 MAKE_PMC_REG(0x1C0)
#define APBDEV_PMC_VDDP_SEL_0 MAKE_PMC_REG(0x1CC)
#define APBDEV_PMC_SCRATCH49_0 MAKE_PMC_REG(0x244)
#define APBDEV_PMC_TSC_MULT_0 MAKE_PMC_REG(0x2B4)
#define APBDEV_PMC_REG_SHORT_0 MAKE_PMC_REG(0x2CC)
#define APBDEV_PMC_WEAK_BIAS_0 MAKE_PMC_REG(0x2C8)
#define APBDEV_PMC_SECURE_SCRATCH21_0 MAKE_PMC_REG(0x334)
#define APBDEV_PMC_SECURE_SCRATCH32_0 MAKE_PMC_REG(0x360)
#define APBDEV_PMC_SECURE_SCRATCH49_0 MAKE_PMC_REG(0x3A4)
#define APBDEV_PMC_CNTRL2_0 MAKE_PMC_REG(0x440)
#define APBDEV_PMC_IO_DPD4_REQ_0 MAKE_PMC_REG(0x464)
#define APBDEV_PMC_UTMIP_PAD_CFG1_0 MAKE_PMC_REG(0x4C4)
#define APBDEV_PMC_UTMIP_PAD_CFG3_0 MAKE_PMC_REG(0x4CC)
#define APBDEV_PMC_DDR_CNTRL_0 MAKE_PMC_REG(0x4E4)
#define APBDEV_PMC_SCRATCH43_0 MAKE_PMC_REG(0x22C)
#define APBDEV_PMC_SCRATCH188_0 MAKE_PMC_REG(0x810)
#define APBDEV_PMC_SCRATCH190_0 MAKE_PMC_REG(0x818)
#define APBDEV_PMC_SCRATCH200_0 MAKE_PMC_REG(0x840)
#define APBDEV_PMC_SCRATCH45_0 MAKE_PMC_REG(0x234)
#define APBDEV_PMC_SCRATCH46_0 MAKE_PMC_REG(0x238)
#define APBDEV_PMC_SCRATCH33_0 MAKE_PMC_REG(0x120)
#define APBDEV_PMC_SCRATCH40_0 MAKE_PMC_REG(0x13C)
typedef struct {
uint32_t cntrl;
uint32_t sec_disable;
uint32_t pmc_swrst;
uint32_t wake_mask;
uint32_t wake_lvl;
uint32_t wake_status;
uint32_t sw_wake_status;
uint32_t dpd_pads_oride;
uint32_t dpd_sample;
uint32_t dpd_enable;
uint32_t pwrgate_timer_off;
uint32_t clamp_status;
uint32_t pwrgate_toggle;
uint32_t remove_clamping;
uint32_t pwrgate_status;
uint32_t pwrgood_timer;
uint32_t blink_timer;
uint32_t no_iopower;
uint32_t pwr_det;
uint32_t pwr_det_latch;
uint32_t scratch0;
uint32_t scratch1;
uint32_t scratch2;
uint32_t scratch3;
uint32_t scratch4;
uint32_t scratch5;
uint32_t scratch6;
uint32_t scratch7;
uint32_t scratch8;
uint32_t scratch9;
uint32_t scratch10;
uint32_t scratch11;
uint32_t scratch12;
uint32_t scratch13;
uint32_t scratch14;
uint32_t scratch15;
uint32_t scratch16;
uint32_t scratch17;
uint32_t scratch18;
uint32_t scratch19;
uint32_t scratch20;
uint32_t scratch21;
uint32_t scratch22;
uint32_t scratch23;
uint32_t secure_scratch0;
uint32_t secure_scratch1;
uint32_t secure_scratch2;
uint32_t secure_scratch3;
uint32_t secure_scratch4;
uint32_t secure_scratch5;
uint32_t cpupwrgood_timer;
uint32_t cpupwroff_timer;
uint32_t pg_mask;
uint32_t pg_mask_1;
uint32_t auto_wake_lvl;
uint32_t auto_wake_lvl_mask;
uint32_t wake_delay;
uint32_t pwr_det_val;
uint32_t ddr_pwr;
uint32_t usb_debounce_del;
uint32_t usb_ao;
uint32_t crypto_op;
uint32_t pllp_wb0_override;
uint32_t scratch24;
uint32_t scratch25;
uint32_t scratch26;
uint32_t scratch27;
uint32_t scratch28;
uint32_t scratch29;
uint32_t scratch30;
uint32_t scratch31;
uint32_t scratch32;
uint32_t scratch33;
uint32_t scratch34;
uint32_t scratch35;
uint32_t scratch36;
uint32_t scratch37;
uint32_t scratch38;
uint32_t scratch39;
uint32_t scratch40;
uint32_t scratch41;
uint32_t scratch42;
uint32_t bo_mirror0;
uint32_t bo_mirror1;
uint32_t bo_mirror2;
uint32_t sys_33v_en;
uint32_t bo_mirror_access;
uint32_t gate;
uint32_t wake2_mask;
uint32_t wake2_lvl;
uint32_t wake2_stat;
uint32_t sw_wake2_stat;
uint32_t auto_wake2_lvl_mask;
uint32_t pg_mask2;
uint32_t pg_mask_ce1;
uint32_t pg_mask_ce2;
uint32_t pg_mask_ce3;
uint32_t pwrgate_timer_ce0;
uint32_t pwrgate_timer_ce1;
uint32_t pwrgate_timer_ce2;
uint32_t pwrgate_timer_ce3;
uint32_t pwrgate_timer_ce4;
uint32_t pwrgate_timer_ce5;
uint32_t pwrgate_timer_ce6;
uint32_t pcx_edpd_cntrl;
uint32_t osc_edpd_over;
uint32_t clk_out_cntrl;
uint32_t sata_pwrgate;
uint32_t sensor_ctrl;
uint32_t reset_status;
uint32_t io_dpd_req;
uint32_t io_dpd_stat;
uint32_t io_dpd2_req;
uint32_t io_dpd2_stat;
uint32_t sel_dpd_tim;
uint32_t vddp_sel;
uint32_t ddr_cfg;
uint32_t e_no_vttgen;
uint32_t _reserved0;
uint32_t pllm_wb0_ovrride_frq;
uint32_t test_pwrgate;
uint32_t pwrgate_timer_mult;
uint32_t dsi_sel_dpd;
uint32_t utmip_uhsic_triggers;
uint32_t utmip_uhsic_saved_st;
uint32_t utmip_pad_cfg;
uint32_t utmip_term_pad_cfg;
uint32_t utmip_uhsic_sleep_cfg;
uint32_t utmip_uhsic_sleepwalk_cfg;
uint32_t utmip_sleepwalk_p[3];
uint32_t uhsic_sleepwalk_p0;
uint32_t utmip_uhsic_status;
uint32_t utmip_uhsic_fake;
uint32_t bo_mirror3[2];
uint32_t secure_scratch6;
uint32_t secure_scratch7;
uint32_t scratch43;
uint32_t scratch44;
uint32_t scratch45;
uint32_t scratch46;
uint32_t scratch47;
uint32_t scratch48;
uint32_t scratch49;
uint32_t scratch50;
uint32_t scratch51;
uint32_t scratch52;
uint32_t scratch53;
uint32_t scratch54;
uint32_t scratch55;
uint32_t scratch0_eco;
uint32_t por_dpd_ctrl;
uint32_t scratch2_eco;
uint32_t utmip_uhsic_line_wakeup;
uint32_t utmip_bias_master_cntrl;
uint32_t utmip_master_config;
uint32_t td_pwrgate_inter_part_timer;
uint32_t utmip_uhsic2_triggers;
uint32_t utmip_uhsic2_saved_state;
uint32_t utmip_uhsic2_sleep_cfg;
uint32_t utmip_uhsic2_sleepwalk_cfg;
uint32_t uhsic2_sleepwalk_p1;
uint32_t utmip_uhsic2_status;
uint32_t utmip_uhsic2_fake;
uint32_t utmip_uhsic2_line_wakeup;
uint32_t utmip_master2_config;
uint32_t utmip_uhsic_rpd_cfg;
uint32_t pg_mask_ce0;
uint32_t pg_mask3[2];
uint32_t pllm_wb0_override2;
uint32_t tsc_mult;
uint32_t cpu_vsense_override;
uint32_t glb_amap_cfg;
uint32_t sticky_bits;
uint32_t sec_disable2;
uint32_t weak_bias;
uint32_t reg_short;
uint32_t pg_mask_andor;
uint32_t _reserved1[11];
uint32_t secure_scratch8;
uint32_t secure_scratch9;
uint32_t secure_scratch10;
uint32_t secure_scratch11;
uint32_t secure_scratch12;
uint32_t secure_scratch13;
uint32_t secure_scratch14;
uint32_t secure_scratch15;
uint32_t secure_scratch16;
uint32_t secure_scratch17;
uint32_t secure_scratch18;
uint32_t secure_scratch19;
uint32_t secure_scratch20;
uint32_t secure_scratch21;
uint32_t secure_scratch22;
uint32_t secure_scratch23;
uint32_t secure_scratch24;
uint32_t secure_scratch25;
uint32_t secure_scratch26;
uint32_t secure_scratch27;
uint32_t secure_scratch28;
uint32_t secure_scratch29;
uint32_t secure_scratch30;
uint32_t secure_scratch31;
uint32_t secure_scratch32;
uint32_t secure_scratch33;
uint32_t secure_scratch34;
uint32_t secure_scratch35;
uint32_t secure_scratch36;
uint32_t secure_scratch37;
uint32_t secure_scratch38;
uint32_t secure_scratch39;
uint32_t secure_scratch40;
uint32_t secure_scratch41;
uint32_t secure_scratch42;
uint32_t secure_scratch43;
uint32_t secure_scratch44;
uint32_t secure_scratch45;
uint32_t secure_scratch46;
uint32_t secure_scratch47;
uint32_t secure_scratch48;
uint32_t secure_scratch49;
uint32_t secure_scratch50;
uint32_t secure_scratch51;
uint32_t secure_scratch52;
uint32_t secure_scratch53;
uint32_t secure_scratch54;
uint32_t secure_scratch55;
uint32_t secure_scratch56;
uint32_t secure_scratch57;
uint32_t secure_scratch58;
uint32_t secure_scratch59;
uint32_t secure_scratch60;
uint32_t secure_scratch61;
uint32_t secure_scratch62;
uint32_t secure_scratch63;
uint32_t secure_scratch64;
uint32_t secure_scratch65;
uint32_t secure_scratch66;
uint32_t secure_scratch67;
uint32_t secure_scratch68;
uint32_t secure_scratch69;
uint32_t secure_scratch70;
uint32_t secure_scratch71;
uint32_t secure_scratch72;
uint32_t secure_scratch73;
uint32_t secure_scratch74;
uint32_t secure_scratch75;
uint32_t secure_scratch76;
uint32_t secure_scratch77;
uint32_t secure_scratch78;
uint32_t secure_scratch79;
uint32_t _reserved2[8];
uint32_t cntrl2;
uint32_t _reserved3[2];
uint32_t event_counter;
uint32_t fuse_control;
uint32_t scratch1_eco;
uint32_t _reserved4;
uint32_t io_dpd3_req;
uint32_t io_dpd3_status;
uint32_t io_dpd4_req;
uint32_t io_dpd4_status;
uint32_t _reserved5[30];
uint32_t ddr_cntrl;
uint32_t _reserved6[70];
uint32_t scratch56;
uint32_t scratch57;
uint32_t scratch58;
uint32_t scratch59;
uint32_t scratch60;
uint32_t scratch61;
uint32_t scratch62;
uint32_t scratch63;
uint32_t scratch64;
uint32_t scratch65;
uint32_t scratch66;
uint32_t scratch67;
uint32_t scratch68;
uint32_t scratch69;
uint32_t scratch70;
uint32_t scratch71;
uint32_t scratch72;
uint32_t scratch73;
uint32_t scratch74;
uint32_t scratch75;
uint32_t scratch76;
uint32_t scratch77;
uint32_t scratch78;
uint32_t scratch79;
uint32_t scratch80;
uint32_t scratch81;
uint32_t scratch82;
uint32_t scratch83;
uint32_t scratch84;
uint32_t scratch85;
uint32_t scratch86;
uint32_t scratch87;
uint32_t scratch88;
uint32_t scratch89;
uint32_t scratch90;
uint32_t scratch91;
uint32_t scratch92;
uint32_t scratch93;
uint32_t scratch94;
uint32_t scratch95;
uint32_t scratch96;
uint32_t scratch97;
uint32_t scratch98;
uint32_t scratch99;
uint32_t scratch100;
uint32_t scratch101;
uint32_t scratch102;
uint32_t scratch103;
uint32_t scratch104;
uint32_t scratch105;
uint32_t scratch106;
uint32_t scratch107;
uint32_t scratch108;
uint32_t scratch109;
uint32_t scratch110;
uint32_t scratch111;
uint32_t scratch112;
uint32_t scratch113;
uint32_t scratch114;
uint32_t scratch115;
uint32_t scratch116;
uint32_t scratch117;
uint32_t scratch118;
uint32_t scratch119;
uint32_t scratch120;
uint32_t scratch121;
uint32_t scratch122;
uint32_t scratch123;
uint32_t scratch124;
uint32_t scratch125;
uint32_t scratch126;
uint32_t scratch127;
uint32_t scratch128;
uint32_t scratch129;
uint32_t scratch130;
uint32_t scratch131;
uint32_t scratch132;
uint32_t scratch133;
uint32_t scratch134;
uint32_t scratch135;
uint32_t scratch136;
uint32_t scratch137;
uint32_t scratch138;
uint32_t scratch139;
uint32_t scratch140;
uint32_t scratch141;
uint32_t scratch142;
uint32_t scratch143;
uint32_t scratch144;
uint32_t scratch145;
uint32_t scratch146;
uint32_t scratch147;
uint32_t scratch148;
uint32_t scratch149;
uint32_t scratch150;
uint32_t scratch151;
uint32_t scratch152;
uint32_t scratch153;
uint32_t scratch154;
uint32_t scratch155;
uint32_t scratch156;
uint32_t scratch157;
uint32_t scratch158;
uint32_t scratch159;
uint32_t scratch160;
uint32_t scratch161;
uint32_t scratch162;
uint32_t scratch163;
uint32_t scratch164;
uint32_t scratch165;
uint32_t scratch166;
uint32_t scratch167;
uint32_t scratch168;
uint32_t scratch169;
uint32_t scratch170;
uint32_t scratch171;
uint32_t scratch172;
uint32_t scratch173;
uint32_t scratch174;
uint32_t scratch175;
uint32_t scratch176;
uint32_t scratch177;
uint32_t scratch178;
uint32_t scratch179;
uint32_t scratch180;
uint32_t scratch181;
uint32_t scratch182;
uint32_t scratch183;
uint32_t scratch184;
uint32_t scratch185;
uint32_t scratch186;
uint32_t scratch187;
uint32_t scratch188;
uint32_t scratch189;
uint32_t scratch190;
uint32_t scratch191;
uint32_t scratch192;
uint32_t scratch193;
uint32_t scratch194;
uint32_t scratch195;
uint32_t scratch196;
uint32_t scratch197;
uint32_t scratch198;
uint32_t scratch199;
uint32_t scratch200;
uint32_t scratch201;
uint32_t scratch202;
uint32_t scratch203;
uint32_t scratch204;
uint32_t scratch205;
uint32_t scratch206;
uint32_t scratch207;
uint32_t scratch208;
uint32_t scratch209;
uint32_t scratch210;
uint32_t scratch211;
uint32_t scratch212;
uint32_t scratch213;
uint32_t scratch214;
uint32_t scratch215;
uint32_t scratch216;
uint32_t scratch217;
uint32_t scratch218;
uint32_t scratch219;
uint32_t scratch220;
uint32_t scratch221;
uint32_t scratch222;
uint32_t scratch223;
uint32_t scratch224;
uint32_t scratch225;
uint32_t scratch226;
uint32_t scratch227;
uint32_t scratch228;
uint32_t scratch229;
uint32_t scratch230;
uint32_t scratch231;
uint32_t scratch232;
uint32_t scratch233;
uint32_t scratch234;
uint32_t scratch235;
uint32_t scratch236;
uint32_t scratch237;
uint32_t scratch238;
uint32_t scratch239;
uint32_t scratch240;
uint32_t scratch241;
uint32_t scratch242;
uint32_t scratch243;
uint32_t scratch244;
uint32_t scratch245;
uint32_t scratch246;
uint32_t scratch247;
uint32_t scratch248;
uint32_t scratch249;
uint32_t scratch250;
uint32_t scratch251;
uint32_t scratch252;
uint32_t scratch253;
uint32_t scratch254;
uint32_t scratch255;
uint32_t scratch256;
uint32_t scratch257;
uint32_t scratch258;
uint32_t scratch259;
uint32_t scratch260;
uint32_t scratch261;
uint32_t scratch262;
uint32_t scratch263;
uint32_t scratch264;
uint32_t scratch265;
uint32_t scratch266;
uint32_t scratch267;
uint32_t scratch268;
uint32_t scratch269;
uint32_t scratch270;
uint32_t scratch271;
uint32_t scratch272;
uint32_t scratch273;
uint32_t scratch274;
uint32_t scratch275;
uint32_t scratch276;
uint32_t scratch277;
uint32_t scratch278;
uint32_t scratch279;
uint32_t scratch280;
uint32_t scratch281;
uint32_t scratch282;
uint32_t scratch283;
uint32_t scratch284;
uint32_t scratch285;
uint32_t scratch286;
uint32_t scratch287;
uint32_t scratch288;
uint32_t scratch289;
uint32_t scratch290;
uint32_t scratch291;
uint32_t scratch292;
uint32_t scratch293;
uint32_t scratch294;
uint32_t scratch295;
uint32_t scratch296;
uint32_t scratch297;
uint32_t scratch298;
uint32_t scratch299;
uint32_t _reserved7[50];
uint32_t secure_scratch80;
uint32_t secure_scratch81;
uint32_t secure_scratch82;
uint32_t secure_scratch83;
uint32_t secure_scratch84;
uint32_t secure_scratch85;
uint32_t secure_scratch86;
uint32_t secure_scratch87;
uint32_t secure_scratch88;
uint32_t secure_scratch89;
uint32_t secure_scratch90;
uint32_t secure_scratch91;
uint32_t secure_scratch92;
uint32_t secure_scratch93;
uint32_t secure_scratch94;
uint32_t secure_scratch95;
uint32_t secure_scratch96;
uint32_t secure_scratch97;
uint32_t secure_scratch98;
uint32_t secure_scratch99;
uint32_t secure_scratch100;
uint32_t secure_scratch101;
uint32_t secure_scratch102;
uint32_t secure_scratch103;
uint32_t secure_scratch104;
uint32_t secure_scratch105;
uint32_t secure_scratch106;
uint32_t secure_scratch107;
uint32_t secure_scratch108;
uint32_t secure_scratch109;
uint32_t secure_scratch110;
uint32_t secure_scratch111;
uint32_t secure_scratch112;
uint32_t secure_scratch113;
uint32_t secure_scratch114;
uint32_t secure_scratch115;
uint32_t secure_scratch116;
uint32_t secure_scratch117;
uint32_t secure_scratch118;
uint32_t secure_scratch119;
} tegra_pmc_t;
static inline volatile tegra_pmc_t *pmc_get_regs(void)
{
return (volatile tegra_pmc_t *)PMC_BASE;
}
#endif

View file

@ -0,0 +1,757 @@
/*
* 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/>.
*/
#include <string.h>
#include "utils.h"
#include "se.h"
void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const void *src, size_t src_size);
/* Globals for driver. */
static unsigned int g_se_modulus_sizes[KEYSLOT_RSA_MAX];
static unsigned int g_se_exp_sizes[KEYSLOT_RSA_MAX];
/* Initialize a SE linked list. */
void NOINLINE ll_init(volatile se_ll_t *ll, void *buffer, size_t size) {
ll->num_entries = 0; /* 1 Entry. */
if (buffer != NULL) {
ll->addr_info.address = (uint32_t) get_physical_address(buffer);
ll->addr_info.size = (uint32_t) size;
} else {
ll->addr_info.address = 0;
ll->addr_info.size = 0;
}
}
void se_check_error_status_reg(void) {
if (se_get_regs()->ERR_STATUS_REG) {
generic_panic();
}
}
void se_check_for_error(void) {
volatile tegra_se_t *se = se_get_regs();
if (se->INT_STATUS_REG & 0x10000 || se->FLAGS_REG & 3 || se->ERR_STATUS_REG) {
generic_panic();
}
}
void se_verify_flags_cleared(void) {
if (se_get_regs()->FLAGS_REG & 3) {
generic_panic();
}
}
/* 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();
}
/* Misc flags. */
if (flags & ~0x80) {
se->AES_KEYSLOT_FLAGS[keyslot] = ~flags;
}
/* Disable keyslot reads. */
if (flags & 0x80) {
se->AES_KEY_READ_DISABLE_REG &= ~(1 << keyslot);
}
}
/* 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();
}
/* Misc flags. */
if (flags & ~0x80) {
/* TODO: Why are flags assigned this way? */
se->RSA_KEYSLOT_FLAGS[keyslot] = (((flags >> 4) & 4) | (flags & 3)) ^ 7;
}
/* Disable keyslot reads. */
if (flags & 0x80) {
se->RSA_KEY_READ_DISABLE_REG &= ~(1 << keyslot);
}
}
void clear_aes_keyslot(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
/* Zero out the whole keyslot and IV. */
for (unsigned int i = 0; i < 0x10; i++) {
se->AES_KEYTABLE_ADDR = (keyslot << 4) | i;
se->AES_KEYTABLE_DATA = 0;
}
}
void clear_rsa_keyslot(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_RSA_MAX) {
generic_panic();
}
/* Zero out the whole keyslot. */
for (unsigned int i = 0; i < 0x40; i++) {
/* Select Keyslot Modulus[i] */
se->RSA_KEYTABLE_ADDR = (keyslot << 7) | i | 0x40;
se->RSA_KEYTABLE_DATA = 0;
}
for (unsigned int i = 0; i < 0x40; i++) {
/* Select Keyslot Expontent[i] */
se->RSA_KEYTABLE_ADDR = (keyslot << 7) | i;
se->RSA_KEYTABLE_DATA = 0;
}
}
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();
}
for (size_t i = 0; i < (key_size >> 2); i++) {
se->AES_KEYTABLE_ADDR = (keyslot << 4) | i;
se->AES_KEYTABLE_DATA = read32le(key, 4 * i);
}
}
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();
}
for (size_t i = 0; i < (modulus_size >> 2); i++) {
se->RSA_KEYTABLE_ADDR = (keyslot << 7) | 0x40 | i;
se->RSA_KEYTABLE_DATA = read32be(modulus, (4 * (modulus_size >> 2)) - (4 * i) - 4);
}
for (size_t i = 0; i < (exp_size >> 2); i++) {
se->RSA_KEYTABLE_ADDR = (keyslot << 7) | i;
se->RSA_KEYTABLE_DATA = read32be(exponent, (4 * (exp_size >> 2)) - (4 * i) - 4);
}
g_se_modulus_sizes[keyslot] = modulus_size;
g_se_exp_sizes[keyslot] = exp_size;
}
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();
}
for (size_t i = 0; i < (iv_size >> 2); i++) {
se->AES_KEYTABLE_ADDR = (keyslot << 4) | 8 | i;
se->AES_KEYTABLE_DATA = read32le(iv, 4 * i);
}
}
void clear_aes_keyslot_iv(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
for (size_t i = 0; i < (0x10 >> 2); i++) {
se->AES_KEYTABLE_ADDR = (keyslot << 4) | 8 | i;
se->AES_KEYTABLE_DATA = 0;
}
}
void set_se_ctr(const void *ctr) {
for (unsigned int i = 0; i < 4; i++) {
se_get_regs()->CRYPTO_CTR_REG[i] = read32le(ctr, i * 4);
}
}
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();
}
/* Write config, validate. */
se->CONFIG_REG = (ALG_AES_DEC | DST_KEYTAB);
if (se->CONFIG_REG != (ALG_AES_DEC | DST_KEYTAB)) {
generic_panic();
}
se->CRYPTO_REG = keyslot_src << 24;
if (se->CRYPTO_REG != (keyslot_src << 24)) {
generic_panic();
}
se->BLOCK_COUNT_REG = 0;
if (se->BLOCK_COUNT_REG != 0) {
generic_panic();
}
se->CRYPTO_KEYTABLE_DST_REG = keyslot_dst << 8;
if (se->CRYPTO_KEYTABLE_DST_REG != (keyslot_dst << 8)) {
generic_panic();
}
/* Clear address context. */
se->IN_LL_ADDR_REG = 0;
se->OUT_LL_ADDR_REG = 0;
if (se->IN_LL_ADDR_REG != 0 || se->OUT_LL_ADDR_REG != 0) {
generic_panic();
}
trigger_se_blocking_op(OP_START, NULL, 0, wrapped_key, wrapped_key_size);
/* Validate address context. */
if (se->IN_LL_ADDR_REG == 0 || se->OUT_LL_ADDR_REG == 0) {
generic_panic();
}
}
void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
volatile tegra_se_t *se = se_get_regs();
uint8_t ALIGN(16) stack_buf[KEYSIZE_RSA_MAX];
if (keyslot >= KEYSLOT_RSA_MAX || src_size > KEYSIZE_RSA_MAX || dst_size > KEYSIZE_RSA_MAX) {
generic_panic();
}
/* Endian swap the input. */
for (size_t i = 0; i < src_size; i++) {
stack_buf[i] = *((uint8_t *)src + src_size - i - 1);
}
se->CONFIG_REG = (ALG_RSA | DST_RSAREG);
se->RSA_CONFIG = keyslot << 24;
se->RSA_KEY_SIZE_REG = (g_se_modulus_sizes[keyslot] >> 6) - 1;
se->RSA_EXP_SIZE_REG = g_se_exp_sizes[keyslot] >> 2;
trigger_se_blocking_op(OP_START, NULL, 0, stack_buf, src_size);
se_get_exp_mod_output(dst, dst_size);
}
void se_get_exp_mod_output(void *buf, size_t size) {
size_t num_dwords = (size >> 2);
if (num_dwords < 1) {
return;
}
uint32_t *p_out = ((uint32_t *)buf) + num_dwords - 1;
uint32_t offset = 0;
/* Copy endian swapped output. */
while (num_dwords) {
*p_out = read32be(se_get_regs()->RSA_OUTPUT, offset);
offset += 4;
p_out--;
num_dwords--;
}
}
bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const void *modulus, size_t modulus_size, const void *data, size_t data_size) {
uint8_t message[RSA_2048_BYTES];
uint8_t h_buf[0x24];
/* Hardcode RSA with keyslot 0. */
const uint8_t public_exponent[4] = {0x00, 0x01, 0x00, 0x01};
set_rsa_keyslot(0, modulus, modulus_size, public_exponent, sizeof(public_exponent));
se_synchronous_exp_mod(0, message, sizeof(message), signature, signature_size);
/* Validate sanity byte. */
if (message[RSA_2048_BYTES - 1] != 0xBC) {
return false;
}
/* Copy Salt into MGF1 Hash Buffer. */
memset(h_buf, 0, sizeof(h_buf));
memcpy(h_buf, message + RSA_2048_BYTES - 0x20 - 0x1, 0x20);
/* Decrypt maskedDB (via inline MGF1). */
uint8_t seed = 0;
uint8_t mgf1_buf[0x20];
for (unsigned int ofs = 0; ofs < RSA_2048_BYTES - 0x20 - 1; ofs += 0x20) {
h_buf[sizeof(h_buf) - 1] = seed++;
se_calculate_sha256(mgf1_buf, h_buf, sizeof(h_buf));
for (unsigned int i = ofs; i < ofs + 0x20 && i < RSA_2048_BYTES - 0x20 - 1; i++) {
message[i] ^= mgf1_buf[i - ofs];
}
}
/* Constant lmask for rsa-2048-pss. */
message[0] &= 0x7F;
/* Validate DB is of the form 0000...0001. */
for (unsigned int i = 0; i < RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1; i++) {
if (message[i] != 0) {
return false;
}
}
if (message[RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1] != 1) {
return false;
}
/* Check hash correctness. */
uint8_t validate_buf[8 + 0x20 + 0x20];
uint8_t validate_hash[0x20];
memset(validate_buf, 0, sizeof(validate_buf));
se_calculate_sha256(&validate_buf[8], data, data_size);
memcpy(&validate_buf[0x28], &message[RSA_2048_BYTES - 0x20 - 0x20 - 1], 0x20);
se_calculate_sha256(validate_hash, validate_buf, sizeof(validate_buf));
return memcmp(h_buf, validate_hash, 0x20) == 0;
}
void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const void *src, size_t src_size) {
volatile tegra_se_t *se = se_get_regs();
se_ll_t in_ll;
se_ll_t out_ll;
ll_init(&in_ll, (void *)src, src_size);
ll_init(&out_ll, dst, dst_size);
/* Set the LLs. */
se->IN_LL_ADDR_REG = (uint32_t) get_physical_address(&in_ll);
se->OUT_LL_ADDR_REG = (uint32_t) get_physical_address(&out_ll);
/* Set registers for operation. */
se->ERR_STATUS_REG = se->ERR_STATUS_REG;
se->INT_STATUS_REG = se->INT_STATUS_REG;
if (se->IN_LL_ADDR_REG != (uint32_t) get_physical_address(&in_ll) || se->OUT_LL_ADDR_REG != (uint32_t) get_physical_address(&out_ll) || (se->INT_STATUS_REG & 0x10) || (se->FLAGS_REG & 0x3)) {
generic_panic();
}
se->OPERATION_REG = op;
while (!(se->INT_STATUS_REG & 0x10)) { /* Wait a while */ }
se_check_for_error();
}
/* Secure AES Functionality. */
void se_perform_aes_block_operation(void *dst, size_t dst_size, const void *src, size_t src_size) {
uint8_t block[0x10] = {0};
if (src_size > sizeof(block) || dst_size > sizeof(block)) {
generic_panic();
}
/* Load src data into block. */
if (src_size != 0) {
memcpy(block, src, src_size);
}
/* Trigger AES operation. */
se_get_regs()->BLOCK_COUNT_REG = 0;
trigger_se_blocking_op(OP_START, block, sizeof(block), block, sizeof(block));
/* Copy output data into dst. */
if (dst_size != 0) {
memcpy(dst, block, dst_size);
}
}
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();
}
unsigned int num_blocks = src_size >> 4;
/* Unknown what this write does, but official code writes it for CTR mode. */
se->SPARE_0 = 1;
se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY);
se->CRYPTO_REG = (keyslot << 24) | 0x91E;
set_se_ctr(ctr);
/* Handle any aligned blocks. */
size_t aligned_size = (size_t)num_blocks << 4;
if (aligned_size) {
se->BLOCK_COUNT_REG = num_blocks - 1;
trigger_se_blocking_op(OP_START, dst, dst_size, src, aligned_size);
}
/* Handle final, unaligned block. */
if (aligned_size < dst_size && aligned_size < src_size) {
size_t last_block_size = dst_size - aligned_size;
if (src_size < dst_size) {
last_block_size = src_size - aligned_size;
}
se_perform_aes_block_operation(dst + aligned_size, last_block_size, (uint8_t *)src + aligned_size, src_size - aligned_size);
}
}
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();
}
/* Set configuration high (256-bit vs 128-bit) based on parameter. */
se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY) | (config_high << 16);
se->CRYPTO_REG = keyslot << 24 | 0x100;
se_perform_aes_block_operation(dst, 0x10, src, 0x10);
}
void se_aes_128_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
se_aes_ecb_encrypt_block(keyslot, dst, dst_size, src, src_size, 0);
}
void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
se_aes_ecb_encrypt_block(keyslot, dst, dst_size, src, src_size, 0x202);
}
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();
}
se->CONFIG_REG = (ALG_AES_DEC | DST_MEMORY);
se->CRYPTO_REG = keyslot << 24;
se_perform_aes_block_operation(dst, 0x10, src, 0x10);
}
void shift_left_xor_rb(uint8_t *key) {
uint8_t prev_high_bit = 0;
for (unsigned int i = 0; i < 0x10; i++) {
uint8_t cur_byte = key[0xF - i];
key[0xF - i] = (cur_byte << 1) | (prev_high_bit);
prev_high_bit = cur_byte >> 7;
}
if (prev_high_bit) {
key[0xF] ^= 0x87;
}
}
void shift_left_xor_rb_le(uint8_t *key) {
uint8_t prev_high_bit = 0;
for (unsigned int i = 0; i < 0x10; i++) {
uint8_t cur_byte = key[i];
key[i] = (cur_byte << 1) | (prev_high_bit);
prev_high_bit = cur_byte >> 7;
}
if (prev_high_bit) {
key[0x0] ^= 0x87;
}
}
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();
}
/* Generate the derived key, to be XOR'd with final output block. */
uint8_t ALIGN(16) derived_key[0x10] = {0};
se_aes_ecb_encrypt_block(keyslot, derived_key, sizeof(derived_key), derived_key, sizeof(derived_key), config_high);
shift_left_xor_rb(derived_key);
if (data_size & 0xF) {
shift_left_xor_rb(derived_key);
}
se->CONFIG_REG = (ALG_AES_ENC | DST_HASHREG) | (config_high << 16);
se->CRYPTO_REG = (keyslot << 24) | (0x145);
clear_aes_keyslot_iv(keyslot);
unsigned int num_blocks = (data_size + 0xF) >> 4;
/* Handle aligned blocks. */
if (num_blocks > 1) {
se->BLOCK_COUNT_REG = num_blocks - 2;
trigger_se_blocking_op(OP_START, NULL, 0, data, data_size);
se->CRYPTO_REG |= 0x80;
}
/* Create final block. */
uint8_t ALIGN(16) last_block[0x10] = {0};
if (data_size & 0xF) {
memcpy(last_block, data + (data_size & ~0xF), data_size & 0xF);
last_block[data_size & 0xF] = 0x80; /* Last block = data || 100...0 */
} else if (data_size >= 0x10) {
memcpy(last_block, data + data_size - 0x10, 0x10);
}
for (unsigned int i = 0; i < 0x10; i++) {
last_block[i] ^= derived_key[i];
}
/* Perform last operation. */
se->BLOCK_COUNT_REG = 0;
trigger_se_blocking_op(OP_START, NULL, 0, last_block, sizeof(last_block));
/* Copy output CMAC. */
for (unsigned int i = 0; i < (cmac_size >> 2); i++) {
((uint32_t *)cmac)[i] = read32le(se->HASH_RESULT_REG, i << 2);
}
}
void se_compute_aes_128_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size) {
se_compute_aes_cmac(keyslot, cmac, cmac_size, data, data_size, 0);
}
void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size) {
se_compute_aes_cmac(keyslot, cmac, cmac_size, data, data_size, 0x202);
}
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();
}
se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY) | (0x202 << 16);
se->CRYPTO_REG = (keyslot << 24) | 0x144;
set_aes_keyslot_iv(keyslot, iv, 0x10);
se->BLOCK_COUNT_REG = (src_size >> 4) - 1;
trigger_se_blocking_op(OP_START, dst, dst_size, src, src_size);
}
void se_aes_128_cbc_decrypt(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 || src_size < 0x10) {
generic_panic();
}
se->CONFIG_REG = (ALG_AES_DEC | DST_MEMORY) | (0x000 << 16);
se->CRYPTO_REG = (keyslot << 24) | 0x66;
clear_aes_keyslot_iv(keyslot);
se->BLOCK_COUNT_REG = (src_size >> 4) - 1;
trigger_se_blocking_op(OP_START, dst, dst_size, src, src_size);
}
/* 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->CONFIG_REG = (ENCMODE_SHA256 | ALG_SHA | DST_HASHREG);
se->SHA_CONFIG_REG = 1;
se->SHA_MSG_LENGTH_REG = (uint32_t)(src_size << 3);
se->_0x208 = 0;
se->_0x20C = 0;
se->_0x210 = 0;
se->SHA_MSG_LEFT_REG = (uint32_t)(src_size << 3);
se->_0x218 = 0;
se->_0x21C = 0;
se->_0x220 = 0;
/* Trigger the operation. */
trigger_se_blocking_op(OP_START, NULL, 0, src, src_size);
/* Copy output hash. */
for (unsigned int i = 0; i < (0x20 >> 2); i++) {
((uint32_t *)dst)[i] = read32be(se->HASH_RESULT_REG, i << 2);
}
}
/* RNG API */
void se_initialize_rng(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
/* To initialize the RNG, we'll perform an RNG operation into an output buffer. */
/* This will be discarded, when done. */
uint8_t ALIGN(16) output_buf[0x10];
se->RNG_SRC_CONFIG_REG = 3; /* Entropy enable + Entropy lock enable */
se->RNG_RESEED_INTERVAL_REG = 70001;
se->CONFIG_REG = (ALG_RNG | DST_MEMORY);
se->CRYPTO_REG = (keyslot << 24) | 0x108;
se->RNG_CONFIG_REG = 5;
se->BLOCK_COUNT_REG = 0;
trigger_se_blocking_op(OP_START, output_buf, 0x10, NULL, 0);
}
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();
}
uint32_t num_blocks = size >> 4;
size_t aligned_size = num_blocks << 4;
se->CONFIG_REG = (ALG_RNG | DST_MEMORY);
se->CRYPTO_REG = (keyslot << 24) | 0x108;
se->RNG_CONFIG_REG = 4;
if (num_blocks >= 1) {
se->BLOCK_COUNT_REG = num_blocks - 1;
trigger_se_blocking_op(OP_START, dst, aligned_size, NULL, 0);
}
if (size > aligned_size) {
se_perform_aes_block_operation(dst + aligned_size, size - aligned_size, NULL, 0);
}
}
void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot) {
volatile tegra_se_t *se = se_get_regs();
if (dst_keyslot >= KEYSLOT_AES_MAX || rng_keyslot >= KEYSLOT_AES_MAX) {
generic_panic();
}
/* Setup Config. */
se->CONFIG_REG = (ALG_RNG | DST_KEYTAB);
se->CRYPTO_REG = (rng_keyslot << 24) | 0x108;
se->RNG_CONFIG_REG = 4;
se->BLOCK_COUNT_REG = 0;
/* Generate low part of key. */
se->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8);
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
/* Generate high part of key. */
se->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8) | 1;
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
}
/* SE context save API. */
void se_set_in_context_save_mode(bool is_context_save_mode) {
volatile tegra_se_t *se = se_get_regs();
uint32_t val = se->_0x0;
if (is_context_save_mode) {
val |= 0x10000;
} else {
val &= 0xFFFEFFFF;
}
se->_0x0 = val;
/* Perform a useless read from flags reg. */
(void)(se->FLAGS_REG);
}
void se_generate_srk(unsigned int srkgen_keyslot) {
volatile tegra_se_t *se = se_get_regs();
se->CONFIG_REG = (ALG_RNG | DST_SRK);
se->CRYPTO_REG = (srkgen_keyslot << 24) | 0x108;
se->RNG_CONFIG_REG = 6;
se->BLOCK_COUNT_REG = 0;
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
}
void se_encrypt_with_srk(void *dst, size_t dst_size, const void *src, size_t src_size) {
uint8_t output[0x80];
uint8_t *aligned_out = (uint8_t *)(((uintptr_t)output + 0x7F) & ~0x3F);
if (dst_size > 0x10) {
generic_panic();
}
if (dst_size) {
trigger_se_blocking_op(OP_CTX_SAVE, aligned_out, dst_size, src, src_size);
memcpy(dst, aligned_out, dst_size);
} else {
trigger_se_blocking_op(OP_CTX_SAVE, aligned_out, 0, src, src_size);
}
}
void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void *dst) {
volatile tegra_se_t *se = se_get_regs();
uint8_t _work_buf[0x80];
uint8_t *work_buf = (uint8_t *)(((uintptr_t)_work_buf + 0x7F) & ~0x3F);
/* Generate the SRK (context save encryption key). */
se_generate_random_key(srkgen_keyslot, rng_keyslot);
se_generate_srk(srkgen_keyslot);
se_generate_random(rng_keyslot, work_buf, 0x10);
/* Save random initial block. */
se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY);
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_MEM);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(dst, 0x10, work_buf, 0x10);
/* Save Sticky Bits. */
for (unsigned int i = 0; i < 0x2; i++) {
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_STICKY_BITS) | (i << CTX_SAVE_STICKY_BIT_INDEX_SHIFT);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(dst + 0x10 + (i * 0x10), 0x10, NULL, 0);
}
/* Save AES Key Table. */
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(dst + 0x30 + (i * 0x20), 0x10, NULL, 0);
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_HIGH_BITS);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(dst + 0x40 + (i * 0x20), 0x10, NULL, 0);
}
/* Save AES Original IVs. */
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_ORIGINAL_IV);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(dst + 0x230 + (i * 0x10), 0x10, NULL, 0);
}
/* Save AES Updated IVs */
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_UPDATED_IV);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(dst + 0x330 + (i * 0x10), 0x10, NULL, 0);
}
/* Save RSA Keytable. */
uint8_t *rsa_ctx_out = (uint8_t *)dst + 0x430;
for (unsigned int rsa_key = 0; rsa_key < KEYSLOT_RSA_MAX; rsa_key++) {
for (unsigned int mod_exp = 0; mod_exp < 2; mod_exp++) {
for (unsigned int sub_block = 0; sub_block < 0x10; sub_block++) {
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_RSA) | ((2 * rsa_key + (1 - mod_exp)) << CTX_SAVE_RSA_KEY_INDEX_SHIFT) | (sub_block << CTX_SAVE_RSA_KEY_BLOCK_INDEX_SHIFT);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(rsa_ctx_out, 0x10, NULL, 0);
rsa_ctx_out += 0x10;
}
}
}
/* Save "Known Pattern. " */
static const uint8_t context_save_known_pattern[0x10] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_MEM);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(dst + 0x830, 0x10, context_save_known_pattern, 0x10);
/* Save SRK into PMC registers. */
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_SRK);
se->BLOCK_COUNT_REG = 0;
se_encrypt_with_srk(work_buf, 0, NULL, 0);
se->CONFIG_REG = 0;
se_encrypt_with_srk(work_buf, 0, NULL, 0);
}

View file

@ -0,0 +1,225 @@
/*
* 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/>.
*/
#include <stdbool.h>
#ifndef FUSEE_SE_H
#define FUSEE_SE_H
#define SE_BASE 0x70012000
#define MAKE_SE_REG(n) MAKE_REG32(SE_BASE + n)
#define KEYSLOT_SWITCH_LP0TZRAMKEY 0x2
#define KEYSLOT_SWITCH_SRKGENKEY 0x8
#define KEYSLOT_SWITCH_PACKAGE2KEY 0x8
#define KEYSLOT_SWITCH_TEMPKEY 0x9
#define KEYSLOT_SWITCH_SESSIONKEY 0xA
#define KEYSLOT_SWITCH_RNGKEY 0xB
#define KEYSLOT_SWITCH_MASTERKEY 0xC
#define KEYSLOT_SWITCH_DEVICEKEY 0xD
/* This keyslot was added in 4.0.0. */
#define KEYSLOT_SWITCH_4XNEWDEVICEKEYGENKEY 0xD
#define KEYSLOT_SWITCH_4XNEWCONSOLEKEYGENKEY 0xE
#define KEYSLOT_SWITCH_4XOLDDEVICEKEY 0xF
/* This keyslot was added in 5.0.0. */
#define KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY 0xA
#define KEYSLOT_AES_MAX 0x10
#define KEYSLOT_RSA_MAX 0x2
#define KEYSIZE_AES_MAX 0x20
#define KEYSIZE_RSA_MAX 0x100
#define ALG_SHIFT (12)
#define ALG_DEC_SHIFT (8)
#define ALG_NOP (0 << ALG_SHIFT)
#define ALG_AES_ENC (1 << ALG_SHIFT)
#define ALG_AES_DEC ((1 << ALG_DEC_SHIFT) | ALG_NOP)
#define ALG_RNG (2 << ALG_SHIFT)
#define ALG_SHA (3 << ALG_SHIFT)
#define ALG_RSA (4 << ALG_SHIFT)
#define DST_SHIFT (2)
#define DST_MEMORY (0 << DST_SHIFT)
#define DST_HASHREG (1 << DST_SHIFT)
#define DST_KEYTAB (2 << DST_SHIFT)
#define DST_SRK (3 << DST_SHIFT)
#define DST_RSAREG (4 << DST_SHIFT)
#define ENCMODE_SHIFT (24)
#define DECMODE_SHIFT (16)
#define ENCMODE_SHA256 (5 << ENCMODE_SHIFT)
#define HASH_DISABLE (0x0)
#define HASH_ENABLE (0x1)
#define OP_ABORT 0
#define OP_START 1
#define OP_RESTART 2
#define OP_CTX_SAVE 3
#define OP_RESTART_IN 4
#define CTX_SAVE_SRC_SHIFT 29
#define CTX_SAVE_SRC_STICKY_BITS (0 << CTX_SAVE_SRC_SHIFT)
#define CTX_SAVE_SRC_KEYTABLE_AES (2 << CTX_SAVE_SRC_SHIFT)
#define CTX_SAVE_SRC_KEYTABLE_RSA (1 << CTX_SAVE_SRC_SHIFT)
#define CTX_SAVE_SRC_MEM (4 << CTX_SAVE_SRC_SHIFT)
#define CTX_SAVE_SRC_SRK (6 << CTX_SAVE_SRC_SHIFT)
#define CTX_SAVE_KEY_LOW_BITS 0
#define CTX_SAVE_KEY_HIGH_BITS 1
#define CTX_SAVE_KEY_ORIGINAL_IV 2
#define CTX_SAVE_KEY_UPDATED_IV 3
#define CTX_SAVE_STICKY_BIT_INDEX_SHIFT 24
#define CTX_SAVE_KEY_INDEX_SHIFT 8
#define CTX_SAVE_RSA_KEY_INDEX_SHIFT 16
#define CTX_SAVE_RSA_KEY_BLOCK_INDEX_SHIFT 12
#define RSA_2048_BYTES 0x100
typedef struct {
uint32_t _0x0;
uint32_t _0x4;
uint32_t OPERATION_REG;
uint32_t INT_ENABLE_REG;
uint32_t INT_STATUS_REG;
uint32_t CONFIG_REG;
uint32_t IN_LL_ADDR_REG;
uint32_t _0x1C;
uint32_t _0x20;
uint32_t OUT_LL_ADDR_REG;
uint32_t _0x28;
uint32_t _0x2C;
uint8_t HASH_RESULT_REG[0x20];
uint8_t _0x50[0x20];
uint32_t CONTEXT_SAVE_CONFIG_REG;
uint8_t _0x74[0x18C];
uint32_t SHA_CONFIG_REG;
uint32_t SHA_MSG_LENGTH_REG;
uint32_t _0x208;
uint32_t _0x20C;
uint32_t _0x210;
uint32_t SHA_MSG_LEFT_REG;
uint32_t _0x218;
uint32_t _0x21C;
uint32_t _0x220;
uint32_t _0x224;
uint8_t _0x228[0x58];
uint32_t AES_KEY_READ_DISABLE_REG;
uint32_t AES_KEYSLOT_FLAGS[0x10];
uint8_t _0x2C4[0x3C];
uint32_t _0x300;
uint32_t CRYPTO_REG;
uint32_t CRYPTO_CTR_REG[4];
uint32_t BLOCK_COUNT_REG;
uint32_t AES_KEYTABLE_ADDR;
uint32_t AES_KEYTABLE_DATA;
uint32_t _0x324;
uint32_t _0x328;
uint32_t _0x32C;
uint32_t CRYPTO_KEYTABLE_DST_REG;
uint8_t _0x334[0xC];
uint32_t RNG_CONFIG_REG;
uint32_t RNG_SRC_CONFIG_REG;
uint32_t RNG_RESEED_INTERVAL_REG;
uint8_t _0x34C[0xB4];
uint32_t RSA_CONFIG;
uint32_t RSA_KEY_SIZE_REG;
uint32_t RSA_EXP_SIZE_REG;
uint32_t RSA_KEY_READ_DISABLE_REG;
uint32_t RSA_KEYSLOT_FLAGS[2];
uint32_t _0x418;
uint32_t _0x41C;
uint32_t RSA_KEYTABLE_ADDR;
uint32_t RSA_KEYTABLE_DATA;
uint8_t RSA_OUTPUT[0x100];
uint8_t _0x528[0x2D8];
uint32_t FLAGS_REG;
uint32_t ERR_STATUS_REG;
uint32_t _0x808;
uint32_t SPARE_0;
uint32_t _0x810;
uint32_t _0x814;
uint32_t _0x818;
uint32_t _0x81C;
uint8_t _0x820[0x17E0];
} tegra_se_t;
typedef struct {
uint32_t address;
uint32_t size;
} se_addr_info_t;
typedef struct {
uint32_t num_entries; /* Set to total entries - 1 */
se_addr_info_t addr_info; /* This should really be an array...but for our use case it works. */
} se_ll_t;
static inline volatile tegra_se_t *se_get_regs(void) {
return (volatile tegra_se_t *)SE_BASE;
}
void se_check_error_status_reg(void);
void se_check_for_error(void);
void se_trigger_interrupt(void);
void se_validate_stored_vector(void);
void se_generate_stored_vector(void);
void se_verify_flags_cleared(void);
void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags);
void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags);
void clear_aes_keyslot(unsigned int keyslot);
void clear_rsa_keyslot(unsigned int keyslot);
void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size);
void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_size);
void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_size, const void *exponent, size_t exp_size);
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_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);
void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
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);
void se_aes_ecb_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_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);
void se_aes_128_cbc_decrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
/* Hash API */
void se_calculate_sha256(void *dst, const void *src, size_t src_size);
/* RSA API */
void se_get_exp_mod_output(void *buf, size_t size);
void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const void *modulus, size_t modulus_size, const void *data, size_t data_size);
/* RNG API */
void se_initialize_rng(unsigned int keyslot);
void se_generate_random(unsigned int keyslot, void *dst, size_t size);
/* SE context save API. */
void se_generate_srk(unsigned int srkgen_keyslot);
void se_set_in_context_save_mode(bool is_context_save_mode);
void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot);
void se_save_context(unsigned int srk_keyslot, unsigned int rng_keyslot, void *dst);
#endif

View file

@ -0,0 +1,99 @@
/*
* 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/>.
*/
/* For some reason GAS doesn't know about it, even with .cpu cortex-a57 */
#define cpuactlr_el1 s3_1_c15_c2_0
#define cpuectlr_el1 s3_1_c15_c2_1
.macro RESET_CORE
mov x0, #(1 << 63)
msr cpuactlr_el1, x0 /* disable regional clock gating */
isb
mov x0, #3
msr rmr_el3, x0
isb
dsb sy
/* Nintendo forgot to copy-paste the branch instruction below. */
1:
wfi
b 1b
.endm
.macro ERRATUM_INVALIDATE_BTB_AT_BOOT
/* Nintendo copy-pasted https://github.com/ARM-software/arm-trusted-firmware/blob/master/plat/nvidia/tegra/common/aarch64/tegra_helpers.S#L312 */
/*
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/* The following comments are mine. */
/* mask all interrupts */
msr daifset, 0b1111
/*
Enable invalidates of branch target buffer, then flush
the entire instruction cache at the local level, and
with the reg change, the branch target buffer, then disable
invalidates of the branch target buffer again.
*/
mrs x0, cpuactlr_el1
orr x0, x0, #1
msr cpuactlr_el1, x0
dsb sy
isb
ic iallu
dsb sy
isb
mrs x0, cpuactlr_el1
bic x0, x0, #1
msr cpuactlr_el1, x0
.rept 7
nop /* wait long enough for the write to cpuactlr_el1 to have completed */
.endr
/* if the OS lock is set, disable it and request a warm reset */
mrs x0, oslsr_el1
ands x0, x0, #2
b.eq 2f
mov x0, xzr
msr oslar_el1, x0
RESET_CORE
.rept 65
nop /* guard against speculative excecution */
.endr
2:
/* set the OS lock */
mov x0, #1
msr oslar_el1, x0
.endm
.section .text.start
.align 4
.global _start
_start:
ERRATUM_INVALIDATE_BTB_AT_BOOT
msr spsel, #0
ldr x0, =__start__
mov sp, x0
mov fp, #0x0
bl derive_keys

View file

@ -0,0 +1,33 @@
/*
* 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/>.
*/
#include <stdbool.h>
#include <stdarg.h>
#include "utils.h"
#include "se.h"
#include <inttypes.h>
__attribute__ ((noreturn)) void generic_panic(void) {
/* Clear keyslots. */
clear_aes_keyslot(0xD);
clear_aes_keyslot(0xE);
for (size_t i = 0; i < 0x10; i++) {
clear_aes_keyslot(i);
}
clear_aes_keyslot(0xD);
clear_aes_keyslot(0xE);
while(1) { /* ... */ }
}

View file

@ -0,0 +1,122 @@
/*
* 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 FUSEE_UTILS_H
#define FUSEE_UTILS_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#define BIT(n) (1u << (n))
#define BITL(n) (1ull << (n))
#define MASK(n) (BIT(n) - 1)
#define MASKL(n) (BITL(n) - 1)
#define MASK2(a,b) (MASK(a) & ~MASK(b))
#define MASK2L(a,b) (MASKL(a) & ~MASKL(b))
#define MAKE_REG32(a) (*(volatile uint32_t *)(a))
#define ALIGN(m) __attribute__((aligned(m)))
#define PACKED __attribute__((packed))
#define ALINLINE __attribute__((always_inline))
#define NOINLINE __attribute__((noinline))
#define SET_SYSREG(reg, val) do { temp_reg = (val); __asm__ __volatile__ ("msr " #reg ", %0" :: "r"(temp_reg) : "memory"); } while(false)
static inline uintptr_t get_physical_address(const void *addr) {
return (uintptr_t)addr;
}
static inline uint32_t read32le(const volatile void *dword, size_t offset) {
uintptr_t addr = (uintptr_t)dword + offset;
volatile uint32_t *target = (uint32_t *)addr;
return *target;
}
static inline uint32_t read32be(const volatile void *dword, size_t offset) {
return __builtin_bswap32(read32le(dword, offset));
}
static inline uint64_t read64le(const volatile void *qword, size_t offset) {
uintptr_t addr = (uintptr_t)qword + offset;
volatile uint64_t *target = (uint64_t *)addr;
return *target;
}
static inline uint64_t read64be(const volatile void *qword, size_t offset) {
return __builtin_bswap64(read64le(qword, offset));
}
static inline void write32le(volatile void *dword, size_t offset, uint32_t value) {
uintptr_t addr = (uintptr_t)dword + offset;
volatile uint32_t *target = (uint32_t *)addr;
*target = value;
}
static inline void write32be(volatile void *dword, size_t offset, uint32_t value) {
write32le(dword, offset, __builtin_bswap32(value));
}
static inline void write64le(volatile void *qword, size_t offset, uint64_t value) {
uintptr_t addr = (uintptr_t)qword + offset;
volatile uint64_t *target = (uint64_t *)addr;
*target = value;
}
static inline void write64be(volatile void *qword, size_t offset, uint64_t value) {
write64le(qword, offset, __builtin_bswap64(value));
}
static inline bool check_32bit_additive_overflow(uint32_t a, uint32_t b) {
return __builtin_add_overflow_p(a, b, (uint32_t)0);
}
static inline bool check_32bit_address_loadable(uintptr_t addr) {
/* FWIW the bootROM forbids loading anything between 0x40000000 and 0x40010000, using it for itself... */
return (addr >= 0x40010000u && addr < 0x40040000u) || addr >= 0x80000000u;
}
static inline bool check_32bit_address_range_loadable(uintptr_t addr, size_t size) {
return
!__builtin_add_overflow_p(addr, size, (uintptr_t)0) && /* the range doesn't overflow */
check_32bit_address_loadable(addr) && check_32bit_address_loadable(addr + size) && /* bounds are valid */
!(addr >= 0x40010000u && addr < 0x40040000u && addr + size >= 0x40040000u) /* the range doesn't cross MMIO */
;
}
bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be);
static inline bool overlaps_a(const void *as, const void *ae, const void *bs, const void *be) {
return overlaps((uint64_t)(uintptr_t)as, (uint64_t)(uintptr_t)ae, (uint64_t)(uintptr_t)bs, (uint64_t)(uintptr_t)be);
}
static inline bool check_32bit_address_range_in_program(uintptr_t addr, size_t size) {
extern uint8_t __chainloader_start__[], __chainloader_end__[];
extern uint8_t __stack_bottom__[], __stack_top__[];
extern uint8_t __start__[], __end__[];
uint8_t *start = (uint8_t *)addr, *end = start + size;
return overlaps_a(start, end, __chainloader_start__, __chainloader_end__) ||
overlaps_a(start, end, __stack_bottom__, __stack_top__) ||
overlaps_a(start, end, (void *)0xC0000000, (void *)0xC03C0000) || /* framebuffer */
overlaps_a(start, end, __start__, __end__);
}
__attribute__((noreturn)) void generic_panic(void);
#endif

View file

@ -20,8 +20,8 @@ MEMORY
SECTIONS
{
PROVIDE(__start__ = 0x40010000);
PROVIDE(__stack_top__ = 0x40010000);
PROVIDE(__stack_bottom__ = 0x4000C000);
PROVIDE(__stack_top__ = 0x4003C000);
PROVIDE(__stack_bottom__ = 0x40038000);
PROVIDE(__heap_start__ = 0);
PROVIDE(__heap_end__ = 0);

View file

@ -1,5 +1,5 @@
#!/usr/bin/env python
import sys
import sys, os
from struct import pack as pk, unpack as up
from Crypto.Cipher import AES
from Crypto.Hash import CMAC
@ -41,7 +41,7 @@ def get_last_block_for_desired_mac(key, data, desired_mac):
return last_block
def sign_encrypt_code(code, sig_key, enc_key, iv, desired_mac):
def sign_encrypt_code(code, sig_key, enc_key, iv, desired_mac, version):
# Pad with 0x20 of zeroes.
code = code + bytearray(0x20)
code_len = len(code)
@ -49,6 +49,9 @@ def sign_encrypt_code(code, sig_key, enc_key, iv, desired_mac):
code_len &= ~0xFFF
code = code + bytearray(code_len - len(code))
# Insert version
code = code[:8] + pk('<I', version) + code[12:]
# Add empty trustzone, warmboot segments.
code = code + bytearray(0x1FE0 - 0x10)
pk11_hdr = b'PK11' + pk('<IIIIIII', 0x1000, 0, 0, code_len - 0x20, 0, 0x1000, 0)
@ -69,8 +72,10 @@ def main(argc, argv):
if len(code) & 0xF:
code = code + bytearray(0x10 - (len(code) & 0xF))
# TODO: Support dev unit crypto
with open(argv[2], 'wb') as f:
f.write(sign_encrypt_code(code, KEYS.HOVI_SIG_KEY_PRD, KEYS.HOVI_ENC_KEY_PRD, KEYS.IV, b'THANKS_NVIDIA_<3'))
fn, fext = os.path.splitext(argv[2])
for key in range(KEYS.NUM_KEYS):
with open(fn + ('_%02X' % key) + fext, 'wb') as f:
f.write(sign_encrypt_code(code, KEYS.HOVI_SIG_KEY_PRD[key], KEYS.HOVI_ENC_KEY_PRD[key], KEYS.IV[key], b'THANKS_NVIDIA_<3', key))
return 0

View file

@ -0,0 +1,178 @@
/*
* Copyright (c) 2018 naehrwert
* 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/>.
*/
#include <stdint.h>
#include "cluster.h"
#include "flow.h"
#include "sysreg.h"
#include "i2c.h"
#include "car.h"
#include "mc.h"
#include "timers.h"
#include "pmc.h"
#include "max77620.h"
void _cluster_enable_power()
{
/* Reboot I2C5. */
clkrst_reboot(CARDEVICE_I2C5);
i2c_init(I2C_5);
uint8_t val = 0;
i2c_query(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_AME_GPIO, &val, 1);
val &= 0xDF;
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_AME_GPIO, &val, 1);
val = 0x09;
i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_GPIO5, &val, 1);
/* Enable power. */
val = 0x20;
i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x02, &val, 1);
val = 0x8D;
i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x03, &val, 1);
val = 0xB7;
i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x00, &val, 1);
val = 0xB7;
i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x01, &val, 1);
}
int _cluster_pmc_enable_partition(uint32_t part, uint32_t toggle)
{
volatile tegra_pmc_t *pmc = pmc_get_regs();
/* Check if the partition has already been turned on. */
if (pmc->pwrgate_status & part)
return 1;
uint32_t i = 5001;
while (pmc->pwrgate_toggle & 0x100)
{
udelay(1);
i--;
if (i < 1)
return 0;
}
pmc->pwrgate_toggle = (toggle | 0x100);
i = 5001;
while (i > 0)
{
if (pmc->pwrgate_status & part)
break;
udelay(1);
i--;
}
return 1;
}
void cluster_boot_cpu0(uint32_t entry)
{
volatile tegra_car_t *car = car_get_regs();
/* Set ACTIVE_CLUSER to FAST. */
FLOW_CTLR_BPMP_CLUSTER_CONTROL_0 &= 0xFFFFFFFE;
_cluster_enable_power();
if (!(car->pllx_base & 0x40000000))
{
car->pllx_misc3 &= 0xFFFFFFF7;
udelay(2);
car->pllx_base = 0x80404E02;
car->pllx_base = 0x404E02;
car->pllx_misc = ((car->pllx_misc & 0xFFFBFFFF) | 0x40000);
car->pllx_base = 0x40404E02;
}
while (!(car->pllx_base & 0x8000000)) {
/* Wait. */
}
/* Configure MSELECT source and enable clock. */
car->clk_source_mselect = ((car->clk_source_mselect & 0x1FFFFF00) | 6);
car->clk_out_enb_v = ((car->clk_out_enb_v & 0xFFFFFFF7) | 8);
/* Configure initial CPU clock frequency and enable clock. */
car->cclk_brst_pol = 0x20008888;
car->super_cclk_div = 0x80000000;
car->clk_enb_v_set = 1;
clkrst_reboot(CARDEVICE_CORESIGHT);
/* CAR2PMC_CPU_ACK_WIDTH should be set to 0. */
car->cpu_softrst_ctrl2 &= 0xFFFFF000;
/* Enable CPU rail. */
_cluster_pmc_enable_partition(1, 0);
/* Enable cluster 0 non-CPU. */
_cluster_pmc_enable_partition(0x8000, 15);
/* Enable CE0. */
_cluster_pmc_enable_partition(0x4000, 14);
/* Request and wait for RAM repair. */
FLOW_CTLR_RAM_REPAIR_0 = 1;
while (!(FLOW_CTLR_RAM_REPAIR_0 & 2)) {
/* Wait. */
}
MAKE_EXCP_VEC_REG(0x100) = 0;
/* Check for reset vector lock. */
if (SB_CSR_0 & 2) {
generic_panic();
}
/* Set reset vector. */
SB_AA64_RESET_LOW_0 = (entry | 1);
SB_AA64_RESET_HIGH_0 = 0;
/* Non-secure reset vector write disable. */
SB_CSR_0 = 2;
(void)SB_CSR_0;
/* Validate reset vector lock + RESET_LOW/HIGH values. */
if (!(SB_CSR_0 & 2)) {
generic_panic();
}
/* TODO: Should we even bother taking as a parameter? */
if (SB_AA64_RESET_LOW_0 != (0x4003D000 | 1) || SB_AA64_RESET_HIGH_0 != 0) {
generic_panic();
}
/* Set CPU_STRICT_TZ_APERTURE_CHECK. */
/* NOTE: [4.0.0+] This was added, but it breaks Exosphère. */
/* MAKE_MC_REG(MC_TZ_SECURITY_CTRL) = 1; */
/* Clear MSELECT reset. */
car->rst_dev_v &= 0xFFFFFFF7;
/* Clear NONCPU reset. */
car->rst_cpug_cmplx_clr = 0x20000000;
/* Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset.*/
/* NOTE: [5.0.0+] This was changed so only CPU0 reset is cleared. */
/* car->rst_cpug_cmplx_clr = 0x411F000F; */
car->rst_cpug_cmplx_clr = 0x41010001;
}

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2018 naehrwert
* 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 FUSEE_CLUSTER_H_
#define FUSEE_CLUSTER_H_
void cluster_boot_cpu0(uint32_t entry);
#endif

View file

@ -17,64 +17,65 @@
#include <stdio.h>
#include "key_derivation.h"
#include "se.h"
#include "cluster.h"
#include "timers.h"
#include "fuse.h"
#include "utils.h"
#define AL16 ALIGN(16)
#define u8 uint8_t
#define u32 uint32_t
#include "key_derivation_bin.h"
#undef u8
#undef u32
static const uint8_t AL16 keyblob_seed_00[0x10] = {
0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3
};
static const uint8_t AL16 masterkey_seed[0x10] = {
0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C
};
void derive_keys(uint32_t version) {
/* Clear mailbox. */
volatile uint32_t *mailbox = (volatile uint32_t *)0x4003FF00;
while (*mailbox != 0) {
*mailbox = 0;
}
static const uint8_t AL16 devicekey_seed[0x10] = {
0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78
};
/* Set derivation id. */
*((volatile uint32_t *)0x4003E800) = version;
static const uint8_t AL16 devicekey_4x_seed[0x10] = {
0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28
};
/* Copy key derivation stub into IRAM high. */
for (size_t i = 0; i < key_derivation_bin_size; i += sizeof(uint32_t)) {
write32le((void *)0x4003D000, i, read32le(key_derivation_bin, i));
}
static const uint8_t AL16 masterkey_4x_seed[0x10] = {
0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66
};
cluster_boot_cpu0(0x4003D000);
static const uint8_t AL16 new_master_kek_seed_7x[0x10] = {
0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C
};
void derive_7x_keys(const void *tsec_key, void *tsec_root_key) {
uint8_t AL16 work_buffer[0x10];
/* Set keyslot flags properly in preparation of derivation. */
set_aes_keyslot_flags(0xE, 0x15);
set_aes_keyslot_flags(0xD, 0x15);
/* Set the TSEC key. */
set_aes_keyslot(0xD, tsec_key, 0x10);
/* Derive keyblob key 0. */
se_aes_ecb_decrypt_block(0xD, work_buffer, 0x10, keyblob_seed_00, 0x10);
decrypt_data_into_keyslot(0xF, 0xE, work_buffer, 0x10);
/* Clear the SBK. */
clear_aes_keyslot(0xE);
/* Derive the master kek. */
set_aes_keyslot(0xC, tsec_root_key, 0x10);
decrypt_data_into_keyslot(0xC, 0xC, new_master_kek_seed_7x, 0x10);
/* Derive keys for exosphere. */
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);
decrypt_data_into_keyslot(0xC, 0xC, masterkey_seed, 0x10);
/* Clear master kek from memory. */
for (size_t i = 0; i < sizeof(work_buffer); i++) {
work_buffer[i] = 0xCC;
while (*mailbox != 7) {
/* Wait until keys have been derived. */
}
}
void load_keys(const uint8_t *se_state) {
/* Clear keyslots up to 0xA. */
for (size_t i = 0; i < 0xA; i++) {
clear_aes_keyslot(i);
}
/* Copy device keygen key out of state keyslot 0xA into keyslot 0xA. */
set_aes_keyslot(0xA, se_state + 0x30 + (0xA * 0x20), 0x10);
/* Clear keyslot 0xB. */
clear_aes_keyslot(0xB);
/* Copy master key out of state keyslot 0xC into keyslot 0xC. */
set_aes_keyslot(0xC, se_state + 0x30 + (0xC * 0x20), 0x10);
/* Copy firmware device key out of state keyslot 0xE into keyslot 0xD. */
set_aes_keyslot(0xD, se_state + 0x30 + (0xE * 0x20), 0x10);
/* Clear keyslot 0xE. */
clear_aes_keyslot(0xE);
/* Copy device key out of state keyslot 0xF into keyslot 0xF. */
set_aes_keyslot(0xF, se_state + 0x30 + (0xF * 0x20), 0x10);
/* Set keyslot flags properly in preparation for secmon. */
set_aes_keyslot_flags(0xE, 0x15);
set_aes_keyslot_flags(0xD, 0x15);
}

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 SEPT_KEYDERIVATION_H
#define SEPT_KEYDERIVATION_H
@ -21,6 +21,7 @@
#include <stdbool.h>
#include <stdint.h>
void derive_7x_keys(const void *tsec_key, void *tsec_root_key);
void derive_keys(uint32_t version);
void load_keys(const uint8_t *se_state);
#endif

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 "utils.h"
#include "exception_handlers.h"
#include "panic.h"
@ -22,6 +22,7 @@
#include "se.h"
#include "pmc.h"
#include "emc.h"
#include "sysreg.h"
#include "key_derivation.h"
#include "timers.h"
#include "fs_utils.h"
@ -39,9 +40,6 @@ extern void (*__program_exit_callback)(int rc);
static void *g_framebuffer;
static uint32_t g_tsec_root_key[0x4] = {0};
static uint32_t g_tsec_key[0x4] = {0};
static bool has_rebooted(void) {
return MAKE_REG32(0x4003FFFC) == 0xFAFAFAFA;
}
@ -51,27 +49,19 @@ static void set_has_rebooted(bool rebooted) {
}
static void exfiltrate_keys_and_reboot_if_needed(void) {
static void exfiltrate_keys_and_reboot_if_needed(uint32_t version) {
volatile tegra_pmc_t *pmc = pmc_get_regs();
uint8_t *enc_se_state = (uint8_t *)0x4003E000;
uint8_t *dec_se_state = (uint8_t *)0x4003F000;
if (!has_rebooted()) {
/* Prepare for a reboot before doing anything else. */
prepare_for_reboot_to_self();
set_has_rebooted(true);
/* Save the security engine context. */
se_get_regs()->_0x4 = 0x0;
se_set_in_context_save_mode(true);
se_save_context(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY, enc_se_state);
se_set_in_context_save_mode(false);
/* Clear all keyslots. */
for (size_t k = 0; k < 0x10; k++) {
clear_aes_keyslot(k);
}
/* Derive keys. */
derive_keys(version);
reboot_to_self();
} else {
/* Decrypt the security engine state. */
@ -82,13 +72,10 @@ static void exfiltrate_keys_and_reboot_if_needed(void) {
context_key[3] = pmc->secure_scratch7;
set_aes_keyslot(0xC, context_key, sizeof(context_key));
se_aes_128_cbc_decrypt(0xC, dec_se_state, 0x840, enc_se_state, 0x840);
/* Copy out tsec key + tsec root key. */
for (size_t i = 0; i < 0x10; i += 4) {
g_tsec_key[i/4] = MAKE_REG32((uintptr_t)(dec_se_state) + 0x1B0 + i);
g_tsec_root_key[i/4] = MAKE_REG32((uintptr_t)(dec_se_state) + 0x1D0 + i);
}
/* Load keys in from decrypted state. */
load_keys(dec_se_state);
/* Clear the security engine state. */
for (size_t i = 0; i < 0x840; i += 4) {
MAKE_REG32((uintptr_t)(enc_se_state) + i) = 0xCCCCCCCC;
@ -101,11 +88,6 @@ static void exfiltrate_keys_and_reboot_if_needed(void) {
pmc->secure_scratch5 = 0xCCCCCCCC;
pmc->secure_scratch6 = 0xCCCCCCCC;
pmc->secure_scratch7 = 0xCCCCCCCC;
/* Clear all keyslots except for SBK/SSK. */
for (size_t k = 0; k < 0xE; k++) {
clear_aes_keyslot(k);
}
}
}
@ -115,9 +97,6 @@ static void setup_env(void) {
/* Initialize hardware. */
nx_hwinit();
/* Check for panics. */
check_and_display_panic();
/* Zero-fill the framebuffer and register it as printk provider. */
video_init(g_framebuffer);
@ -126,7 +105,7 @@ static void setup_env(void) {
/* Set the framebuffer. */
display_init_framebuffer(g_framebuffer);
/* Draw splash. */
draw_splash((volatile uint32_t *)g_framebuffer);
@ -136,7 +115,7 @@ static void setup_env(void) {
/* Set up the exception handlers. */
setup_exception_handlers();
/* Mount the SD card. */
mount_sd();
}
@ -154,33 +133,29 @@ static void exit_callback(int rc) {
relocate_and_chainload();
}
int main(void) {
int sept_main(uint32_t version) {
const char *stage2_path;
stage2_args_t *stage2_args;
uint32_t stage2_version = 0;
ScreenLogLevel log_level = SCREEN_LOG_LEVEL_NONE;
/* Validate that we can safely boot the CCPLEX. */
if (SB_CSR_0 & 2) {
generic_panic();
}
/* Extract keys from the security engine, which TSEC FW locked down. */
exfiltrate_keys_and_reboot_if_needed();
exfiltrate_keys_and_reboot_if_needed(version);
/* Override the global logging level. */
log_set_log_level(log_level);
/* Initialize the display, console, etc. */
setup_env();
/* Derive keys. */
derive_7x_keys(g_tsec_key, g_tsec_root_key);
/* Cleanup keys in memory. */
for (size_t i = 0; i < 0x10; i += 4) {
g_tsec_root_key[i/4] = 0xCCCCCCCC;
g_tsec_key[i/4] = 0xCCCCCCCC;
}
/* Mark EMC scratch to say that sept has run. */
MAKE_EMC_REG(EMC_SCRATCH0) |= 0x80000000;
/* Load the loader payload into DRAM. */
load_stage2();
@ -194,10 +169,10 @@ int main(void) {
stage2_args->display_initialized = false;
strcpy(stage2_args->bct0, "");
g_chainloader_argc = 2;
/* Wait a while. */
mdelay(1500);
/* Deinitialize the display, console, etc. */
cleanup_env();

View file

@ -13,76 +13,17 @@
* 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 <stdint.h>
#include <stddef.h>
#include "panic.h"
#include "di.h"
#include "pmc.h"
#include "se.h"
#include "fuse.h"
#include "utils.h"
static uint32_t g_panic_code = 0;
void check_and_display_panic(void) {
/* We also handle our own panics. */
/* In the case of our own panics, we assume that the display has already been initialized. */
bool has_panic = APBDEV_PMC_RST_STATUS_0 != 0 || g_panic_code != 0;
uint32_t code = g_panic_code == 0 ? APBDEV_PMC_SCRATCH200_0 : g_panic_code;
has_panic = has_panic && !(APBDEV_PMC_RST_STATUS_0 != 1 && code == PANIC_CODE_SAFEMODE);
if (has_panic) {
uint32_t color;
/* Check for predefined codes: */
switch (code & MASK(20)) {
case 0x01: /* Package2 signature verification failed. */
case 0x02: /* Package2 meta verification failed. */
case 0x03: /* Package2 version check failed. */
case 0x04: /* Package2 payload verification failed. */
color = PANIC_COLOR_KERNEL;
break;
case 0x05: /* Unknown SMC. */
case 0x06: /* Unknown Abort. */
color = PANIC_COLOR_SECMON_GENERIC;
break;
case 0x07: /* Invalid CPU context. */
case 0x08: /* Invalid SE state. */
case 0x09: /* CPU is already awake (2.0.0+). */
color = PANIC_COLOR_SECMON_DEEPSLEEP;
break;
case 0x10: /* Unknown exception. */
color = PANIC_COLOR_SECMON_EXCEPTION;
break;
case 0x30: /* General bootloader error. */
case 0x31: /* Invalid DRAM ID. */
case 0x32: /* Invalid size. */
case 0x33: /* Invalid arguement. */
case 0x34: /* Bad GPT. */
case 0x35: /* Failed to boot SafeMode. */
case 0x36: /* Activity monitor fired (4.0.0+). */
color = PANIC_COLOR_BOOTLOADER_GENERIC;
break;
case 0x40: /* Kernel panic. */
color = PANIC_COLOR_KERNEL;
break;
default:
color = code >> 20;
color |= color << 4;
break;
}
if (g_panic_code == 0) {
display_init();
}
display_color_screen(color);
wait_for_button_and_reboot();
} else {
g_panic_code = 0;
APBDEV_PMC_SCRATCH200_0 = 0;
}
}
__attribute__ ((noreturn)) void panic(uint32_t code) {
/* Set panic code. */
if (g_panic_code == 0) {
@ -90,9 +31,13 @@ __attribute__ ((noreturn)) void panic(uint32_t code) {
APBDEV_PMC_SCRATCH200_0 = code;
}
/* Clear all keyslots. */
for (size_t i = 0; i < 0x10; i++) {
clear_aes_keyslot(i);
}
fuse_disable_programming();
APBDEV_PMC_CRYPTO_OP_0 = 1; /* Disable all SE operations. */
check_and_display_panic();
while(true);
}

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_PANIC_H
#define FUSEE_PANIC_H
@ -28,7 +28,6 @@
#define PANIC_CODE_SAFEMODE 0x00000020
void check_and_display_panic(void);
__attribute__ ((noreturn)) void panic(uint32_t code);
#endif

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/>.
*/
.macro CLEAR_GPR_REG_ITER
mov r\@, #0
.endm
@ -26,13 +26,18 @@
_start:
/* Switch to system mode, mask all interrupts, clear all flags */
msr cpsr_cxsf, #0xDF
b begin_relocation_loop
_version:
.word 0x00000000 /* Version. */
.word 0x00000000 /* Reserved. */
begin_relocation_loop:
/* Relocate ourselves if necessary */
ldr r2, =__start__
adr r3, _start
cmp r2, r3
beq _relocation_loop_end
/* If we are relocating, we are not rebooting to ourselves. Note that. */
ldr r0, =0x4003FFFC
mov r1, #0x0
@ -50,12 +55,12 @@ _start:
ldr r12, =_second_relocation_start
bx r12
_second_relocation_start:
ldr r4, =__bss_start__
sub r4, r4, r2
mov r1, #0x0
_second_relocation_loop:
ldmia r3!, {r5-r12}
stmia r2!, {r5-r12}
@ -67,7 +72,7 @@ _start:
bx r12
_relocation_loop_end:
/* Set the stack pointer */
ldr sp, =__stack_top__
mov fp, #0
@ -78,7 +83,9 @@ _start:
CLEAR_GPR_REG_ITER
.endr
ldr lr, =__program_exit
b main
ldr r0, =_version
ldr r0, [r0]
b sept_main
/* No need to include this in normal programs: */
.section .chainloader.text.start, "ax", %progbits

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 <stdbool.h>
#include <stdarg.h>
#include "utils.h"
@ -66,13 +66,16 @@ __attribute__((noreturn)) void pmc_reboot(uint32_t scratch0) {
}
void prepare_for_reboot_to_self(void) {
/* Write warmboot to scratch0. */
APBDEV_PMC_SCRATCH0_0 = 0x00000001;
/* Patch SDRAM init to perform an SVC immediately after second write */
APBDEV_PMC_SCRATCH45_0 = 0x2E38DFFF;
APBDEV_PMC_SCRATCH46_0 = 0x6001DC28;
/* Set SVC handler to jump to reboot stub in IRAM. */
APBDEV_PMC_SCRATCH33_0 = 0x4003F000;
APBDEV_PMC_SCRATCH40_0 = 0x6000F208;
/* Copy reboot stub into IRAM high. */
for (size_t i = 0; i < rebootstub_bin_size; i += sizeof(uint32_t)) {
write32le((void *)0x4003F000, i, read32le(rebootstub_bin, i));
@ -82,7 +85,7 @@ void prepare_for_reboot_to_self(void) {
__attribute__((noreturn)) void reboot_to_self(void) {
/* Prep IRAM for reboot. */
prepare_for_reboot_to_self();
/* Trigger warm reboot. */
pmc_reboot(1 << 0);
}

@ -1 +1 @@
Subproject commit 777984476ea7b1da56c9a3fd3f55575a8b899896
Subproject commit 7e0ed3b38f437791fdd398c7058c376c9d2a6853

View file

@ -37,7 +37,7 @@ class NpdmUtils {
u8 default_cpuid;
u32 _0x10;
u32 system_resource_size;
u32 process_category;
u32 version;
u32 main_stack_size;
char title_name[0x50];
u32 aci0_offset;

View file

@ -25,6 +25,35 @@
#include "ldr_npdm.hpp"
#include "ldr_nso.hpp"
static inline bool IsDisallowedVersion810(const u64 title_id, const u32 version) {
return version == 0 &&
(title_id == TitleId_Settings ||
title_id == TitleId_Bus ||
title_id == TitleId_Audio ||
title_id == TitleId_NvServices ||
title_id == TitleId_Ns ||
title_id == TitleId_Ssl ||
title_id == TitleId_Es ||
title_id == TitleId_Creport ||
title_id == TitleId_Ro);
}
Result ProcessCreation::ValidateProcessVersion(u64 title_id, u32 version) {
if (GetRuntimeFirmwareVersion() < FirmwareVersion_810) {
return ResultSuccess;
} else {
#ifdef LDR_VALIDATE_PROCESS_VERSION
if (IsDisallowedVersion810(title_id, version)) {
return ResultLoaderInvalidVersion;
} else {
return ResultSuccess;
}
#else
return ResultSuccess;
#endif
}
}
Result ProcessCreation::InitializeProcessInfo(NpdmUtils::NpdmInfo *npdm, Handle reslimit_h, u64 arg_flags, ProcessInfo *out_proc_info) {
/* Initialize a ProcessInfo using an npdm. */
*out_proc_info = {};
@ -36,8 +65,8 @@ Result ProcessCreation::InitializeProcessInfo(NpdmUtils::NpdmInfo *npdm, Handle
/* Set title id. */
out_proc_info->title_id = npdm->aci0->title_id;
/* Set process category. */
out_proc_info->process_category = npdm->header->process_category;
/* Set version. */
out_proc_info->version = npdm->header->version;
/* Copy reslimit handle raw. */
out_proc_info->reslimit_h = reslimit_h;
@ -145,6 +174,9 @@ Result ProcessCreation::CreateProcess(Handle *out_process_h, u64 index, char *nc
/* Load the process's NPDM. */
R_TRY(NpdmUtils::LoadNpdmFromCache(target_process->tid_sid.title_id, &npdm_info));
/* Validate version. */
R_TRY(ValidateProcessVersion(target_process->tid_sid.title_id, npdm_info.header->version));
/* Validate the title we're loading is what we expect. */
if (npdm_info.aci0->title_id < npdm_info.acid->title_id_range_min || npdm_info.aci0->title_id > npdm_info.acid->title_id_range_max) {
return ResultLoaderInvalidProgramId;

View file

@ -27,7 +27,7 @@ class ProcessCreation {
public:
struct ProcessInfo {
u8 name[12];
u32 process_category;
u32 version;
u64 title_id;
u64 code_addr;
u32 code_num_pages;
@ -35,6 +35,7 @@ class ProcessCreation {
Handle reslimit_h;
u32 system_resource_num_pages;
};
static Result ValidateProcessVersion(u64 title_id, u32 version);
static Result InitializeProcessInfo(NpdmUtils::NpdmInfo *npdm, Handle reslimit_h, u64 arg_flags, ProcessInfo *out_proc_info);
static Result CreateProcess(Handle *out_process_h, u64 index, char *nca_path, LaunchQueue::LaunchItem *launch_item, u64 arg_flags, Handle reslimit_h);
};