mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
exo2: implement the rest of cpu suspend (security checks TODO)
This commit is contained in:
parent
34098f7215
commit
2fb363dcf0
12 changed files with 384 additions and 8 deletions
|
@ -1007,7 +1007,7 @@ namespace ams::secmon {
|
|||
se::InitializeRandom();
|
||||
se::SetRandomKey(pkg1::AesKeySlot_Temporary);
|
||||
se::GenerateSrk();
|
||||
se::SetRandomKey(pkg1::AesKeySlot_TzramSave);
|
||||
se::SetRandomKey(pkg1::AesKeySlot_TzramSaveKek);
|
||||
|
||||
/* Initialize pmc secure scratch. */
|
||||
pmc::InitializeRandomScratch();
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "../secmon_cache.hpp"
|
||||
#include "../secmon_cpu_context.hpp"
|
||||
#include "../secmon_error.hpp"
|
||||
#include "../secmon_misc.hpp"
|
||||
#include "secmon_smc_power_management.hpp"
|
||||
#include "secmon_smc_se_lock.hpp"
|
||||
|
||||
|
@ -152,11 +153,137 @@ namespace ams::secmon::smc {
|
|||
}
|
||||
|
||||
void ValidateSocStateForSuspend() {
|
||||
/* Validate that all other cores are off. */
|
||||
AMS_ABORT_UNLESS(reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, PMC_REG_BITS_VALUE(PWRGATE_STATUS_CE123, 0)));
|
||||
|
||||
/* Validate that the bpmp is appropriately halted. */
|
||||
AMS_ABORT_UNLESS(reg::Read(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS) != reg::Encode(FLOW_REG_BITS_ENUM (HALT_COP_EVENTS_MODE, FLOW_MODE_STOP),
|
||||
FLOW_REG_BITS_ENUM_SEL(HALT_COP_EVENTS_JTAG, IsJtagEnabled(), ENABLED, DISABLED)));
|
||||
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
void GenerateCryptographicallyRandomBytes(void * const dst, int size) {
|
||||
/* Flush the region we're about to fill to ensure consistency with the SE. */
|
||||
hw::FlushDataCache(dst, size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Generate random bytes. */
|
||||
se::GenerateRandomBytes(dst, size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Flush to ensure the CPU sees consistent data for the region. */
|
||||
hw::FlushDataCache(dst, size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
|
||||
void SaveSecureContextForErista() {
|
||||
/* TODO */
|
||||
/* Generate a random key source. */
|
||||
util::AlignedBuffer<hw::DataCacheLineSize, se::AesBlockSize> key_source;
|
||||
GenerateCryptographicallyRandomBytes(key_source, se::AesBlockSize);
|
||||
|
||||
const u32 * const key_source_32 = reinterpret_cast<const u32 *>(static_cast<u8 *>(key_source));
|
||||
|
||||
/* Ensure that the key source registers are not locked. */
|
||||
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_KeySourceReadWrite) != pmc::LockState::Locked);
|
||||
|
||||
/* Write the key source, lock writes to the key source, and verify that the key source is write-locked. */
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH24, key_source_32[0]);
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH25, key_source_32[1]);
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH26, key_source_32[2]);
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH27, key_source_32[3]);
|
||||
pmc::LockSecureRegister(pmc::SecureRegister_KeySourceWrite);
|
||||
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_KeySourceWrite) == pmc::LockState::Locked);
|
||||
|
||||
/* Verify the key source is correct in registers, and read-lock the key source registers. */
|
||||
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH24) == key_source_32[0]);
|
||||
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH25) == key_source_32[1]);
|
||||
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH26) == key_source_32[2]);
|
||||
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH27) == key_source_32[3]);
|
||||
pmc::LockSecureRegister(pmc::SecureRegister_KeySourceRead);
|
||||
|
||||
/* Ensure that the key source registers are locked. */
|
||||
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_KeySourceReadWrite) == pmc::LockState::Locked);
|
||||
|
||||
/* Generate a random kek into keyslot 2. */
|
||||
se::SetRandomKey(pkg1::AesKeySlot_TzramSaveKek);
|
||||
|
||||
/* Verify that the se is in a validate state, context save, and validate again. */
|
||||
{
|
||||
se::ValidateErrStatus();
|
||||
ON_SCOPE_EXIT { se::ValidateErrStatus(); };
|
||||
|
||||
{
|
||||
/* Transition to non-secure mode for the duration of the context save operation. */
|
||||
se::SetSecure(false);
|
||||
ON_SCOPE_EXIT { se::SetSecure(true); };
|
||||
|
||||
/* Get a pointer to the context storage. */
|
||||
se::Context * const context = MemoryRegionVirtualDramSecureDataStoreSecurityEngineState.GetPointer<se::Context>();
|
||||
static_assert(MemoryRegionVirtualDramSecureDataStoreSecurityEngineState.GetSize() == sizeof(*context));
|
||||
|
||||
/* Save the context. */
|
||||
se::SaveContext(context);
|
||||
|
||||
/* Ensure that the cpu sees consistent data. */
|
||||
hw::FlushDataCache(context, sizeof(*context));
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Write the context pointer to pmc scratch, so that the bootrom will restore it on wake. */
|
||||
reg::Write(PMC + APBDEV_PMC_SCRATCH43, MemoryRegionPhysicalDramSecureDataStoreSecurityEngineState.GetAddress());
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear keyslot 3, and then derive the save key. */
|
||||
se::ClearAesKeySlot(pkg1::AesKeySlot_TzramSaveKey);
|
||||
se::SetEncryptedAesKey256(pkg1::AesKeySlot_TzramSaveKey, pkg1::AesKeySlot_TzramSaveKek, key_source, sizeof(key_source));
|
||||
|
||||
/* Declare a temporary block to be used as both iv and mac. */
|
||||
u32 temp_block[se::AesBlockSize / sizeof(u32)] = {};
|
||||
|
||||
/* Ensure that the SE sees consistent data for tzram. */
|
||||
const void * const tzram_save_src = MemoryRegionVirtualTzramReadOnlyAlias.GetPointer<u8>() + MemoryRegionVirtualTzramVolatileData.GetSize() + MemoryRegionVirtualTzramVolatileStack.GetSize();
|
||||
void * const tzram_save_dst = MemoryRegionVirtualIramSc7Work.GetPointer<void>();
|
||||
constexpr size_t TzramSaveSize = MemoryRegionVirtualDramSecureDataStoreTzram.GetSize();
|
||||
|
||||
hw::FlushDataCache(tzram_save_src, TzramSaveSize);
|
||||
hw::FlushDataCache(tzram_save_dst, TzramSaveSize);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Encrypt tzram using our random key. */
|
||||
se::EncryptAes256Cbc(tzram_save_dst, TzramSaveSize, pkg1::AesKeySlot_TzramSaveKey, tzram_save_src, TzramSaveSize, temp_block, se::AesBlockSize);
|
||||
hw::FlushDataCache(tzram_save_dst, TzramSaveSize);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Copy the data from work space to the secure storage destination. */
|
||||
void * const tzram_store_dst = MemoryRegionVirtualDramSecureDataStoreTzram.GetPointer<void>();
|
||||
std::memcpy(tzram_store_dst, tzram_save_dst, TzramSaveSize);
|
||||
hw::FlushDataCache(tzram_store_dst, TzramSaveSize);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Compute cmac of tzram into our temporary block. */
|
||||
se::ComputeAes256Cmac(temp_block, se::AesBlockSize, pkg1::AesKeySlot_TzramSaveKey, tzram_save_src, TzramSaveSize);
|
||||
|
||||
/* Ensure that the cmac registers are not locked. */
|
||||
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_CmacReadWrite) != pmc::LockState::Locked);
|
||||
|
||||
/* Write the cmac, lock writes to the cmac, and verify that the cmac is write-locked. */
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH112, temp_block[0]);
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH113, temp_block[1]);
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH114, temp_block[2]);
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH115, temp_block[3]);
|
||||
pmc::LockSecureRegister(pmc::SecureRegister_CmacWrite);
|
||||
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_CmacWrite) == pmc::LockState::Locked);
|
||||
|
||||
/* Verify the key source is correct in registers, and read-lock the key source registers. */
|
||||
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH112) == temp_block[0]);
|
||||
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH113) == temp_block[1]);
|
||||
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH114) == temp_block[2]);
|
||||
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH115) == temp_block[3]);
|
||||
pmc::LockSecureRegister(pmc::SecureRegister_CmacRead);
|
||||
|
||||
/* Ensure that the key source registers are locked. */
|
||||
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_CmacReadWrite) == pmc::LockState::Locked);
|
||||
}
|
||||
|
||||
void SaveSecureContextForMariko() {
|
||||
|
|
|
@ -21,7 +21,8 @@ namespace ams::pkg1 {
|
|||
enum AesKeySlot {
|
||||
AesKeySlot_UserStart = 0,
|
||||
|
||||
AesKeySlot_TzramSave = 2,
|
||||
AesKeySlot_TzramSaveKek = 2,
|
||||
AesKeySlot_TzramSaveKey = 3,
|
||||
|
||||
AesKeySlot_UserLast = 5,
|
||||
AesKeySlot_UserEnd = AesKeySlot_UserLast + 1,
|
||||
|
|
|
@ -42,8 +42,8 @@ namespace ams::pmc {
|
|||
void LockSecureRegister(SecureRegister reg);
|
||||
|
||||
enum class LockState {
|
||||
Locked = 0,
|
||||
NotLocked = 1,
|
||||
Locked = 0,
|
||||
NotLocked = 1,
|
||||
PartiallyLocked = 2,
|
||||
};
|
||||
|
||||
|
|
|
@ -38,6 +38,9 @@ namespace ams::se {
|
|||
void ComputeAes128Cmac(void *dst, size_t dst_size, int slot, const void *src, size_t src_size);
|
||||
void ComputeAes256Cmac(void *dst, size_t dst_size, int slot, const void *src, size_t src_size);
|
||||
|
||||
void EncryptAes128Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size);
|
||||
void EncryptAes256Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size);
|
||||
|
||||
void EncryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler);
|
||||
void DecryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler);
|
||||
void ComputeAes128CtrAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler);
|
||||
|
|
|
@ -30,6 +30,7 @@ namespace ams::se {
|
|||
|
||||
void HandleInterrupt();
|
||||
|
||||
void ValidateErrStatus();
|
||||
void ValidateAesOperationResult();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,5 +51,6 @@ namespace ams::se {
|
|||
static_assert(util::is_pod<StickyBits>::value);
|
||||
|
||||
bool ValidateStickyBits(const StickyBits &bits);
|
||||
void SaveContext(Context *dst);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ DEFINE_FLOW_REG_BIT_ENUM(HALT_CPUN_EVENTS_LIC_IRQN, 11, DISABLE, ENABLE);
|
|||
|
||||
DEFINE_FLOW_REG_THREE_BIT_ENUM(HALT_CPUN_EVENTS_FLOW_MODE, 29, NONE, RUN_AND_INT, WAITEVENT, WAITEVENT_AND_INT, STOP_UNTIL_IRQ, STOP_UNTIL_EVENT_AND_IRQ, RESERVED6, RESERVED7);
|
||||
|
||||
DEFINE_FLOW_REG_BIT_ENUM(HALT_COP_EVENTS_JTAG, 28, ENABLED, DISABLED);
|
||||
DEFINE_FLOW_REG_BIT_ENUM(HALT_COP_EVENTS_JTAG, 28, DISABLED, ENABLED);
|
||||
DEFINE_FLOW_REG_THREE_BIT_ENUM(HALT_COP_EVENTS_MODE, 29, FLOW_MODE_NONE, FLOW_MODE_RUN_AND_INT, FLOW_MODE_STOP, FLOW_MODE_STOP_AND_INT, FLOW_MODE_STOP_UNTIL_IRQ, FLOW_MODE_STOP_UNTIL_IRQ_AND_INT, FLOW_MODE_STOP_UNTIL_EVENT_AND_IRQ, RESERVED7);
|
||||
|
||||
DEFINE_FLOW_REG_BIT_ENUM(FLOW_DBG_QUAL_FIQ2CCPLEX_ENABLE, 28, DISABLE, ENABLE);
|
||||
|
|
|
@ -185,6 +185,8 @@ DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_AUD, 27, OFF, ON);
|
|||
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_DFD, 28, OFF, ON);
|
||||
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_VE2, 29, OFF, ON);
|
||||
|
||||
DEFINE_PMC_REG(PWRGATE_STATUS_CE123, 9, 3);
|
||||
|
||||
DEFINE_PMC_REG(SET_SW_CLAMP_CRAIL, 0, 1);
|
||||
|
||||
DEFINE_PMC_REG_TWO_BIT_ENUM(IO_DPD_REQ_CODE, 30, IDLE, DPD_OFF, DPD_ON, RESERVED3);
|
||||
|
|
|
@ -277,6 +277,37 @@ namespace ams::se {
|
|||
GetCmacResult(SE, dst, dst_size);
|
||||
}
|
||||
|
||||
void EncryptAesCbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size, AesMode mode) {
|
||||
/* If nothing to encrypt, succeed. */
|
||||
if (src_size == 0) { return; }
|
||||
|
||||
/* Validate input. */
|
||||
AMS_ABORT_UNLESS(iv_size == AesBlockSize);
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount);
|
||||
|
||||
/* Get the engine. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Determine extents. */
|
||||
const size_t num_blocks = src_size / AesBlockSize;
|
||||
const size_t aligned_size = num_blocks * AesBlockSize;
|
||||
AMS_ABORT_UNLESS(src_size == aligned_size);
|
||||
|
||||
/* Configure for aes-cbc encryption. */
|
||||
SetConfig(SE, true, SE_CONFIG_DST_MEMORY);
|
||||
SetAesConfig(SE, slot, true, AesConfigCbcEncrypt);
|
||||
UpdateAesMode(SE, mode);
|
||||
|
||||
/* Set the iv. */
|
||||
SetAesKeyIv(SE, slot, iv, iv_size);
|
||||
|
||||
/* Set the block count. */
|
||||
SetBlockCount(SE, num_blocks);
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteOperation(SE, SE_OPERATION_OP_START, dst, dst_size, src, aligned_size);
|
||||
}
|
||||
|
||||
void ComputeAes128Async(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, DoneHandler handler, u32 config, bool encrypt, volatile SecurityEngineRegisters *SE) {
|
||||
/* If nothing to decrypt, succeed. */
|
||||
if (size == 0) { return; }
|
||||
|
@ -448,6 +479,14 @@ namespace ams::se {
|
|||
return ComputeAesCmac(dst, dst_size, slot, src, src_size, AesMode_Aes256);
|
||||
}
|
||||
|
||||
void EncryptAes128Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size) {
|
||||
return EncryptAesCbc(dst, dst_size, slot, src, src_size, iv, iv_size, AesMode_Aes128);
|
||||
}
|
||||
|
||||
void EncryptAes256Cbc(void *dst, size_t dst_size, int slot, const void *src, size_t src_size, const void *iv, size_t iv_size) {
|
||||
return EncryptAesCbc(dst, dst_size, slot, src, src_size, iv, iv_size, AesMode_Aes256);
|
||||
}
|
||||
|
||||
void EncryptAes128CbcAsync(u32 out_ll_address, int slot, u32 in_ll_address, u32 size, const void *iv, size_t iv_size, DoneHandler handler) {
|
||||
/* Validate the iv. */
|
||||
AMS_ABORT_UNLESS(iv_size == AesBlockSize);
|
||||
|
|
|
@ -158,6 +158,16 @@ namespace ams::se {
|
|||
SE_CONFIG_ENC_MODE_SHA512 = 7,
|
||||
};
|
||||
|
||||
/* SE_CTX_SAVE_CONFIG */
|
||||
DEFINE_SE_REG_TWO_BIT_ENUM(CTX_SAVE_CONFIG_AES_WORD_QUAD, 0, KEYS_0_3, KEYS_4_7, ORIGINAL_IVS, UPDATED_IVS);
|
||||
DEFINE_SE_REG(CTX_SAVE_CONFIG_PKA1_WORD_QUAD_L, 0, 4);
|
||||
DEFINE_SE_REG(CTX_SAVE_CONFIG_AES_KEY_INDEX, 8, 4);
|
||||
DEFINE_SE_REG(CTX_SAVE_CONFIG_RSA_WORD_QUAD, 12, 4);
|
||||
DEFINE_SE_REG(CTX_SAVE_CONFIG_PKA1_WORD_QUAD_H, 12, 4);
|
||||
DEFINE_SE_REG_TWO_BIT_ENUM(CTX_SAVE_CONFIG_RSA_KEY_INDEX, 16, SLOT0_EXPONENT, SLOT0_MODULUS, SLOT1_EXPONENT, SLOT1_MODULUS);
|
||||
DEFINE_SE_REG_BIT_ENUM(CTX_SAVE_CONFIG_STICKY_WORD_QUAD, 24, WORDS_0_3, WORDS_4_7);
|
||||
DEFINE_SE_REG_THREE_BIT_ENUM(CTX_SAVE_CONFIG_SRC, 29, STICKY_BITS, RSA_KEYTABLE, AES_KEYTABLE, PKA1_STICKY_BITS, MEM, RESERVED5, SRK, PKA1_KEYTABLE);
|
||||
|
||||
/* SE_SHA_CONFIG */
|
||||
DEFINE_SE_REG(SHA_CONFIG_HW_INIT_HASH, 0, 1);
|
||||
|
||||
|
|
|
@ -20,10 +20,50 @@ namespace ams::se {
|
|||
|
||||
namespace {
|
||||
|
||||
constinit const u8 FixedPattern[AesBlockSize] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
|
||||
};
|
||||
|
||||
bool TestRegister(volatile u32 &r, u16 v) {
|
||||
return (static_cast<u16>(reg::Read(r))) == v;
|
||||
}
|
||||
|
||||
void ExecuteContextSaveOperation(volatile SecurityEngineRegisters *SE, void *dst, size_t dst_size, const void *src, size_t src_size) {
|
||||
/* Save the output to a temporary buffer. */
|
||||
util::AlignedBuffer<hw::DataCacheLineSize, AesBlockSize> temp;
|
||||
AMS_ABORT_UNLESS(dst_size <= AesBlockSize);
|
||||
|
||||
/* Ensure that the cpu and SE see consistent data. */
|
||||
if (src_size > 0) {
|
||||
hw::FlushDataCache(src, src_size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
if (dst_size > 0) {
|
||||
hw::FlushDataCache(temp, AesBlockSize);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteOperation(SE, SE_OPERATION_OP_CTX_SAVE, dst, dst_size, src, src_size);
|
||||
|
||||
/* Copy output from the operation, if any. */
|
||||
if (dst_size > 0) {
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
hw::FlushDataCache(temp, AesBlockSize);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
std::memcpy(dst, temp, dst_size);
|
||||
}
|
||||
}
|
||||
|
||||
void SaveContextBlock(volatile SecurityEngineRegisters *SE, void *dst) {
|
||||
/* Configure to encrypt a single block. */
|
||||
reg::Write(SE->SE_CRYPTO_LAST_BLOCK, 0);
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteContextSaveOperation(SE, dst, AesBlockSize, nullptr, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool ValidateStickyBits(const StickyBits &bits) {
|
||||
|
@ -56,4 +96,156 @@ namespace ams::se {
|
|||
return true;
|
||||
}
|
||||
|
||||
void SaveContext(Context *dst) {
|
||||
/* Get the registers. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Generate a random srk. */
|
||||
GenerateSrk();
|
||||
|
||||
/* Save a randomly-generated block. */
|
||||
{
|
||||
util::AlignedBuffer<hw::DataCacheLineSize, AesBlockSize> random_block;
|
||||
|
||||
/* Flush the region we're about to fill to ensure consistency with the SE. */
|
||||
hw::FlushDataCache(random_block, AesBlockSize);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Generate random bytes. */
|
||||
GenerateRandomBytes(random_block, AesBlockSize);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Flush to ensure the CPU sees consistent data for the region. */
|
||||
hw::FlushDataCache(random_block, AesBlockSize);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Configure to encrypt the random block to memory. */
|
||||
reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM(CONFIG_ENC_MODE, AESMODE_KEY128),
|
||||
SE_REG_BITS_ENUM(CONFIG_DEC_MODE, AESMODE_KEY128),
|
||||
SE_REG_BITS_ENUM(CONFIG_ENC_ALG, AES_ENC),
|
||||
SE_REG_BITS_ENUM(CONFIG_DEC_ALG, NOP),
|
||||
SE_REG_BITS_ENUM(CONFIG_DST, MEMORY));
|
||||
|
||||
/* Configure to context save using memory as source. */
|
||||
reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM(CTX_SAVE_CONFIG_SRC, MEM));
|
||||
|
||||
/* Configure to encrypt a single block. */
|
||||
reg::Write(SE->SE_CRYPTO_LAST_BLOCK, 0);
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteContextSaveOperation(SE, dst->random, AesBlockSize, random_block, AesBlockSize);
|
||||
}
|
||||
|
||||
/* Save the sticky bits. */
|
||||
for (size_t i = 0; i < util::size(dst->sticky_bits); ++i) {
|
||||
/* Configure to encrypt the sticky bits block. */
|
||||
reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_SRC, STICKY_BITS),
|
||||
SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_STICKY_WORD_QUAD, i));
|
||||
|
||||
/* Save the block. */
|
||||
SaveContextBlock(SE, dst->sticky_bits[i]);
|
||||
}
|
||||
|
||||
/* Save the aes keytable. */
|
||||
{
|
||||
for (size_t key = 0; key < util::size(dst->aes_key); ++key) {
|
||||
for (auto part = 0; part < AesKeySlotPartCount; ++part) {
|
||||
/* Configure to encrypt the part of the key. */
|
||||
reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_SRC, AES_KEYTABLE),
|
||||
SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_AES_KEY_INDEX, key),
|
||||
SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_AES_WORD_QUAD, part));
|
||||
|
||||
/* Save the block. */
|
||||
SaveContextBlock(SE, dst->aes_key[key][part]);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t key = 0; key < util::size(dst->aes_oiv); ++key) {
|
||||
/* Configure to encrypt the original iv. */
|
||||
reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_SRC, AES_KEYTABLE),
|
||||
SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_AES_KEY_INDEX, key),
|
||||
SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_AES_WORD_QUAD, ORIGINAL_IVS));
|
||||
|
||||
/* Save the block. */
|
||||
SaveContextBlock(SE, dst->aes_oiv[key]);
|
||||
}
|
||||
|
||||
for (size_t key = 0; key < util::size(dst->aes_uiv); ++key) {
|
||||
/* Configure to encrypt the updated iv. */
|
||||
reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_SRC, AES_KEYTABLE),
|
||||
SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_AES_KEY_INDEX, key),
|
||||
SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_AES_WORD_QUAD, UPDATED_IVS));
|
||||
|
||||
/* Save the block. */
|
||||
SaveContextBlock(SE, dst->aes_uiv[key]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Save the rsa keytable. */
|
||||
for (size_t key = 0; key < util::size(dst->rsa_key); ++key) {
|
||||
for (auto part = 0; part < RsaKeySlotPartCount; ++part) {
|
||||
/* Note that the parts are done in reverse order. */
|
||||
const auto part_index = RsaKeySlotPartCount - 1 - part;
|
||||
|
||||
/* Determine a total key index. */
|
||||
const auto key_index = key * util::size(dst->rsa_key) + part_index;
|
||||
|
||||
for (size_t block = 0; block < RsaSize / AesBlockSize; ++block) {
|
||||
/* Configure to encrypt the part of the key. */
|
||||
reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM (CTX_SAVE_CONFIG_SRC, RSA_KEYTABLE),
|
||||
SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_RSA_KEY_INDEX, key_index),
|
||||
SE_REG_BITS_VALUE(CTX_SAVE_CONFIG_RSA_WORD_QUAD, block));
|
||||
|
||||
/* Save the block. */
|
||||
SaveContextBlock(SE, dst->rsa_key[key][part][block]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Save the fixed pattern. */
|
||||
{
|
||||
/* Configure to context save using memory as source. */
|
||||
reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM(CTX_SAVE_CONFIG_SRC, MEM));
|
||||
|
||||
/* Configure to encrypt a single block. */
|
||||
reg::Write(SE->SE_CRYPTO_LAST_BLOCK, 0);
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteContextSaveOperation(SE, dst->fixed_pattern, AesBlockSize, FixedPattern, AesBlockSize);
|
||||
}
|
||||
|
||||
/* Save the srk. */
|
||||
{
|
||||
/* Configure to context save using srk as source. */
|
||||
reg::Write(SE->SE_CTX_SAVE_CONFIG, SE_REG_BITS_ENUM(CTX_SAVE_CONFIG_SRC, SRK));
|
||||
|
||||
/* Configure to encrypt a single block. */
|
||||
reg::Write(SE->SE_CRYPTO_LAST_BLOCK, 0);
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteContextSaveOperation(SE, nullptr, 0, nullptr, 0);
|
||||
}
|
||||
|
||||
/* Perform a no-op context save operation. */
|
||||
{
|
||||
/* Configure to perform no-op. */
|
||||
reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM(CONFIG_ENC_ALG, NOP),
|
||||
SE_REG_BITS_ENUM(CONFIG_DEC_ALG, NOP));
|
||||
|
||||
/* Execute the operation. */
|
||||
ExecuteContextSaveOperation(SE, nullptr, 0, nullptr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void ValidateErrStatus() {
|
||||
/* Get the registers. */
|
||||
auto *SE = GetRegisters();
|
||||
|
||||
/* Ensure there is no error status. */
|
||||
AMS_ABORT_UNLESS(reg::Read(SE->SE_ERR_STATUS) == 0);
|
||||
|
||||
/* Ensure no error occurred. */
|
||||
AMS_ABORT_UNLESS(reg::HasValue(SE->SE_INT_STATUS, SE_REG_BITS_ENUM(INT_STATUS_ERR_STAT, CLEAR)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue