mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-05-25 20:24:21 -04:00
exo2: implement SmcComputeAes, SmcGetResult, SmcGetResultData
This commit is contained in:
parent
b6b114ec40
commit
e0dbfc69a8
16 changed files with 486 additions and 24 deletions
|
@ -206,6 +206,10 @@ namespace ams::gic {
|
|||
ReadWrite(g_distributor_address + offsetof(GicDistributor, icfgr), 2, interrupt_id, static_cast<u32>(mode) << 1);
|
||||
}
|
||||
|
||||
void SetPending(int interrupt_id) {
|
||||
Write(g_distributor_address + offsetof(GicDistributor, ispendr), 1, interrupt_id, 1);
|
||||
}
|
||||
|
||||
int GetInterruptRequestId() {
|
||||
return reg::Read(GetCpuInterface()->iar);
|
||||
}
|
||||
|
|
|
@ -33,21 +33,37 @@ namespace ams::se {
|
|||
MemoryInterface_Mc = SE_CRYPTO_CONFIG_MEMIF_MCCIF,
|
||||
};
|
||||
|
||||
constexpr inline u32 AesConfigEcb = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, MEMORY),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, MEMORY),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, BYPASS),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE));
|
||||
constexpr inline u32 AesConfigEcb = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, MEMORY),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, MEMORY),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, BYPASS),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE));
|
||||
|
||||
constexpr inline u32 AesConfigCtr = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 1),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, MEMORY),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, LINEAR_CTR),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, BOTTOM),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE));
|
||||
constexpr inline u32 AesConfigCtr = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 1),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, MEMORY),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, LINEAR_CTR),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, BOTTOM),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE));
|
||||
|
||||
constexpr inline u32 AesConfigCbcEncrypt = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, INIT_AESOUT),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, MEMORY),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, TOP),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE));
|
||||
|
||||
constexpr inline u32 AesConfigCbcDecrypt = reg::Encode(SE_REG_BITS_VALUE(CRYPTO_CONFIG_CTR_CNTN, 0),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_KEYSCH_BYPASS, DISABLE),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_IV_SELECT, ORIGINAL),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_VCTRAM_SEL, INIT_PREV_MEMORY),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_INPUT_SEL, MEMORY),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_XOR_POS, BOTTOM),
|
||||
SE_REG_BITS_ENUM (CRYPTO_CONFIG_HASH_ENB, DISABLE));
|
||||
|
||||
void SetConfig(volatile SecurityEngineRegisters *SE, bool encrypt, SE_CONFIG_DST dst) {
|
||||
reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM (CONFIG_ENC_MODE, AESMODE_KEY128),
|
||||
|
@ -73,9 +89,9 @@ namespace ams::se {
|
|||
reg::ReadWrite(SE->SE_CONFIG, REG_BITS_VALUE(16, 16, mode));
|
||||
}
|
||||
|
||||
// void UpdateMemoryInterface(volatile SecurityEngineRegisters *SE, MemoryInterface memif) {
|
||||
// reg::ReadWrite(SE->SE_CRYPTO_CONFIG, SE_REG_BITS_VALUE(CRYPTO_CONFIG_MEMIF, memif));
|
||||
// }
|
||||
void UpdateMemoryInterface(volatile SecurityEngineRegisters *SE, MemoryInterface memif) {
|
||||
reg::ReadWrite(SE->SE_CRYPTO_CONFIG, SE_REG_BITS_VALUE(CRYPTO_CONFIG_MEMIF, memif));
|
||||
}
|
||||
|
||||
void SetCounter(volatile SecurityEngineRegisters *SE, const void *ctr) {
|
||||
const u32 *ctr_32 = reinterpret_cast<const u32 *>(ctr);
|
||||
|
@ -87,6 +103,25 @@ namespace ams::se {
|
|||
reg::Write(SE->SE_CRYPTO_LINEAR_CTR[3], util::LoadLittleEndian(ctr_32 + 3));
|
||||
}
|
||||
|
||||
void SetAesKeyIv(volatile SecurityEngineRegisters *SE, int slot, const void *iv, size_t iv_size) {
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount);
|
||||
AMS_ABORT_UNLESS(iv_size <= AesBlockSize);
|
||||
|
||||
/* Set each iv word in order. */
|
||||
const u32 *iv_u32 = static_cast<const u32 *>(iv);
|
||||
const int num_words = iv_size / sizeof(u32);
|
||||
for (int i = 0; i < num_words; ++i) {
|
||||
/* Select the keyslot. */
|
||||
reg::Write(SE->SE_CRYPTO_KEYTABLE_ADDR, SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, slot),
|
||||
SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_KEYIV_SEL, IV),
|
||||
SE_REG_BITS_ENUM (CRYPTO_KEYTABLE_ADDR_KEYIV_IV_SEL, ORIGINAL_IV),
|
||||
SE_REG_BITS_VALUE(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_WORD, i));
|
||||
|
||||
/* Set the key word. */
|
||||
SE->SE_CRYPTO_KEYTABLE_DATA = *(iv_u32++);
|
||||
}
|
||||
}
|
||||
|
||||
void SetEncryptedAesKey(int dst_slot, int kek_slot, const void *key, size_t key_size, AesMode mode) {
|
||||
AMS_ABORT_UNLESS(key_size <= AesKeySizeMax);
|
||||
AMS_ABORT_UNLESS(0 <= dst_slot && dst_slot < AesKeySlotCount);
|
||||
|
@ -133,6 +168,29 @@ namespace ams::se {
|
|||
ExecuteOperationSingleBlock(SE, dst, dst_size, src, src_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; }
|
||||
|
||||
/* Validate input. */
|
||||
AMS_ABORT_UNLESS(0 <= slot && slot < AesKeySlotCount);
|
||||
|
||||
/* Configure for the specific operation. */
|
||||
SetConfig(SE, encrypt, SE_CONFIG_DST_MEMORY);
|
||||
SetAesConfig(SE, slot, encrypt, config);
|
||||
UpdateMemoryInterface(SE, MemoryInterface_Mc);
|
||||
|
||||
/* Configure the number of blocks. */
|
||||
const int num_blocks = size / AesBlockSize;
|
||||
SetBlockCount(SE, num_blocks);
|
||||
|
||||
/* Set the done handler. */
|
||||
SetDoneHandler(SE, handler);
|
||||
|
||||
/* Start the raw operation. */
|
||||
StartOperationRaw(SE, SE_OPERATION_OP_START, out_ll_address, in_ll_address);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ClearAesKeySlot(int slot) {
|
||||
|
@ -270,4 +328,49 @@ namespace ams::se {
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/* Get the registers. */
|
||||
volatile auto *SE = GetRegisters();
|
||||
|
||||
/* Set the iv. */
|
||||
SetAesKeyIv(SE, slot, iv, iv_size);
|
||||
|
||||
/* Perform the asynchronous aes operation. */
|
||||
ComputeAes128Async(out_ll_address, slot, in_ll_address, size, handler, AesConfigCbcEncrypt, true, SE);
|
||||
}
|
||||
|
||||
void DecryptAes128CbcAsync(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);
|
||||
|
||||
/* Get the registers. */
|
||||
volatile auto *SE = GetRegisters();
|
||||
|
||||
/* Set the iv. */
|
||||
SetAesKeyIv(SE, slot, iv, iv_size);
|
||||
|
||||
/* Perform the asynchronous aes operation. */
|
||||
ComputeAes128Async(out_ll_address, slot, in_ll_address, size, handler, AesConfigCbcDecrypt, false, SE);
|
||||
}
|
||||
|
||||
void ComputeAes128CtrAsync(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);
|
||||
|
||||
/* Get the registers. */
|
||||
volatile auto *SE = GetRegisters();
|
||||
|
||||
/* Here Nintendo writes 1 to SE_SPARE. It's unclear why they do this, but we will do so as well. */
|
||||
SE->SE_SPARE = 0x1;
|
||||
|
||||
/* Set the counter. */
|
||||
SetCounter(SE, iv);
|
||||
|
||||
/* Perform the asynchronous aes operation. */
|
||||
ComputeAes128Async(out_ll_address, slot, in_ll_address, size, handler, AesConfigCtr, true, SE);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -64,6 +64,13 @@ namespace ams::se {
|
|||
reg::Write(SE->SE_OPERATION, SE_REG_BITS_VALUE(OPERATION_OP, op));
|
||||
}
|
||||
|
||||
void EnsureOperationStarted(volatile SecurityEngineRegisters *SE) {
|
||||
/* Read the operation register to make sure our write takes. */
|
||||
reg::Read(SE->SE_OPERATION);
|
||||
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
|
||||
void WaitForOperationComplete(volatile SecurityEngineRegisters *SE) {
|
||||
/* Spin until the operation is done. */
|
||||
while (reg::HasValue(SE->SE_INT_STATUS, SE_REG_BITS_ENUM(INT_STATUS_SE_OP_DONE, CLEAR))) { /* ... */ }
|
||||
|
@ -124,6 +131,18 @@ namespace ams::se {
|
|||
std::memcpy(dst, aligned, dst_size);
|
||||
}
|
||||
|
||||
void StartOperationRaw(volatile SecurityEngineRegisters *SE, SE_OPERATION_OP op, u32 out_ll_address, u32 in_ll_address) {
|
||||
/* Configure the linked list addresses. */
|
||||
reg::Write(SE->SE_IN_LL_ADDR, in_ll_address);
|
||||
reg::Write(SE->SE_OUT_LL_ADDR, out_ll_address);
|
||||
|
||||
/* Start the operation. */
|
||||
StartOperation(SE, op);
|
||||
|
||||
/* Ensure the operation is started. */
|
||||
EnsureOperationStarted(SE);
|
||||
}
|
||||
|
||||
void ValidateAesOperationResult(volatile SecurityEngineRegisters *SE) {
|
||||
/* Ensure no error occurred. */
|
||||
AMS_ABORT_UNLESS(reg::HasValue(SE->SE_INT_STATUS, SE_REG_BITS_ENUM(INT_STATUS_ERR_STAT, CLEAR)));
|
||||
|
@ -132,7 +151,11 @@ namespace ams::se {
|
|||
AMS_ABORT_UNLESS(reg::HasValue(SE->SE_STATUS, SE_REG_BITS_ENUM(STATUS_STATE, IDLE)));
|
||||
|
||||
/* Ensure there is no error status. */
|
||||
AMS_ABORT_UNLESS(reg::Read(SE->SE_ERR_STATUS) == 0);
|
||||
AMS_ABORT_UNLESS(reg::Read(SE->SE_ERR_STATUS) == 0);
|
||||
}
|
||||
|
||||
void ValidateAesOperationResult() {
|
||||
return ValidateAesOperationResult(GetRegisters());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,9 @@ namespace ams::se {
|
|||
void ExecuteOperation(volatile SecurityEngineRegisters *SE, SE_OPERATION_OP op, void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
void ExecuteOperationSingleBlock(volatile SecurityEngineRegisters *SE, void *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
|
||||
void StartOperationRaw(volatile SecurityEngineRegisters *SE, SE_OPERATION_OP op, u32 out_ll_address, u32 in_ll_address);
|
||||
void SetDoneHandler(volatile SecurityEngineRegisters *SE, DoneHandler handler);
|
||||
|
||||
void ValidateAesOperationResult(volatile SecurityEngineRegisters *SE);
|
||||
|
||||
}
|
||||
|
|
|
@ -105,4 +105,12 @@ namespace ams::se {
|
|||
}
|
||||
}
|
||||
|
||||
void SetDoneHandler(volatile SecurityEngineRegisters *SE, DoneHandler handler) {
|
||||
/* Set the done handler. */
|
||||
g_done_handler = handler;
|
||||
|
||||
/* Configure to trigger an interrupt when done. */
|
||||
reg::Write(SE->SE_INT_ENABLE, SE_REG_BITS_ENUM(INT_ENABLE_SE_OP_DONE, ENABLE));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue