exo2: Initial work on the exosphere rewrite.

exo2: Implement uncompressor stub and boot code up to Main().

exo2: implement some more init (uart/gic)

exo2: implement more of init

exo2: improve reg api, add keyslot flag setters

exo2: implement se aes decryption/enc

exo2: fix bugs in loader stub/mmu mappings

exo2: start skeletoning bootconfig/global context types

arch: fix makefile flags

exo2: implement through master key derivation

exo2: implement device master keygen

exo2: more init through start of SetupSocSecurity

exo2: implement pmc secure scratch management

se: implement sticky bit validation

libexosphere: fix building for arm32

libexo: fix makefile flags

libexo: support building for arm64/arm

sc7fw: skeleton binary

sc7fw: skeleton a little more

sc7fw: implement all non-dram functionality

exo2: fix DivideUp error

sc7fw: implement more dram code, fix reg library errors

sc7fw: complete sc7fw impl.

exo2: skeleton the rest of SetupSocSecurity

exo2: implement fiq interrupt handler

exo2: implement all exception handlers

exo2: skeleton the entire smc api, implement the svc invoker

exo2: implement rest of SetupSocSecurity

exo2: correct slave security errors

exo2: fix register definition

exo2: minor fixes
This commit is contained in:
Michael Scire 2020-05-04 23:33:16 -07:00 committed by SciresM
parent 71e0102f7a
commit f66b41c027
192 changed files with 15093 additions and 24 deletions

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
namespace ams::secmon::boot {
void MakePageTable();
void InitializeColdBoot();
}

View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
namespace ams::secmon::boot {
/* TODO */
}

View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
namespace ams::secmon::boot {
/* TODO */
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "secmon_boot_functions.hpp"
namespace ams::secmon::boot {
void ClearIram() {
/* Clear the boot code image from where it was loaded in IRAM. */
util::ClearMemory(MemoryRegionPhysicalIramBootCodeImage.GetPointer(), MemoryRegionPhysicalIramBootCodeImage.GetSize());
}
}

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
namespace ams::secmon::boot {
void ClearIram();
}

View file

@ -0,0 +1,337 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "secmon_boot.hpp"
#include "../secmon_setup.hpp"
#include "../secmon_key_storage.hpp"
namespace ams::secmon::boot {
namespace {
void ValidateSystemCounters() {
const uintptr_t sysctr0 = MemoryRegionVirtualDeviceSysCtr0.GetAddress();
/* Validate the system counter frequency is as expected. */
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_CNTFID0) == 19'200'000u);
/* Validate the system counters are as expected. */
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 0)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 1)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 2)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 3)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 4)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 5)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 6)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 7)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 8)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID( 9)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID(10)) == 0);
AMS_ABORT_UNLESS(reg::Read(sysctr0 + SYSCTR0_COUNTERID(11)) == 0);
}
void SetupPmcRegisters() {
const auto pmc = MemoryRegionVirtualDevicePmc.GetAddress();
/* Set the physical address of the warmboot binary to scratch 1. */
reg::Write(pmc + APBDEV_PMC_SCRATCH1, static_cast<u32>(MemoryRegionPhysicalDramSecureDataStoreWarmbootFirmware.GetAddress()));
/* Configure logging by setting bits 18-19 of scratch 20. */
reg::ReadWrite(pmc + APBDEV_PMC_SCRATCH20, REG_BITS_VALUE(18, 2, 0));
/* Clear the wdt reset flag. */
reg::ReadWrite(pmc + APBDEV_PMC_SCRATCH190, REG_BITS_VALUE(0, 1, 0));
/* Configure warmboot to set Set FUSE_PRIVATEKEYDISABLE to KEY_INVISIBLE. */
reg::ReadWrite(pmc + APBDEV_PMC_SECURE_SCRATCH21, REG_BITS_VALUE(4, 1, 1));
/* Write the warmboot key. */
/* TODO */
}
/* This function derives the master kek and device keys using the tsec root key. */
/* NOTE: Exosphere does not use this in practice, and expects the bootloader to set up keys already. */
/* NOTE: This function is currently not implemented. If implemented, it will only be a reference implementation. */
[[maybe_unused]]
void DeriveMasterKekAndDeviceKey() {
/* TODO: Decide whether to implement this. */
}
void SetupRandomKey(int slot, se::KeySlotLockFlags flags) {
/* Create an aligned buffer to hold the key. */
constexpr size_t KeySize = se::AesBlockSize;
util::AlignedBuffer<hw::DataCacheLineSize, KeySize> key;
/* Ensure data is consistent before triggering the SE. */
hw::FlushDataCache(key, KeySize);
hw::DataSynchronizationBarrierInnerShareable();
/* Generate random bytes into the key. */
se::GenerateRandomBytes(key, KeySize);
/* Ensure that the CPU sees consistent data. */
hw::DataSynchronizationBarrierInnerShareable();
hw::FlushDataCache(key, KeySize);
hw::DataSynchronizationBarrierInnerShareable();
/* Use the random bytes as a key source. */
se::SetEncryptedAesKey128(slot, pkg1::AesKeySlot_DeviceMaster, key, KeySize);
/* Lock the keyslot. */
se::LockAesKeySlot(slot, flags);
}
constinit const u8 MasterKeyVectorsDev[pkg1::OldMasterKeyCount + 1][se::AesBlockSize] = {
{0x46, 0x22, 0xB4, 0x51, 0x9A, 0x7E, 0xA7, 0x7F, 0x62, 0xA1, 0x1F, 0x8F, 0xC5, 0x3A, 0xDB, 0xFE}, /* Zeroes encrypted with Master Key 00. */
{0x39, 0x33, 0xF9, 0x31, 0xBA, 0xE4, 0xA7, 0x21, 0x2C, 0xDD, 0xB7, 0xD8, 0xB4, 0x4E, 0x37, 0x23}, /* Master key 00 encrypted with Master key 01. */
{0x97, 0x29, 0xB0, 0x32, 0x43, 0x14, 0x8C, 0xA6, 0x85, 0xE9, 0x5A, 0x94, 0x99, 0x39, 0xAC, 0x5D}, /* Master key 01 encrypted with Master key 02. */
{0x2C, 0xCA, 0x9C, 0x31, 0x1E, 0x07, 0xB0, 0x02, 0x97, 0x0A, 0xD8, 0x03, 0xA2, 0x76, 0x3F, 0xA3}, /* Master key 02 encrypted with Master key 03. */
{0x9B, 0x84, 0x76, 0x14, 0x72, 0x94, 0x52, 0xCB, 0x54, 0x92, 0x9B, 0xC4, 0x8C, 0x5B, 0x0F, 0xBA}, /* Master key 03 encrypted with Master key 04. */
{0x78, 0xD5, 0xF1, 0x20, 0x3D, 0x16, 0xE9, 0x30, 0x32, 0x27, 0x34, 0x6F, 0xCF, 0xE0, 0x27, 0xDC}, /* Master key 04 encrypted with Master key 05. */
{0x6F, 0xD2, 0x84, 0x1D, 0x05, 0xEC, 0x40, 0x94, 0x5F, 0x18, 0xB3, 0x81, 0x09, 0x98, 0x8D, 0x4E}, /* Master key 05 encrypted with Master key 06. */
{0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19}, /* Master key 06 encrypted with Master key 07. */
{0xEC, 0xE1, 0x46, 0x89, 0x37, 0xFD, 0xD2, 0x15, 0x8C, 0x3F, 0x24, 0x82, 0xEF, 0x49, 0x68, 0x04}, /* Master key 07 encrypted with Master key 08. */
{0x43, 0x3D, 0xC5, 0x3B, 0xEF, 0x91, 0x02, 0x21, 0x61, 0x54, 0x63, 0x8A, 0x35, 0xE7, 0xCA, 0xEE}, /* Master key 08 encrypted with Master key 09. */
{0x6C, 0x2E, 0xCD, 0xB3, 0x34, 0x61, 0x77, 0xF5, 0xF9, 0xB1, 0xDD, 0x61, 0x98, 0x19, 0x3E, 0xD4}, /* Master key 09 encrypted with Master key 0A. */
};
constinit const u8 MasterKeyVectorsProd[pkg1::OldMasterKeyCount + 1][se::AesBlockSize] = {
{0x0C, 0xF0, 0x59, 0xAC, 0x85, 0xF6, 0x26, 0x65, 0xE1, 0xE9, 0x19, 0x55, 0xE6, 0xF2, 0x67, 0x3D}, /* Zeroes encrypted with Master Key 00. */
{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. */
{0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */
{0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */
{0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */
{0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */
{0x4D, 0xD9, 0x98, 0x42, 0x45, 0x0D, 0xB1, 0x3C, 0x52, 0x0C, 0x9A, 0x44, 0xBB, 0xAD, 0xAF, 0x80}, /* Master key 08 encrypted with Master key 09. */
{0xB8, 0x96, 0x9E, 0x4A, 0x00, 0x0D, 0xD6, 0x28, 0xB3, 0xD1, 0xDB, 0x68, 0x5F, 0xFB, 0xE1, 0x2A}, /* Master key 09 encrypted with Master key 0A. */
};
bool TestKeyGeneration(int generation, bool is_prod) {
/* Decrypt the vector chain from generation to start. */
int slot = pkg1::AesKeySlot_Master;
for (int i = generation; i > 0; --i) {
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Temporary, slot, is_prod ? MasterKeyVectorsProd[i] : MasterKeyVectorsDev[i], se::AesBlockSize);
slot = pkg1::AesKeySlot_Temporary;
}
/* Decrypt the final vector. */
u8 test_vector[se::AesBlockSize];
se::DecryptAes128(test_vector, se::AesBlockSize, slot, is_prod ? MasterKeyVectorsProd[0] : MasterKeyVectorsDev[0], se::AesBlockSize);
constexpr u8 ZeroBlock[se::AesBlockSize] = {};
return crypto::IsSameBytes(ZeroBlock, test_vector, se::AesBlockSize);
}
int DetermineKeyGeneration(bool is_prod) {
/* Test each generation in order. */
for (int generation = 0; generation < pkg1::KeyGeneration_Count; ++generation) {
if (TestKeyGeneration(generation, is_prod)) {
return generation;
}
}
/* We must have found a correct key generation. */
AMS_ABORT();
}
void DeriveAllMasterKeys(bool is_prod, u8 * const work_block) {
/* Determine the generation. */
const int generation = DetermineKeyGeneration(is_prod);
/* Set the global generation. */
::ams::secmon::impl::SetKeyGeneration(generation);
/* Derive all old keys. */
int slot = pkg1::AesKeySlot_Master;
for (int i = generation; i > 0; --i) {
/* Decrypt the old master key. */
se::DecryptAes128(work_block, se::AesBlockSize, slot, is_prod ? MasterKeyVectorsProd[i] : MasterKeyVectorsDev[i], se::AesBlockSize);
/* Set the old master key. */
SetMasterKey(generation - 1, work_block, se::AesBlockSize);
/* Set the old master key into a temporary keyslot. */
se::SetAesKey(pkg1::AesKeySlot_Temporary, work_block, se::AesBlockSize);
/* Perform the next decryption with the older master key. */
slot = pkg1::AesKeySlot_Temporary;
}
}
constinit const u8 DeviceMasterKeySourceSources[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
{0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.0.0 Device Master Key Source Source. */
{0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.0.0 Device Master Key Source Source. */
{0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.0.0 Device Master Key Source Source. */
{0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 Device Master Key Source Source. */
{0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 Device Master Key Source Source. */
{0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE}, /* 8.1.0 Device Master Key Source Source. */
{0x4A, 0xC3, 0x4E, 0x14, 0x8B, 0x96, 0x4A, 0xD5, 0xD4, 0x99, 0x73, 0xC4, 0x45, 0xAB, 0x8B, 0x49}, /* 9.0.0 Device Master Key Source Source. */
{0x14, 0xB8, 0x74, 0x12, 0xCB, 0xBD, 0x0B, 0x8F, 0x20, 0xFB, 0x30, 0xDA, 0x27, 0xE4, 0x58, 0x94}, /* 9.1.0 Device Master Key Source Source. */
};
constinit const u8 DeviceMasterKekSourcesDev[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
{0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34}, /* 4.0.0 Device Master Kek Source. */
{0x59, 0x2D, 0x20, 0x69, 0x33, 0xB5, 0x17, 0xBA, 0xCF, 0xB1, 0x4E, 0xFD, 0xE4, 0xC2, 0x7B, 0xA8}, /* 5.0.0 Device Master Kek Source. */
{0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5}, /* 6.0.0 Device Master Kek Source. */
{0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38}, /* 6.2.0 Device Master Kek Source. */
{0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 7.0.0 Device Master Kek Source. */
{0x94, 0xD6, 0xA8, 0xC0, 0x95, 0xAF, 0xD0, 0xA6, 0x27, 0x53, 0x5E, 0xE5, 0x8E, 0x70, 0x1F, 0x87}, /* 8.1.0 Device Master Kek Source. */
{0x61, 0x6A, 0x88, 0x21, 0xA3, 0x52, 0xB0, 0x19, 0x16, 0x25, 0xA4, 0xE3, 0x4C, 0x54, 0x02, 0x0F}, /* 9.0.0 Device Master Kek Source. */
{0x9D, 0xB1, 0xAE, 0xCB, 0xF6, 0xF6, 0xE3, 0xFE, 0xAB, 0x6F, 0xCB, 0xAF, 0x38, 0x03, 0xFC, 0x7B}, /* 9.1.0 Device Master Kek Source. */
};
constinit const u8 DeviceMasterKekSourcesProd[pkg1::OldDeviceMasterKeyCount][se::AesBlockSize] = {
{0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.0.0 Device Master Kek Source. */
{0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.0.0 Device Master Kek Source. */
{0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.0.0 Device Master Kek Source. */
{0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 Device Master Kek Source. */
{0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 Device Master Kek Source. */
{0xA6, 0x81, 0x71, 0xE7, 0xB5, 0x23, 0x74, 0xB0, 0x39, 0x8C, 0xB7, 0xFF, 0xA0, 0x62, 0x9F, 0x8D}, /* 8.1.0 Device Master Kek Source. */
{0x03, 0xE7, 0xEB, 0x43, 0x1B, 0xCF, 0x5F, 0xB5, 0xED, 0xDC, 0x97, 0xAE, 0x21, 0x8D, 0x19, 0xED}, /* 9.0.0 Device Master Kek Source. */
{0xCE, 0xFE, 0x41, 0x0F, 0x46, 0x9A, 0x30, 0xD6, 0xF2, 0xE9, 0x0C, 0x6B, 0xB7, 0x15, 0x91, 0x36}, /* 9.1.0 Device Master Kek Source. */
};
void DeriveAllDeviceMasterKeys(bool is_prod, u8 * const work_block) {
/* Get the current key generation. */
const int current_generation = secmon::GetKeyGeneration();
/* Iterate for all generations. */
for (int i = 0; i < pkg1::OldDeviceMasterKeyCount; ++i) {
const int generation = pkg1::KeyGeneration_4_0_0 + i;
/* Load the first master key into the temporary keyslot keyslot. */
LoadMasterKey(pkg1::AesKeySlot_Temporary, pkg1::KeyGeneration_1_0_0);
/* Decrypt the device master kek for the generation. */
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Temporary, pkg1::AesKeySlot_Temporary, is_prod ? DeviceMasterKekSourcesProd[i] : DeviceMasterKekSourcesDev[i], se::AesBlockSize);
/* Decrypt the device master key source into the work block. */
se::DecryptAes128(work_block, se::AesBlockSize, pkg1::AesKeySlot_DeviceMasterKeySourceKek, DeviceMasterKeySourceSources[i], se::AesBlockSize);
/* If we're decrypting the current device master key, decrypt into the keyslot. */
if (generation == current_generation) {
se::SetEncryptedAesKey128(pkg1::AesKeySlot_DeviceMaster, pkg1::AesKeySlot_Temporary, work_block, se::AesBlockSize);
} else {
/* Otherwise, decrypt the work block into itself and set the old device master key. */
se::DecryptAes128(work_block, se::AesBlockSize, pkg1::AesKeySlot_Temporary, work_block, se::AesBlockSize);
/* Set the device master key. */
SetDeviceMasterKey(generation, work_block, se::AesBlockSize);
}
}
/* Clear and lock the Device Master Key Source Kek. */
se::ClearAesKeySlot(pkg1::AesKeySlot_DeviceMasterKeySourceKek);
se::LockAesKeySlot(pkg1::AesKeySlot_DeviceMasterKeySourceKek, se::KeySlotLockFlags_AllLockKek);
}
void DeriveAllKeys() {
/* Determine whether we're prod. */
const bool is_prod = fuse::GetHardwareState() != fuse::HardwareState_Development;
/* Get the ephemeral work block. */
u8 * const work_block = se::GetEphemeralWorkBlock();
ON_SCOPE_EXIT { util::ClearMemory(work_block, se::AesBlockSize); };
/* Lock the master key as a key. */
se::LockAesKeySlot(pkg1::AesKeySlot_Master, se::KeySlotLockFlags_AllLockKey);
/* Setup a random key to protect the old master and device master keys. */
SetupRandomKey(pkg1::AesKeySlot_RandomForKeyStorageWrap, se::KeySlotLockFlags_AllLockKey);
/* Derive the master keys. */
DeriveAllMasterKeys(is_prod, work_block);
/* Derive the device master keys. */
DeriveAllDeviceMasterKeys(is_prod, work_block);
/* Lock the device master key as a kek. */
se::LockAesKeySlot(pkg1::AesKeySlot_DeviceMaster, se::KeySlotLockFlags_AllLockKek);
/* Setup a random key to protect user keys. */
SetupRandomKey(pkg1::AesKeySlot_RandomForUserWrap, se::KeySlotLockFlags_AllLockKek);
}
void InitializeKeys() {
/* Read lock all aes keys. */
for (int i = 0; i < se::AesKeySlotCount; ++i) {
se::LockAesKeySlot(i, se::KeySlotLockFlags_AllReadLock);
}
/* Lock the secure monitor aes keys to be secmon only and non-readable. */
for (int i = pkg1::AesKeySlot_SecmonStart; i < pkg1::AesKeySlot_SecmonEnd; ++i) {
se::LockAesKeySlot(i, se::KeySlotLockFlags_KeyUse | se::KeySlotLockFlags_PerKey);
}
/* Lock the unused keyslots entirely. */
static_assert(pkg1::AesKeySlot_UserEnd <= pkg1::AesKeySlot_SecmonStart);
for (int i = pkg1::AesKeySlot_UserEnd; i < pkg1::AesKeySlot_SecmonStart; ++i) {
se::LockAesKeySlot(i, se::KeySlotLockFlags_AllLockKek);
}
/* Read lock all rsa keys. */
for (int i = 0; i < se::RsaKeySlotCount; ++i) {
se::LockRsaKeySlot(i, se::KeySlotLockFlags_KeyUse | se::KeySlotLockFlags_PerKey | se::KeySlotLockFlags_KeyRead);
}
/* Initialize the rng. */
se::InitializeRandom();
/* Derive the master kek and device key. */
if constexpr (false) {
DeriveMasterKekAndDeviceKey();
}
/* Lock the device key as only usable as a kek. */
se::LockAesKeySlot(pkg1::AesKeySlot_Device, se::KeySlotLockFlags_AllLockKek);
/* Derive all keys. */
DeriveAllKeys();
}
}
void InitializeColdBoot() {
/* Ensure that the system counters are valid. */
ValidateSystemCounters();
/* Set the security engine to Tzram Secure. */
se::SetTzramSecure();
/* Set the security engine to Per Key Secure. */
se::SetPerKeySecure();
/* Setup the PMC registers. */
SetupPmcRegisters();
/* Lockout the scratch that we've just written. */
/* pmc::LockSecureRegisters(1); */
/* Generate a random srk. */
se::GenerateSrk();
/* Initialize the SE keyslots. */
InitializeKeys();
/* Save a test vector for the SE keyslots. */
SaveSecurityEngineAesKeySlotTestVector();
}
}

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
.section .crt0.text.start, "ax", %progbits
.align 6
.global _start
_start:
/* mask all interrupts */
msr daifset, #0xF
/* Set the stack pointer to a temporary location. */
ldr x20, =0x7C010800
mov sp, x20
/* Initialize all memory to expected state. */
ldr x0, =__bss_start__
ldr x1, =__bss_end__
ldr x2, =__boot_bss_start__
ldr x3, =__boot_bss_end__
bl _ZN3ams6secmon4boot10InitializeEmmmm
/* Jump to the first bit of virtual code. */
ldr x16, =_ZN3ams6secmon5StartEv
br x16

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "secmon_boot.hpp"
#include "../secmon_setup.hpp"
extern "C" void __libc_init_array();
namespace ams::secmon::boot {
void Initialize(uintptr_t bss_start, size_t bss_end, uintptr_t boot_bss_start, uintptr_t boot_bss_end) {
/* Set our start time. */
auto &secmon_params = *MemoryRegionPhysicalDeviceBootloaderParams.GetPointer<pkg1::SecureMonitorParameters>();
secmon_params.secmon_start_time = *reinterpret_cast<volatile u32 *>(MemoryRegionPhysicalDeviceTimer.GetAddress() + 0x10);
/* Setup DMA controllers. */
SetupSocDmaControllers();
/* Make the page table. */
MakePageTable();
/* Setup memory controllers the MMU. */
SetupCpuMemoryControllersEnableMmu();
/* Clear bss. */
std::memset(reinterpret_cast<void *>(bss_start), 0, bss_end - bss_start);
std::memset(reinterpret_cast<void *>(boot_bss_start), 0, boot_bss_end - boot_bss_start);
/* Call init array. */
__libc_init_array();
}
}

View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
namespace ams::secmon::boot {
/* TODO */
}

View file

@ -0,0 +1,69 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "secmon_boot.hpp"
#include "secmon_boot_functions.hpp"
#include "../secmon_setup.hpp"
#include "../secmon_misc.hpp"
namespace ams::secmon {
void Main() {
/* Set library register addresses. */
/* actmon::SetRegisterAddress(MemoryRegionVirtualDeviceActivityMonitor.GetAddress()); */
clkrst::SetRegisterAddress(MemoryRegionVirtualDeviceClkRst.GetAddress());
/* flowctrl::SetRegisterAddress(); */
fuse::SetRegisterAddress(MemoryRegionVirtualDeviceFuses.GetAddress());
gic::SetRegisterAddress(MemoryRegionVirtualDeviceGicDistributor.GetAddress(), MemoryRegionVirtualDeviceGicCpuInterface.GetAddress());
i2c::SetRegisterAddress(i2c::Port_1, MemoryRegionVirtualDeviceI2c1.GetAddress());
i2c::SetRegisterAddress(i2c::Port_5, MemoryRegionVirtualDeviceI2c5.GetAddress());
/* pinmux::SetRegisterAddress(); */
pmc::SetRegisterAddress(MemoryRegionVirtualDevicePmc.GetAddress());
se::SetRegisterAddress(MemoryRegionVirtualDeviceSecurityEngine.GetAddress());
uart::SetRegisterAddress(MemoryRegionVirtualDeviceUart.GetAddress());
wdt::SetRegisterAddress(MemoryRegionVirtualDeviceTimer.GetAddress());
util::SetRegisterAddress(MemoryRegionVirtualDeviceTimer.GetAddress());
/* Get the secure monitor parameters. */
auto &secmon_params = *reinterpret_cast<pkg1::SecureMonitorParameters *>(MemoryRegionVirtualDeviceBootloaderParams.GetAddress());
/* Perform initialization. */
{
/* Perform initial setup. */
/* This checks the security engine's validity, and configures common interrupts in the GIC. */
/* This also initializes the global configuration context. */
secmon::Setup1();
/* Save the boot info. */
secmon::SaveBootInfo(secmon_params);
/* Perform cold-boot specific init. */
secmon::boot::InitializeColdBoot();
/* Setup the SoC security measures. */
secmon::SetupSocSecurity();
/* TODO: More init. */
/* Clear the crt0 code that was present in iram. */
secmon::boot::ClearIram();
/* Alert the bootloader that we're initialized. */
secmon_params.secmon_state = pkg1::SecureMonitorState_Initialized;
}
}
}

View file

@ -0,0 +1,147 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "../secmon_setup.hpp"
#include "secmon_boot.hpp"
namespace ams::secmon::boot {
namespace {
using namespace ams::mmu;
constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureRoCode = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRoCode, MemoryAttributeIndexNormal);
constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureRwCode = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRwCode, MemoryAttributeIndexNormal);
constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureRoData = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRoData, MemoryAttributeIndexNormal);
constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureRwData = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRwData, MemoryAttributeIndexNormal);
constexpr inline PageTableMappingAttribute MappingAttributesEl3NonSecureRwData = AddMappingAttributeIndex(PageTableMappingAttributes_El3NonSecureRwData, MemoryAttributeIndexNormal);
constexpr inline PageTableMappingAttribute MappingAttributesEl3SecureDevice = AddMappingAttributeIndex(PageTableMappingAttributes_El3SecureRwData, MemoryAttributeIndexDevice);
constexpr inline PageTableMappingAttribute MappingAttributesEl3NonSecureDevice = AddMappingAttributeIndex(PageTableMappingAttributes_El3NonSecureRwData, MemoryAttributeIndexDevice);
constexpr void ClearMemory(volatile u64 *start, size_t size) {
volatile u64 * const end = start + (size / sizeof(u64));
for (volatile u64 *cur = start; cur < end; ++cur) {
*cur = 0;
}
}
constexpr void MakePageTablesImpl(u64 *l1, u64 *l2, u64 *l3) {
/* Setup the L1 table. */
{
ClearMemory(l1, MemoryRegionPhysicalTzramL1PageTable.GetSize());
/* Create an L1 table entry for the physical region. */
SetL1TableEntry(l1, MemoryRegionPhysical.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode);
static_assert(GetL1EntryIndex(MemoryRegionPhysical.GetAddress()) == 1);
/* Create an L1 mapping entry for dram. */
SetL1BlockEntry(l1, MemoryRegionDram.GetAddress(), MemoryRegionDram.GetAddress(), MemoryRegionDram.GetSize(), MappingAttributesEl3NonSecureRwData);
/* Create an L1 table entry for the virtual region. */
SetL1TableEntry(l1, MemoryRegionVirtual.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode);
}
/* Setup the L2 table. */
{
ClearMemory(l2, MemoryRegionPhysicalTzramL2L3PageTable.GetSize());
/* Create an L2 table entry for the virtual region. */
SetL2TableEntry(l2, MemoryRegionVirtualL2.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode);
/* Create an L2 table entry for the physical iram region. */
SetL2TableEntry(l2, MemoryRegionPhysicalIramL2.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode);
/* Create an L2 table entry for the physical tzram region. */
SetL2TableEntry(l2, MemoryRegionPhysicalTzramL2.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), PageTableTableAttributes_El3SecureCode);
}
/* Setup the L3 table. */
{
/* L2 and L3 share a page table. */
if (l2 != l3) {
ClearMemory(l3, MemoryRegionPhysicalTzramL2L3PageTable.GetSize());
}
/* Identity-map TZRAM as rwx. */
SetL3BlockEntry(l3, MemoryRegionPhysicalTzram.GetAddress(), MemoryRegionPhysicalTzram.GetAddress(), MemoryRegionPhysicalTzram.GetSize(), MappingAttributesEl3SecureRwCode);
/* Identity-map IRAM boot code as rwx. */
SetL3BlockEntry(l3, MemoryRegionPhysicalIramBootCode.GetAddress(), MemoryRegionPhysicalIramBootCode.GetAddress(), MemoryRegionPhysicalIramBootCode.GetSize(), MappingAttributesEl3SecureRwCode);
/* Map all devices. */
{
#define MAP_DEVICE_REGION(_NAME_, _PREV_, _ADDRESS_, _SIZE_, _SECURE_) \
SetL3BlockEntry(l3, MemoryRegionVirtualDevice##_NAME_.GetAddress(), MemoryRegionPhysicalDevice##_NAME_.GetAddress(), MemoryRegionVirtualDevice##_NAME_.GetSize(), _SECURE_ ? MappingAttributesEl3SecureDevice : MappingAttributesEl3NonSecureDevice);
AMS_SECMON_FOREACH_DEVICE_REGION(MAP_DEVICE_REGION);
#undef MAP_DEVICE_REGION
}
/* Map the IRAM SC7 work region. */
SetL3BlockEntry(l3, MemoryRegionVirtualIramSc7Work.GetAddress(), MemoryRegionPhysicalIramSc7Work.GetAddress(), MemoryRegionVirtualIramSc7Work.GetSize(), MappingAttributesEl3NonSecureDevice);
/* Map the IRAM SC7 firmware region. */
SetL3BlockEntry(l3, MemoryRegionVirtualIramSc7Firmware.GetAddress(), MemoryRegionPhysicalIramSc7Firmware.GetAddress(), MemoryRegionVirtualIramSc7Firmware.GetSize(), MappingAttributesEl3NonSecureDevice);
/* Map the TZRAM ro alias region. */
SetL3BlockEntry(l3, MemoryRegionVirtualTzramReadOnlyAlias.GetAddress(), MemoryRegionPhysicalTzramReadOnlyAlias.GetAddress(), MemoryRegionVirtualTzramReadOnlyAlias.GetSize(), MappingAttributesEl3SecureRoData);
/* Map the DRAM secure data store region. */
SetL3BlockEntry(l3, MemoryRegionVirtualDramSecureDataStore.GetAddress(), MemoryRegionPhysicalDramSecureDataStore.GetAddress(), MemoryRegionVirtualDramSecureDataStore.GetSize(), MappingAttributesEl3NonSecureDevice);
/* Map the program region as rwx. */
SetL3BlockEntry(l3, MemoryRegionVirtualTzramProgram.GetAddress(), MemoryRegionPhysicalTzramProgram.GetAddress(), MemoryRegionVirtualTzramProgram.GetSize(), MappingAttributesEl3SecureRwCode);
/* Map the boot code region. */
SetL3BlockEntry(l3, MemoryRegionVirtualTzramBootCode.GetAddress(), MemoryRegionPhysicalTzramBootCode.GetAddress(), MemoryRegionVirtualTzramBootCode.GetSize(), MappingAttributesEl3SecureRwCode);
/* Map the volatile data regions regions. */
SetL3BlockEntry(l3, MemoryRegionVirtualTzramVolatileData.GetAddress(), MemoryRegionPhysicalTzramVolatileData.GetAddress(), MemoryRegionVirtualTzramVolatileData.GetSize(), MappingAttributesEl3SecureRwData);
SetL3BlockEntry(l3, MemoryRegionVirtualTzramVolatileStack.GetAddress(), MemoryRegionPhysicalTzramVolatileStack.GetAddress(), MemoryRegionVirtualTzramVolatileStack.GetSize(), MappingAttributesEl3SecureRwData);
/* Map the configuration data. */
SetL3BlockEntry(l3, MemoryRegionVirtualTzramConfigurationData.GetAddress(), MemoryRegionPhysicalTzramConfigurationData.GetAddress(), MemoryRegionVirtualTzramConfigurationData.GetSize(), MappingAttributesEl3SecureRwData);
/* Map the page tables. */
SetL3BlockEntry(l3, util::AlignDown(MemoryRegionVirtualTzramL1PageTable.GetAddress(), PageSize), util::AlignDown(MemoryRegionPhysicalTzramL1PageTable.GetAddress(), PageSize), PageSize, MappingAttributesEl3SecureDevice);
SetL3BlockEntry(l3, MemoryRegionVirtualTzramL2L3PageTable.GetAddress(), MemoryRegionPhysicalTzramL2L3PageTable.GetAddress(), MemoryRegionVirtualTzramL2L3PageTable.GetSize(), MappingAttributesEl3SecureRwData);
}
}
constexpr bool ValidateTzramPageTables() {
u64 l1_table[MemoryRegionPhysicalTzramL1PageTable.GetSize() / sizeof(u64)] = {};
u64 l2_l3_table[MemoryRegionPhysicalTzramL2L3PageTable.GetSize() / sizeof(u64)] = {};
MakePageTablesImpl(l1_table, l2_l3_table, l2_l3_table);
return true;
}
static_assert(ValidateTzramPageTables());
}
void MakePageTable() {
u64 * const l1 = MemoryRegionPhysicalTzramL1PageTable.GetPointer<u64>();
u64 * const l2_l3 = MemoryRegionPhysicalTzramL2L3PageTable.GetPointer<u64>();
MakePageTablesImpl(l1, l2_l3, l2_l3);
}
}

View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
namespace ams::secmon::boot {
/* TODO */
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
.section .metadata.sizes, "ax", %progbits
.align 6
.global __metadata__sizes
__metadata__sizes:
.quad 0xAAAAAAAAAAAAAAAA, 0xBBBBBBBBBBBBBBBB
.quad __glob_start__
.quad __bootcode_start__
.quad __bootcode_end__
.quad __program_start__
.quad 0xCCCCCCCCCCCCCCCC, 0xDDDDDDDDDDDDDDDD

View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
void FlushEntireDataCache();
void InvalidateEntireDataCache();
void EnsureMappingConsistency();
void EnsureMappingConsistency(uintptr_t address);
void EnsureInstructionConsistency();

View file

@ -0,0 +1,132 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
namespace {
ALWAYS_INLINE int FloorLog2(int v) {
return BITSIZEOF(u32) - (hw::CountLeadingZeros(static_cast<u32>(v)) + 1);
}
ALWAYS_INLINE int CeilLog2(int v) {
const int log = FloorLog2(v);
return ((1 << log) == v) ? log : log + 1;
}
void FlushDataCacheTo(int loc) {
for (int level = 0; level < loc; ++level) {
/* Set the selection register. */
{
util::BitPack32 csselr = {};
csselr.Set<hw::CsselrEl1::InD>(0);
csselr.Set<hw::CsselrEl1::Level>(level);
HW_CPU_SET_CSSELR_EL1(csselr);
}
/* Ensure that reordering doesn't occur around this operation. */
hw::InstructionSynchronizationBarrier();
/* Get ccsidr. */
util::BitPack32 ccsidr;
HW_CPU_GET_CCSIDR_EL1(ccsidr);
/* Get cache size id info. */
const int num_sets = ccsidr.Get<hw::CcsidrEl1::NumSets>() + 1;
const int num_ways = ccsidr.Get<hw::CcsidrEl1::Associativity>() + 1;
const int line_size = ccsidr.Get<hw::CcsidrEl1::LineSize>() + 4;
const int way_shift = 32 - FloorLog2(num_ways);
const int set_shift = line_size;
for (int way = 0; way <= num_ways; way++) {
for (int set = 0; set <= num_sets; set++) {
const u64 value = (static_cast<u64>(way) << way_shift) | (static_cast<u64>(set) << set_shift) | (static_cast<u64>(level) << 1);
__asm__ __volatile__("dc cisw, %[value]" :: [value]"r"(value) : "memory");
}
}
}
}
void InvalidateDataCacheTo(int loc) {
for (int level = 0; level < loc; ++level) {
/* Set the selection register. */
{
util::BitPack32 csselr = {};
csselr.Set<hw::CsselrEl1::InD>(0);
csselr.Set<hw::CsselrEl1::Level>(level);
HW_CPU_SET_CSSELR_EL1(csselr);
}
/* Ensure that reordering doesn't occur around this operation. */
hw::InstructionSynchronizationBarrier();
/* Get ccsidr. */
util::BitPack32 ccsidr;
HW_CPU_GET_CCSIDR_EL1(ccsidr);
/* Get cache size id info. */
const int num_sets = ccsidr.Get<hw::CcsidrEl1::NumSets>() + 1;
const int num_ways = ccsidr.Get<hw::CcsidrEl1::Associativity>() + 1;
const int line_size = ccsidr.Get<hw::CcsidrEl1::LineSize>() + 4;
const int way_shift = 32 - FloorLog2(num_ways);
const int set_shift = line_size;
for (int way = 0; way <= num_ways; way++) {
for (int set = 0; set <= num_sets; set++) {
const u64 value = (static_cast<u64>(way) << way_shift) | (static_cast<u64>(set) << set_shift) | (static_cast<u64>(level) << 1);
__asm__ __volatile__("dc isw, %[value]" :: [value]"r"(value) : "memory");
}
}
}
}
}
void FlushEntireDataCache() {
util::BitPack32 clidr;
HW_CPU_GET_CLIDR_EL1(clidr);
FlushDataCacheTo(clidr.Get<hw::ClidrEl1::Loc>());
}
void InvalidateEntireDataCache() {
util::BitPack32 clidr;
HW_CPU_GET_CLIDR_EL1(clidr);
InvalidateDataCacheTo(clidr.Get<hw::ClidrEl1::Loc>());
}
void EnsureMappingConsistency() {
::ams::hw::DataSynchronizationBarrierInnerShareable();
::ams::hw::InvalidateEntireTlb();
::ams::hw::DataSynchronizationBarrierInnerShareable();
::ams::hw::InstructionSynchronizationBarrier();
}
void EnsureMappingConsistency(uintptr_t address) {
::ams::hw::DataSynchronizationBarrierInnerShareable();
::ams::hw::InvalidateTlb(address);
::ams::hw::DataSynchronizationBarrierInnerShareable();
::ams::hw::InstructionSynchronizationBarrier();
}
void EnsureInstructionConsistency() {
::ams::hw::DataSynchronizationBarrierInnerShareable();
::ams::hw::InvalidateEntireInstructionCache();
::ams::hw::DataSynchronizationBarrierInnerShareable();
::ams::hw::InstructionSynchronizationBarrier();
}

View file

@ -0,0 +1,192 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "secmon_cpu_context.hpp"
#include "secmon_error.hpp"
namespace ams::secmon {
namespace {
struct DebugRegisters {
u32 osdttrx_el1;
u32 osdtrtx_el1;
u32 mdscr_el1;
u32 oseccr_el1;
u32 mdccint_el1;
u32 dbgclaimclr_el1;
u32 dbgvcr32_el2;
u32 sder32_el3;
u32 mdcr_el2;
u32 mdcr_el3;
u32 spsr_el3;
u64 dbgbvcr_el1[12];
u64 dbgwvcr_el1[ 8];
};
struct CoreContext {
EntryContext entry_context;
bool is_on;
bool is_reset_expected;
bool is_debug_registers_saved;
DebugRegisters debug_registers;
};
void SaveDebugRegisters(DebugRegisters &dr) {
/* Set the OS lock; this will be unlocked by entry code. */
HW_CPU_SET_OSLAR_EL1(1);
/* Save general debug registers. */
HW_CPU_GET_OSDTRRX_EL1 (dr.osdttrx_el1);
HW_CPU_GET_OSDTRTX_EL1 (dr.osdtrtx_el1);
HW_CPU_GET_MDSCR_EL1 (dr.mdscr_el1);
HW_CPU_GET_OSECCR_EL1 (dr.oseccr_el1);
HW_CPU_GET_MDCCINT_EL1 (dr.mdccint_el1);
HW_CPU_GET_DBGCLAIMCLR_EL1(dr.dbgclaimclr_el1);
HW_CPU_GET_DBGVCR32_EL2 (dr.dbgvcr32_el2);
HW_CPU_GET_SDER32_EL3 (dr.sder32_el3);
HW_CPU_GET_MDCR_EL2 (dr.mdcr_el2);
HW_CPU_GET_MDCR_EL3 (dr.mdcr_el3);
HW_CPU_GET_SPSR_EL3 (dr.spsr_el3);
/* Save debug breakpoints. */
HW_CPU_GET_DBGBVR0_EL1(dr.dbgbvcr_el1[ 0]);
HW_CPU_GET_DBGBCR0_EL1(dr.dbgbvcr_el1[ 1]);
HW_CPU_GET_DBGBVR1_EL1(dr.dbgbvcr_el1[ 2]);
HW_CPU_GET_DBGBCR1_EL1(dr.dbgbvcr_el1[ 3]);
HW_CPU_GET_DBGBVR2_EL1(dr.dbgbvcr_el1[ 4]);
HW_CPU_GET_DBGBCR2_EL1(dr.dbgbvcr_el1[ 5]);
HW_CPU_GET_DBGBVR3_EL1(dr.dbgbvcr_el1[ 6]);
HW_CPU_GET_DBGBCR3_EL1(dr.dbgbvcr_el1[ 7]);
HW_CPU_GET_DBGBVR4_EL1(dr.dbgbvcr_el1[ 8]);
HW_CPU_GET_DBGBCR4_EL1(dr.dbgbvcr_el1[ 9]);
HW_CPU_GET_DBGBVR5_EL1(dr.dbgbvcr_el1[10]);
HW_CPU_GET_DBGBCR5_EL1(dr.dbgbvcr_el1[11]);
/* Save debug watchpoints. */
HW_CPU_GET_DBGWVR0_EL1(dr.dbgwvcr_el1[0]);
HW_CPU_GET_DBGWCR0_EL1(dr.dbgwvcr_el1[1]);
HW_CPU_GET_DBGWVR1_EL1(dr.dbgwvcr_el1[2]);
HW_CPU_GET_DBGWCR1_EL1(dr.dbgwvcr_el1[3]);
HW_CPU_GET_DBGWVR2_EL1(dr.dbgwvcr_el1[4]);
HW_CPU_GET_DBGWCR2_EL1(dr.dbgwvcr_el1[5]);
HW_CPU_GET_DBGWVR3_EL1(dr.dbgwvcr_el1[6]);
HW_CPU_GET_DBGWCR3_EL1(dr.dbgwvcr_el1[7]);
}
void RestoreDebugRegisters(const DebugRegisters &dr) {
/* Restore general debug registers. */
HW_CPU_SET_OSDTRRX_EL1 (dr.osdttrx_el1);
HW_CPU_SET_OSDTRTX_EL1 (dr.osdtrtx_el1);
HW_CPU_SET_MDSCR_EL1 (dr.mdscr_el1);
HW_CPU_SET_OSECCR_EL1 (dr.oseccr_el1);
HW_CPU_SET_MDCCINT_EL1 (dr.mdccint_el1);
HW_CPU_SET_DBGCLAIMCLR_EL1(dr.dbgclaimclr_el1);
HW_CPU_SET_DBGVCR32_EL2 (dr.dbgvcr32_el2);
HW_CPU_SET_SDER32_EL3 (dr.sder32_el3);
HW_CPU_SET_MDCR_EL2 (dr.mdcr_el2);
HW_CPU_SET_MDCR_EL3 (dr.mdcr_el3);
HW_CPU_SET_SPSR_EL3 (dr.spsr_el3);
/* Restore debug breakpoints. */
HW_CPU_SET_DBGBVR0_EL1(dr.dbgbvcr_el1[ 0]);
HW_CPU_SET_DBGBCR0_EL1(dr.dbgbvcr_el1[ 1]);
HW_CPU_SET_DBGBVR1_EL1(dr.dbgbvcr_el1[ 2]);
HW_CPU_SET_DBGBCR1_EL1(dr.dbgbvcr_el1[ 3]);
HW_CPU_SET_DBGBVR2_EL1(dr.dbgbvcr_el1[ 4]);
HW_CPU_SET_DBGBCR2_EL1(dr.dbgbvcr_el1[ 5]);
HW_CPU_SET_DBGBVR3_EL1(dr.dbgbvcr_el1[ 6]);
HW_CPU_SET_DBGBCR3_EL1(dr.dbgbvcr_el1[ 7]);
HW_CPU_SET_DBGBVR4_EL1(dr.dbgbvcr_el1[ 8]);
HW_CPU_SET_DBGBCR4_EL1(dr.dbgbvcr_el1[ 9]);
HW_CPU_SET_DBGBVR5_EL1(dr.dbgbvcr_el1[10]);
HW_CPU_SET_DBGBCR5_EL1(dr.dbgbvcr_el1[11]);
/* Restore debug watchpoints. */
HW_CPU_SET_DBGWVR0_EL1(dr.dbgwvcr_el1[0]);
HW_CPU_SET_DBGWCR0_EL1(dr.dbgwvcr_el1[1]);
HW_CPU_SET_DBGWVR1_EL1(dr.dbgwvcr_el1[2]);
HW_CPU_SET_DBGWCR1_EL1(dr.dbgwvcr_el1[3]);
HW_CPU_SET_DBGWVR2_EL1(dr.dbgwvcr_el1[4]);
HW_CPU_SET_DBGWCR2_EL1(dr.dbgwvcr_el1[5]);
HW_CPU_SET_DBGWVR3_EL1(dr.dbgwvcr_el1[6]);
HW_CPU_SET_DBGWCR3_EL1(dr.dbgwvcr_el1[7]);
}
constinit CoreContext g_core_contexts[NumCores] = {};
}
bool IsCoreOn(int core) {
return g_core_contexts[core].is_on;
}
void SetCoreOff() {
g_core_contexts[hw::GetCurrentCoreId()].is_on = false;
}
bool IsResetExpected() {
return g_core_contexts[hw::GetCurrentCoreId()].is_reset_expected;
}
void SetResetExpected(int core, bool expected) {
g_core_contexts[core].is_reset_expected = expected;
}
void SetResetExpected(bool expected) {
SetResetExpected(hw::GetCurrentCoreId(), expected);
}
void SetEntryContext(int core, uintptr_t address, uintptr_t arg) {
g_core_contexts[core].entry_context.pc = address;
g_core_contexts[core].entry_context.x0 = arg;
}
void GetEntryContext(EntryContext *out) {
auto &ctx = g_core_contexts[hw::GetCurrentCoreId()];
const auto pc = ctx.entry_context.pc;
const auto x0 = ctx.entry_context.x0;
if (pc == 0 || ctx.is_on) {
SetError(pkg1::ErrorInfo_InvalidCoreContext);
AMS_ABORT("Invalid core context");
}
ctx.entry_context = {};
ctx.is_on = true;
out->pc = pc;
out->x0 = x0;
}
void SaveDebugRegisters() {
auto &ctx = g_core_contexts[hw::GetCurrentCoreId()];
SaveDebugRegisters(ctx.debug_registers);
ctx.is_debug_registers_saved = true;
}
void RestoreDebugRegisters() {
auto &ctx = g_core_contexts[hw::GetCurrentCoreId()];
if (ctx.is_debug_registers_saved) {
RestoreDebugRegisters(ctx.debug_registers);
ctx.is_debug_registers_saved = false;
}
}
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
namespace ams::secmon {
constexpr inline int NumCores = 4;
struct EntryContext {
u64 x0;
u64 pc;
};
bool IsCoreOn(int core);
void SetCoreOff();
bool IsResetExpected();
void SetResetExpected(int core, bool expected);
void SetResetExpected(bool expected);
void SetEntryContext(int core, uintptr_t address, uintptr_t arg);
void GetEntryContext(EntryContext *out);
void SaveDebugRegisters();
void RestoreDebugRegisters();
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "secmon_error.hpp"
namespace ams::diag {
void AbortImpl() {
secmon::SetError(pkg1::ErrorInfo_UnknownAbort);
secmon::ErrorReboot();
}
}
namespace ams::secmon {
void SetError(pkg1::ErrorInfo info) {
const uintptr_t address = secmon::MemoryRegionVirtualDevicePmc.GetAddress() + PKG1_SECURE_MONITOR_PMC_ERROR_SCRATCH;
if (reg::Read(address) == pkg1::ErrorInfo_None) {
reg::Write(address, info);
}
}
NORETURN void ErrorReboot() {
/* Lockout the security engine. */
se::Lockout();
/* TODO: Lockout fuses. */
/* TODO: Disable SE Crypto Operations. */
while (true) {
wdt::Reboot();
}
}
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
namespace ams::secmon {
void SetError(pkg1::ErrorInfo info);
NORETURN void ErrorReboot();
}

View file

@ -0,0 +1,326 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Some macros taken from https://github.com/ARM-software/arm-trusted-firmware/blob/master/include/common/aarch64/asm_macros.S */
/*
* Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* Declare the exception vector table, enforcing it is aligned on a
* 2KB boundary, as required by the ARMv8 architecture.
* Use zero bytes as the fill value to be stored in the padding bytes
* so that it inserts illegal AArch64 instructions. This increases
* security, robustness and potentially facilitates debugging.
*/
.macro vector_base label, section_name=.vectors
.section \section_name, "ax"
.align 11, 0
\label:
.endm
/*
* Create an entry in the exception vector table, enforcing it is
* aligned on a 128-byte boundary, as required by the ARMv8 architecture.
* Use zero bytes as the fill value to be stored in the padding bytes
* so that it inserts illegal AArch64 instructions. This increases
* security, robustness and potentially facilitates debugging.
*/
.macro vector_entry label, section_name=.vectors
.cfi_sections .debug_frame
.section \section_name, "ax"
.align 7, 0
.type \label, %function
.func \label
.cfi_startproc
\label:
.endm
/*
* This macro verifies that the given vector doesnt exceed the
* architectural limit of 32 instructions. This is meant to be placed
* immediately after the last instruction in the vector. It takes the
* vector entry as the parameter
*/
.macro check_vector_size since
.endfunc
.cfi_endproc
.if (. - \since) > (32 * 4)
.error "Vector exceeds 32 instructions"
.endif
.endm
/* Actual Vectors for Secure Monitor. */
.global _ZN3ams6secmon16ExceptionVectorsEv
vector_base _ZN3ams6secmon16ExceptionVectorsEv
/* Current EL, SP0 */
vector_entry synch_sp0
/* Branch to the exception handler. */
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
.endfunc
.cfi_endproc
_ZN3ams6secmon26UnexpectedExceptionHandlerEv:
/* Load the ErrorInfo scratch. */
ldr x0, =0x1F004AC40
/* Write ErrorInfo_UnknownAbort to it. */
ldr w1, =0x07F00010
str w1, [x0]
/* Perform an error reboot. */
b _ZN3ams6secmon11ErrorRebootEv
vector_entry irq_sp0
/* An unexpected exception was taken. */
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
check_vector_size irq_sp0
vector_entry fiq_sp0
/* An unexpected exception was taken. */
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
check_vector_size fiq_sp0
vector_entry serror_sp0
/* An unexpected exception was taken. */
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
check_vector_size serror_sp0
/* Current EL, SPx */
vector_entry synch_spx
/* An unexpected exception was taken. */
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
check_vector_size synch_spx
vector_entry irq_spx
/* An unexpected exception was taken. */
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
check_vector_size irq_spx
vector_entry fiq_spx
/* An unexpected exception was taken. */
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
check_vector_size fiq_spx
vector_entry serror_spx
/* An unexpected exception was taken. */
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
check_vector_size serror_spx
/* Lower EL, A64 */
vector_entry synch_a64
/* Check whether the exception is an SMC. If it's not, take the unexpected handler. */
stp x29, x30, [sp, #-0x10]!
mrs x30, esr_el3
lsr w29, w30, #26
cmp w29, #0x17
ldp x29, x30, [sp], #0x10
b.ne _ZN3ams6secmon26UnexpectedExceptionHandlerEv
/* Save x29 and x30. */
stp x29, x30, [sp, #-0x10]!
/* Get the current core. */
mrs x29, mpidr_el1
and x29, x29, #3
/* If we're not on core 3, take the core0-2 handler. */
cmp x29, #3
b.ne _ZN3ams6secmon25HandleSmcExceptionCore012Ev
/* Handle the smc. */
bl _ZN3ams6secmon18HandleSmcExceptionEv
/* Return. */
ldp x29, x30, [sp], #0x10
eret
check_vector_size synch_a64
vector_entry irq_a64
/* An unexpected exception was taken. */
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
check_vector_size irq_a64
vector_entry fiq_a64
/* Save X29, X30. */
stp x29, x30, [sp, #-0x10]!
/* Get the current core ID, ensure it's core 3. */
mrs x29, mpidr_el1
and x29, x29, #3
cmp x29, #3
b.ne _ZN3ams6secmon26UnexpectedExceptionHandlerEv
/* Save x26-x28, x18. */
stp x28, x18, [sp, #-0x10]!
stp x26, x27, [sp, #-0x10]!
/* Set x18 to the global data region. */
ldr x18, =0x1F01FA000
/* Handle the fiq exception. */
bl _ZN3ams6secmon18HandleFiqExceptionEv
/* Restore registers. */
ldp x26, x27, [sp], #0x10
ldp x28, x18, [sp], #0x10
ldp x29, x30, [sp], #0x10
/* Return. */
eret
check_vector_size fiq_a64
vector_entry serror_a64
/* An unexpected exception was taken. */
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
.endfunc
.cfi_endproc
_ZN3ams6secmon25HandleSmcExceptionCore012Ev:
/* Acquire exclusive access to the common smc stack. */
stp x4, x5, [sp, #-0x10]!
stp x2, x3, [sp, #-0x10]!
stp x0, x1, [sp, #-0x10]!
bl _ZN3ams6secmon25AcquireCommonSmcStackLockEv
ldp x0, x1, [sp], #0x10
ldp x2, x3, [sp], #0x10
ldp x4, x5, [sp], #0x10
/* Pivot to use the common smc stack. */
mov x30, sp
ldr x29, =0x1F01F6E80
mov sp, x29
stp x29, x30, [sp, #-0x10]!
/* Handle the SMC. */
bl _ZN3ams6secmon18HandleSmcExceptionEv
/* Restore our core-specific stack. */
ldp x29, x30, [sp], #0x10
mov x30, sp
/* Release our exclusive access to the common smc stack. */
stp x0, x1, [sp, #-0x10]!
bl _ZN3ams6secmon25ReleaseCommonSmcStackLockEv
ldp x0, x1, [sp], #0x10
/* Return. */
ldp x29, x30, [sp], #0x10
eret
/* Lower EL, A32 */
vector_entry synch_a32
/* An unexpected exception was taken. */
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
check_vector_size synch_a32
vector_entry irq_a32
/* An unexpected exception was taken. */
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
.endfunc
.cfi_endproc
_ZN3ams6secmon18HandleSmcExceptionEv:
/* Save registers. */
stp x29, x30, [sp, #-0x10]!
stp x18, x19, [sp, #-0x10]!
stp x16, x17, [sp, #-0x10]!
stp x14, x15, [sp, #-0x10]!
stp x12, x13, [sp, #-0x10]!
stp x10, x11, [sp, #-0x10]!
stp x8, x9, [sp, #-0x10]!
stp x6, x7, [sp, #-0x10]!
stp x4, x5, [sp, #-0x10]!
stp x2, x3, [sp, #-0x10]!
stp x0, x1, [sp, #-0x10]!
/* Set x18 to the global data region. */
ldr x18, =0x1F01FA000
/* Get esr. */
mrs x0, esr_el3
and x0, x0, #0xFFFF
/* Get the function arguments. */
mov x1, sp
/* Invoke the smc handler. */
bl _ZN3ams6secmon3smc9HandleSmcEiRNS1_12SmcArgumentsE
/* Restore registers. */
ldp x0, x1, [sp], #0x10
ldp x2, x3, [sp], #0x10
ldp x4, x5, [sp], #0x10
ldp x6, x7, [sp], #0x10
ldp x8, x9, [sp], #0x10
ldp x10, x11, [sp], #0x10
ldp x12, x13, [sp], #0x10
ldp x14, x15, [sp], #0x10
ldp x16, x17, [sp], #0x10
ldp x18, x19, [sp], #0x10
ldp x29, x30, [sp], #0x10
ret
vector_entry fiq_a32
/* Handle fiq from a32 the same as fiq from a64. */
b fiq_a64
.endfunc
.cfi_endproc
_ZN3ams6secmon18HandleFiqExceptionEv:
/* Save registers. */
stp x29, x30, [sp, #-0x10]!
stp x24, x25, [sp, #-0x10]!
stp x22, x23, [sp, #-0x10]!
stp x20, x21, [sp, #-0x10]!
stp x18, x19, [sp, #-0x10]!
stp x16, x17, [sp, #-0x10]!
stp x14, x15, [sp, #-0x10]!
stp x12, x13, [sp, #-0x10]!
stp x10, x11, [sp, #-0x10]!
stp x8, x9, [sp, #-0x10]!
stp x6, x7, [sp, #-0x10]!
stp x4, x5, [sp, #-0x10]!
stp x2, x3, [sp, #-0x10]!
stp x0, x1, [sp, #-0x10]!
/* Invoke the interrupt handler. */
bl _ZN3ams6secmon15HandleInterruptEv
/* Restore registers. */
ldp x0, x1, [sp], #0x10
ldp x2, x3, [sp], #0x10
ldp x4, x5, [sp], #0x10
ldp x6, x7, [sp], #0x10
ldp x8, x9, [sp], #0x10
ldp x10, x11, [sp], #0x10
ldp x12, x13, [sp], #0x10
ldp x14, x15, [sp], #0x10
ldp x16, x17, [sp], #0x10
ldp x18, x19, [sp], #0x10
ldp x20, x21, [sp], #0x10
ldp x22, x23, [sp], #0x10
ldp x24, x25, [sp], #0x10
ldp x29, x30, [sp], #0x10
ret
vector_entry serror_a32
/* An unexpected exception was taken. */
b _ZN3ams6secmon26UnexpectedExceptionHandlerEv
check_vector_size serror_a32
/* Instantiate the literal pool for the exception vectors. */
.ltorg

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "secmon_interrupt_handler.hpp"
#include "secmon_error.hpp"
namespace ams::secmon {
namespace {
constexpr inline int InterruptHandlersMax = 4;
constinit InterruptHandler g_handlers[InterruptHandlersMax] = {};
constinit int g_interrupt_ids[InterruptHandlersMax] = {};
}
void SetInterruptHandler(int interrupt_id, InterruptHandler handler) {
for (int i = 0; i < InterruptHandlersMax; ++i) {
if (g_interrupt_ids[i] == 0) {
g_interrupt_ids[i] = interrupt_id;
g_handlers[i] = handler;
return;
}
}
AMS_ABORT("Failed to register interrupt handler");
}
void HandleInterrupt() {
/* Get the interrupt id. */
const int interrupt_id = gic::GetInterruptRequestId();
if (interrupt_id >= gic::InterruptCount) {
/* Invalid interrupt number, just return. */
return;
}
/* Check each handler. */
for (int i = 0; i < InterruptHandlersMax; ++i) {
if (g_interrupt_ids[i] == interrupt_id) {
/* Invoke the handler. */
g_handlers[i]();
gic::SetEndOfInterrupt(interrupt_id);
return;
}
}
AMS_ABORT("Failed to find interrupt handler.");
}
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
namespace ams::secmon {
using InterruptHandler = void (*)();
void SetInterruptHandler(int interrupt_id, InterruptHandler handler);
}

View file

@ -0,0 +1,103 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "secmon_key_storage.hpp"
namespace ams::secmon {
namespace {
constinit u8 g_rsa_moduli[ImportRsaKey_Count][se::RsaSize] = {};
constinit bool g_rsa_modulus_committed[ImportRsaKey_Count] = {};
ALWAYS_INLINE u8 *GetRsaKeyModulus(ImportRsaKey which) {
return g_rsa_moduli[which];
}
ALWAYS_INLINE u8 *GetRsaKeyPrivateExponent(ImportRsaKey which) {
return ::ams::secmon::impl::GetRsaPrivateExponentStorage(static_cast<int>(which));
}
ALWAYS_INLINE bool IsRsaKeyProvisional(ImportRsaKey which) {
return g_rsa_modulus_committed[which] == false;
}
void ClearRsaKeyModulus(ImportRsaKey which) {
g_rsa_modulus_committed[which] = false;
std::memset(g_rsa_moduli[which], 0, se::RsaSize);
}
ALWAYS_INLINE u8 *GetMasterKeyStorage(int index) {
return ::ams::secmon::impl::GetMasterKeyStorage(index);
}
ALWAYS_INLINE u8 *GetDeviceMasterKeyStorage(int index) {
return ::ams::secmon::impl::GetDeviceMasterKeyStorage(index);
}
}
void ImportRsaKeyExponent(ImportRsaKey which, const void *src, size_t size) {
/* If we import an exponent, the modulus is not committed. */
ClearRsaKeyModulus(which);
/* Copy the exponent. */
std::memcpy(GetRsaKeyPrivateExponent(which), src, size);
}
void ImportRsaKeyModulusProvisionally(ImportRsaKey which, const void *src, size_t size) {
std::memcpy(GetRsaKeyModulus(which), src, std::min(static_cast<int>(size), se::RsaSize));
}
void CommitRsaKeyModulus(ImportRsaKey which) {
g_rsa_modulus_committed[which] = true;
}
bool LoadRsaKey(int slot, ImportRsaKey which) {
/* If the key is still provisional, we can't load it. */
if (IsRsaKeyProvisional(which)) {
return false;
}
se::SetRsaKey(slot, GetRsaKeyModulus(which), se::RsaSize, GetRsaKeyPrivateExponent(which), se::RsaSize);
return true;
}
void LoadProvisionalRsaKey(int slot, ImportRsaKey which) {
se::SetRsaKey(slot, GetRsaKeyModulus(which), se::RsaSize, GetRsaKeyPrivateExponent(which), se::RsaSize);
}
void SetMasterKey(int generation, const void *src, size_t size) {
const int index = generation - pkg1::KeyGeneration_Min;
se::EncryptAes128(GetMasterKeyStorage(index), se::AesBlockSize, pkg1::AesKeySlot_RandomForKeyStorageWrap, src, size);
}
void LoadMasterKey(int slot, int generation) {
const int index = std::min(0, generation - pkg1::KeyGeneration_Min);
se::SetEncryptedAesKey128(slot, pkg1::AesKeySlot_RandomForKeyStorageWrap, GetMasterKeyStorage(index), se::AesBlockSize);
}
void SetDeviceMasterKey(int generation, const void *src, size_t size) {
const int index = generation - pkg1::KeyGeneration_4_0_0;
se::EncryptAes128(GetDeviceMasterKeyStorage(index), se::AesBlockSize, pkg1::AesKeySlot_RandomForKeyStorageWrap, src, size);
}
void LoadDeviceMasterKey(int slot, int generation) {
const int index = std::min(0, generation - pkg1::KeyGeneration_4_0_0);
se::SetEncryptedAesKey128(slot, pkg1::AesKeySlot_RandomForKeyStorageWrap, GetDeviceMasterKeyStorage(index), se::AesBlockSize);
}
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
namespace ams::secmon {
enum ImportRsaKey {
ImportRsaKey_EsDrmCert = 0,
ImportRsaKey_Lotus = 1,
ImportRsaKey_Ssl = 2,
ImportRsaKey_EsClientCert = 3,
ImportRsaKey_Count = 4,
};
static_assert(util::size(secmon::ConfigurationContext{}.rsa_private_exponents) == ImportRsaKey_Count);
void ImportRsaKeyExponent(ImportRsaKey which, const void *src, size_t size);
void ImportRsaKeyModulusProvisionally(ImportRsaKey which, const void *src, size_t size);
void CommitRsaKeyModulus(ImportRsaKey which);
bool LoadRsaKey(int slot, ImportRsaKey which);
void LoadProvisionalRsaKey(int slot, ImportRsaKey which);
void SetMasterKey(int generation, const void *src, size_t size);
void LoadMasterKey(int slot, int generation);
void SetDeviceMasterKey(int generation, const void *src, size_t size);
void LoadDeviceMasterKey(int slot, int generation);
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "secmon_misc.hpp"
namespace ams::secmon {
namespace {
pkg1::BctParameters g_bct_params;
}
void SaveBootInfo(const pkg1::SecureMonitorParameters &secmon_params) {
/* Save the BCT parameters. */
g_bct_params = secmon_params.bct_params;
}
bool IsRecoveryBoot() {
return (g_bct_params.bootloader_attributes & pkg1::BootloaderAttribute_RecoveryBoot) != 0;
}
u32 GetRestrictedSmcMask() {
return (g_bct_params.bootloader_attributes & pkg1::BootloaderAttribute_RestrictedSmcMask) >> pkg1::BootloaderAttribute_RestrictedSmcShift;
}
bool IsJtagEnabled() {
util::BitPack32 dbg_auth;
HW_CPU_GET_DBGAUTHSTATUS_EL1(dbg_auth);
return dbg_auth.Get<hw::DbgAuthStatusEl1::Nsid>() == 3;
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
namespace ams::secmon {
void SaveBootInfo(const pkg1::SecureMonitorParameters &secmon_params);
bool IsRecoveryBoot();
u32 GetRestrictedSmcMask();
bool IsJtagEnabled();
}

View file

@ -0,0 +1,750 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "secmon_setup.hpp"
#include "secmon_error.hpp"
#include "secmon_cpu_context.hpp"
#include "secmon_interrupt_handler.hpp"
namespace ams::secmon {
namespace {
constexpr inline const uintptr_t TIMER = secmon::MemoryRegionVirtualDeviceTimer.GetAddress();
constexpr inline const uintptr_t APB_MISC = secmon::MemoryRegionVirtualDeviceApbMisc.GetAddress();
constexpr inline const uintptr_t FLOW_CTLR = secmon::MemoryRegionVirtualDeviceFlowController.GetAddress();
constexpr inline const uintptr_t PMC = secmon::MemoryRegionVirtualDevicePmc.GetAddress();
constexpr inline const uintptr_t MC = secmon::MemoryRegionVirtualDeviceMemoryController.GetAddress();
alignas(8) constinit u8 g_se_aes_key_slot_test_vector[se::AesBlockSize] = {};
struct Carveout {
uintptr_t address;
size_t size;
};
constinit Carveout g_kernel_carveouts[KernelCarveoutCount] = {
{ secmon::MemoryRegionDramDefaultKernelCarveout.GetAddress(), secmon::MemoryRegionDramDefaultKernelCarveout.GetSize(), },
{ 0, 0, },
};
constinit bool g_is_cold_boot = true;
constinit const se::StickyBits ExpectedSeStickyBits = {
.se_security = (1 << 0), /* SE_HARD_SETTING */
.tzram_security = 0,
.crypto_security_perkey = 0,
.crypto_keytable_access = {
(1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 0: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
(1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 1: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
(1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 2: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
(1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 3: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
(1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 4: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
(1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 5: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
(0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 6: Unused keyslot. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */
(0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 7: Unused keyslot. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */
(0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 8: Temp keyslot. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */
(0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 9: SmcTemp keyslot. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */
(0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 10: Wrap1 keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
(0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 11: Wrap2 keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
(0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 12: DMaster keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
(0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 13: Master keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
(0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 14: Unused keyslot. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */
(0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 13: Device keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
},
.rsa_security_perkey = 0,
.rsa_keytable_access = {
(0 << 2) | (1 << 1) | (0 << 0), /* KEYUSE/KEYREAD disabled, KEYUPDATE enabled. */
(0 << 2) | (1 << 1) | (0 << 0), /* KEYUSE/KEYREAD disabled, KEYUPDATE enabled. */
},
};
void InitializeConfigurationContext() {
/* Get the global context. */
auto &ctx = ::ams::secmon::impl::GetConfigurationContext();
/* Clear the context to zero. */
std::memset(std::addressof(ctx), 0, sizeof(ctx));
/* If the storage context is valid, we want to copy it to the global context. */
if (const auto &storage_ctx = *MemoryRegionPhysicalDramMonitorConfiguration.GetPointer<const SecureMonitorStorageConfiguration>(); storage_ctx.IsValid()) {
ctx.secmon_cfg.CopyFrom(storage_ctx);
ctx.emummc_cfg = storage_ctx.emummc_cfg;
} else {
/* If we don't have a valid storage context, we can just use the default one. */
ctx.secmon_cfg = DefaultSecureMonitorConfiguration;
}
}
void GenerateSecurityEngineAesKeySlotTestVector(void *dst, size_t size) {
/* Clear the output. */
AMS_ABORT_UNLESS(size == se::AesBlockSize);
std::memset(dst, 0, se::AesBlockSize);
/* Ensure output is seen as cleared by the se. */
hw::FlushDataCache(dst, se::AesBlockSize);
hw::DataSynchronizationBarrierInnerShareable();
/* Declare a block. */
alignas(8) u8 empty_block[se::AesBlockSize];
/* Iteratively transform an empty block. */
#define TRANSFORM_WITH_KEY(key) \
__builtin_memset(empty_block, 0, sizeof(empty_block)); \
se::SetEncryptedAesKey256(pkg1::AesKeySlot_Temporary, key, empty_block, sizeof(empty_block)); \
se::DecryptAes128(dst, se::AesBlockSize, pkg1::AesKeySlot_Temporary, dst, se::AesBlockSize)
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_RandomForUserWrap);
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_RandomForKeyStorageWrap);
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_Master);
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_DeviceMaster);
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_Device);
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_RandomForUserWrap);
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_RandomForKeyStorageWrap);
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_Master);
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_DeviceMaster);
TRANSFORM_WITH_KEY(pkg1::AesKeySlot_Device);
/* Ensure output is seen correctly by the cpu. */
hw::FlushDataCache(dst, se::AesBlockSize);
hw::DataSynchronizationBarrierInnerShareable();
/* Clear the temporary key slot. */
se::ClearAesKeySlot(pkg1::AesKeySlot_Temporary);
}
void VerifySecurityEngineStickyBits() {
if (!se::ValidateStickyBits(ExpectedSeStickyBits)) {
SetError(pkg1::ErrorInfo_InvalidSecurityEngineStickyBits);
AMS_ABORT("Invalid sticky bits");
}
}
void VerifySecurityEngineAesKeySlotTestVector() {
alignas(8) u8 test_vector[se::AesBlockSize];
GenerateSecurityEngineAesKeySlotTestVector(test_vector, sizeof(test_vector));
AMS_ABORT_UNLESS(crypto::IsSameBytes(g_se_aes_key_slot_test_vector, test_vector, se::AesBlockSize));
}
void ClearAesKeySlots() {
/* Clear all non-secure monitor keys. */
for (int i = 0; i < pkg1::AesKeySlot_SecmonStart; ++i) {
se::ClearAesKeySlot(i);
}
/* Clear the secure-monitor temporary keys. */
se::ClearAesKeySlot(pkg1::AesKeySlot_Temporary);
se::ClearAesKeySlot(pkg1::AesKeySlot_Smc);
}
void ClearRsaKeySlots() {
/* Clear all rsa keyslots. */
for (int i = 0; i < se::RsaKeySlotCount; ++i) {
se::ClearRsaKeySlot(i);
}
}
void SetupKernelCarveouts() {
#define MC_ENABLE_CLIENT_ACCESS(INDEX, WHICH) MC_REG_BITS_ENUM(CLIENT_ACCESS##INDEX##_##WHICH, ENABLE)
constexpr u32 ClientAccess0 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(0, PTCR),
MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0A),
MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0AB),
MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0B),
MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0BB),
MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0C),
MC_ENABLE_CLIENT_ACCESS(0, DISPLAY0CB),
MC_ENABLE_CLIENT_ACCESS(0, AFIR),
MC_ENABLE_CLIENT_ACCESS(0, DISPLAYHC),
MC_ENABLE_CLIENT_ACCESS(0, DISPLAYHCB),
MC_ENABLE_CLIENT_ACCESS(0, HDAR),
MC_ENABLE_CLIENT_ACCESS(0, HOST1XDMAR),
MC_ENABLE_CLIENT_ACCESS(0, HOST1XR),
MC_ENABLE_CLIENT_ACCESS(0, NVENCSRD),
MC_ENABLE_CLIENT_ACCESS(0, PPCSAHBDMAR),
MC_ENABLE_CLIENT_ACCESS(0, PPCSAHBSLVR));
constexpr u32 ClientAccess1 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(1, MPCORER),
MC_ENABLE_CLIENT_ACCESS(1, NVENCSWR),
MC_ENABLE_CLIENT_ACCESS(1, AFIW),
MC_ENABLE_CLIENT_ACCESS(1, HDAW),
MC_ENABLE_CLIENT_ACCESS(1, HOST1XW),
MC_ENABLE_CLIENT_ACCESS(1, MPCOREW),
MC_ENABLE_CLIENT_ACCESS(1, PPCSAHBDMAW),
MC_ENABLE_CLIENT_ACCESS(1, PPCSAHBSLVW));
constexpr u32 ClientAccess2 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(2, XUSB_HOSTR),
MC_ENABLE_CLIENT_ACCESS(2, XUSB_HOSTW),
MC_ENABLE_CLIENT_ACCESS(2, XUSB_DEVR),
MC_ENABLE_CLIENT_ACCESS(2, XUSB_DEVW));
constexpr u32 ClientAccess2_100 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(2, XUSB_HOSTR),
MC_ENABLE_CLIENT_ACCESS(2, XUSB_HOSTW),
MC_ENABLE_CLIENT_ACCESS(2, XUSB_DEVR),
MC_ENABLE_CLIENT_ACCESS(2, XUSB_DEVW),
MC_ENABLE_CLIENT_ACCESS(2, TSECSRD),
MC_ENABLE_CLIENT_ACCESS(2, TSECSWR));
constexpr u32 ClientAccess3 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(3, SDMMCRA),
MC_ENABLE_CLIENT_ACCESS(3, SDMMCRAA),
MC_ENABLE_CLIENT_ACCESS(3, SDMMCRAB),
MC_ENABLE_CLIENT_ACCESS(3, SDMMCWA),
MC_ENABLE_CLIENT_ACCESS(3, SDMMCWAA),
MC_ENABLE_CLIENT_ACCESS(3, SDMMCWAB),
MC_ENABLE_CLIENT_ACCESS(3, VICSRD),
MC_ENABLE_CLIENT_ACCESS(3, VICSWR),
MC_ENABLE_CLIENT_ACCESS(3, DISPLAYD),
MC_ENABLE_CLIENT_ACCESS(3, APER),
MC_ENABLE_CLIENT_ACCESS(3, APEW),
MC_ENABLE_CLIENT_ACCESS(3, NVJPGSRD),
MC_ENABLE_CLIENT_ACCESS(3, NVJPGSWR));
constexpr u32 ClientAccess3_100 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(3, SDMMCRA),
MC_ENABLE_CLIENT_ACCESS(3, SDMMCRAA),
MC_ENABLE_CLIENT_ACCESS(3, SDMMCRAB),
MC_ENABLE_CLIENT_ACCESS(3, SDMMCWA),
MC_ENABLE_CLIENT_ACCESS(3, SDMMCWAA),
MC_ENABLE_CLIENT_ACCESS(3, SDMMCWAB),
MC_ENABLE_CLIENT_ACCESS(3, VICSRD),
MC_ENABLE_CLIENT_ACCESS(3, VICSWR),
MC_ENABLE_CLIENT_ACCESS(3, DISPLAYD),
MC_ENABLE_CLIENT_ACCESS(3, NVDECSRD),
MC_ENABLE_CLIENT_ACCESS(3, NVDECSWR),
MC_ENABLE_CLIENT_ACCESS(3, APER),
MC_ENABLE_CLIENT_ACCESS(3, APEW),
MC_ENABLE_CLIENT_ACCESS(3, NVJPGSRD),
MC_ENABLE_CLIENT_ACCESS(3, NVJPGSWR));
constexpr u32 ClientAccess4 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(4, SESRD),
MC_ENABLE_CLIENT_ACCESS(4, SESWR));
constexpr u32 ClientAccess4_800 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(4, SESRD),
MC_ENABLE_CLIENT_ACCESS(4, SESWR),
MC_ENABLE_CLIENT_ACCESS(4, TSECRDB),
MC_ENABLE_CLIENT_ACCESS(4, TSECWRB));
constexpr u32 ClientAccess4_100 = reg::Encode(MC_ENABLE_CLIENT_ACCESS(4, SESRD),
MC_ENABLE_CLIENT_ACCESS(4, SESWR));
#undef MC_ENABLE_CLIENT_ACCESS
constexpr u32 ForceInternalAccess0 = reg::Encode(MC_REG_BITS_ENUM(CLIENT_ACCESS0_AVPCARM7R, ENABLE));
constexpr u32 ForceInternalAccess0_100 = 0;
constexpr u32 ForceInternalAccess1 = reg::Encode(MC_REG_BITS_ENUM(CLIENT_ACCESS1_AVPCARM7W, ENABLE));
constexpr u32 ForceInternalAccess1_100 = 0;
constexpr u32 CarveoutConfig = reg::Encode(MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID, 0),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3, ENABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0, ENABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3, ENABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0, ENABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE, ANY_ADDRESS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE, LOCKED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE, TZ_SECURE));
constexpr u32 CarveoutConfig_100 = reg::Encode(MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID, 0),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0, ENABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0, ENABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE, ANY_ADDRESS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE, LOCKED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE, TZ_SECURE));
const u32 target_fw = GetTargetFirmware();
u32 client_access_2;
u32 client_access_3;
u32 client_access_4;
u32 carveout_config;
if (target_fw >= TargetFirmware_8_1_0) {
client_access_2 = ClientAccess2;
client_access_3 = ClientAccess3;
client_access_4 = ClientAccess4;
carveout_config = CarveoutConfig;
} else if (target_fw >= TargetFirmware_8_0_0) {
client_access_2 = ClientAccess2;
client_access_3 = ClientAccess3;
client_access_4 = ClientAccess4_800;
carveout_config = CarveoutConfig;
} else {
client_access_2 = ClientAccess2_100;
client_access_3 = ClientAccess3_100;
client_access_4 = ClientAccess4_100;
carveout_config = CarveoutConfig_100;
}
/* Configure carveout 4. */
reg::Write(MC + MC_SECURITY_CARVEOUT4_BOM, g_kernel_carveouts[0].address >> 0);
reg::Write(MC + MC_SECURITY_CARVEOUT4_BOM_HI, g_kernel_carveouts[0].address >> 32);
reg::Write(MC + MC_SECURITY_CARVEOUT4_SIZE_128KB, g_kernel_carveouts[0].size / 128_KB);
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS0, ClientAccess0);
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS1, ClientAccess1);
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS2, client_access_2);
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS3, client_access_3);
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_ACCESS4, client_access_4);
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS0, (target_fw >= TargetFirmware_4_0_0) ? ForceInternalAccess0 : ForceInternalAccess0_100);
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS1, (target_fw >= TargetFirmware_4_0_0) ? ForceInternalAccess1 : ForceInternalAccess1_100);
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS2, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS3, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT4_CLIENT_FORCE_INTERNAL_ACCESS4, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT4_CFG0, carveout_config);
/* Configure carveout 5. */
reg::Write(MC + MC_SECURITY_CARVEOUT5_BOM, g_kernel_carveouts[0].address >> 0);
reg::Write(MC + MC_SECURITY_CARVEOUT5_BOM_HI, g_kernel_carveouts[0].address >> 32);
reg::Write(MC + MC_SECURITY_CARVEOUT5_SIZE_128KB, g_kernel_carveouts[0].size / 128_KB);
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS0, ClientAccess0);
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS1, ClientAccess1);
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS2, client_access_2);
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS3, client_access_3);
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_ACCESS4, client_access_4);
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS0, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS1, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS2, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS3, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT5_CLIENT_FORCE_INTERNAL_ACCESS4, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT5_CFG0, carveout_config);
}
void ConfigureSlaveSecurity() {
u32 reg0, reg1, reg2;
if (GetTargetFirmware() > TargetFirmware_1_0_0) {
reg0 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(0, SATA_AUX, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(0, DTV, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(0, QSPI, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(0, SE, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(0, SATA, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(0, LA, ENABLE));
reg1 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, SPI1, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(1, SPI2, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(1, SPI3, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(1, SPI5, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(1, SPI6, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(1, I2C6, ENABLE));
reg2 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(2, SDMMC3, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(2, DDS, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(2, DP2, ENABLE));
const auto hw_type = fuse::GetHardwareType();
/* Switch Lite can't use HDMI, so set CEC to secure on hoag. */
if (hw_type == fuse::HardwareType_Hoag) {
reg0 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(0, CEC, ENABLE));
}
/* Icosa, Iowa, and Five all set I2C4 to be secure. */
if (hw_type == fuse::HardwareType_Icosa && hw_type == fuse::HardwareType_Iowa && hw_type == fuse::HardwareType_Five) {
reg1 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, I2C4, ENABLE));
}
/* Hoag additionally sets UART_B to secure. */
if (hw_type == fuse::HardwareType_Hoag) {
reg1 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, UART_B, ENABLE));
}
/* Copper and Calcio lack a lot of hardware, so set the corresponding registers to secure for them. */
if (hw_type == fuse::HardwareType_Calcio || hw_type == fuse::HardwareType_Copper) {
reg1 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, UART_B, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(1, UART_C, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(1, SPI4, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(1, I2C2, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(1, I2C3, ENABLE));
/* Copper/Calcio have no gamecard reader, and thus set SDMMC2 as secure. */
reg2 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(2, SDMMC2, ENABLE));
}
/* Mariko hardware types (not Icosa or Copper) additionally set mariko-only mmio (SE2, PKA1, FEK) as secure. */
if (hw_type != fuse::HardwareType_Icosa && hw_type != fuse::HardwareType_Copper) {
reg2 |= reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(2, SE2, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(2, PKA1, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(2, FEK, ENABLE));
}
} else {
reg0 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(0, SATA_AUX, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(0, DTV, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(0, QSPI, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(0, SATA, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(0, LA, ENABLE));
reg1 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(1, SPI1, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(1, SPI2, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(1, SPI3, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(1, SPI5, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(1, SPI6, ENABLE),
SLAVE_SECURITY_REG_BITS_ENUM(1, I2C6, ENABLE));
reg2 = reg::Encode(SLAVE_SECURITY_REG_BITS_ENUM(2, DDS, ENABLE),
REG_BITS_VALUE(5, 1, 1), /* Note: Bit 5 is not documented in TRM. */
REG_BITS_VALUE(4, 1, 1)); /* Note: Bit 4 is not documented in TRM. */
}
reg::Write(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0, reg0);
reg::Write(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0, reg1);
reg::Write(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG2_0, reg2);
}
void SetupSecureRegisters() {
/* Configure timers 5-8 and watchdog timers 0-3 as secure. */
reg::Write(TIMER + TIMER_SHARED_TIMER_SECURE_CFG, TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_TMR5, ENABLE),
TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_TMR6, ENABLE),
TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_TMR7, ENABLE),
TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_TMR8, ENABLE),
TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_WDT0, ENABLE),
TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_WDT1, ENABLE),
TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_WDT2, ENABLE),
TIMER_REG_BITS_ENUM(SHARED_TIMER_SECURE_CFG_WDT3, ENABLE));
/* Lock cluster switching, to prevent usage of the A53 cores. */
reg::Write(FLOW_CTLR + FLOW_CTLR_BPMP_CLUSTER_CONTROL, FLOW_REG_BITS_ENUM(BPMP_CLUSTER_CONTROL_ACTIVE_CLUSTER_LOCK, ENABLE),
FLOW_REG_BITS_ENUM(BPMP_CLUSTER_CONTROL_CLUSTER_SWITCH_ENABLE, DISABLE),
FLOW_REG_BITS_ENUM(BPMP_CLUSTER_CONTROL_ACTIVE_CLUSTER, FAST));
/* Enable flow controller debug qualifier for legacy FIQs. */
reg::Write(FLOW_CTLR + FLOW_CTLR_FLOW_DBG_QUAL, FLOW_REG_BITS_ENUM(FLOW_DBG_QUAL_FIQ2CCPLEX_ENABLE, ENABLE));
/* Configure the PMC to disable deep power-down. */
reg::Write(PMC + APBDEV_PMC_DPD_ENABLE, PMC_REG_BITS_ENUM(DPD_ENABLE_TSC_MULT_EN, DISABLE),
PMC_REG_BITS_ENUM(DPD_ENABLE_ON, DISABLE));
/* Configure the video protect region. */
reg::Write(MC + MC_VIDEO_PROTECT_GPU_OVERRIDE_0, 1);
reg::Write(MC + MC_VIDEO_PROTECT_GPU_OVERRIDE_1, 0);
reg::Write(MC + MC_VIDEO_PROTECT_BOM, 0);
reg::Write(MC + MC_VIDEO_PROTECT_SIZE_MB, 0);
reg::Write(MC + MC_VIDEO_PROTECT_REG_CTRL, MC_REG_BITS_ENUM(VIDEO_PROTECT_REG_CTRL_VIDEO_PROTECT_ALLOW_TZ_WRITE, DISABLED),
MC_REG_BITS_ENUM(VIDEO_PROTECT_REG_CTRL_VIDEO_PROTECT_WRITE_ACCESS, DISABLED));
/* Configure the SEC carveout. */
reg::Write(MC + MC_SEC_CARVEOUT_BOM, 0);
reg::Write(MC + MC_SEC_CARVEOUT_SIZE_MB, 0);
reg::Write(MC + MC_SEC_CARVEOUT_REG_CTRL, MC_REG_BITS_ENUM(SEC_CARVEOUT_REG_CTRL_SEC_CARVEOUT_WRITE_ACCESS, DISABLED));
/* Configure the MTS carveout. */
reg::Write(MC + MC_MTS_CARVEOUT_BOM, 0);
reg::Write(MC + MC_MTS_CARVEOUT_SIZE_MB, 0);
reg::Write(MC + MC_MTS_CARVEOUT_ADR_HI, 0);
reg::Write(MC + MC_MTS_CARVEOUT_REG_CTRL, MC_REG_BITS_ENUM(MTS_CARVEOUT_REG_CTRL_MTS_CARVEOUT_WRITE_ACCESS, DISABLED));
/* Configure the security carveout. */
reg::Write(MC + MC_SECURITY_CFG0, MC_REG_BITS_VALUE(SECURITY_CFG0_SECURITY_BOM, 0));
reg::Write(MC + MC_SECURITY_CFG1, MC_REG_BITS_VALUE(SECURITY_CFG1_SECURITY_SIZE, 0));
reg::Write(MC + MC_SECURITY_CFG3, MC_REG_BITS_VALUE(SECURITY_CFG3_SECURITY_BOM_HI, 3));
/* Configure security carveout 1. */
reg::Write(MC + MC_SECURITY_CARVEOUT1_BOM, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT1_BOM_HI, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT1_SIZE_128KB, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS0, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS1, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS2, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS3, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_ACCESS4, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS0, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS1, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS2, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS3, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT1_CLIENT_FORCE_INTERNAL_ACCESS4, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT1_CFG0, MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH, ENABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID, 0),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE, UNTRANSLATED_ONLY),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE, LOCKED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE, LOCKBIT_SECURE));
/* Security carveout 2 will be configured later by SetupGpuCarveout, after magic values are written to configure gpu/tsec. */
/* Configure carveout 3. */
reg::Write(MC + MC_SECURITY_CARVEOUT3_BOM, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT3_BOM_HI, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT3_SIZE_128KB, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS0, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS1, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS2, MC_REG_BITS_ENUM (CLIENT_ACCESS2_GPUSRD, ENABLE),
MC_REG_BITS_ENUM (CLIENT_ACCESS2_GPUSWR, ENABLE));
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS3, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_ACCESS4, MC_REG_BITS_ENUM (CLIENT_ACCESS4_GPUSRD2, ENABLE),
MC_REG_BITS_ENUM (CLIENT_ACCESS4_GPUSWR2, ENABLE));
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS0, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS1, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS2, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS3, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT3_CLIENT_FORCE_INTERNAL_ACCESS4, 0);
reg::Write(MC + MC_SECURITY_CARVEOUT3_CFG0, MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_IS_WPR, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_FORCE_APERTURE_ID_MATCH, ENABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ALLOW_APERTURE_ID_MISMATCH, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_RD_EN, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_TZ_GLOBAL_WR_EN, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_SEND_CFG_TO_GPU, ENABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_WRITE_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL3, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL2, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL1, ENABLE_CHECKS),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_DISABLE_READ_CHECK_ACCESS_LEVEL0, ENABLE_CHECKS),
MC_REG_BITS_VALUE(SECURITY_CARVEOUT_CFG0_APERTURE_ID, 3),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL3, ENABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL2, ENABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL1, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_WRITE_ACCESS_LEVEL0, DISABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL3, ENABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL2, ENABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL1, ENABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_READ_ACCESS_LEVEL0, ENABLED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_ADDRESS_TYPE, UNTRANSLATED_ONLY),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_LOCK_MODE, LOCKED),
MC_REG_BITS_ENUM (SECURITY_CARVEOUT_CFG0_PROTECT_MODE, LOCKBIT_SECURE));
/* Configure the two kernel carveouts. */
SetupKernelCarveouts();
/* Configure slave register security. */
ConfigureSlaveSecurity();
}
void SetupSmmu() {
/* Turn on SMMU translation for all devices. */
reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_0, ~0u);
reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_1, ~0u);
reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_2, ~0u);
reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_3, ~0u);
reg::Write(MC + MC_SMMU_TRANSLATION_ENABLE_4, ~0u);
/* Configure ASIDs 1-3 as secure, and all others as non-secure. */
reg::Write(MC + MC_SMMU_ASID_SECURITY, MC_REG_BITS_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_1, SECURE),
MC_REG_BITS_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_2, SECURE),
MC_REG_BITS_ENUM(SMMU_ASID_SECURITY_SECURE_ASIDS_3, SECURE));
reg::Write(MC + MC_SMMU_ASID_SECURITY_1, 0);
reg::Write(MC + MC_SMMU_ASID_SECURITY_2, 0);
reg::Write(MC + MC_SMMU_ASID_SECURITY_3, 0);
reg::Write(MC + MC_SMMU_ASID_SECURITY_4, 0);
reg::Write(MC + MC_SMMU_ASID_SECURITY_5, 0);
reg::Write(MC + MC_SMMU_ASID_SECURITY_6, 0);
reg::Write(MC + MC_SMMU_ASID_SECURITY_7, 0);
/* Initialize the PTB registers to zero .*/
reg::Write(MC + MC_SMMU_PTB_ASID, 0);
reg::Write(MC + MC_SMMU_PTB_DATA, 0);
/* Configure the TLB and PTC, then read TLB_CONFIG to ensure configuration takes. */
reg::Write(MC + MC_SMMU_TLB_CONFIG, MC_REG_BITS_ENUM (SMMU_TLB_CONFIG_TLB_HIT_UNDER_MISS, ENABLE),
MC_REG_BITS_ENUM (SMMU_TLB_CONFIG_TLB_ROUND_ROBIN_ARBITRATION, ENABLE),
MC_REG_BITS_VALUE(SMMU_TLB_CONFIG_TLB_ACTIVE_LINES, 0x30));
reg::Write(MC + MC_SMMU_PTC_CONFIG, MC_REG_BITS_ENUM (SMMU_PTC_CONFIG_PTC_CACHE_ENABLE, ENABLE),
MC_REG_BITS_VALUE(SMMU_PTC_CONFIG_PTC_REQ_LIMIT, 8),
MC_REG_BITS_VALUE(SMMU_PTC_CONFIG_PTC_INDEX_MAP, 0x3F));
reg::Read (MC + MC_SMMU_TLB_CONFIG);
/* Flush the entire page table cache, and read TLB_CONFIG to ensure the flush takes. */
reg::Write(MC + MC_SMMU_PTC_FLUSH, 0);
reg::Read (MC + MC_SMMU_TLB_CONFIG);
/* Flush the entire translation lookaside buffer, and read TLB_CONFIG to ensure the flush takes. */
reg::Write(MC + MC_SMMU_PTC_FLUSH, 0);
reg::Read (MC + MC_SMMU_TLB_CONFIG);
/* Enable the SMMU, and read TLB_CONFIG to ensure the enable takes. */
reg::Write(MC + MC_SMMU_CONFIG, MC_REG_BITS_ENUM (SMMU_CONFIG_SMMU_ENABLE, ENABLE));
reg::Read (MC + MC_SMMU_TLB_CONFIG);
}
}
void Setup1() {
/* Load the global configuration context. */
InitializeConfigurationContext();
/* Initialize uart for logging. */
log::Initialize();
/* Initialize the security engine. */
se::Initialize();
/* Initialize the gic. */
gic::InitializeCommon();
}
void SaveSecurityEngineAesKeySlotTestVector() {
GenerateSecurityEngineAesKeySlotTestVector(g_se_aes_key_slot_test_vector, sizeof(g_se_aes_key_slot_test_vector));
}
void SetupSocSecurity() {
/* Set the fuse visibility. */
clkrst::SetFuseVisibility(true);
/* Set fuses as only secure-writable. */
fuse::SetWriteSecureOnly();
/* Lockout the fuses. */
fuse::Lockout();
/* Set the security engine to secure mode. */
se::SetSecure(true);
/* Verify the security engine's sticky bits. */
VerifySecurityEngineStickyBits();
/* Verify the security engine's Aes slots contain correct contents. */
VerifySecurityEngineAesKeySlotTestVector();
/* Clear aes keyslots. */
ClearAesKeySlots();
/* Clear rsa keyslots. */
ClearRsaKeySlots();
/* Overwrite keys that we want to be random with random contents. */
se::InitializeRandom();
se::SetRandomKey(pkg1::AesKeySlot_Temporary);
se::GenerateSrk();
se::SetRandomKey(pkg1::AesKeySlot_TzramSave);
/* Initialize pmc secure scratch. */
pmc::InitializeRandomScratch();
/* Setup secure registers. */
SetupSecureRegisters();
/* Setup the smmu. */
SetupSmmu();
/* Clear the cpu reset vector. */
reg::Write(secmon::MemoryRegionVirtualDeviceExceptionVectors.GetAddress() + EVP_CPU_RESET_VECTOR, 0);
/* Configure the SB registers to our start address. */
constexpr u32 ResetVectorLow = static_cast<u32>((PhysicalTzramProgramResetVector >> 0));
constexpr u32 ResetVectorHigh = static_cast<u32>((PhysicalTzramProgramResetVector >> BITSIZEOF(u32)));
/* Write our reset vector to the secure boot registers. */
reg::Write(secmon::MemoryRegionVirtualDeviceSystem.GetAddress() + SB_AA64_RESET_LOW, ResetVectorLow);
reg::Write(secmon::MemoryRegionVirtualDeviceSystem.GetAddress() + SB_AA64_RESET_HIGH, ResetVectorHigh);
/* Disable non-secure writes to the reset vector. */
reg::Write(secmon::MemoryRegionVirtualDeviceSystem.GetAddress() + SB_CSR, SB_REG_BITS_ENUM(CSR_NS_RST_VEC_WR_DIS, DISABLE));
/* Read back SB_CSR to make sure our non-secure write disable takes. */
reg::Read(secmon::MemoryRegionVirtualDeviceSystem.GetAddress() + SB_CSR);
/* Write our reset vector to scratch registers used by warmboot, and lock those scratch registers. */
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH34, ResetVectorLow);
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH35, ResetVectorHigh);
pmc::LockSecureRegister(pmc::SecureRegister_ResetVector);
/* Setup the security engine interrupt. */
constexpr int SecurityEngineInterruptId = 90;
gic::SetPriority (SecurityEngineInterruptId, gic::HighestPriority);
gic::SetInterruptGroup(SecurityEngineInterruptId, 0);
gic::SetEnable (SecurityEngineInterruptId, true);
gic::SetSpiTargetCpu (SecurityEngineInterruptId, (1 << 3));
gic::SetSpiMode (SecurityEngineInterruptId, gic::InterruptMode_Level);
/* Setup the activity monitor interrupt. */
constexpr int ActivityMonitorInterruptId = 77;
gic::SetPriority (ActivityMonitorInterruptId, gic::HighestPriority);
gic::SetInterruptGroup(ActivityMonitorInterruptId, 0);
gic::SetEnable (ActivityMonitorInterruptId, true);
gic::SetSpiTargetCpu (ActivityMonitorInterruptId, (1 << 3));
gic::SetSpiMode (ActivityMonitorInterruptId, gic::InterruptMode_Level);
/* If we're coldboot, perform one-time setup. */
if (g_is_cold_boot) {
/* Register both interrupt handlers. */
SetInterruptHandler(SecurityEngineInterruptId, se::HandleInterrupt);
SetInterruptHandler(ActivityMonitorInterruptId, actmon::HandleInterrupt);
/* We're expecting the other cores to come out of reset. */
for (int i = 1; i < NumCores; ++i) {
SetResetExpected(i, true);
}
/* We only coldboot once. */
g_is_cold_boot = false;
}
}
void SetupSocProtections() {
}
}

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
namespace ams::secmon {
constexpr inline u64 MemoryAttributeIndexNormal = 0;
constexpr inline u64 MemoryAttributeIndexDevice = 1;
constexpr inline int KernelCarveoutCount = 2;
void SetupCpuMemoryControllersEnableMmu();
void SetupSocDmaControllers();
void SetupSocSecurity();
void SetupSocProtections();
void Setup1();
void SaveSecurityEngineAesKeySlotTestVector();
}

View file

@ -0,0 +1,206 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "secmon_setup.hpp"
namespace ams::secmon {
namespace setup {
#include "secmon_cache_impl.inc"
}
namespace {
using namespace ams::mmu;
void SetupCpuCommonControllers() {
/* Set cpuactlr_el1. */
{
util::BitPack64 cpuactlr = {};
cpuactlr.Set<hw::CpuactlrEl1CortexA57::NonCacheableStreamingEnhancement>(1);
cpuactlr.Set<hw::CpuactlrEl1CortexA57::DisableLoadPassDmb>(1);
HW_CPU_SET_CPUACTLR_EL1(cpuactlr);
}
/* Set cpuectlr_el1. */
{
util::BitPack64 cpuectlr = {};
cpuectlr.Set<hw::CpuectlrEl1CortexA57::Smpen>(1);
cpuectlr.Set<hw::CpuectlrEl1CortexA57::L2LoadStoreDataPrefetchDistance>(3);
cpuectlr.Set<hw::CpuectlrEl1CortexA57::L2InstructionFetchPrefetchDistance>(3);
HW_CPU_SET_CPUECTLR_EL1(cpuectlr);
}
/* Prevent instruction reordering. */
hw::InstructionSynchronizationBarrier();
}
void SetupCpuEl3Controllers() {
/* Set scr_el3. */
{
util::BitPack32 scr = {};
scr.Set<hw::ScrEl3::Ns >(1); /* Set EL0/EL1 as Non-Secure. */
scr.Set<hw::ScrEl3::Irq >(0); /* IRQs are taken in IRQ mode. */
scr.Set<hw::ScrEl3::Fiq >(1); /* FIQs are taken in Monitor mode. */
scr.Set<hw::ScrEl3::Ea >(1); /* External aborts are taken in Monitor mode. */
scr.Set<hw::ScrEl3::Fw >(1); /* CPSR.F is non-secure writable. */
scr.Set<hw::ScrEl3::Aw >(1); /* CPSR.A is non-secure writable. */
scr.Set<hw::ScrEl3::Net >(0); /* This bit is not implemented. */
scr.Set<hw::ScrEl3::Smd >(0); /* Secure Monitor Call is allowed. */
scr.Set<hw::ScrEl3::Hce >(0); /* Hypervisor Calls are disabled. */ /* TODO: Enable for thermosphere? */
scr.Set<hw::ScrEl3::Sif >(1); /* Secure mode cannot fetch instructions from non-secure memory. */
scr.Set<hw::ScrEl3::RwCortexA53>(1); /* Reserved bit. N probably sets it because on Cortex A53, this sets kernel as aarch64. */
scr.Set<hw::ScrEl3::StCortexA53>(0); /* Reserved bit. On Cortex A53, this sets secure registers to EL3 only. */
scr.Set<hw::ScrEl3::Twi >(0); /* WFI is not trapped. */
scr.Set<hw::ScrEl3::Twe >(0); /* WFE is not trapped. */
HW_CPU_SET_SCR_EL3(scr);
}
/* Set ttbr0_el3. */
{
constexpr u64 ttbr0 = MemoryRegionPhysicalTzramL1PageTable.GetAddress();
HW_CPU_SET_TTBR0_EL3(ttbr0);
}
/* Set tcr_el3. */
{
util::BitPack32 tcr = { hw::TcrEl3::Res1 };
tcr.Set<hw::TcrEl3::T0sz >(31); /* Configure TTBR0 addressed size to be 64 GiB */
tcr.Set<hw::TcrEl3::Irgn0>(1); /* Configure PTE walks as inner write-back write-allocate cacheable */
tcr.Set<hw::TcrEl3::Orgn0>(1); /* Configure PTE walks as outer write-back write-allocate cacheable */
tcr.Set<hw::TcrEl3::Sh0 >(3); /* Configure PTE walks as inner shareable */
tcr.Set<hw::TcrEl3::Tg0 >(0); /* Set TTBR0_EL3 granule as 4 KiB */
tcr.Set<hw::TcrEl3::Ps >(1); /* Set the physical addrss size as 36-bit (64 GiB) */
tcr.Set<hw::TcrEl3::Tbi >(0); /* Top byte is not ignored in addrss calculations */
HW_CPU_SET_TCR_EL3(tcr);
}
/* Clear cptr_el3. */
{
util::BitPack32 cptr = {};
cptr.Set<hw::CptrEl3::Tfp >(0); /* FP/SIMD instructions don't trap. */
cptr.Set<hw::CptrEl3::Tta >(0); /* Reserved bit (no trace functionality present). */
cptr.Set<hw::CptrEl3::Tcpac>(0); /* Access to cpacr_El1 does not trap. */
HW_CPU_SET_CPTR_EL3(cptr);
}
/* Set mair_el3. */
{
u64 mair = (MemoryRegionAttributes_Normal << (MemoryRegionAttributeWidth * MemoryAttributeIndexNormal)) |
(MemoryRegionAttributes_Device << (MemoryRegionAttributeWidth * MemoryAttributeIndexDevice));
HW_CPU_SET_MAIR_EL3(mair);
}
/* Set vectors. */
{
constexpr u64 vectors = MemoryRegionVirtualTzramProgramExceptionVectors.GetAddress();
HW_CPU_SET_VBAR_EL3(vectors);
}
/* Prevent instruction re-ordering around this point. */
hw::InstructionSynchronizationBarrier();
}
void EnableMmu() {
/* Create sctlr value. */
util::BitPack32 sctlr = { hw::SctlrEl3::Res1 };
sctlr.Set<hw::SctlrEl3::M>(1); /* Globally enable the MMU. */
sctlr.Set<hw::SctlrEl3::A>(0); /* Disable alignment fault checking. */
sctlr.Set<hw::SctlrEl3::C>(1); /* Globally enable the data and unified caches. */
sctlr.Set<hw::SctlrEl3::Sa>(0); /* Disable stack alignment checking. */
sctlr.Set<hw::SctlrEl3::I>(1); /* Globally enable the instruction cache. */
sctlr.Set<hw::SctlrEl3::Wxn>(0); /* Do not force writable pages to be ExecuteNever. */
sctlr.Set<hw::SctlrEl3::Ee>(0); /* Exceptions should be little endian. */
/* Ensure all writes are done before turning on the mmu. */
hw::DataSynchronizationBarrierInnerShareable();
/* Invalidate the entire tlb. */
hw::InvalidateEntireTlb();
/* Ensure instruction consistency. */
hw::DataSynchronizationBarrierInnerShareable();
hw::InstructionSynchronizationBarrier();
/* Set sctlr_el3. */
HW_CPU_SET_SCTLR_EL3(sctlr);
hw::InstructionSynchronizationBarrier();
}
}
void SetupCpuMemoryControllersEnableMmu() {
SetupCpuCommonControllers();
SetupCpuEl3Controllers();
EnableMmu();
}
void SetupSocDmaControllers() {
/* Ensure that our caches are managed. */
setup::InvalidateEntireDataCache();
setup::EnsureInstructionConsistency();
/* Lock tsec. */
tsec::Lock();
/* Enable SWID[0] for all bits. */
reg::Write(AHB_ARBC(AHB_MASTER_SWID), ~0u);
/* Clear SWID1 for all bits. */
reg::Write(AHB_ARBC(AHB_MASTER_SWID_1), 0u);
/* Set MSELECT config to set WRAP_TO_INCR_SLAVE0(APC) | WRAP_TO_INCR_SLAVE1(PCIe) | WRAP_TO_INCR_SLAVE2(GPU) */
/* and clear ERR_RESP_EN_SLAVE1(PCIe) | ERR_RESP_EN_SLAVE2(GPU) */
{
auto mselect_cfg = reg::Read(MSELECT(MSELECT_CONFIG));
mselect_cfg &= ~(1u << 24); /* Clear ERR_RESP_EN_SLAVE1(PCIe) */
mselect_cfg &= ~(1u << 25); /* Clear ERR_RESP_EN_SLAVE2(GPU) */
mselect_cfg |= (1u << 27); /* Set WRAP_TO_INCR_SLAVE0(APC) */
mselect_cfg |= (1u << 28); /* Set WRAP_TO_INCR_SLAVE1(PCIe) */
mselect_cfg |= (1u << 29); /* Set WRAP_TO_INCR_SLAVE2(GPU) */
reg::Write(MSELECT(MSELECT_CONFIG), mselect_cfg);
}
/* Disable USB, USB2, AHB-DMA from arbitration. */
{
auto arb_dis = reg::Read(AHB_ARBC(AHB_ARBITRATION_DISABLE));
arb_dis |= (1u << 5); /* Disable AHB-DMA */
arb_dis |= (1u << 6); /* Disable USB */
arb_dis |= (1u << 18); /* Disable USB2 */
reg::Write(AHB_ARBC(AHB_ARBITRATION_DISABLE), arb_dis);
}
/* Select high priority group with priority 7. */
{
u32 priority_ctrl = {};
priority_ctrl |= (7u << 29); /* Set group 7. */
priority_ctrl |= (1u << 0); /* Set high priority. */
reg::Write(AHB_ARBC(AHB_ARBITRATION_PRIORITY_CTRL), priority_ctrl);
}
/* Prevent splitting AHB writes to TZRAM. */
{
reg::Write(AHB_ARBC(AHB_GIZMO_TZRAM), (1u << 7));
}
}
}

View file

@ -0,0 +1,83 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
.section .text._ZN3ams6secmon5StartEv, "ax", %progbits
.align 6
.global _ZN3ams6secmon5StartEv
_ZN3ams6secmon5StartEv:
/* Set SPSEL 1 stack pointer to the core 0 exception stack address. */
msr spsel, #1
ldr x20, =0x1F01F6F00
mov sp, x20
/* Set SPSEL 0 stack pointer to a temporary location in volatile memory. */
msr spsel, #1
ldr x20, =0x1F01C0800
mov sp, x20
/* Setup X18 to point to the global context. */
ldr x18, =0x1F01FA000
/* Invoke main. */
bl _ZN3ams6secmon4MainEv
/* Set the stack pointer to the core 3 exception stack address. */
ldr x20, =0x1F01FB000
mov sp, x20
/* TODO: JumpToLowerExceptionLevel */
1: b 1b
.section .text._ZN3ams6secmon25AcquireCommonSmcStackLockEv, "ax", %progbits
.align 4
.global _ZN3ams6secmon25AcquireCommonSmcStackLockEv
_ZN3ams6secmon25AcquireCommonSmcStackLockEv:
/* Get the address of the lock. */
ldr x0, =_ZN3ams6secmon18CommonSmcStackLockE
/* Prepare to try to take the spinlock. */
mov w1, #1
sevl
prfm pstl1keep, [x0]
1: /* Repeatedly try to take the lock. */
wfe
ldaxr w2, [x0]
cbnz w2, 1b
stxr w2, w1, [x0]
cbnz w2, 1b
/* Return. */
ret
.section .text._ZN3ams6secmon25ReleaseCommonSmcStackLockEv, "ax", %progbits
.align 4
.global _ZN3ams6secmon25ReleaseCommonSmcStackLockEv
_ZN3ams6secmon25ReleaseCommonSmcStackLockEv:
/* Get the address of the lock. */
ldr x0, =_ZN3ams6secmon18CommonSmcStackLockE
/* Release the spinlock. */
stlr wzr, [x0]
/* Return. */
ret
.section .data._ZN3ams6secmon18CommonSmcStackLockE, "aw", %progbits
.global _ZN3ams6secmon18CommonSmcStackLockE
_ZN3ams6secmon18CommonSmcStackLockE:
/* Define storage for the global common smc stack spinlock. */
.word 0

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "../secmon_error.hpp"
#include "secmon_smc_aes.hpp"
namespace ams::secmon::smc {
SmcResult SmcGenerateAesKek(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
SmcResult SmcLoadAesKey(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
SmcResult SmcComputeAes(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
SmcResult SmcGenerateSpecificAesKey(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
SmcResult SmcComputeCmac(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
SmcResult SmcLoadPreparedAesKey(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
SmcResult SmcGenerateAesKek(const SmcArguments &args);
SmcResult SmcLoadAesKey(const SmcArguments &args);
SmcResult SmcComputeAes(const SmcArguments &args);
SmcResult SmcGenerateSpecificAesKey(const SmcArguments &args);
SmcResult SmcComputeCmac(const SmcArguments &args);
SmcResult SmcLoadPreparedAesKey(const SmcArguments &args);
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "../secmon_error.hpp"
#include "secmon_smc_carveout.hpp"
namespace ams::secmon::smc {
SmcResult SmcSetKernelCarveoutRegion(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
SmcResult SmcSetKernelCarveoutRegion(const SmcArguments &args);
}

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
namespace ams::secmon::smc {
enum class SmcResult : u32 {
Success = 0,
NotImplemented = 1,
InvalidArgument = 2,
InProgress = 3,
NoAsyncOperation = 4,
InvalidAsyncOperation = 5,
NotPermitted = 6,
NotInitialized = 7,
PsciSuccess = 0,
PsciNotSupported = static_cast<u32>(-1),
PsciInvalidParameters = static_cast<u32>(-2),
PsciDenied = static_cast<u32>(-3),
PsciAlreadyOn = static_cast<u32>(-4),
};
struct SmcArguments {
u64 r[8];
};
constexpr inline int SecurityEngineUserInterruptId = 44;
constexpr inline u64 InvalidAsyncKey = 0;
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "../secmon_error.hpp"
#include "secmon_smc_device_unique_data.hpp"
namespace ams::secmon::smc {
SmcResult SmcDecryptDeviceUniqueData(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
SmcResult SmcReencryptDeviceUniqueData(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
/* Legacy APIs. */
SmcResult SmcDecryptAndImportEsDeviceKey(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
SmcResult SmcDecryptAndImportLotusKey(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
SmcResult SmcDecryptDeviceUniqueData(const SmcArguments &args);
SmcResult SmcReencryptDeviceUniqueData(const SmcArguments &args);
/* Legacy APIs. */
SmcResult SmcDecryptAndImportEsDeviceKey(const SmcArguments &args);
SmcResult SmcDecryptAndImportLotusKey(const SmcArguments &args);
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "../secmon_error.hpp"
#include "secmon_smc_error.hpp"
namespace ams::secmon::smc {
SmcResult SmcShowError(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
SmcResult SmcShowError(const SmcArguments &args);
}

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "../secmon_error.hpp"
#include "secmon_smc_es.hpp"
namespace ams::secmon::smc {
SmcResult SmcPrepareEsDeviceUniqueKey(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
SmcResult SmcPrepareEsCommonKey(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
}

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
enum EsKeyType {
EsKeyType_TitleKey = 0,
EsKeyType_ArchiveKey = 1,
EsKeyType_Count = 2,
};
SmcResult SmcPrepareEsDeviceUniqueKey(const SmcArguments &args);
SmcResult SmcPrepareEsCommonKey(const SmcArguments &args);
}

View file

@ -0,0 +1,233 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "../secmon_error.hpp"
#include "../secmon_misc.hpp"
#include "secmon_smc_common.hpp"
#include "secmon_smc_handler.hpp"
#include "secmon_smc_aes.hpp"
#include "secmon_smc_carveout.hpp"
#include "secmon_smc_device_unique_data.hpp"
#include "secmon_smc_error.hpp"
#include "secmon_smc_es.hpp"
#include "secmon_smc_info.hpp"
#include "secmon_smc_memory_access.hpp"
#include "secmon_smc_power_management.hpp"
#include "secmon_smc_random.hpp"
#include "secmon_smc_register_access.hpp"
#include "secmon_smc_result.hpp"
#include "secmon_smc_rsa.hpp"
namespace ams::secmon::smc {
namespace {
struct HandlerInfo {
u32 function_id;
u32 restriction_mask;
SmcHandler handler;
};
struct HandlerTable {
const HandlerInfo *entries;
size_t count;
};
enum HandlerType : int {
HandlerType_User = 0,
HandlerType_Kern = 1,
HandlerType_Count = 2,
};
enum Restriction {
Restriction_None = (0 << 0),
Restriction_Normal = (1 << 0),
Restriction_DeviceUniqueDataNotAllowed = (1 << 1),
Restriction_SafeModeNotAllowed = (1 << 2),
};
enum SmcCallRange {
SmcCallRange_ArmArch = 0,
SmcCallRange_Cpu = 1,
SmcCallRange_Sip = 2,
SmcCallRange_Oem = 3,
SmcCallRange_Standard = 4,
SmcCallRange_TrustedApp = 0x30,
};
enum SmcArgumentType {
ArgumentType_Integer = 0,
ArgumentType_Pointer = 1,
};
enum SmcConvention {
Convention_Smc32 = 0,
Convention_Smc64 = 1,
};
enum SmcCallType {
SmcCallType_YieldingCall = 0,
SmcCallType_FastCall = 1,
};
struct SmcFunctionId {
using FunctionId = util::BitPack64::Field< 0, 8, u32>;
using ArgumentType0 = util::BitPack64::Field< 8, 1, SmcArgumentType>;
using ArgumentType1 = util::BitPack64::Field< 9, 1, SmcArgumentType>;
using ArgumentType2 = util::BitPack64::Field<10, 1, SmcArgumentType>;
using ArgumentType3 = util::BitPack64::Field<11, 1, SmcArgumentType>;
using ArgumentType4 = util::BitPack64::Field<12, 1, SmcArgumentType>;
using ArgumentType5 = util::BitPack64::Field<13, 1, SmcArgumentType>;
using ArgumentType6 = util::BitPack64::Field<14, 1, SmcArgumentType>;
using ArgumentType7 = util::BitPack64::Field<15, 1, SmcArgumentType>;
using Reserved = util::BitPack64::Field<16, 8, u32>;
using CallRange = util::BitPack64::Field<24, 6, SmcCallRange>;
using Convention = util::BitPack64::Field<30, 1, SmcConvention>;
using CallType = util::BitPack64::Field<31, 1, SmcCallType>;
using Reserved2 = util::BitPack64::Field<32, 32, u32>;
};
constinit HandlerInfo g_user_handlers[] = {
{ 0x00000000, Restriction_SafeModeNotAllowed, nullptr },
{ 0xC3000401, Restriction_SafeModeNotAllowed, SmcSetConfig },
{ 0xC3000002, Restriction_Normal, SmcGetConfigUser },
{ 0xC3000003, Restriction_Normal, SmcGetResult },
{ 0xC3000404, Restriction_Normal, SmcGetResultData },
{ 0xC3000E05, Restriction_SafeModeNotAllowed, SmcModularExponentiate },
{ 0xC3000006, Restriction_Normal, SmcGenerateRandomBytes },
{ 0xC3000007, Restriction_Normal, SmcGenerateAesKek },
{ 0xC3000008, Restriction_Normal, SmcLoadAesKey },
{ 0xC3000009, Restriction_Normal, SmcComputeAes },
{ 0xC300000A, Restriction_Normal, SmcGenerateSpecificAesKey },
{ 0xC300040B, Restriction_Normal, SmcComputeCmac },
{ 0xC300D60C, Restriction_Normal, SmcReencryptDeviceUniqueData },
{ 0xC300100D, Restriction_DeviceUniqueDataNotAllowed, SmcDecryptDeviceUniqueData },
{ 0xC300000E, Restriction_SafeModeNotAllowed, nullptr },
{ 0xC300060F, Restriction_DeviceUniqueDataNotAllowed, SmcModularExponentiateByStorageKey },
{ 0xC3000610, Restriction_SafeModeNotAllowed, SmcPrepareEsDeviceUniqueKey },
{ 0xC3000011, Restriction_SafeModeNotAllowed, SmcLoadPreparedAesKey },
{ 0xC3000012, Restriction_SafeModeNotAllowed, SmcPrepareEsCommonKey }
};
constinit HandlerInfo g_kern_handlers[] = {
{ 0x00000000, Restriction_SafeModeNotAllowed, nullptr },
{ 0xC4000001, Restriction_SafeModeNotAllowed, SmcSuspendCpu },
{ 0x84000002, Restriction_SafeModeNotAllowed, SmcPowerOffCpu },
{ 0xC4000003, Restriction_SafeModeNotAllowed, SmcPowerOnCpu },
{ 0xC3000002, Restriction_Normal, SmcGetConfigKern },
{ 0xC3000005, Restriction_Normal, SmcGenerateRandomBytesNonBlocking },
{ 0xC3000006, Restriction_Normal, SmcShowError },
{ 0xC3000007, Restriction_Normal, SmcSetKernelCarveoutRegion },
{ 0xC3000008, Restriction_Normal, SmcReadWriteRegister },
};
constinit HandlerInfo g_ams_handlers[] = {
{ 0x00000000, Restriction_SafeModeNotAllowed, nullptr },
{ 0xF0000201, Restriction_None, SmcIramCopy },
{ 0xF0000002, Restriction_None, SmcReadWriteRegister },
{ 0xF0000003, Restriction_None, SmcWriteAddress },
{ 0xF0000003, Restriction_None, SmcGetEmummcConfig },
};
constinit HandlerTable g_handler_tables[] = {
{ g_user_handlers, util::size(g_user_handlers) },
{ g_kern_handlers, util::size(g_kern_handlers) },
};
constinit HandlerTable g_ams_handler_table = {
g_ams_handlers, util::size(g_ams_handlers)
};
NORETURN void InvalidSmcError(u64 id) {
SetError(pkg1::ErrorInfo_UnknownSmc);
AMS_ABORT("Invalid SMC: %lx", id);
}
const HandlerTable &GetHandlerTable(HandlerType type, u64 id) {
/* Ensure we have a valid handler type. */
if (AMS_UNLIKELY(!(0 <= type && type < HandlerType_Count))) {
InvalidSmcError(id);
}
/* Check if we're a user SMC. */
if (type == HandlerType_User) {
/* Nintendo uses OEM SMCs. */
/* We will assign Atmosphere extension SMCs the TrustedApplication range. */
if (util::BitPack64{id}.Get<SmcFunctionId::CallRange>() == SmcCallRange_TrustedApp) {
return g_ams_handler_table;
}
/* If we're not performing an atmosphere extension smc, require that we're being invoked by spl on core 3. */
if (AMS_UNLIKELY(hw::GetCurrentCoreId() != 3)) {
InvalidSmcError(id);
}
}
return g_handler_tables[type];
}
const HandlerInfo &GetHandlerInfo(const HandlerTable &table, u64 id) {
/* Get and check the index. */
const auto index = util::BitPack64{id}.Get<SmcFunctionId::FunctionId>();
if (AMS_UNLIKELY(index >= table.count)) {
InvalidSmcError(id);
}
/* Get and check the handler info. */
const auto &handler_info = table.entries[index];
/* Check that the handler isn't null. */
if (AMS_UNLIKELY(handler_info.handler == nullptr)) {
InvalidSmcError(id);
}
/* Check that the handler's id matches. */
if (AMS_UNLIKELY(handler_info.function_id != id)) {
InvalidSmcError(id);
}
return handler_info;
}
bool IsHandlerRestricted(const HandlerInfo &info) {
return (info.restriction_mask & secmon::GetRestrictedSmcMask()) != 0;
}
SmcResult InvokeSmcHandler(const HandlerInfo &info, const SmcArguments &args) {
/* Check if the smc is restricted. */
if (AMS_UNLIKELY(IsHandlerRestricted(info))) {
return SmcResult::NotPermitted;
}
/* Invoke the smc. */
return info.handler(args);
}
}
void HandleSmc(int type, SmcArguments &args) {
/* Get the table. */
const auto &table = GetHandlerTable(static_cast<HandlerType>(type), args.r[0]);
/* Get the handler info. */
const auto &info = GetHandlerInfo(table, args.r[0]);
/* Set the invocation result. */
args.r[0] = static_cast<u64>(InvokeSmcHandler(info, args));
}
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
using SmcHandler = SmcResult (*)(const SmcArguments &args);
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "../secmon_error.hpp"
#include "secmon_smc_info.hpp"
namespace ams::secmon::smc {
SmcResult SmcGetConfigUser(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
SmcResult SmcGetConfigKern(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
SmcResult SmcSetConfig(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
/* This is an atmosphere extension smc. */
SmcResult SmcGetEmummcConfig(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
enum class ConfigItem : u32 {
/* Standard config items. */
DisableProgramVerification = 1,
DramId = 2,
SecurityEngineIrqNumber = 3,
FuseVersion = 4,
HardwareType = 5,
IsRetail = 6,
IsRecoveryBoot = 7,
DeviceId = 8,
BootReason = 9,
MemoryMode = 10,
IsDebugMode = 11,
KernelConfiguration = 12,
IsChargerHiZModeEnabled = 13,
IsQuest = 14,
RegulatorType = 15,
DeviceUniqueKeyGeneration = 16,
Package2Hash = 17,
/* Extension config items for exosphere. */
ExosphereApiVersion = 65000,
ExosphereNeedsReboot = 65001,
ExosphereNeedsShutdown = 65002,
ExosphereGitCommitHash = 65003,
ExosphereHasRcmBugPatch = 65004,
ExosphereBlankProdInfo = 65005,
ExosphereAllowCalWrites = 65006,
};
SmcResult SmcGetConfigUser(const SmcArguments &args);
SmcResult SmcGetConfigKern(const SmcArguments &args);
SmcResult SmcSetConfig(const SmcArguments &args);
/* This is an atmosphere extension smc. */
SmcResult SmcGetEmummcConfig(const SmcArguments &args);
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "../secmon_error.hpp"
#include "secmon_smc_memory_access.hpp"
namespace ams::secmon::smc {
/* This is an atmosphere extension smc. */
SmcResult SmcIramCopy(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
SmcResult SmcWriteAddress(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
}

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
/* This is an atmosphere extension smc. */
SmcResult SmcIramCopy(const SmcArguments &args);
SmcResult SmcWriteAddress(const SmcArguments &args);
}

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "../secmon_error.hpp"
#include "secmon_smc_power_management.hpp"
namespace ams::secmon::smc {
SmcResult SmcPowerOffCpu(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
SmcResult SmcPowerOnCpu(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
SmcResult SmcSuspendCpu(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
SmcResult SmcPowerOffCpu(const SmcArguments &args);
SmcResult SmcPowerOnCpu(const SmcArguments &args);
SmcResult SmcSuspendCpu(const SmcArguments &args);
}

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "../secmon_error.hpp"
#include "secmon_smc_random.hpp"
namespace ams::secmon::smc {
SmcResult SmcGenerateRandomBytes(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
SmcResult SmcGenerateRandomBytesNonBlocking(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
SmcResult SmcGenerateRandomBytes(const SmcArguments &args);
SmcResult SmcGenerateRandomBytesNonBlocking(const SmcArguments &args);
}

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "../secmon_error.hpp"
#include "secmon_smc_register_access.hpp"
namespace ams::secmon::smc {
SmcResult SmcReadWriteRegister(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
}

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
SmcResult SmcReadWriteRegister(const SmcArguments &args);
}

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "../secmon_error.hpp"
#include "secmon_smc_result.hpp"
namespace ams::secmon::smc {
SmcResult SmcGetResult(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
SmcResult SmcGetResultData(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
}

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
using GetResultHandler = SmcResult (*)(void *dst, size_t dst_size);
u64 BeginAsyncOperation(GetResultHandler handler);
void CancelAsyncOperation(u64 async_key);
void EndAsyncOperation();
SmcResult SmcGetResult(const SmcArguments &args);
SmcResult SmcGetResultData(const SmcArguments &args);
}

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <exosphere.hpp>
#include "../secmon_error.hpp"
#include "secmon_smc_rsa.hpp"
namespace ams::secmon::smc {
SmcResult SmcModularExponentiate(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
SmcResult SmcModularExponentiateByStorageKey(const SmcArguments &args) {
/* TODO */
return SmcResult::NotImplemented;
}
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <exosphere.hpp>
#include "secmon_smc_common.hpp"
namespace ams::secmon::smc {
SmcResult SmcModularExponentiate(const SmcArguments &args);
SmcResult SmcModularExponentiateByStorageKey(const SmcArguments &args);
}