mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +00:00
Integrate 5.x SMC API changes, add 4.x specific setup, implement target firmware selection
This commit is contained in:
parent
c6ee1bffb7
commit
c2eed3caf6
34 changed files with 734 additions and 80 deletions
|
@ -11,7 +11,9 @@
|
|||
#define MAKE_ACTMON_REG(n) MAKE_REG32(ACTMON_BASE + n)
|
||||
|
||||
#define ACTMON_GLB_STATUS_0 MAKE_ACTMON_REG(0x000)
|
||||
#define ACTMON_GLB_PERIOD_CTRL_0 MAKE_ACTMON_REG(0x004)
|
||||
#define ACTMON_COP_CTRL_0 MAKE_ACTMON_REG(0x0C0)
|
||||
#define ACTMON_COP_UPPER_WMARK_0 MAKE_ACTMON_REG(0x0C4)
|
||||
#define ACTMON_COP_INTR_STATUS_0 MAKE_ACTMON_REG(0x0E4)
|
||||
|
||||
void actmon_interrupt_handler(void);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "bootconfig.h"
|
||||
|
||||
static boot_reason_t g_boot_reason = {0};
|
||||
static uint64_t g_package2_hash_for_recovery[4] = {0};
|
||||
|
||||
bool bootconfig_matches_hardware_info(void) {
|
||||
uint32_t hardware_info[4];
|
||||
|
@ -114,6 +115,16 @@ void bootconfig_load_boot_reason(volatile boot_reason_t *boot_reason) {
|
|||
g_boot_reason = *boot_reason;
|
||||
}
|
||||
|
||||
void bootconfig_set_package2_hash_for_recovery(const void *package2, size_t package2_size) {
|
||||
se_calculate_sha256(g_package2_hash_for_recovery, package2, package2_size);
|
||||
}
|
||||
|
||||
void bootconfig_get_package2_hash_for_recovery(uint64_t *out_hash) {
|
||||
for (unsigned int i = 0; i < 4; i++) {
|
||||
out_hash[i] = g_package2_hash_for_recovery[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool bootconfig_is_recovery_boot(void) {
|
||||
return (g_boot_reason.is_recovery_boot != 0);
|
||||
}
|
||||
|
|
|
@ -47,6 +47,9 @@ void bootconfig_clear(void);
|
|||
|
||||
void bootconfig_load_boot_reason(volatile boot_reason_t *boot_reason);
|
||||
|
||||
void bootconfig_set_package2_hash_for_recovery(const void *package2, size_t package2_size);
|
||||
void bootconfig_get_package2_hash_for_recovery(uint64_t *out_hash);
|
||||
|
||||
/* Actual configuration getters. */
|
||||
bool bootconfig_is_package2_plaintext(void);
|
||||
bool bootconfig_is_package2_unsigned(void);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "bootup.h"
|
||||
|
||||
#include "fuse.h"
|
||||
#include "bpmp.h"
|
||||
#include "flow.h"
|
||||
#include "pmc.h"
|
||||
#include "mc.h"
|
||||
|
@ -20,6 +21,7 @@
|
|||
#include "cpu_context.h"
|
||||
#include "actmon.h"
|
||||
#include "sysctr0.h"
|
||||
#include "exocfg.h"
|
||||
|
||||
#include "mmu.h"
|
||||
#include "arm.h"
|
||||
|
@ -49,7 +51,7 @@ void bootup_misc_mmio(void) {
|
|||
se_generate_srk(KEYSLOT_SWITCH_SRKGENKEY);
|
||||
|
||||
/* TODO: Why does this DRAM write occur? */
|
||||
if (!g_has_booted_up && mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) {
|
||||
if (!g_has_booted_up && exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
/* 4.x writes this magic number into DRAM. Why? */
|
||||
(*(volatile uint32_t *)(0x8005FFFC)) = 0xC0EDBBCC;
|
||||
}
|
||||
|
@ -94,7 +96,7 @@ void bootup_misc_mmio(void) {
|
|||
/* Also mark I2C5 secure only, */
|
||||
sec_disable_1 |= 0x20000000;
|
||||
}
|
||||
if (hardware_type != 0 && mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) {
|
||||
if (hardware_type != 0 && exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
/* Starting on 4.x on non-dev units, mark UARTB, UARTC, SPI4, I2C3 secure only. */
|
||||
sec_disable_1 |= 0x10806000;
|
||||
/* Starting on 4.x on non-dev units, mark SDMMC1 secure only. */
|
||||
|
@ -164,7 +166,7 @@ void bootup_misc_mmio(void) {
|
|||
set_core_is_active(core, false);
|
||||
}
|
||||
g_has_booted_up = true;
|
||||
} else if (mkey_get_revision() < MASTERKEY_REVISION_400_CURRENT) {
|
||||
} else if (exosphere_get_target_firmware() < EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
/* TODO: What are these MC reg writes? */
|
||||
MAKE_MC_REG(0x65C) = 0xFFFFF000;
|
||||
MAKE_MC_REG(0x660) = 0;
|
||||
|
@ -174,7 +176,61 @@ void bootup_misc_mmio(void) {
|
|||
}
|
||||
|
||||
void setup_4x_mmio(void) {
|
||||
/* TODO */
|
||||
/* TODO: What are these MC reg writes? */
|
||||
MAKE_MC_REG(0x65C) = 0xFFFFF000;
|
||||
MAKE_MC_REG(0x660) = 0;
|
||||
MAKE_MC_REG(0x964) |= 1;
|
||||
CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD_0 &= 0xFFF7FFFF;
|
||||
/* TODO: What are these PMC scratch writes? */
|
||||
APBDEV_PMC_SECURE_SCRATCH51_0 = (APBDEV_PMC_SECURE_SCRATCH51_0 & 0xFFFF8000) | 0x4000;
|
||||
APBDEV_PMC_SECURE_SCRATCH16_0 &= 0x3FFFFFFF;
|
||||
APBDEV_PMC_SECURE_SCRATCH55_0 = (APBDEV_PMC_SECURE_SCRATCH55_0 & 0xFF000FFF) | 0x1000;
|
||||
APBDEV_PMC_SECURE_SCRATCH74_0 = 0x40008000;
|
||||
APBDEV_PMC_SECURE_SCRATCH75_0 = 0x40000;
|
||||
APBDEV_PMC_SECURE_SCRATCH76_0 = 0x0;
|
||||
APBDEV_PMC_SECURE_SCRATCH77_0 = 0x0;
|
||||
APBDEV_PMC_SECURE_SCRATCH78_0 = 0x0;
|
||||
APBDEV_PMC_SECURE_SCRATCH99_0 = 0x40008000;
|
||||
APBDEV_PMC_SECURE_SCRATCH100_0 = 0x40000;
|
||||
APBDEV_PMC_SECURE_SCRATCH101_0 = 0x0;
|
||||
APBDEV_PMC_SECURE_SCRATCH102_0 = 0x0;
|
||||
APBDEV_PMC_SECURE_SCRATCH103_0 = 0x0;
|
||||
APBDEV_PMC_SECURE_SCRATCH39_0 = (APBDEV_PMC_SECURE_SCRATCH39_0 & 0xF8000000) | 0x88;
|
||||
/* TODO: Do we want to bother locking the secure scratch registers? */
|
||||
/* 4.x Jamais Vu mitigations. */
|
||||
/* Overwrite exception vectors. */
|
||||
BPMP_VECTOR_RESET = BPMP_MITIGATION_RESET_VAL;
|
||||
BPMP_VECTOR_UNDEF = BPMP_MITIGATION_RESET_VAL;
|
||||
BPMP_VECTOR_SWI = BPMP_MITIGATION_RESET_VAL;
|
||||
BPMP_VECTOR_PREFETCH_ABORT = BPMP_MITIGATION_RESET_VAL;
|
||||
BPMP_VECTOR_DATA_ABORT = BPMP_MITIGATION_RESET_VAL;
|
||||
BPMP_VECTOR_UNK = BPMP_MITIGATION_RESET_VAL;
|
||||
BPMP_VECTOR_IRQ = BPMP_MITIGATION_RESET_VAL;
|
||||
BPMP_VECTOR_FIQ = BPMP_MITIGATION_RESET_VAL;
|
||||
/* Disable AHB arbitration for the BPMP. */
|
||||
AHB_ARBITRATION_DISABLE_0 |= 2;
|
||||
/* Set SMMU for BPMP/APB-DMA to point to TZRAM. */
|
||||
MC_SMMU_PTB_ASID_0 = 1;
|
||||
MC_SMMU_PTB_DATA_0 = 0x70012;
|
||||
MC_SMMU_AVPC_ASID_0 = 0x80000001;
|
||||
MC_SMMU_PPCS1_ASID_0 = 0x80000001;
|
||||
/* Wait for the BPMP to halt. */
|
||||
while ((FLOW_CTLR_HALT_COP_EVENTS_0 >> 29) != 5) {
|
||||
wait(1);
|
||||
}
|
||||
/* If not in a debugging context, setup the activity monitor. */
|
||||
if ((get_debug_authentication_status() & 3) != 3) {
|
||||
FLOW_CTLR_HALT_COP_EVENTS_0 = 0x40000000;
|
||||
clkrst_reboot(CARDEVICE_ACTMON);
|
||||
/* Sample every microsecond. */
|
||||
ACTMON_GLB_PERIOD_CTRL_0 = 0x100;
|
||||
/* Fire interrupt every wakeup. */
|
||||
ACTMON_COP_UPPER_WMARK_0 = 0;
|
||||
/* Cause a panic() on BPMP wakeup. */
|
||||
actmon_set_callback(actmon_on_bpmp_wakeup);
|
||||
/* Enable interrupt when above watermark, periodic sampling. */
|
||||
ACTMON_COP_CTRL_0 = 0xC0040000;
|
||||
}
|
||||
}
|
||||
|
||||
void setup_current_core_state(void) {
|
||||
|
@ -226,7 +282,7 @@ void identity_unmap_iram_cd_tzram(void) {
|
|||
}
|
||||
|
||||
void secure_additional_devices(void) {
|
||||
if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) {
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0 |= 0x2000; /* make PMC secure-only (2.x+ but see note below) */
|
||||
APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0 |= 0X510; /* make MC0, MC1, MCB secure-only (4.x+) */
|
||||
} else {
|
||||
|
|
|
@ -23,4 +23,6 @@ static inline uintptr_t get_bpmp_vector_base(void) {
|
|||
#define BPMP_VECTOR_IRQ MAKE_REG32(BPMP_VECTOR_BASE + 0x218)
|
||||
#define BPMP_VECTOR_FIQ MAKE_REG32(BPMP_VECTOR_BASE + 0x21C)
|
||||
|
||||
#define BPMP_MITIGATION_RESET_VAL 0x7D000000
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,6 +10,7 @@ static inline uint32_t get_special_clk_reg(CarDevice dev) {
|
|||
case CARDEVICE_UARTB: return 0x17C;
|
||||
case CARDEVICE_I2C1: return 0x124;
|
||||
case CARDEVICE_I2C5: return 0x128;
|
||||
case CARDEVICE_ACTMON: return 0x3E8;
|
||||
case CARDEVICE_BPMP: return 0;
|
||||
default: generic_panic();
|
||||
}
|
||||
|
@ -21,6 +22,7 @@ static inline uint32_t get_special_clk_val(CarDevice dev) {
|
|||
case CARDEVICE_UARTB: return 0;
|
||||
case CARDEVICE_I2C1: return (6 << 29);
|
||||
case CARDEVICE_I2C5: return (6 << 29);
|
||||
case CARDEVICE_ACTMON: return (6 << 29);
|
||||
case CARDEVICE_BPMP: return 0;
|
||||
default: generic_panic();
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ typedef enum {
|
|||
CARDEVICE_UARTB = 7,
|
||||
CARDEVICE_I2C1 = 12,
|
||||
CARDEVICE_I2C5 = 47,
|
||||
CARDEVICE_ACTMON = 119,
|
||||
CARDEVICE_BPMP = 1
|
||||
} CarDevice;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "arm.h"
|
||||
#include "package2.h"
|
||||
#include "timers.h"
|
||||
#include "exocfg.h"
|
||||
|
||||
#undef MAILBOX_NX_BOOTLOADER_BASE
|
||||
#undef TIMERS_BASE
|
||||
|
@ -149,6 +150,7 @@ void coldboot_init(coldboot_crt0_reloc_list_t *reloc_list, boot_func_list_t *fun
|
|||
*/
|
||||
func_list->funcs.flush_dcache_all();
|
||||
func_list->funcs.invalidate_icache_all();
|
||||
|
||||
|
||||
/* TODO: Set NX BOOTLOADER clock time field */
|
||||
|
||||
|
@ -157,10 +159,13 @@ void coldboot_init(coldboot_crt0_reloc_list_t *reloc_list, boot_func_list_t *fun
|
|||
do_relocation(reloc_list, i);
|
||||
}
|
||||
/* At this point, we can (and will) access functions located in .warm_crt0 */
|
||||
|
||||
/* Set target firmware. */
|
||||
func_list->target_firmware = exosphere_get_target_firmware_physical();
|
||||
|
||||
/* Initialize DMA controllers, and write to AHB_GIZMO_TZRAM. */
|
||||
/* TZRAM accesses should work normally after this point. */
|
||||
func_list->funcs.init_dma_controllers();
|
||||
func_list->funcs.init_dma_controllers(func_list->target_firmware);
|
||||
|
||||
configure_ttbls();
|
||||
func_list->funcs.set_memory_registers_enable_mmu();
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "fuse.h"
|
||||
#include "utils.h"
|
||||
#include "masterkey.h"
|
||||
#include "exocfg.h"
|
||||
|
||||
static bool g_battery_profile = false;
|
||||
|
||||
|
@ -81,7 +82,7 @@ uint32_t configitem_get(ConfigItem item, uint64_t *p_outvalue) {
|
|||
break;
|
||||
case CONFIGITEM_BOOTREASON:
|
||||
/* For some reason, Nintendo removed it on 4.0 */
|
||||
if (mkey_get_revision() < MASTERKEY_REVISION_400_CURRENT) {
|
||||
if (exosphere_get_target_firmware() < EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
*p_outvalue = bootconfig_get_boot_reason();
|
||||
} else {
|
||||
result = 2;
|
||||
|
@ -101,12 +102,36 @@ uint32_t configitem_get(ConfigItem item, uint64_t *p_outvalue) {
|
|||
break;
|
||||
case CONFIGITEM_ODM4BIT10_4X:
|
||||
/* Added on 4.x ... where is it being used? */
|
||||
if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) {
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
*p_outvalue = (fuse_get_reserved_odm(4) >> 10) & 1;
|
||||
} else {
|
||||
result = 2;
|
||||
}
|
||||
break;
|
||||
case CONFIGITEM_NEWHARDWARETYPE_5X:
|
||||
/* Added in 5.x, currently hardcoded to 0. */
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_500) {
|
||||
*p_outvalue = 0;
|
||||
} else {
|
||||
result = 2;
|
||||
}
|
||||
break;
|
||||
case CONFIGITEM_NEWKEYGENERATION_5X:
|
||||
/* Added in 5.x. */
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_500) {
|
||||
*p_outvalue = fuse_get_5x_key_generation();
|
||||
} else {
|
||||
result = 2;
|
||||
}
|
||||
break;
|
||||
case CONFIGITEM_PACKAGE2HASH_5X:
|
||||
/* Added in 5.x. */
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_500 && bootconfig_is_recovery_boot()) {
|
||||
bootconfig_get_package2_hash_for_recovery(p_outvalue);
|
||||
} else {
|
||||
result = 2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
result = 2;
|
||||
break;
|
||||
|
|
|
@ -19,6 +19,9 @@ typedef enum {
|
|||
CONFIGITEM_KERNELMEMORYCONFIGURATION = 12,
|
||||
CONFIGITEM_BATTERYPROFILE = 13,
|
||||
CONFIGITEM_ODM4BIT10_4X = 14,
|
||||
CONFIGITEM_NEWHARDWARETYPE_5X = 15,
|
||||
CONFIGITEM_NEWKEYGENERATION_5X = 16,
|
||||
CONFIGITEM_PACKAGE2HASH_5X = 17
|
||||
} ConfigItem;
|
||||
|
||||
uint32_t configitem_set(ConfigItem item, uint64_t value);
|
||||
|
|
37
exosphere/src/exocfg.c
Normal file
37
exosphere/src/exocfg.c
Normal file
|
@ -0,0 +1,37 @@
|
|||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "exocfg.h"
|
||||
#include "mmu.h"
|
||||
#include "memory_map.h"
|
||||
|
||||
#define MAILBOX_BASE (MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_NXBOOTLOADER_MAILBOX))
|
||||
|
||||
/* TODO: Should this be at a non-static location? */
|
||||
#define MAILBOX_EXOSPHERE_CONFIG (*((volatile exosphere_config_t *)(MAILBOX_BASE + 0xE40ULL)))
|
||||
|
||||
static exosphere_config_t g_exosphere_cfg = {MAGIC_ATMOSPHERE, EXOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG};
|
||||
static bool g_has_loaded_config = false;
|
||||
|
||||
/* Read config out of IRAM, return target firmware version. */
|
||||
unsigned int exosphere_load_config(void) {
|
||||
if (g_has_loaded_config) {
|
||||
generic_panic();
|
||||
}
|
||||
g_has_loaded_config = true;
|
||||
|
||||
if (MAILBOX_EXOSPHERE_CONFIG.magic == MAGIC_ATMOSPHERE) {
|
||||
g_exosphere_cfg = MAILBOX_EXOSPHERE_CONFIG;
|
||||
}
|
||||
|
||||
return g_exosphere_cfg.target_firmware;
|
||||
}
|
||||
|
||||
unsigned int exosphere_get_target_firmware(void) {
|
||||
if (!g_has_loaded_config) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
return g_exosphere_cfg.target_firmware;
|
||||
}
|
41
exosphere/src/exocfg.h
Normal file
41
exosphere/src/exocfg.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#ifndef EXOSPHERE_EXOSPHERE_CONFIG_H
|
||||
#define EXOSPHERE_EXOSPHERE_CONFIG_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "utils.h"
|
||||
|
||||
#include "memory_map.h"
|
||||
|
||||
/* This serves to set configuration for *exosphere itself*, separate from the SecMon Exosphere mimics. */
|
||||
|
||||
/* "AMS0" */
|
||||
#define MAGIC_ATMOSPHERE (0x30534D41)
|
||||
|
||||
#define EXOSPHERE_TARGET_FIRMWARE_100 1
|
||||
#define EXOSPHERE_TARGET_FIRMWARE_200 2
|
||||
#define EXOSPHERE_TARGET_FIRMWARE_300 3
|
||||
#define EXOSPHERE_TARGET_FIRMWARE_400 4
|
||||
#define EXOSPHERE_TARGET_FIRMWARE_500 5
|
||||
|
||||
/* TODO: What should this be, for release? */
|
||||
#define EXOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG EXOSPHERE_TARGET_FIRMWARE_200
|
||||
|
||||
#define MAILBOX_BASE_PHYS (MMIO_GET_DEVICE_PA(MMIO_DEVID_NXBOOTLOADER_MAILBOX))
|
||||
|
||||
/* TODO: Should this be at a non-static location? */
|
||||
#define MAILBOX_EXOSPHERE_CONFIG_PHYS (*((volatile exosphere_config_t *)(MAILBOX_BASE_PHYS + 0xE40ULL)))
|
||||
|
||||
|
||||
typedef struct {
|
||||
unsigned int magic;
|
||||
unsigned int target_firmware;
|
||||
} exosphere_config_t;
|
||||
|
||||
unsigned int exosphere_load_config(void);
|
||||
unsigned int exosphere_get_target_firmware(void);
|
||||
|
||||
static inline unsigned int exosphere_get_target_firmware_physical(void) {
|
||||
return MAILBOX_EXOSPHERE_CONFIG_PHYS.magic == MAGIC_ATMOSPHERE ? MAILBOX_EXOSPHERE_CONFIG_PHYS.target_firmware : EXOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -4,6 +4,7 @@
|
|||
#include "fuse.h"
|
||||
#include "utils.h"
|
||||
#include "timers.h"
|
||||
#include "exocfg.h"
|
||||
|
||||
#include "masterkey.h"
|
||||
/* Prototypes for internal commands. */
|
||||
|
@ -150,6 +151,14 @@ uint32_t fuse_get_reserved_odm(uint32_t idx)
|
|||
return FUSE_CHIP_REGS->FUSE_RESERVED_ODM[idx];
|
||||
}
|
||||
|
||||
uint32_t fuse_get_5x_key_generation(void) {
|
||||
if ((fuse_get_reserved_odm(4) & 0x800) && fuse_get_reserved_odm(0) == 0x8E61ECAE && fuse_get_reserved_odm(1) == 0xF2BA3BB2) {
|
||||
return fuse_get_reserved_odm(2) & 0x1F;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Derive the Device ID using values in the shadow cache */
|
||||
uint64_t fuse_get_device_id(void) {
|
||||
uint64_t device_id = 0;
|
||||
|
@ -182,7 +191,7 @@ uint32_t fuse_get_hardware_type(void) {
|
|||
/* This function is very different between 4.x and < 4.x */
|
||||
uint32_t hardware_type = ((FUSE_CHIP_REGS->FUSE_RESERVED_ODM[4] >> 7) & 2) | ((FUSE_CHIP_REGS->FUSE_RESERVED_ODM[4] >> 2) & 1);
|
||||
|
||||
if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) {
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
static const uint32_t types[] = {0,1,4,3};
|
||||
|
||||
hardware_type |= (FUSE_CHIP_REGS->FUSE_RESERVED_ODM[4] >> 14) & 0x3C;
|
||||
|
|
|
@ -190,6 +190,8 @@ uint32_t fuse_get_sku_info(void);
|
|||
uint32_t fuse_get_spare_bit(uint32_t idx);
|
||||
uint32_t fuse_get_reserved_odm(uint32_t idx);
|
||||
|
||||
uint32_t fuse_get_5x_key_generation(void);
|
||||
|
||||
uint32_t fuse_get_bootrom_patch_version(void);
|
||||
uint64_t fuse_get_device_id(void);
|
||||
uint32_t fuse_get_dram_id(void);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "arm.h"
|
||||
#include "utils.h"
|
||||
#include "fuse.h"
|
||||
#include "gcm.h"
|
||||
|
@ -112,7 +113,7 @@ static void ghash(void *dst, const void *data, size_t data_size, const void *j_b
|
|||
|
||||
|
||||
/* This function is a doozy. It decrypts and validates a (non-standard) AES-GCM wrapped keypair. */
|
||||
size_t gcm_decrypt_key(void *dst, size_t dst_size, const void *src, size_t src_size, const void *sealed_kek, size_t kek_size, const void *wrapped_key, size_t key_size, unsigned int usecase, bool is_personalized) {
|
||||
size_t gcm_decrypt_key(void *dst, size_t dst_size, const void *src, size_t src_size, const void *sealed_kek, size_t kek_size, const void *wrapped_key, size_t key_size, unsigned int usecase, bool is_personalized, uint8_t *out_deviceid_high) {
|
||||
if (is_personalized == 0) {
|
||||
/* Devkit keys use a different keyformat without a MAC/Device ID. */
|
||||
if (src_size <= 0x10 || src_size - 0x10 > dst_size) {
|
||||
|
@ -163,8 +164,48 @@ size_t gcm_decrypt_key(void *dst, size_t dst_size, const void *src, size_t src_s
|
|||
if ((read64be(intermediate_buf, src_size - 0x28) & 0x00FFFFFFFFFFFFFFULL) != fuse_get_device_id()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (out_deviceid_high != NULL) {
|
||||
*out_deviceid_high = intermediate_buf[src_size - 0x28];
|
||||
}
|
||||
|
||||
memcpy(dst, intermediate_buf, src_size - 0x30);
|
||||
memset(intermediate_buf, 0, sizeof(intermediate_buf));
|
||||
return src_size - 0x30;
|
||||
}
|
||||
|
||||
void gcm_encrypt_key(void *dst, size_t dst_size, const void *src, size_t src_size, const void *sealed_kek, size_t kek_size, const void *wrapped_key, size_t key_size, unsigned int usecase, uint64_t deviceid_high) {
|
||||
uint8_t intermediate_buf[0x400] = {0};
|
||||
if (src_size + 0x30 > dst_size) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Unwrap the key */
|
||||
unseal_key(KEYSLOT_SWITCH_TEMPKEY, sealed_kek, kek_size, usecase);
|
||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, KEYSLOT_SWITCH_TEMPKEY, wrapped_key, key_size);
|
||||
|
||||
/* Generate a random CTR. */
|
||||
flush_dcache_range(intermediate_buf, intermediate_buf + 0x10);
|
||||
se_generate_random(KEYSLOT_SWITCH_RNGKEY, intermediate_buf, 0x10);
|
||||
flush_dcache_range(intermediate_buf, intermediate_buf + 0x10);
|
||||
|
||||
/* Write Device ID. */
|
||||
write64be(intermediate_buf, src_size + 0x18, fuse_get_device_id() | (deviceid_high << 56));
|
||||
|
||||
|
||||
/* J = GHASH(CTR); */
|
||||
uint8_t j_block[0x10];
|
||||
ghash(j_block, intermediate_buf, 0x10, NULL, false);
|
||||
|
||||
/* MAC = GHASH(PLAINTEXT) ^ ENCRYPT(J) */
|
||||
/* Note: That MAC is calculated over plaintext is non-standard. */
|
||||
/* It is supposed to be over the ciphertext. */
|
||||
ghash(intermediate_buf + src_size + 0x20, intermediate_buf + 0x10, src_size + 0x10, j_block, true);
|
||||
|
||||
/* Encrypt the GCM keypair, AES-CTR with CTR = blob[:0x10]. */
|
||||
se_aes_ctr_crypt(KEYSLOT_SWITCH_TEMPKEY, intermediate_buf + 0x10, src_size + 0x10, intermediate_buf + 0x10, src_size + 0x10, intermediate_buf, 0x10);
|
||||
|
||||
/* Copy the wrapped key out. */
|
||||
memcpy(dst, intermediate_buf, src_size + 0x30);
|
||||
memset(intermediate_buf, 0, sizeof(intermediate_buf));
|
||||
}
|
||||
|
|
|
@ -8,6 +8,14 @@ size_t gcm_decrypt_key(void *dst, size_t dst_size,
|
|||
const void *src, size_t src_size,
|
||||
const void *sealed_kek, size_t kek_size,
|
||||
const void *wrapped_key, size_t key_size,
|
||||
unsigned int usecase, bool is_personalized);
|
||||
unsigned int usecase, bool is_personalized,
|
||||
uint8_t *out_deviceid_high);
|
||||
|
||||
|
||||
void gcm_encrypt_key(void *dst, size_t dst_size,
|
||||
const void *src, size_t src_size,
|
||||
const void *sealed_kek, size_t kek_size,
|
||||
const void *wrapped_key, size_t key_size,
|
||||
unsigned int usecase, uint64_t deviceid_high);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "smc_api.h"
|
||||
#include "timers.h"
|
||||
#include "misc.h"
|
||||
#include "exocfg.h"
|
||||
|
||||
extern const uint8_t bpmpfw_bin[];
|
||||
extern const uint32_t bpmpfw_bin_size;
|
||||
|
@ -123,14 +124,14 @@ uint32_t cpu_suspend(uint64_t power_state, uint64_t entrypoint, uint64_t argumen
|
|||
}
|
||||
|
||||
/* For debugging, make this check always pass. */
|
||||
if ((mkey_get_revision() < MASTERKEY_REVISION_400_CURRENT || (get_debug_authentication_status() & 3) == 3)) {
|
||||
if ((exosphere_get_target_firmware() < EXOSPHERE_TARGET_FIRMWARE_400 || (get_debug_authentication_status() & 3) == 3)) {
|
||||
FLOW_CTLR_HALT_COP_EVENTS_0 = 0x50000000;
|
||||
} else {
|
||||
FLOW_CTLR_HALT_COP_EVENTS_0 = 0x40000000;
|
||||
}
|
||||
|
||||
/* Jamais Vu mitigation #2: Ensure the BPMP is halted. */
|
||||
if (mkey_get_revision() < MASTERKEY_REVISION_400_CURRENT || (get_debug_authentication_status() & 3) == 3) {
|
||||
if (exosphere_get_target_firmware() < EXOSPHERE_TARGET_FIRMWARE_400 || (get_debug_authentication_status() & 3) == 3) {
|
||||
/* BPMP should just be plainly halted, in debugging conditions. */
|
||||
if (FLOW_CTLR_HALT_COP_EVENTS_0 != 0x50000000) {
|
||||
generic_panic();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "masterkey.h"
|
||||
|
@ -9,6 +10,7 @@ static unsigned int g_mkey_revision = 0;
|
|||
static bool g_determined_mkey_revision = false;
|
||||
|
||||
static uint8_t g_old_masterkeys[MASTERKEY_REVISION_MAX][0x10];
|
||||
static uint8_t g_old_devicekeys[MASTERKEY_NUM_NEW_DEVICE_KEYS - 1][0x10];
|
||||
|
||||
/* TODO: Dev keys. */
|
||||
|
||||
|
@ -19,6 +21,7 @@ static const uint8_t mkey_vectors[MASTERKEY_REVISION_MAX][0x10] =
|
|||
{0x29, 0x4C, 0x04, 0xC8, 0xEB, 0x10, 0xED, 0x9D, 0x51, 0x64, 0x97, 0xFB, 0xF3, 0x4D, 0x50, 0xDD}, /* Master key 00 encrypted with Master key 01. */
|
||||
{0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72}, /* Master key 01 encrypted with Master key 02. */
|
||||
{0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07}, /* Master key 02 encrypted with Master key 03. */
|
||||
{0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9}, /* Master key 03 encrypted with Master key 04. */
|
||||
};
|
||||
|
||||
bool check_mkey_revision(unsigned int revision) {
|
||||
|
@ -88,3 +91,34 @@ unsigned int mkey_get_keyslot(unsigned int revision) {
|
|||
return KEYSLOT_SWITCH_TEMPKEY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void set_old_devkey(unsigned int revision, const uint8_t *key) {
|
||||
if (revision < MASTERKEY_REVISION_400_410 || MASTERKEY_REVISION_500_CURRENT <= revision) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
memcpy(g_old_devicekeys[revision - MASTERKEY_REVISION_400_410], key, 0x10);
|
||||
}
|
||||
|
||||
unsigned int devkey_get_keyslot(unsigned int revision) {
|
||||
if (!g_determined_mkey_revision || revision >= MASTERKEY_REVISION_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
if (revision > g_mkey_revision) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
if (revision >= 1) {
|
||||
if (revision == MASTERKEY_REVISION_500_CURRENT) {
|
||||
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 {
|
||||
return KEYSLOT_SWITCH_4XOLDDEVICEKEY;
|
||||
}
|
||||
}
|
|
@ -3,13 +3,16 @@
|
|||
|
||||
/* This is glue code to enable master key support across versions. */
|
||||
|
||||
/* TODO: Update to 0x5 on release of new master key. */
|
||||
#define MASTERKEY_REVISION_MAX 0x4
|
||||
/* TODO: Update to 0x6 on release of new master key. */
|
||||
#define MASTERKEY_REVISION_MAX 0x5
|
||||
|
||||
#define MASTERKEY_REVISION_100_230 0x00
|
||||
#define MASTERKEY_REVISION_300 0x01
|
||||
#define MASTERKEY_REVISION_301_302 0x02
|
||||
#define MASTERKEY_REVISION_400_CURRENT 0x03
|
||||
#define MASTERKEY_REVISION_400_410 0x03
|
||||
#define MASTERKEY_REVISION_500_CURRENT 0x04
|
||||
|
||||
#define MASTERKEY_NUM_NEW_DEVICE_KEYS (MASTERKEY_REVISION_MAX - MASTERKEY_REVISION_400_410)
|
||||
|
||||
/* This should be called early on in initialization. */
|
||||
void mkey_detect_revision(void);
|
||||
|
@ -18,4 +21,7 @@ unsigned int mkey_get_revision(void);
|
|||
|
||||
unsigned int mkey_get_keyslot(unsigned int revision);
|
||||
|
||||
void set_old_devkey(unsigned int revision, const uint8_t *key);
|
||||
unsigned int devkey_get_keyslot(unsigned int revision);
|
||||
|
||||
#endif
|
|
@ -14,6 +14,11 @@ static inline uintptr_t get_mc_base(void) {
|
|||
|
||||
#define MAKE_MC_REG(n) MAKE_REG32(MC_BASE + n)
|
||||
|
||||
#define MC_SMMU_PTB_ASID_0 MAKE_MC_REG(0x01C)
|
||||
#define MC_SMMU_PTB_DATA_0 MAKE_MC_REG(0x020)
|
||||
#define MC_SMMU_AVPC_ASID_0 MAKE_MC_REG(0x23C)
|
||||
#define MC_SMMU_PPCS1_ASID_0 MAKE_MC_REG(0x298)
|
||||
|
||||
#define MC_SECURITY_CFG0_0 MAKE_MC_REG(0x070)
|
||||
#define MC_SECURITY_CFG1_0 MAKE_MC_REG(0x074)
|
||||
#define MC_SECURITY_CFG3_0 MAKE_MC_REG(0x9BC)
|
||||
|
|
|
@ -15,10 +15,37 @@
|
|||
#include "randomcache.h"
|
||||
#include "timers.h"
|
||||
#include "bootconfig.h"
|
||||
#include "exocfg.h"
|
||||
#include "smc_api.h"
|
||||
|
||||
extern void *__start_cold_addr;
|
||||
extern size_t __bin_size;
|
||||
|
||||
static void derive_new_device_keys(unsigned int keygen_keyslot) {
|
||||
uint8_t work_buffer[0x10];
|
||||
static const uint8_t new_device_key_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
|
||||
{0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.x New Device Key Source. */
|
||||
{0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C} /* 5.x New Device Key Source. */
|
||||
};
|
||||
|
||||
static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
|
||||
{0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.x New Device Keygen Source. */
|
||||
{0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E} /* 5.x New Device Keygen Source. */
|
||||
};
|
||||
for (unsigned int revision = 0; revision < MASTERKEY_NUM_NEW_DEVICE_KEYS; revision++) {
|
||||
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), new_device_keygen_sources[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);
|
||||
} else {
|
||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10);
|
||||
}
|
||||
}
|
||||
set_aes_keyslot_flags(KEYSLOT_SWITCH_DEVICEKEY, 0xFF);
|
||||
clear_aes_keyslot(keygen_keyslot);
|
||||
}
|
||||
|
||||
/* Hardware init, sets up the RNG and SESSION keyslots, derives new DEVICE key. */
|
||||
static void setup_se(void) {
|
||||
uint8_t work_buffer[0x10];
|
||||
|
@ -52,13 +79,18 @@ static void setup_se(void) {
|
|||
/* Detect Master Key revision. */
|
||||
mkey_detect_revision();
|
||||
|
||||
/* Setup new device key, if necessary. */
|
||||
if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) {
|
||||
const uint8_t new_devicekey_source_4x[0x10] = {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D};
|
||||
se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_4XNEWDEVICEKEYGENKEY, work_buffer, 0x10, new_devicekey_source_4x, 0x10);
|
||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_4XNEWCONSOLEKEYGENKEY, work_buffer, 0x10);
|
||||
clear_aes_keyslot(KEYSLOT_SWITCH_4XNEWCONSOLEKEYGENKEY);
|
||||
set_aes_keyslot_flags(KEYSLOT_SWITCH_DEVICEKEY, 0xFF);
|
||||
/* Derive new device keys. */
|
||||
switch (exosphere_get_target_firmware()) {
|
||||
case EXOSPHERE_TARGET_FIRMWARE_100:
|
||||
case EXOSPHERE_TARGET_FIRMWARE_200:
|
||||
case EXOSPHERE_TARGET_FIRMWARE_300:
|
||||
break;
|
||||
case EXOSPHERE_TARGET_FIRMWARE_400:
|
||||
derive_new_device_keys(KEYSLOT_SWITCH_4XNEWDEVICEKEYGENKEY);
|
||||
break;
|
||||
case EXOSPHERE_TARGET_FIRMWARE_500:
|
||||
derive_new_device_keys(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY);
|
||||
break;
|
||||
}
|
||||
|
||||
se_initialize_rng(KEYSLOT_SWITCH_DEVICEKEY);
|
||||
|
@ -151,6 +183,10 @@ static void verify_header_signature(package2_header_t *header) {
|
|||
}
|
||||
}
|
||||
|
||||
static uint32_t get_package2_size(package2_meta_t *metadata) {
|
||||
return metadata->ctr_dwords[0] ^ metadata->ctr_dwords[2] ^ metadata->ctr_dwords[3];
|
||||
}
|
||||
|
||||
static bool validate_package2_metadata(package2_meta_t *metadata) {
|
||||
if (metadata->magic != MAGIC_PK21) {
|
||||
return false;
|
||||
|
@ -355,6 +391,9 @@ uintptr_t get_pk2ldr_stack_address(void) {
|
|||
/* This function is called during coldboot init, and validates a package2. */
|
||||
/* This package2 is read into memory by a concurrent BPMP bootloader. */
|
||||
void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
|
||||
/* Load Exosphere-specific config. */
|
||||
exosphere_load_config();
|
||||
|
||||
/* Setup the Security Engine. */
|
||||
setup_se();
|
||||
|
||||
|
@ -385,7 +424,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
|
|||
setup_boot_config();
|
||||
|
||||
/* Synchronize with NX BOOTLOADER. */
|
||||
if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) {
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
sync_with_nx_bootloader(NX_BOOTLOADER_STATE_DRAM_INITIALIZED_4X);
|
||||
/* TODO: copy_warmboot_bin_to_dram(); */
|
||||
sync_with_nx_bootloader(NX_BOOTLOADER_STATE_LOADED_PACKAGE2_4X);
|
||||
|
@ -411,6 +450,11 @@ 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));
|
||||
}
|
||||
|
||||
/* Load Package2 Sections. */
|
||||
load_package2_sections(&header.metadata, package2_mkey_rev);
|
||||
|
||||
|
@ -427,12 +471,15 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
|
|||
/* Synchronize with NX BOOTLOADER. */
|
||||
sync_with_nx_bootloader(NX_BOOTLOADER_STATE_FINISHED);
|
||||
|
||||
if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) {
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
sync_with_nx_bootloader(NX_BOOTLOADER_STATE_FINISHED_4X);
|
||||
setup_4x_mmio(); /* TODO */
|
||||
setup_4x_mmio();
|
||||
} else {
|
||||
sync_with_nx_bootloader(NX_BOOTLOADER_STATE_FINISHED);
|
||||
}
|
||||
|
||||
/* Prepare the SMC API with version-dependent SMCs. */
|
||||
set_version_specific_smcs();
|
||||
|
||||
/* Update SCR_EL3 depending on value in Bootconfig. */
|
||||
set_extabt_serror_taken_to_el3(bootconfig_take_extabt_serror_to_el3());
|
||||
|
|
|
@ -39,6 +39,20 @@ static inline uintptr_t get_pmc_base(void) {
|
|||
#define APBDEV_PMC_SECURE_SCRATCH34_0 MAKE_REG32(PMC_BASE + 0x368)
|
||||
#define APBDEV_PMC_SECURE_SCRATCH35_0 MAKE_REG32(PMC_BASE + 0x36C)
|
||||
|
||||
#define APBDEV_PMC_SECURE_SCRATCH16_0 MAKE_REG32(PMC_BASE + 0x320)
|
||||
#define APBDEV_PMC_SECURE_SCRATCH51_0 MAKE_REG32(PMC_BASE + 0x3AC)
|
||||
#define APBDEV_PMC_SECURE_SCRATCH55_0 MAKE_REG32(PMC_BASE + 0x3BC)
|
||||
#define APBDEV_PMC_SECURE_SCRATCH74_0 MAKE_REG32(PMC_BASE + 0x408)
|
||||
#define APBDEV_PMC_SECURE_SCRATCH75_0 MAKE_REG32(PMC_BASE + 0x40C)
|
||||
#define APBDEV_PMC_SECURE_SCRATCH76_0 MAKE_REG32(PMC_BASE + 0x410)
|
||||
#define APBDEV_PMC_SECURE_SCRATCH77_0 MAKE_REG32(PMC_BASE + 0x414)
|
||||
#define APBDEV_PMC_SECURE_SCRATCH78_0 MAKE_REG32(PMC_BASE + 0x418)
|
||||
#define APBDEV_PMC_SECURE_SCRATCH99_0 MAKE_REG32(PMC_BASE + 0xAE4)
|
||||
#define APBDEV_PMC_SECURE_SCRATCH100_0 MAKE_REG32(PMC_BASE + 0xAE8)
|
||||
#define APBDEV_PMC_SECURE_SCRATCH101_0 MAKE_REG32(PMC_BASE + 0xAEC)
|
||||
#define APBDEV_PMC_SECURE_SCRATCH102_0 MAKE_REG32(PMC_BASE + 0xAF0)
|
||||
#define APBDEV_PMC_SECURE_SCRATCH103_0 MAKE_REG32(PMC_BASE + 0xAF4)
|
||||
#define APBDEV_PMC_SECURE_SCRATCH39_0 MAKE_REG32(PMC_BASE + 0x37C)
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
#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
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "exocfg.h"
|
||||
#include "sealedkeys.h"
|
||||
#include "se.h"
|
||||
|
||||
|
@ -9,13 +10,24 @@ static const uint8_t g_titlekey_seal_key_source[0x10] = {
|
|||
0xCB, 0xB7, 0x6E, 0x38, 0xA1, 0xCB, 0x77, 0x0F, 0xB2, 0xA5, 0xB2, 0x9D, 0xD8, 0x56, 0x9F, 0x76
|
||||
};
|
||||
|
||||
static const uint8_t g_seal_key_sources[CRYPTOUSECASE_MAX][0x10] = {
|
||||
static const uint8_t g_seal_key_sources[CRYPTOUSECASE_MAX_5X][0x10] = {
|
||||
{0xF4, 0x0C, 0x16, 0x26, 0x0D, 0x46, 0x3B, 0xE0, 0x8C, 0x6A, 0x56, 0xE5, 0x82, 0xD4, 0x1B, 0xF6},
|
||||
{0x7F, 0x54, 0x2C, 0x98, 0x1E, 0x54, 0x18, 0x3B, 0xBA, 0x63, 0xBD, 0x4C, 0x13, 0x5B, 0xF1, 0x06},
|
||||
{0xC7, 0x3F, 0x73, 0x60, 0xB7, 0xB9, 0x9D, 0x74, 0x0A, 0xF8, 0x35, 0x60, 0x1A, 0x18, 0x74, 0x63},
|
||||
{0x0E, 0xE0, 0xC4, 0x33, 0x82, 0x66, 0xE8, 0x08, 0x39, 0x13, 0x41, 0x7D, 0x04, 0x64, 0x2B, 0x6D}
|
||||
{0x0E, 0xE0, 0xC4, 0x33, 0x82, 0x66, 0xE8, 0x08, 0x39, 0x13, 0x41, 0x7D, 0x04, 0x64, 0x2B, 0x6D},
|
||||
{0xE1, 0xA8, 0xAA, 0x6A, 0x2D, 0x9C, 0xDE, 0x43, 0x0C, 0xDE, 0xC6, 0x17, 0xF6, 0xC7, 0xF1, 0xDE},
|
||||
{0x74, 0x20, 0xF6, 0x46, 0x77, 0xB0, 0x59, 0x2C, 0xE8, 0x1B, 0x58, 0x64, 0x47, 0x41, 0x37, 0xD9},
|
||||
{0xAA, 0x19, 0x0F, 0xFA, 0x4C, 0x30, 0x3B, 0x2E, 0xE8, 0x1B, 0x58, 0x64, 0x47, 0x41, 0x37, 0xD9}
|
||||
};
|
||||
|
||||
bool usecase_is_invalid(unsigned int usecase) {
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_500) {
|
||||
return usecase >= CRYPTOUSECASE_MAX_5X;
|
||||
} else {
|
||||
return usecase >= CRYPTOUSECASE_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
void seal_key_internal(void *dst, const void *src, const uint8_t *seal_key_source) {
|
||||
decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, KEYSLOT_SWITCH_SESSIONKEY, seal_key_source, 0x10);
|
||||
se_aes_128_ecb_encrypt_block(KEYSLOT_SWITCH_TEMPKEY, dst, 0x10, src, 0x10);
|
||||
|
@ -46,7 +58,7 @@ void unseal_titlekey(unsigned int keyslot, const void *src, size_t src_size) {
|
|||
|
||||
|
||||
void seal_key(void *dst, size_t dst_size, const void *src, size_t src_size, unsigned int usecase) {
|
||||
if (usecase >= CRYPTOUSECASE_MAX || dst_size != 0x10 || src_size != 0x10) {
|
||||
if (usecase_is_invalid(usecase) || dst_size != 0x10 || src_size != 0x10) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
|
@ -55,7 +67,7 @@ void seal_key(void *dst, size_t dst_size, const void *src, size_t src_size, unsi
|
|||
}
|
||||
|
||||
void unseal_key(unsigned int keyslot, const void *src, size_t src_size, unsigned int usecase) {
|
||||
if (usecase >= CRYPTOUSECASE_MAX || src_size != 0x10) {
|
||||
if (usecase_is_invalid(usecase) || src_size != 0x10) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,12 @@
|
|||
#define CRYPTOUSECASE_RSAPRIVATE 1
|
||||
#define CRYPTOUSECASE_SECUREEXPMOD 2
|
||||
#define CRYPTOUSECASE_RSAOAEP 3
|
||||
#define CRYPTOUSECASE_RSAIMPORT 4
|
||||
#define CRYPTOUSECASE_UNK5 5
|
||||
#define CRYPTOUSECASE_UNK6 6
|
||||
|
||||
#define CRYPTOUSECASE_MAX 4
|
||||
#define CRYPTOUSECASE_MAX_5X 7
|
||||
|
||||
void seal_titlekey(void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
void unseal_titlekey(unsigned int keyslot, const void *src, size_t src_size);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "userpage.h"
|
||||
#include "titlekey.h"
|
||||
#include "lp0.h"
|
||||
#include "exocfg.h"
|
||||
|
||||
#define SMC_USER_HANDLERS 0x13
|
||||
#define SMC_PRIV_HANDLERS 0x9
|
||||
|
@ -43,6 +44,10 @@ uint32_t smc_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args);
|
|||
uint32_t smc_load_titlekey(smc_args_t *args);
|
||||
uint32_t smc_unwrap_aes_wrapped_titlekey(smc_args_t *args);
|
||||
|
||||
/* 5.x SMC prototypes. */
|
||||
uint32_t smc_encrypt_rsa_key_for_import(smc_args_t *args);
|
||||
uint32_t smc_decrypt_or_import_rsa_key(smc_args_t *args);
|
||||
|
||||
/* Privileged SMC prototypes */
|
||||
uint32_t smc_cpu_suspend(smc_args_t *args);
|
||||
uint32_t smc_cpu_off(smc_args_t *args);
|
||||
|
@ -114,6 +119,32 @@ static atomic_flag g_is_priv_smc_in_progress = ATOMIC_FLAG_INIT;
|
|||
/* Global for smc_configure_carveout. */
|
||||
static bool g_configured_carveouts[2] = {false, false};
|
||||
|
||||
void set_version_specific_smcs(void) {
|
||||
switch (exosphere_get_target_firmware()) {
|
||||
case EXOSPHERE_TARGET_FIRMWARE_100:
|
||||
/* 1.0.0 doesn't have ConfigureCarveout or ReadWriteRegister. */
|
||||
g_smc_priv_table[7].handler = NULL;
|
||||
g_smc_priv_table[8].handler = NULL;
|
||||
/* 1.0.0 doesn't have UnwrapAesWrappedTitlekey. */
|
||||
g_smc_user_table[0x12].handler = NULL;
|
||||
break;
|
||||
case EXOSPHERE_TARGET_FIRMWARE_200:
|
||||
case EXOSPHERE_TARGET_FIRMWARE_300:
|
||||
case EXOSPHERE_TARGET_FIRMWARE_400:
|
||||
/* Do nothing. */
|
||||
break;
|
||||
case EXOSPHERE_TARGET_FIRMWARE_500:
|
||||
/* No more LoadSecureExpModKey. */
|
||||
g_smc_user_table[0xE].handler = NULL;
|
||||
g_smc_user_table[0xC].id = 0xC300D60C;
|
||||
g_smc_user_table[0xC].handler = smc_encrypt_rsa_key_for_import;
|
||||
g_smc_user_table[0xD].handler = smc_decrypt_or_import_rsa_key;
|
||||
break;
|
||||
default:
|
||||
panic_predefined(0xF);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uintptr_t get_smc_core012_stack_address(void) {
|
||||
return TZRAM_GET_SEGMENT_ADDRESS(TZRAM_SEGMENT_ID_CORE012_STACK) + 0x1000;
|
||||
|
@ -427,6 +458,15 @@ uint32_t smc_unwrap_aes_wrapped_titlekey(smc_args_t *args) {
|
|||
return smc_wrapper_sync(args, user_unwrap_aes_wrapped_titlekey);
|
||||
}
|
||||
|
||||
uint32_t smc_encrypt_rsa_key_for_import(smc_args_t *args) {
|
||||
return smc_wrapper_sync(args, user_encrypt_rsa_key_for_import);
|
||||
}
|
||||
|
||||
uint32_t smc_decrypt_or_import_rsa_key(smc_args_t *args) {
|
||||
return smc_wrapper_sync(args, user_decrypt_or_import_rsa_key);
|
||||
}
|
||||
|
||||
|
||||
uint32_t smc_cpu_on(smc_args_t *args) {
|
||||
return cpu_on((uint32_t)args->X[1], args->X[2], args->X[3]);
|
||||
}
|
||||
|
@ -496,7 +536,7 @@ uint32_t smc_read_write_register(smc_args_t *args) {
|
|||
} else {
|
||||
return 2;
|
||||
}
|
||||
} else if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT && MMIO_GET_DEVICE_PA(MMIO_DEVID_MC) <= address &&
|
||||
} else if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_400 && MMIO_GET_DEVICE_PA(MMIO_DEVID_MC) <= address &&
|
||||
address < MMIO_GET_DEVICE_PA(MMIO_DEVID_MC) + MMIO_GET_DEVICE_SIZE(MMIO_DEVID_MC)) {
|
||||
/* Memory Controller RW supported only on 4.0.0+ */
|
||||
const uint8_t mc_whitelist[0x68] = {
|
||||
|
|
|
@ -20,6 +20,8 @@ void clear_priv_smc_in_progress(void);
|
|||
uintptr_t get_smc_core012_stack_address(void);
|
||||
uintptr_t get_exception_entry_stack_address(unsigned int core_id);
|
||||
|
||||
void set_version_specific_smcs(void);
|
||||
|
||||
void call_smc_handler(unsigned int handler_id, smc_args_t *args);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -14,14 +14,15 @@
|
|||
#include "sealedkeys.h"
|
||||
#include "userpage.h"
|
||||
#include "titlekey.h"
|
||||
#include "exocfg.h"
|
||||
|
||||
/* Globals. */
|
||||
static bool g_crypt_aes_done = false;
|
||||
static bool g_exp_mod_done = false;
|
||||
|
||||
static uint8_t g_secure_exp_mod_exponent[0x100];
|
||||
static uint8_t g_rsa_oaep_exponent[0x100];
|
||||
static uint8_t g_imported_exponents[4][0x100];
|
||||
|
||||
static uint8_t g_rsausecase_to_cryptousecase[5] = {1, 2, 3, 5, 6};
|
||||
|
||||
void set_exp_mod_done(bool done) {
|
||||
g_exp_mod_done = done;
|
||||
|
@ -125,12 +126,31 @@ uint32_t user_generate_aes_kek(smc_args_t *args) {
|
|||
uint8_t mask_id = (uint8_t)((packed_options >> 1) & 3);
|
||||
|
||||
/* Switches the output based on how it will be used. */
|
||||
uint8_t usecase = (uint8_t)((packed_options >> 5) & 3);
|
||||
uint8_t usecase = (uint8_t)((packed_options >> 5) & (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_500 ? 7 : 3));
|
||||
|
||||
/* Switched the output based on whether it should be console unique. */
|
||||
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() >= EXOSPHERE_TARGET_FIRMWARE_500) {
|
||||
if (is_personalized) {
|
||||
if (master_key_rev > MASTERKEY_REVISION_500_CURRENT || ((1 << (master_key_rev + 1)) & 0x33) == 0) {
|
||||
return 2;
|
||||
}
|
||||
if (mask_id > 3 || usecase >= CRYPTOUSECASE_MAX_5X) {
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
if (usecase >= CRYPTOUSECASE_UNK6) {
|
||||
return 2;
|
||||
}
|
||||
if (usecase == CRYPTOUSECASE_UNK5 && mask_id >= 4) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Mask 2 is only allowed when booted from recovery. */
|
||||
if (mask_id == 2 && !is_recovery_boot) {
|
||||
|
@ -163,8 +183,10 @@ uint32_t user_generate_aes_kek(smc_args_t *args) {
|
|||
|
||||
unsigned int keyslot;
|
||||
if (is_personalized) {
|
||||
/* Behavior changed in 4.0.0. */
|
||||
if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) {
|
||||
/* Behavior changed in 4.0.0, and in 5.0.0. */
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_500) {
|
||||
keyslot = devkey_get_keyslot(master_key_rev);
|
||||
} else if (exosphere_get_target_firmware() == EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
if (master_key_rev >= 1) {
|
||||
keyslot = KEYSLOT_SWITCH_DEVICEKEY; /* New device key, 4.x. */
|
||||
} else {
|
||||
|
@ -246,7 +268,17 @@ uint32_t user_crypt_aes(smc_args_t *args) {
|
|||
|
||||
size_t size = args->X[6];
|
||||
if (size & 0xF) {
|
||||
generic_panic();
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_500) {
|
||||
/* Disallow dma lists outside of safe range. */
|
||||
if (in_ll_paddr - 0x80000000 >= 0x3FF7F5) {
|
||||
return 2;
|
||||
}
|
||||
if (out_ll_paddr - 0x80000000 >= 0x3FF7F5) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
set_crypt_aes_done(false);
|
||||
|
@ -287,6 +319,9 @@ uint32_t user_generate_specific_aes_key(smc_args_t *args) {
|
|||
if (master_key_rev > 0) {
|
||||
master_key_rev -= 1;
|
||||
}
|
||||
if (exosphere_get_target_firmware() < EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
master_key_rev = 0;
|
||||
}
|
||||
|
||||
if (master_key_rev >= MASTERKEY_REVISION_MAX) {
|
||||
return 2;
|
||||
|
@ -299,9 +334,11 @@ uint32_t user_generate_specific_aes_key(smc_args_t *args) {
|
|||
|
||||
unsigned int keyslot;
|
||||
|
||||
/* Behavior changed in 4.0.0. */
|
||||
if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) {
|
||||
if (master_key_rev >= 2) {
|
||||
/* Behavior changed in 5.0.0. */
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_500) {
|
||||
keyslot = devkey_get_keyslot(master_key_rev);
|
||||
} else if (exosphere_get_target_firmware() == EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
if (master_key_rev >= 1) {
|
||||
keyslot = KEYSLOT_SWITCH_DEVICEKEY; /* New device key, 4.x. */
|
||||
} else {
|
||||
keyslot = KEYSLOT_SWITCH_4XOLDDEVICEKEY; /* Old device key, 4.x. */
|
||||
|
@ -378,6 +415,10 @@ uint32_t user_load_rsa_oaep_key(smc_args_t *args) {
|
|||
size_t size;
|
||||
upage_ref_t page_ref;
|
||||
|
||||
/* This function no longer exists in 5.x+. */
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_500) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Copy keydata */
|
||||
sealed_kek[0] = args->X[1];
|
||||
|
@ -405,11 +446,11 @@ uint32_t user_load_rsa_oaep_key(smc_args_t *args) {
|
|||
flush_dcache_range(user_data, user_data + size);
|
||||
|
||||
/* Ensure that our private key is 0x100 bytes. */
|
||||
if (gcm_decrypt_key(user_data, size, user_data, size, sealed_kek, 0x10, wrapped_key, 0x10, CRYPTOUSECASE_RSAOAEP, is_personalized) < 0x100) {
|
||||
if (gcm_decrypt_key(user_data, size, user_data, size, sealed_kek, 0x10, wrapped_key, 0x10, CRYPTOUSECASE_RSAOAEP, is_personalized, NULL) < 0x100) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
memcpy(g_rsa_oaep_exponent, user_data, 0x100);
|
||||
memcpy(g_imported_exponents[0], user_data, 0x100);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -423,6 +464,10 @@ uint32_t user_decrypt_rsa_private_key(smc_args_t *args) {
|
|||
size_t size;
|
||||
upage_ref_t page_ref;
|
||||
|
||||
/* This function no longer exists in 5.x+. */
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_500) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Copy keydata */
|
||||
sealed_kek[0] = args->X[1];
|
||||
|
@ -455,7 +500,7 @@ uint32_t user_decrypt_rsa_private_key(smc_args_t *args) {
|
|||
|
||||
size_t out_size;
|
||||
|
||||
if ((out_size = gcm_decrypt_key(user_data, size, user_data, size, sealed_kek, 0x10, wrapped_key, 0x10, CRYPTOUSECASE_RSAPRIVATE, is_personalized)) == 0) {
|
||||
if ((out_size = gcm_decrypt_key(user_data, size, user_data, size, sealed_kek, 0x10, wrapped_key, 0x10, CRYPTOUSECASE_RSAPRIVATE, is_personalized, NULL)) == 0) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
@ -477,6 +522,10 @@ uint32_t user_load_secure_exp_mod_key(smc_args_t *args) {
|
|||
size_t size;
|
||||
upage_ref_t page_ref;
|
||||
|
||||
/* This function no longer exists in 5.x+. */
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_500) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Copy keydata */
|
||||
sealed_kek[0] = args->X[1];
|
||||
|
@ -506,15 +555,15 @@ uint32_t user_load_secure_exp_mod_key(smc_args_t *args) {
|
|||
size_t out_size;
|
||||
|
||||
/* Ensure that our key is non-zero bytes. */
|
||||
if ((out_size = gcm_decrypt_key(user_data, size, user_data, size, sealed_kek, 0x10, wrapped_key, 0x10, CRYPTOUSECASE_SECUREEXPMOD, is_personalized)) == 0) {
|
||||
if ((out_size = gcm_decrypt_key(user_data, size, user_data, size, sealed_kek, 0x10, wrapped_key, 0x10, CRYPTOUSECASE_SECUREEXPMOD, is_personalized, NULL)) == 0) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* Copy key to global. */
|
||||
if (out_size <= 0x100) {
|
||||
memcpy(g_secure_exp_mod_exponent, user_data, out_size);
|
||||
memcpy(g_imported_exponents[1], user_data, out_size);
|
||||
} else {
|
||||
memcpy(g_secure_exp_mod_exponent, user_data, 0x100);
|
||||
memcpy(g_imported_exponents[1], user_data, 0x100);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -529,6 +578,23 @@ uint32_t user_secure_exp_mod(smc_args_t *args) {
|
|||
void *user_input = (void *)args->X[1];
|
||||
void *user_modulus = (void *)args->X[2];
|
||||
|
||||
unsigned int exponent_id = 1;
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_500) {
|
||||
switch (args->X[3]) {
|
||||
case 0:
|
||||
exponent_id = 1;
|
||||
break;
|
||||
case 1:
|
||||
exponent_id = 2;
|
||||
break;
|
||||
case 2:
|
||||
exponent_id = 3;
|
||||
break;
|
||||
default:
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy user data into secure memory. */
|
||||
if (upage_init(&page_ref, user_input) == 0) {
|
||||
return 2;
|
||||
|
@ -542,7 +608,7 @@ uint32_t user_secure_exp_mod(smc_args_t *args) {
|
|||
|
||||
set_exp_mod_done(false);
|
||||
/* Hardcode RSA keyslot 0. */
|
||||
set_rsa_keyslot(0, modulus, 0x100, g_secure_exp_mod_exponent, 0x100);
|
||||
set_rsa_keyslot(0, modulus, 0x100, g_imported_exponents[exponent_id], 0x100);
|
||||
se_exp_mod(0, input, 0x100, exp_mod_done_handler);
|
||||
|
||||
return 0;
|
||||
|
@ -562,7 +628,7 @@ uint32_t user_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args) {
|
|||
master_key_rev -= 1;
|
||||
}
|
||||
|
||||
if (mkey_get_revision() > 0 && master_key_rev >= MASTERKEY_REVISION_MAX) {
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_300 && master_key_rev >= MASTERKEY_REVISION_MAX) {
|
||||
return 2;
|
||||
} else {
|
||||
master_key_rev = 0;
|
||||
|
@ -587,7 +653,7 @@ uint32_t user_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args) {
|
|||
tkey_set_master_key_rev(master_key_rev);
|
||||
|
||||
/* Hardcode RSA keyslot 0. */
|
||||
set_rsa_keyslot(0, modulus, 0x100, g_rsa_oaep_exponent, 0x100);
|
||||
set_rsa_keyslot(0, modulus, 0x100, g_imported_exponents[0], 0x100);
|
||||
se_exp_mod(0, wrapped_key, 0x100, exp_mod_done_handler);
|
||||
|
||||
return 0;
|
||||
|
@ -624,7 +690,7 @@ uint32_t user_unwrap_aes_wrapped_titlekey(smc_args_t *args) {
|
|||
if (master_key_rev > 0) {
|
||||
master_key_rev -= 1;
|
||||
}
|
||||
if (mkey_get_revision() > 0 && master_key_rev >= MASTERKEY_REVISION_MAX) {
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_300 && master_key_rev >= MASTERKEY_REVISION_MAX) {
|
||||
return 2;
|
||||
} else {
|
||||
master_key_rev = 0;
|
||||
|
@ -640,3 +706,145 @@ uint32_t user_unwrap_aes_wrapped_titlekey(smc_args_t *args) {
|
|||
|
||||
return 0; /* FIXME: what should we return there */
|
||||
}
|
||||
|
||||
|
||||
uint32_t user_encrypt_rsa_key_for_import(smc_args_t *args) {
|
||||
uint64_t in_sealed_kek[2];
|
||||
uint64_t out_sealed_kek[2];
|
||||
uint64_t in_wrapped_key[2];
|
||||
uint64_t out_wrapped_key[2];
|
||||
uint8_t usecase;
|
||||
|
||||
uint8_t user_data[0x400];
|
||||
void *user_address;
|
||||
void *user_in_kek;
|
||||
void *user_out_kek;
|
||||
void *user_in_key;
|
||||
void *user_out_key;
|
||||
size_t size;
|
||||
upage_ref_t page_ref;
|
||||
|
||||
/* Copy keydata */
|
||||
user_in_kek = (void *)args->X[1];
|
||||
user_out_kek = (void *)args->X[2];
|
||||
usecase = args->X[3] & 7;
|
||||
user_address = (void *)args->X[4];
|
||||
size = (size_t)args->X[5];
|
||||
user_in_key = (void *)args->X[6];
|
||||
user_out_key = (void *)args->X[7];
|
||||
|
||||
if (usecase > CRYPTOUSECASE_RSAIMPORT) {
|
||||
return 2;
|
||||
}
|
||||
if (usecase == 0) {
|
||||
if (size < 0x31 || size > 0x240) {
|
||||
return 2;
|
||||
}
|
||||
} else if (size < 0x130 || size > 0x240) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (upage_init(&page_ref, user_address) == 0
|
||||
|| user_copy_to_secure(&page_ref, user_data, user_address, size) == 0
|
||||
|| user_copy_to_secure(&page_ref, in_sealed_kek, user_in_kek, 0x10) == 0
|
||||
|| user_copy_to_secure(&page_ref, out_sealed_kek, user_out_kek, 0x10) == 0
|
||||
|| user_copy_to_secure(&page_ref, in_wrapped_key, user_in_key, 0x10) == 0
|
||||
|| user_copy_to_secure(&page_ref, out_wrapped_key, user_out_key, 0x10) == 0) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
flush_dcache_range(user_data, user_data + size);
|
||||
|
||||
size_t out_size;
|
||||
|
||||
uint8_t device_id_high;
|
||||
|
||||
if ((out_size = gcm_decrypt_key(user_data, size, user_data, size, in_sealed_kek, 0x10, in_wrapped_key, 0x10, CRYPTOUSECASE_RSAIMPORT, true, &device_id_high)) == 0) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
gcm_encrypt_key(user_data, size, user_data, size - 0x30, out_sealed_kek, 0x10, out_wrapped_key, 0x10, g_rsausecase_to_cryptousecase[usecase], device_id_high);
|
||||
|
||||
if (secure_copy_to_user(&page_ref, user_address, user_data, size) == 0) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args) {
|
||||
uint64_t sealed_kek[2];
|
||||
uint64_t wrapped_key[2];
|
||||
uint8_t usecase;
|
||||
|
||||
uint8_t user_data[0x400];
|
||||
void *user_address;
|
||||
size_t size;
|
||||
upage_ref_t page_ref;
|
||||
|
||||
/* This function no longer exists in 5.x+. */
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_500) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Copy keydata */
|
||||
sealed_kek[0] = args->X[1];
|
||||
sealed_kek[1] = args->X[2];
|
||||
usecase = args->X[3] & 7;
|
||||
user_address = (void *)args->X[4];
|
||||
size = (size_t)args->X[5];
|
||||
wrapped_key[0] = args->X[6];
|
||||
wrapped_key[1] = args->X[7];
|
||||
|
||||
if (usecase > CRYPTOUSECASE_RSAIMPORT) {
|
||||
return 2;
|
||||
}
|
||||
if (usecase == 0) {
|
||||
if (size < 0x31 || size > 0x240) {
|
||||
return 2;
|
||||
}
|
||||
} else if (size < 0x130 || size > 0x240) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (upage_init(&page_ref, user_address) == 0 || user_copy_to_secure(&page_ref, user_data, user_address, size) == 0) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
flush_dcache_range(user_data, user_data + size);
|
||||
|
||||
size_t out_size;
|
||||
|
||||
if ((out_size = gcm_decrypt_key(user_data, size, user_data, size, sealed_kek, 0x10, wrapped_key, 0x10, g_rsausecase_to_cryptousecase[usecase], true, NULL)) == 0) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
unsigned int exponent_id;
|
||||
|
||||
switch (usecase) {
|
||||
case 0:
|
||||
if (secure_copy_to_user(&page_ref, user_address, user_data, size) == 0) {
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
case 1:
|
||||
exponent_id = 1;
|
||||
break;
|
||||
case 2:
|
||||
exponent_id = 0;
|
||||
break;
|
||||
case 3:
|
||||
exponent_id = 2;
|
||||
break;
|
||||
case 4:
|
||||
exponent_id = 3;
|
||||
break;
|
||||
default:
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
/* Copy key to global. */
|
||||
memcpy(g_imported_exponents[exponent_id], user_data, 0x100);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,9 @@ uint32_t user_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args);
|
|||
uint32_t user_load_titlekey(smc_args_t *args);
|
||||
uint32_t user_unwrap_aes_wrapped_titlekey(smc_args_t *args);
|
||||
|
||||
uint32_t user_encrypt_rsa_key_for_import(smc_args_t *args);
|
||||
uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args);
|
||||
|
||||
|
||||
void set_crypt_aes_done(bool done);
|
||||
bool get_crypt_aes_done(void);
|
||||
|
|
|
@ -242,6 +242,7 @@ g_coldboot_crt0_relocation_list:
|
|||
.global g_coldboot_crt0_main_func_list
|
||||
g_coldboot_crt0_main_func_list:
|
||||
.quad 4 /* Number of functions */
|
||||
.quad 0 /* Target firmware, overwritten in coldboot_init. */
|
||||
/* Functions */
|
||||
.quad init_dma_controllers
|
||||
.quad set_memory_registers_enable_mmu
|
||||
|
@ -252,4 +253,4 @@ g_coldboot_crt0_main_func_list:
|
|||
.align 3
|
||||
.global g_warmboot_crt0_main_func_list
|
||||
g_warmboot_crt0_main_func_list:
|
||||
.space (4 * 8)
|
||||
.space (6 * 8)
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#define MAKE_SYSREG(n) MAKE_REG32(SYSREG_BASE + n)
|
||||
#define MAKE_SB_REG(n) MAKE_REG32(SB_BASE + n)
|
||||
|
||||
#define AHB_ARBITRATION_DISABLE_0 MAKE_SYSREG(0x004)
|
||||
|
||||
#define SB_CSR_0 MAKE_SB_REG(0x00)
|
||||
#define SB_PIROM_START_0 MAKE_SB_REG(0x04)
|
||||
#define SB_PFCFG_0 MAKE_SB_REG(0x08)
|
||||
|
|
|
@ -28,9 +28,10 @@
|
|||
/* For warmboot (and coldboot crt0) */
|
||||
typedef struct {
|
||||
size_t nb_funcs;
|
||||
uint64_t target_firmware;
|
||||
union {
|
||||
struct {
|
||||
void (*init_dma_controllers)(void);
|
||||
void (*init_dma_controllers)(unsigned int);
|
||||
void (*set_memory_registers_enable_mmu)(void);
|
||||
void (*flush_dcache_all)(void);
|
||||
void (*invalidate_icache_all)(void);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "mc.h"
|
||||
#include "arm.h"
|
||||
#include "synchronization.h"
|
||||
#include "exocfg.h"
|
||||
|
||||
#undef MC_BASE
|
||||
#define MC_BASE (MMIO_GET_DEVICE_PA(MMIO_DEVID_MC))
|
||||
|
@ -29,39 +30,61 @@ void warmboot_crt0_critical_section_enter(volatile critical_section_t *critical_
|
|||
critical_section_enter(critical_section);
|
||||
}
|
||||
|
||||
void init_dma_controllers(void) {
|
||||
/* TODO: 4.x does slightly different init. How should we handle this? We can't detect master key revision yet. */
|
||||
void init_dma_controllers(unsigned int target_firmware) {
|
||||
if (target_firmware >= EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
/* Set some unknown registers in HOST1X. */
|
||||
MAKE_REG32(0x500038F8) &= 0xFFFFFFFE;
|
||||
MAKE_REG32(0x50003300) = 0;
|
||||
|
||||
/* SYSCTR0_CNTCR_0 = ENABLE | HALT_ON_DEBUG (write-once init) */
|
||||
MAKE_REG32(0x700F0000) = 3;
|
||||
/* AHB_MASTER_SWID_0 - Enable SWID[0] for all bits. */
|
||||
MAKE_REG32(0x6000C018) = 0xFFFFFFFF;
|
||||
|
||||
/* Set some unknown registers in HOST1X. */
|
||||
MAKE_REG32(0x500038F8) &= 0xFFFFFFFE;
|
||||
MAKE_REG32(0x50003300) = 0;
|
||||
/* AHB_MASTER_SWID_1 */
|
||||
MAKE_REG32(0x6000C038) = 0x0;
|
||||
|
||||
/* AHB_MASTER_SWID_0 */
|
||||
MAKE_REG32(0x6000C018) = 0;
|
||||
/* MSELECT_CONFIG_0 |= WRAP_TO_INCR_SLAVE0(APC) | WRAP_TO_INCR_SLAVE1(PCIe) | WRAP_TO_INCR_SLAVE2(GPU) */
|
||||
MAKE_REG32(0x50060000) |= 0x38000000;
|
||||
|
||||
/* AHB_MASTER_SWID_1 - Makes USB1/USB2 use SWID[1] */
|
||||
MAKE_REG32(0x6000C038) = 0x40040;
|
||||
/* AHB_ARBITRATION_DISABLE_0 - Disables USB and USB2 from arbitration */
|
||||
MAKE_REG32(0x6000C004) = 0x40040;
|
||||
|
||||
/* APBDMA_CHANNEL_SWID_0 = ~0 (SWID = 1 for all APB-DMA channels) */
|
||||
MAKE_REG32(0x6002003C) = 0xFFFFFFFF;
|
||||
/* AHB_ARBITRATION_PRIORITY_CTRL_0 - Select high prio group with prio 7 */
|
||||
MAKE_REG32(0x6000C008) = 0xE0000001;
|
||||
|
||||
/* APBDMA_CHANNEL_SWID1_0 = 0 (See above) */
|
||||
MAKE_REG32(0x60020054) = 0;
|
||||
/* AHB_GIZMO_TZRAM_0 |= DONT_SPLIT_AHB_WR */
|
||||
MAKE_REG32(0x6000C054) = 0x80;
|
||||
} else {
|
||||
/* SYSCTR0_CNTCR_0 = ENABLE | HALT_ON_DEBUG (write-once init) */
|
||||
MAKE_REG32(0x700F0000) = 3;
|
||||
|
||||
/* APBDMA_SECURITY_REG_0 = 0 (All APB-DMA channels non-secure) */
|
||||
MAKE_REG32(0x60020038) = 0;
|
||||
/* Set some unknown registers in HOST1X. */
|
||||
MAKE_REG32(0x500038F8) &= 0xFFFFFFFE;
|
||||
MAKE_REG32(0x50003300) = 0;
|
||||
|
||||
/* MSELECT_CONFIG_0 |= WRAP_TO_INCR_SLAVE0(APC) | WRAP_TO_INCR_SLAVE1(PCIe) | WRAP_TO_INCR_SLAVE2(GPU) */
|
||||
MAKE_REG32(0x50060000) |= 0x38000000;
|
||||
/* AHB_MASTER_SWID_0 */
|
||||
MAKE_REG32(0x6000C018) = 0;
|
||||
|
||||
/* AHB_ARBITRATION_PRIORITY_CTRL_0 - Select high prio group with prio 7 */
|
||||
MAKE_REG32(0x6000C008) = 0xE0000001;
|
||||
/* AHB_MASTER_SWID_1 - Makes USB1/USB2 use SWID[1] */
|
||||
MAKE_REG32(0x6000C038) = 0x40040;
|
||||
|
||||
/* AHB_GIZMO_TZRAM_0 |= DONT_SPLIT_AHB_WR */
|
||||
MAKE_REG32(0x6000C054) = 0x80;
|
||||
/* APBDMA_CHANNEL_SWID_0 = ~0 (SWID = 1 for all APB-DMA channels) */
|
||||
MAKE_REG32(0x6002003C) = 0xFFFFFFFF;
|
||||
|
||||
/* APBDMA_CHANNEL_SWID1_0 = 0 (See above) */
|
||||
MAKE_REG32(0x60020054) = 0;
|
||||
|
||||
/* APBDMA_SECURITY_REG_0 = 0 (All APB-DMA channels non-secure) */
|
||||
MAKE_REG32(0x60020038) = 0;
|
||||
|
||||
/* MSELECT_CONFIG_0 |= WRAP_TO_INCR_SLAVE0(APC) | WRAP_TO_INCR_SLAVE1(PCIe) | WRAP_TO_INCR_SLAVE2(GPU) */
|
||||
MAKE_REG32(0x50060000) |= 0x38000000;
|
||||
|
||||
/* AHB_ARBITRATION_PRIORITY_CTRL_0 - Select high prio group with prio 7 */
|
||||
MAKE_REG32(0x6000C008) = 0xE0000001;
|
||||
|
||||
/* AHB_GIZMO_TZRAM_0 |= DONT_SPLIT_AHB_WR */
|
||||
MAKE_REG32(0x6000C054) = 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
void set_memory_registers_enable_mmu(void) {
|
||||
|
@ -144,7 +167,7 @@ void warmboot_init(boot_func_list_t *func_list) {
|
|||
|
||||
/* On warmboot (not cpu_on) only */
|
||||
if (MC_SECURITY_CFG3_0 == 0) {
|
||||
init_dma_controllers();
|
||||
init_dma_controllers(func_list->target_firmware);
|
||||
}
|
||||
|
||||
identity_remap_tzram();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "masterkey.h"
|
||||
#include "bootup.h"
|
||||
#include "smc_api.h"
|
||||
#include "exocfg.h"
|
||||
|
||||
#include "se.h"
|
||||
#include "mc.h"
|
||||
|
@ -45,7 +46,7 @@ void __attribute__((noreturn)) warmboot_main(void) {
|
|||
/* Make PMC (2.x+), MC (4.x+) registers secure-only */
|
||||
secure_additional_devices();
|
||||
|
||||
if (mkey_get_revision() < MASTERKEY_REVISION_400_CURRENT || configitem_get_hardware_type() == 0) {
|
||||
if (exosphere_get_target_firmware() < EXOSPHERE_TARGET_FIRMWARE_400 || configitem_get_hardware_type() == 0) {
|
||||
/* Enable input to I2C1 */
|
||||
PINMUX_AUX_GEN1_I2C_SCL_0 = 0x40;
|
||||
PINMUX_AUX_GEN1_I2C_SDA_0 = 0x40;
|
||||
|
@ -58,9 +59,8 @@ void __attribute__((noreturn)) warmboot_main(void) {
|
|||
|
||||
clear_user_smc_in_progress();
|
||||
|
||||
if (mkey_get_revision() >= MASTERKEY_REVISION_400_CURRENT) {
|
||||
setup_4x_mmio(); /* TODO */
|
||||
}
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
setup_4x_mmio(); }
|
||||
}
|
||||
|
||||
setup_current_core_state();
|
||||
|
|
Loading…
Reference in a new issue