mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-05-30 22:45:17 -04:00
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:
parent
71e0102f7a
commit
f66b41c027
192 changed files with 15093 additions and 24 deletions
25
exosphere2/program/source/boot/secmon_boot.hpp
Normal file
25
exosphere2/program/source/boot/secmon_boot.hpp
Normal 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();
|
||||
|
||||
}
|
22
exosphere2/program/source/boot/secmon_boot_cache.cpp
Normal file
22
exosphere2/program/source/boot/secmon_boot_cache.cpp
Normal 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 */
|
||||
|
||||
}
|
22
exosphere2/program/source/boot/secmon_boot_config.cpp
Normal file
22
exosphere2/program/source/boot/secmon_boot_config.cpp
Normal 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 */
|
||||
|
||||
}
|
26
exosphere2/program/source/boot/secmon_boot_functions.cpp
Normal file
26
exosphere2/program/source/boot/secmon_boot_functions.cpp
Normal 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());
|
||||
}
|
||||
|
||||
}
|
23
exosphere2/program/source/boot/secmon_boot_functions.hpp
Normal file
23
exosphere2/program/source/boot/secmon_boot_functions.hpp
Normal 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();
|
||||
|
||||
}
|
337
exosphere2/program/source/boot/secmon_boot_setup.cpp
Normal file
337
exosphere2/program/source/boot/secmon_boot_setup.cpp
Normal 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();
|
||||
}
|
||||
|
||||
}
|
37
exosphere2/program/source/boot/secmon_crt0.s
Normal file
37
exosphere2/program/source/boot/secmon_crt0.s
Normal 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
|
46
exosphere2/program/source/boot/secmon_crt0_cpp.cpp
Normal file
46
exosphere2/program/source/boot/secmon_crt0_cpp.cpp
Normal 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();
|
||||
}
|
||||
|
||||
}
|
22
exosphere2/program/source/boot/secmon_key_data.cpp
Normal file
22
exosphere2/program/source/boot/secmon_key_data.cpp
Normal 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 */
|
||||
|
||||
}
|
69
exosphere2/program/source/boot/secmon_main.cpp
Normal file
69
exosphere2/program/source/boot/secmon_main.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
147
exosphere2/program/source/boot/secmon_make_page_table.cpp
Normal file
147
exosphere2/program/source/boot/secmon_make_page_table.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
22
exosphere2/program/source/boot/secmon_package2.cpp
Normal file
22
exosphere2/program/source/boot/secmon_package2.cpp
Normal 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 */
|
||||
|
||||
}
|
26
exosphere2/program/source/boot/secmon_size_data.s
Normal file
26
exosphere2/program/source/boot/secmon_size_data.s
Normal 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
|
22
exosphere2/program/source/secmon_cache.inc
Normal file
22
exosphere2/program/source/secmon_cache.inc
Normal 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();
|
132
exosphere2/program/source/secmon_cache_impl.inc
Normal file
132
exosphere2/program/source/secmon_cache_impl.inc
Normal 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();
|
||||
}
|
192
exosphere2/program/source/secmon_cpu_context.cpp
Normal file
192
exosphere2/program/source/secmon_cpu_context.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
41
exosphere2/program/source/secmon_cpu_context.hpp
Normal file
41
exosphere2/program/source/secmon_cpu_context.hpp
Normal 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();
|
||||
|
||||
}
|
51
exosphere2/program/source/secmon_error.cpp
Normal file
51
exosphere2/program/source/secmon_error.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
24
exosphere2/program/source/secmon_error.hpp
Normal file
24
exosphere2/program/source/secmon_error.hpp
Normal 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();
|
||||
|
||||
}
|
326
exosphere2/program/source/secmon_exception_vectors.s
Normal file
326
exosphere2/program/source/secmon_exception_vectors.s
Normal 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
|
64
exosphere2/program/source/secmon_interrupt_handler.cpp
Normal file
64
exosphere2/program/source/secmon_interrupt_handler.cpp
Normal 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.");
|
||||
}
|
||||
|
||||
}
|
25
exosphere2/program/source/secmon_interrupt_handler.hpp
Normal file
25
exosphere2/program/source/secmon_interrupt_handler.hpp
Normal 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);
|
||||
|
||||
}
|
103
exosphere2/program/source/secmon_key_storage.cpp
Normal file
103
exosphere2/program/source/secmon_key_storage.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
44
exosphere2/program/source/secmon_key_storage.hpp
Normal file
44
exosphere2/program/source/secmon_key_storage.hpp
Normal 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);
|
||||
|
||||
}
|
46
exosphere2/program/source/secmon_misc.cpp
Normal file
46
exosphere2/program/source/secmon_misc.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
29
exosphere2/program/source/secmon_misc.hpp
Normal file
29
exosphere2/program/source/secmon_misc.hpp
Normal 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();
|
||||
|
||||
}
|
750
exosphere2/program/source/secmon_setup.cpp
Normal file
750
exosphere2/program/source/secmon_setup.cpp
Normal 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() {
|
||||
|
||||
}
|
||||
|
||||
}
|
36
exosphere2/program/source/secmon_setup.hpp
Normal file
36
exosphere2/program/source/secmon_setup.hpp
Normal 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();
|
||||
|
||||
}
|
206
exosphere2/program/source/secmon_setup_warm.cpp
Normal file
206
exosphere2/program/source/secmon_setup_warm.cpp
Normal 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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
83
exosphere2/program/source/secmon_start_virtual.s
Normal file
83
exosphere2/program/source/secmon_start_virtual.s
Normal 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
|
52
exosphere2/program/source/smc/secmon_smc_aes.cpp
Normal file
52
exosphere2/program/source/smc/secmon_smc_aes.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
29
exosphere2/program/source/smc/secmon_smc_aes.hpp
Normal file
29
exosphere2/program/source/smc/secmon_smc_aes.hpp
Normal 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);
|
||||
|
||||
}
|
27
exosphere2/program/source/smc/secmon_smc_carveout.cpp
Normal file
27
exosphere2/program/source/smc/secmon_smc_carveout.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
24
exosphere2/program/source/smc/secmon_smc_carveout.hpp
Normal file
24
exosphere2/program/source/smc/secmon_smc_carveout.hpp
Normal 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);
|
||||
|
||||
}
|
45
exosphere2/program/source/smc/secmon_smc_common.hpp
Normal file
45
exosphere2/program/source/smc/secmon_smc_common.hpp
Normal 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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
27
exosphere2/program/source/smc/secmon_smc_error.cpp
Normal file
27
exosphere2/program/source/smc/secmon_smc_error.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
24
exosphere2/program/source/smc/secmon_smc_error.hpp
Normal file
24
exosphere2/program/source/smc/secmon_smc_error.hpp
Normal 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);
|
||||
|
||||
}
|
32
exosphere2/program/source/smc/secmon_smc_es.cpp
Normal file
32
exosphere2/program/source/smc/secmon_smc_es.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
32
exosphere2/program/source/smc/secmon_smc_es.hpp
Normal file
32
exosphere2/program/source/smc/secmon_smc_es.hpp
Normal 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);
|
||||
|
||||
}
|
233
exosphere2/program/source/smc/secmon_smc_handler.cpp
Normal file
233
exosphere2/program/source/smc/secmon_smc_handler.cpp
Normal 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));
|
||||
}
|
||||
|
||||
}
|
24
exosphere2/program/source/smc/secmon_smc_handler.hpp
Normal file
24
exosphere2/program/source/smc/secmon_smc_handler.hpp
Normal 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);
|
||||
|
||||
}
|
43
exosphere2/program/source/smc/secmon_smc_info.cpp
Normal file
43
exosphere2/program/source/smc/secmon_smc_info.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
59
exosphere2/program/source/smc/secmon_smc_info.hpp
Normal file
59
exosphere2/program/source/smc/secmon_smc_info.hpp
Normal 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);
|
||||
|
||||
}
|
33
exosphere2/program/source/smc/secmon_smc_memory_access.cpp
Normal file
33
exosphere2/program/source/smc/secmon_smc_memory_access.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
26
exosphere2/program/source/smc/secmon_smc_memory_access.hpp
Normal file
26
exosphere2/program/source/smc/secmon_smc_memory_access.hpp
Normal 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);
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
32
exosphere2/program/source/smc/secmon_smc_random.cpp
Normal file
32
exosphere2/program/source/smc/secmon_smc_random.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
25
exosphere2/program/source/smc/secmon_smc_random.hpp
Normal file
25
exosphere2/program/source/smc/secmon_smc_random.hpp
Normal 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);
|
||||
|
||||
}
|
27
exosphere2/program/source/smc/secmon_smc_register_access.cpp
Normal file
27
exosphere2/program/source/smc/secmon_smc_register_access.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
24
exosphere2/program/source/smc/secmon_smc_register_access.hpp
Normal file
24
exosphere2/program/source/smc/secmon_smc_register_access.hpp
Normal 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);
|
||||
|
||||
}
|
32
exosphere2/program/source/smc/secmon_smc_result.cpp
Normal file
32
exosphere2/program/source/smc/secmon_smc_result.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
31
exosphere2/program/source/smc/secmon_smc_result.hpp
Normal file
31
exosphere2/program/source/smc/secmon_smc_result.hpp
Normal 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);
|
||||
|
||||
}
|
32
exosphere2/program/source/smc/secmon_smc_rsa.cpp
Normal file
32
exosphere2/program/source/smc/secmon_smc_rsa.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
25
exosphere2/program/source/smc/secmon_smc_rsa.hpp
Normal file
25
exosphere2/program/source/smc/secmon_smc_rsa.hpp
Normal 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);
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue