mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-18 08:22:04 +00:00
Implement getters for fuse values, fill out smcGetConfig
This commit is contained in:
parent
b0079e404d
commit
82b4c6763d
8 changed files with 132 additions and 16 deletions
|
@ -20,5 +20,9 @@ void bootconfig_clear(void);
|
||||||
bool bootconfig_is_package2_plaintext(void);
|
bool bootconfig_is_package2_plaintext(void);
|
||||||
bool bootconfig_is_package2_unsigned(void);
|
bool bootconfig_is_package2_unsigned(void);
|
||||||
bool bootconfig_disable_program_verification(void);
|
bool bootconfig_disable_program_verification(void);
|
||||||
|
bool bootconfig_is_debug_mode(void);
|
||||||
|
|
||||||
|
uint64_t bootconfig_get_memory_arrangement(void);
|
||||||
|
uint64_t bootconfig_get_kernel_memory_configuration(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -26,14 +26,23 @@ bool configitem_is_recovery_boot(void) {
|
||||||
return is_recovery_boot != 0;
|
return is_recovery_boot != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool configitem_is_retail(void) {
|
||||||
|
uint64_t is_retail;
|
||||||
|
if (configitem_get(CONFIGITEM_ISRETAIL, &is_retail) != 0) {
|
||||||
|
generic_panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_retail != 0;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t configitem_get(enum ConfigItem item, uint64_t *p_outvalue) {
|
uint32_t configitem_get(enum ConfigItem item, uint64_t *p_outvalue) {
|
||||||
uint32_t result = 0;
|
uint32_t result = 0;
|
||||||
switch (item) {
|
switch (item) {
|
||||||
case CONFIGITEM_DISABLEPROGRAMVERIFICATION:
|
case CONFIGITEM_DISABLEPROGRAMVERIFICATION:
|
||||||
*p_outvalue = (int)(bootconfig_disable_program_verification());
|
*p_outvalue = (int)(bootconfig_disable_program_verification());
|
||||||
break;
|
break;
|
||||||
case CONFIGITEM_MEMORYCONFIGURATION:
|
case CONFIGITEM_DRAMID:
|
||||||
/* TODO: Fuse driver */
|
*p_outvalue = fuse_get_dram_id();
|
||||||
break;
|
break;
|
||||||
case CONFIGITEM_SECURITYENGINEIRQ:
|
case CONFIGITEM_SECURITYENGINEIRQ:
|
||||||
/* SE is interrupt #0x2C. */
|
/* SE is interrupt #0x2C. */
|
||||||
|
@ -44,29 +53,29 @@ uint32_t configitem_get(enum ConfigItem item, uint64_t *p_outvalue) {
|
||||||
*p_outvalue = PACKAGE2_MAXVER_400_CURRENT - 1;
|
*p_outvalue = PACKAGE2_MAXVER_400_CURRENT - 1;
|
||||||
break;
|
break;
|
||||||
case CONFIGITEM_HARDWARETYPE:
|
case CONFIGITEM_HARDWARETYPE:
|
||||||
/* TODO: Fuse driver */
|
*p_outvalue = fuse_get_hardware_type();
|
||||||
break;
|
break;
|
||||||
case CONFIGITEM_ISRETAIL:
|
case CONFIGITEM_ISRETAIL:
|
||||||
/* TODO: Fuse driver */
|
*p_outvalue = fuse_get_retail_type();
|
||||||
break;
|
break;
|
||||||
case CONFIGITEM_ISRECOVERYBOOT:
|
case CONFIGITEM_ISRECOVERYBOOT:
|
||||||
/* TODO: This requires reading values passed to crt0 via NX_Bootloader. TBD pending crt0 implementation. */
|
/* TODO: This requires reading values passed to crt0 via NX_Bootloader. TBD pending crt0 implementation. */
|
||||||
*p_outvalue = 0;
|
*p_outvalue = 0;
|
||||||
break;
|
break;
|
||||||
case CONFIGITEM_DEVICEID:
|
case CONFIGITEM_DEVICEID:
|
||||||
/* TODO: Fuse driver */
|
*p_outvalue = fuse_get_device_id();
|
||||||
break;
|
break;
|
||||||
case CONFIGITEM_BOOTREASON:
|
case CONFIGITEM_BOOTREASON:
|
||||||
/* TODO: This requires reading values passed to crt0 via NX_Bootloader. TBD pending crt0 implementation. */
|
/* TODO: This requires reading values passed to crt0 via NX_Bootloader. TBD pending crt0 implementation. */
|
||||||
break;
|
break;
|
||||||
case CONFIGITEM_MEMORYARRANGE:
|
case CONFIGITEM_MEMORYARRANGE:
|
||||||
/* TODO: More BootConfig stuff. */
|
*p_outvalue = bootconfig_get_memory_arrangement();
|
||||||
break;
|
break;
|
||||||
case CONFIGITEM_ISDEBUGMODE:
|
case CONFIGITEM_ISDEBUGMODE:
|
||||||
/* TODO: More BootConfig stuff. */
|
*p_outvalue = (int)(bootconfig_is_debug_mode());
|
||||||
break;
|
break;
|
||||||
case CONFIGITEM_KERNELMEMORYCONFIGURATION:
|
case CONFIGITEM_KERNELMEMORYCONFIGURATION:
|
||||||
/* TODO: More BootConfig stuff. */
|
*p_outvalue = bootconfig_get_kernel_memory_configuration();
|
||||||
break;
|
break;
|
||||||
case CONFIGITEM_BATTERYPROFILE:
|
case CONFIGITEM_BATTERYPROFILE:
|
||||||
*p_outvalue = g_battery_profile;
|
*p_outvalue = g_battery_profile;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
enum ConfigItem {
|
enum ConfigItem {
|
||||||
CONFIGITEM_DISABLEPROGRAMVERIFICATION = 1,
|
CONFIGITEM_DISABLEPROGRAMVERIFICATION = 1,
|
||||||
CONFIGITEM_MEMORYCONFIGURATION = 2,
|
CONFIGITEM_DRAMID = 2,
|
||||||
CONFIGITEM_SECURITYENGINEIRQ = 3,
|
CONFIGITEM_SECURITYENGINEIRQ = 3,
|
||||||
CONFIGITEM_VERSION = 4,
|
CONFIGITEM_VERSION = 4,
|
||||||
CONFIGITEM_HARDWARETYPE = 5,
|
CONFIGITEM_HARDWARETYPE = 5,
|
||||||
|
|
|
@ -108,6 +108,17 @@ void fuse_hw_sense(void)
|
||||||
fuse_wait_idle();
|
fuse_wait_idle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Disables all fuse programming. */
|
||||||
|
void fuse_disable_programming(void) {
|
||||||
|
FUSE_REGS->FUSE_DIS_PGM = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unknown exactly what this does, but it alters the contents read from the fuse cache. */
|
||||||
|
void fuse_secondary_private_key_disable(void) {
|
||||||
|
FUSE_REGS->FUSE_PRIVATEKEYDISABLE = 0x10;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Read the SKU info register from the shadow cache */
|
/* Read the SKU info register from the shadow cache */
|
||||||
uint32_t fuse_get_sku_info(void)
|
uint32_t fuse_get_sku_info(void)
|
||||||
{
|
{
|
||||||
|
@ -141,3 +152,80 @@ uint32_t fuse_get_reserved_odm(uint32_t idx)
|
||||||
|
|
||||||
return reserved_odm_val;
|
return reserved_odm_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Derive the Device ID using values in the shadow cache */
|
||||||
|
uint64_t fuse_get_device_id(void) {
|
||||||
|
uint64_t device_id = 0;
|
||||||
|
uint64_t y_coord = FUSE_CHIP_REGS->FUSE_Y_COORDINATE & 0x1FF;
|
||||||
|
uint64_t x_coord = FUSE_CHIP_REGS->FUSE_X_COORDINATE & 0x1FF;
|
||||||
|
uint64_t wafer_id = FUSE_CHIP_REGS->FUSE_WAFER_ID & 0x3F;
|
||||||
|
uint32_t lot_code = FUSE_CHIP_REGS->FUSE_LOT_CODE_0;
|
||||||
|
uint64_t fab_code = FUSE_CHIP_REGS->FUSE_FAB_CODE & 0x3F;
|
||||||
|
uint64_t derived_lot_code = 0;
|
||||||
|
for (unsigned int i = 0; i < 5; i++) {
|
||||||
|
derived_lot_code = (derived_lot_code * 0x24) + ((lot_code >> (24 - 6*i)) & 0x3F);
|
||||||
|
}
|
||||||
|
derived_lot_code &= 0x03FFFFFF;
|
||||||
|
|
||||||
|
device_id |= y_coord << 0;
|
||||||
|
device_id |= x_coord << 9;
|
||||||
|
device_id |= wafer_id << 18;
|
||||||
|
device_id |= derived_lot_code << 24;
|
||||||
|
device_id |= fab_code << 50;
|
||||||
|
return device_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the DRAM ID using values in the shadow cache */
|
||||||
|
uint32_t fuse_get_dram_id(void) {
|
||||||
|
return (FUSE_CHIP_REGS->FUSE_RESERVED_ODM[4] >> 3) & 0x7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Derive the Hardware Type using values in the shadow cache */
|
||||||
|
uint32_t fuse_get_hardware_type(void) {
|
||||||
|
uint32_t hardware_type = ((FUSE_CHIP_REGS->FUSE_RESERVED_ODM[4] >> 7) & 2) | ((FUSE_CHIP_REGS->FUSE_RESERVED_ODM[4] >> 2) & 1);
|
||||||
|
if (hardware_type) {
|
||||||
|
if (hardware_type == 1) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (hardware_type == 2) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if ((FUSE_CHIP_REGS->FUSE_SPARE_BIT[9] & 1) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Derive the Retail Type using values in the shadow cache */
|
||||||
|
uint32_t fuse_get_retail_type(void) {
|
||||||
|
/* Retail type = IS_RETAIL | UNIT_TYPE */
|
||||||
|
uint32_t retail_type = ((FUSE_CHIP_REGS->FUSE_RESERVED_ODM[4] >> 7) & 4) | (FUSE_CHIP_REGS->FUSE_RESERVED_ODM[4] & 3);
|
||||||
|
if (retail_type == 4) { /* Standard retail unit, IS_RETAIL | 0. */
|
||||||
|
return 1;
|
||||||
|
} else if (retail_type == 3) { /* Standard dev unit, 0 | DEV_UNIT. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 2; /* IS_RETAIL | DEV_UNIT */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Derive the 16-byte Hardware Info using values in the shadow cache, and copy to output buffer. */
|
||||||
|
void fuse_get_hardware_info(void *dst) {
|
||||||
|
uint32_t hw_info[0x4];
|
||||||
|
|
||||||
|
uint32_t unk_hw_fuse = FUSE_CHIP_REGS->_0x120 & 0x3F;
|
||||||
|
uint32_t y_coord = FUSE_CHIP_REGS->FUSE_Y_COORDINATE & 0x1FF;
|
||||||
|
uint32_t x_coord = FUSE_CHIP_REGS->FUSE_X_COORDINATE & 0x1FF;
|
||||||
|
uint32_t wafer_id = FUSE_CHIP_REGS->FUSE_WAFER_ID & 0x3F;
|
||||||
|
uint32_t lot_code_0 = FUSE_CHIP_REGS->FUSE_LOT_CODE_0;
|
||||||
|
uint32_t lot_code_1 = FUSE_CHIP_REGS->FUSE_LOT_CODE_1 & 0x0FFFFFFF;
|
||||||
|
uint32_t fab_code = FUSE_CHIP_REGS->FUSE_FAB_CODE & 0x3F;
|
||||||
|
uint32_t vendor_code = FUSE_CHIP_REGS->FUSE_VENDOR_CODE & 0xF;
|
||||||
|
|
||||||
|
/* Hardware Info = unk_hw_fuse || Y_COORD || X_COORD || WAFER_ID || LOT_CODE || FAB_CODE || VENDOR_ID */
|
||||||
|
hw_info[0] = (uint32_t)((lot_code_1 << 30) | (wafer_id << 24) | (x_coord << 15) | (y_coord << 6) | (unk_hw_fuse));
|
||||||
|
hw_info[1] = (uint32_t)((lot_code_0 << 26) | (lot_code_1 >> 2));
|
||||||
|
hw_info[2] = (uint32_t)((fab_code << 26) | (lot_code_0 >> 6));
|
||||||
|
hw_info[3] = (uint32_t)(vendor_code);
|
||||||
|
|
||||||
|
memcpy(dst, hw_info, 0x10);
|
||||||
|
}
|
|
@ -176,10 +176,18 @@ void fuse_init(void);
|
||||||
uint32_t fuse_hw_read(uint32_t addr);
|
uint32_t fuse_hw_read(uint32_t addr);
|
||||||
void fuse_hw_write(uint32_t, value, uint32_t addr);
|
void fuse_hw_write(uint32_t, value, uint32_t addr);
|
||||||
void fuse_hw_sense(void);
|
void fuse_hw_sense(void);
|
||||||
|
void fuse_disable_programming(void);
|
||||||
|
void fuse_secondary_private_key_disable(void);
|
||||||
|
|
||||||
uint32_t fuse_get_sku_info(void);
|
uint32_t fuse_get_sku_info(void);
|
||||||
uint32_t fuse_get_bootrom_patch_version(void);
|
|
||||||
uint32_t fuse_get_spare_bit(uint32_t idx);
|
uint32_t fuse_get_spare_bit(uint32_t idx);
|
||||||
uint32_t fuse_get_reserved_odm(uint32_t idx);
|
uint32_t fuse_get_reserved_odm(uint32_t idx);
|
||||||
|
|
||||||
|
uint32_t fuse_get_bootrom_patch_version(void);
|
||||||
|
uint64_t fuse_get_device_id(void);
|
||||||
|
uint32_t fuse_get_dram_id(void);
|
||||||
|
uint32_t fuse_get_hardware_type(void);
|
||||||
|
uint32_t fuse_get_retail_type(void);
|
||||||
|
void fuse_get_hardware_info(void *dst);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "fuse.h"
|
||||||
#include "gcm.h"
|
#include "gcm.h"
|
||||||
|
|
||||||
#include "sealedkeys.h"
|
#include "sealedkeys.h"
|
||||||
|
@ -158,7 +159,9 @@ size_t gcm_decrypt_key(void *dst, size_t dst_size, const void *src, size_t src_s
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Validate Device ID matches in blob data from fuses. */
|
if (read64le(src_bytes, src_size - 0x28) != fuse_get_device_id()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return src_size - 0x30;
|
return src_size - 0x30;
|
||||||
}
|
}
|
||||||
|
|
|
@ -203,7 +203,7 @@ uint32_t user_load_aes_key(smc_args_t *args) {
|
||||||
wrapped_key[0] = args->X[4];
|
wrapped_key[0] = args->X[4];
|
||||||
wrapped_key[1] = args->X[5];
|
wrapped_key[1] = args->X[5];
|
||||||
|
|
||||||
/* TODO: Unseal the kek. */
|
/* Unseal the kek. */
|
||||||
unseal_key(KEYSLOT_SWITCH_TEMPKEY, sealed_kek, 0x10, CRYPTOUSECASE_AES);
|
unseal_key(KEYSLOT_SWITCH_TEMPKEY, sealed_kek, 0x10, CRYPTOUSECASE_AES);
|
||||||
|
|
||||||
/* Unwrap the key. */
|
/* Unwrap the key. */
|
||||||
|
@ -301,7 +301,7 @@ uint32_t user_generate_specific_aes_key(smc_args_t *args) {
|
||||||
keyslot = KEYSLOT_SWITCH_DEVICEKEY;
|
keyslot = KEYSLOT_SWITCH_DEVICEKEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 /* TODO: GET_BOOTROM_PATCH_VERSION < 0x7F */) {
|
if (fuse_get_bootrom_patch_version() < 0x7F) {
|
||||||
/* On dev units, use a fixed "all-zeroes" seed. */
|
/* On dev units, use a fixed "all-zeroes" seed. */
|
||||||
/* Yes, this data really is all-zero in actual TrustZone .rodata. */
|
/* Yes, this data really is all-zero in actual TrustZone .rodata. */
|
||||||
uint8_t dev_specific_aes_key_source[0x10] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t dev_specific_aes_key_source[0x10] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
@ -384,7 +384,7 @@ uint32_t user_load_rsa_oaep_key(smc_args_t *args) {
|
||||||
if (is_personalized && size != 0x240) {
|
if (is_personalized && size != 0x240) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
if (!is_personalized && (size != 0x220 /* TODO: || GET_BOOTROM_PATCH_VERSION >= 0x7F */)) {
|
if (!is_personalized && (size != 0x220 || fuse_get_bootrom_patch_version() >= 0x7F)) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,7 +431,7 @@ uint32_t user_decrypt_rsa_private_key(smc_args_t *args) {
|
||||||
if (is_personalized && size < 0x31) {
|
if (is_personalized && size < 0x31) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
if (!is_personalized && (size < 0x11 /* TODO: || GET_BOOTROM_PATCH_VERSION >= 0x7F */)) {
|
if (!is_personalized && (size < 0x11 || fuse_get_bootrom_patch_version() >= 0x7F)) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,7 +479,7 @@ uint32_t user_load_secure_exp_mod_key(smc_args_t *args) {
|
||||||
if (is_personalized && size != 0x130) {
|
if (is_personalized && size != 0x130) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
if (!is_personalized && (size != 0x110 /* TODO: || GET_BOOTROM_PATCH_VERSION >= 0x7F */)) {
|
if (!is_personalized && (size != 0x110 || fuse_get_bootrom_patch_version() >= 0x7F)) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,10 @@ static inline uint32_t read32be(const unsigned char *dword, size_t offset) {
|
||||||
return __builtin_bswap32(read32le(dword, offset));
|
return __builtin_bswap32(read32le(dword, offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint64_t read64le(const void *qword, size_t offset) {
|
||||||
|
return *(uint32_t *)((uintptr_t)dword + offset);
|
||||||
|
}
|
||||||
|
|
||||||
static __attribute__((noinline)) bool check_32bit_additive_overflow(uint32_t a, uint32_t b) {
|
static __attribute__((noinline)) bool check_32bit_additive_overflow(uint32_t a, uint32_t b) {
|
||||||
uint64_t x = (uint64_t)a + (uint64_t)b;
|
uint64_t x = (uint64_t)a + (uint64_t)b;
|
||||||
return x > (uint64_t)(UINT32_MAX);
|
return x > (uint64_t)(UINT32_MAX);
|
||||||
|
|
Loading…
Reference in a new issue