mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-05-21 02:15:07 -04:00
exo2: rename exosphere2 -> exosphere
This commit is contained in:
parent
282f8f6612
commit
42f1a3bf60
136 changed files with 15 additions and 15 deletions
42
exosphere/program/source/boot/secmon_boot.hpp
Normal file
42
exosphere/program/source/boot/secmon_boot.hpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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 UnmapPhysicalIdentityMapping();
|
||||
void UnmapDram();
|
||||
|
||||
void InitializeColdBoot();
|
||||
|
||||
bool VerifySignature(void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *msg, size_t msg_size);
|
||||
bool VerifyHash(const void *hash, uintptr_t msg, size_t msg_size);
|
||||
|
||||
bool VerifyBootConfigSignature(pkg1::BootConfig &bc, const void *mod, size_t mod_size);
|
||||
bool VerifyBootConfigEcid(const pkg1::BootConfig &bc);
|
||||
|
||||
void CalculatePackage2Hash(se::Sha256Hash *dst, const pkg2::Package2Meta &meta, uintptr_t package2_start);
|
||||
|
||||
bool VerifyPackage2Signature(pkg2::Package2Header &header, const void *mod, size_t mod_size);
|
||||
void DecryptPackage2(void *dst, size_t dst_size, const void *src, size_t src_size, const void *key, size_t key_size, const void *iv, size_t iv_size, u8 key_generation);
|
||||
|
||||
bool VerifyPackage2Meta(const pkg2::Package2Meta &meta);
|
||||
bool VerifyPackage2Version(const pkg2::Package2Meta &meta);
|
||||
bool VerifyPackage2Payloads(const pkg2::Package2Meta &meta, uintptr_t payload_address);
|
||||
|
||||
}
|
23
exosphere/program/source/boot/secmon_boot_cache.cpp
Normal file
23
exosphere/program/source/boot/secmon_boot_cache.cpp
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/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "secmon_boot_cache.hpp"
|
||||
|
||||
namespace ams::secmon::boot {
|
||||
|
||||
#include "../secmon_cache_impl.inc"
|
||||
|
||||
}
|
23
exosphere/program/source/boot/secmon_boot_cache.hpp
Normal file
23
exosphere/program/source/boot/secmon_boot_cache.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 {
|
||||
|
||||
#include "../secmon_cache.inc"
|
||||
|
||||
}
|
34
exosphere/program/source/boot/secmon_boot_config.cpp
Normal file
34
exosphere/program/source/boot/secmon_boot_config.cpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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"
|
||||
|
||||
namespace ams::secmon::boot {
|
||||
|
||||
bool VerifyBootConfigSignature(pkg1::BootConfig &bc, const void *mod, size_t mod_size) {
|
||||
return VerifySignature(std::addressof(bc.signature), sizeof(bc.signature), mod, mod_size, std::addressof(bc.signed_data), sizeof(bc.signed_data));
|
||||
}
|
||||
|
||||
bool VerifyBootConfigEcid(const pkg1::BootConfig &bc) {
|
||||
/* Get the ecid. */
|
||||
br::BootEcid ecid;
|
||||
fuse::GetEcid(std::addressof(ecid));
|
||||
|
||||
/* Verify it matches. */
|
||||
return crypto::IsSameBytes(std::addressof(ecid), bc.signed_data.ecid, sizeof(ecid));
|
||||
}
|
||||
|
||||
}
|
193
exosphere/program/source/boot/secmon_boot_functions.cpp
Normal file
193
exosphere/program/source/boot/secmon_boot_functions.cpp
Normal file
|
@ -0,0 +1,193 @@
|
|||
/*
|
||||
* 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_boot.hpp"
|
||||
#include "secmon_boot_cache.hpp"
|
||||
#include "secmon_boot_functions.hpp"
|
||||
|
||||
namespace ams::secmon::boot {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline uintptr_t SYSCTR0 = MemoryRegionVirtualDeviceSysCtr0.GetAddress();
|
||||
|
||||
NOINLINE void DecryptPayload(uintptr_t dst, uintptr_t src, size_t size, const void *iv, size_t iv_size, u8 key_generation) {
|
||||
secmon::boot::DecryptPackage2(reinterpret_cast<void *>(dst), size, reinterpret_cast<void *>(src), size, secmon::boot::GetPackage2AesKey(), crypto::AesEncryptor128::KeySize, iv, iv_size, key_generation);
|
||||
}
|
||||
|
||||
u32 GetChipId() {
|
||||
constexpr u32 ChipIdErista = 0x210;
|
||||
constexpr u32 ChipIdMariko = 0x214;
|
||||
|
||||
switch (GetSocType()) {
|
||||
case fuse::SocType_Erista: return ChipIdErista;
|
||||
case fuse::SocType_Mariko: return ChipIdMariko;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CheckVerifyResult(bool verify_result, pkg1::ErrorInfo error_info, const char *message) {
|
||||
if (!verify_result) {
|
||||
secmon::SetError(error_info);
|
||||
AMS_ABORT(message);
|
||||
}
|
||||
}
|
||||
|
||||
void ClearIram() {
|
||||
/* Clear the boot code image from where it was loaded in IRAM. */
|
||||
util::ClearMemory(MemoryRegionPhysicalIramBootCodeImage.GetPointer(), MemoryRegionPhysicalIramBootCodeImage.GetSize());
|
||||
}
|
||||
|
||||
void WaitForNxBootloader(const pkg1::SecureMonitorParameters ¶ms, pkg1::BootloaderState state) {
|
||||
/* Check NX Bootloader's state once per microsecond until it's advanced enough. */
|
||||
while (params.bootloader_state < state) {
|
||||
util::WaitMicroSeconds(1);
|
||||
}
|
||||
}
|
||||
|
||||
void LoadBootConfig(const void *src) {
|
||||
pkg1::BootConfig * const dst = secmon::impl::GetBootConfigStorage();
|
||||
|
||||
if (pkg1::IsProduction()) {
|
||||
std::memset(dst, 0, sizeof(*dst));
|
||||
} else {
|
||||
hw::FlushDataCache(src, sizeof(*dst));
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
std::memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
}
|
||||
|
||||
void VerifyOrClearBootConfig() {
|
||||
/* On production hardware, the boot config is already cleared. */
|
||||
if (pkg1::IsProduction()) {
|
||||
return;
|
||||
}
|
||||
|
||||
pkg1::BootConfig * const bc = secmon::impl::GetBootConfigStorage();
|
||||
|
||||
/* Determine if the bc is valid for the device. */
|
||||
bool valid_for_device = false;
|
||||
{
|
||||
const bool valid_signature = secmon::boot::VerifyBootConfigSignature(*bc, secmon::boot::GetBootConfigRsaModulus(), se::RsaSize);
|
||||
if (valid_signature) {
|
||||
valid_for_device = secmon::boot::VerifyBootConfigEcid(*bc);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the boot config is not valid for the device, clear its signed data. */
|
||||
if (!valid_for_device) {
|
||||
util::ClearMemory(std::addressof(bc->signed_data), sizeof(bc->signed_data));
|
||||
}
|
||||
}
|
||||
|
||||
void EnableTsc(u64 initial_tsc_value) {
|
||||
/* Write the initial value to the CNTCV registers. */
|
||||
const u32 lo = static_cast<u32>(initial_tsc_value >> 0);
|
||||
const u32 hi = static_cast<u32>(initial_tsc_value >> 32);
|
||||
|
||||
reg::Write(SYSCTR0 + SYSCTR0_CNTCV0, lo);
|
||||
reg::Write(SYSCTR0 + SYSCTR0_CNTCV1, hi);
|
||||
|
||||
/* Configure the system counter control register. */
|
||||
reg::Write(SYSCTR0 + SYSCTR0_CNTCR, SYSCTR0_REG_BITS_ENUM(CNTCR_HDBG, ENABLE),
|
||||
SYSCTR0_REG_BITS_ENUM(CNTCR_EN, ENABLE));
|
||||
}
|
||||
|
||||
void WriteGpuCarveoutMagicNumbers() {
|
||||
/* Define the magic numbers. */
|
||||
constexpr u32 GpuMagicNumber = 0xC0EDBBCC;
|
||||
constexpr u32 SkuInfo = 0x83;
|
||||
constexpr u32 HdcpMicroCodeVersion = 0x2;
|
||||
|
||||
/* Get our pointers. */
|
||||
u32 *gpu_magic = MemoryRegionDramGpuCarveout.GetEndPointer<u32>() - (0x004 / sizeof(*gpu_magic));
|
||||
u32 *tsec_magic = MemoryRegionDramGpuCarveout.GetEndPointer<u32>() - (0x100 / sizeof(*tsec_magic));
|
||||
|
||||
/* Write the gpu magic number. */
|
||||
gpu_magic[0] = GpuMagicNumber;
|
||||
|
||||
/* Write the tsec magic numbers. */
|
||||
tsec_magic[0] = SkuInfo;
|
||||
tsec_magic[1] = HdcpMicroCodeVersion;
|
||||
tsec_magic[2] = GetChipId();
|
||||
|
||||
/* Flush the magic numbers. */
|
||||
hw::FlushDataCache(gpu_magic, 1 * sizeof(u32));
|
||||
hw::FlushDataCache(tsec_magic, 3 * sizeof(u32));
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
|
||||
void UpdateBootConfigForPackage2Header(const pkg2::Package2Header &header) {
|
||||
/* Check for all-zeroes signature. */
|
||||
bool is_decrypted = header.signature[0] == 0;
|
||||
is_decrypted &= crypto::IsSameBytes(header.signature, header.signature + 1, sizeof(header.signature) - 1);
|
||||
|
||||
/* Check for valid magic. */
|
||||
is_decrypted &= crypto::IsSameBytes(header.meta.magic, pkg2::Package2Meta::Magic::String, sizeof(header.meta.magic));
|
||||
|
||||
/* Set the setting in boot config. */
|
||||
secmon::impl::GetBootConfigStorage()->signed_data.SetPackage2Decrypted(is_decrypted);
|
||||
}
|
||||
|
||||
void VerifyPackage2HeaderSignature(pkg2::Package2Header &header, bool verify) {
|
||||
const u8 * const mod = secmon::boot::GetPackage2RsaModulus(pkg1::IsProductionForPublicKey());
|
||||
const size_t mod_size = se::RsaSize;
|
||||
if (verify) {
|
||||
CheckVerifyResult(secmon::boot::VerifyPackage2Signature(header, mod, mod_size), pkg1::ErrorInfo_InvalidPackage2Signature, "package2 header sign verification failed");
|
||||
}
|
||||
}
|
||||
|
||||
void DecryptPackage2Header(pkg2::Package2Meta *dst, const pkg2::Package2Meta &src, bool encrypted) {
|
||||
if (encrypted) {
|
||||
constexpr int IvSize = 0x10;
|
||||
|
||||
/* Decrypt the header. */
|
||||
DecryptPackage2(dst, sizeof(*dst), std::addressof(src), sizeof(src), secmon::boot::GetPackage2AesKey(), crypto::AesEncryptor128::KeySize, std::addressof(src), IvSize, src.GetKeyGeneration());
|
||||
|
||||
/* Copy back the iv, which encodes encrypted metadata. */
|
||||
std::memcpy(dst, std::addressof(src), IvSize);
|
||||
} else {
|
||||
std::memcpy(dst, std::addressof(src), sizeof(*dst));
|
||||
}
|
||||
}
|
||||
|
||||
void VerifyPackage2Header(const pkg2::Package2Meta &meta) {
|
||||
/* Validate the metadata. */
|
||||
CheckVerifyResult(VerifyPackage2Meta(meta), pkg1::ErrorInfo_InvalidPackage2Meta, "package2 meta verification failed");
|
||||
|
||||
/* Validate the version. */
|
||||
CheckVerifyResult(VerifyPackage2Version(meta), pkg1::ErrorInfo_InvalidPackage2Version, "package2 version verification failed");
|
||||
}
|
||||
|
||||
void DecryptAndLoadPackage2Payloads(uintptr_t dst, const pkg2::Package2Meta &meta, uintptr_t src, bool encrypted) {
|
||||
/* Get the key generation for crypto. */
|
||||
const u8 key_generation = meta.GetKeyGeneration();
|
||||
/* Decrypt or load each payload in order. */
|
||||
for (int i = 0; i < pkg2::PayloadCount; ++i) {
|
||||
if (encrypted) {
|
||||
DecryptPayload(dst + meta.payload_offsets[i], src, meta.payload_sizes[i], meta.payload_ivs[i], sizeof(meta.payload_ivs[i]), key_generation);
|
||||
} else {
|
||||
std::memcpy(reinterpret_cast<void *>(dst + meta.payload_offsets[i]), reinterpret_cast<void *>(src), meta.payload_sizes[i]);
|
||||
}
|
||||
|
||||
src += meta.payload_sizes[i];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
42
exosphere/program/source/boot/secmon_boot_functions.hpp
Normal file
42
exosphere/program/source/boot/secmon_boot_functions.hpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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();
|
||||
|
||||
void WaitForNxBootloader(const pkg1::SecureMonitorParameters ¶ms, pkg1::BootloaderState state);
|
||||
|
||||
void LoadBootConfig(const void *src);
|
||||
void VerifyOrClearBootConfig();
|
||||
|
||||
void EnableTsc(u64 initial_tsc_value);
|
||||
|
||||
void WriteGpuCarveoutMagicNumbers();
|
||||
|
||||
void UpdateBootConfigForPackage2Header(const pkg2::Package2Header &header);
|
||||
void VerifyPackage2HeaderSignature(pkg2::Package2Header &header, bool verify);
|
||||
void DecryptPackage2Header(pkg2::Package2Meta *dst, const pkg2::Package2Meta &src, bool encrypted);
|
||||
|
||||
void VerifyPackage2Header(const pkg2::Package2Meta &meta);
|
||||
|
||||
void DecryptAndLoadPackage2Payloads(uintptr_t dst, const pkg2::Package2Meta &meta, uintptr_t src, bool encrypted);
|
||||
|
||||
void CheckVerifyResult(bool verify_result, pkg1::ErrorInfo error_info, const char *message);
|
||||
|
||||
}
|
77
exosphere/program/source/boot/secmon_boot_key_data.s
Normal file
77
exosphere/program/source/boot/secmon_boot_key_data.s
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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 .volatile_keys._ZN3ams6secmon4boot15VolatileKeyDataE, "aw", %progbits
|
||||
.global _ZN3ams6secmon4boot15VolatileKeyDataE
|
||||
_ZN3ams6secmon4boot15VolatileKeyDataE:
|
||||
/* BootConfig Rsa Modulus. */
|
||||
.byte 0xB5, 0x96, 0x87, 0x31, 0x39, 0xAA, 0xBB, 0x3C, 0x28, 0xF3, 0xF0, 0x65, 0xF1, 0x50, 0x70, 0x64
|
||||
.byte 0xE6, 0x6C, 0x97, 0x50, 0xCD, 0xA6, 0xEE, 0xEA, 0xC3, 0x8F, 0xE6, 0xB5, 0x81, 0x54, 0x65, 0x33
|
||||
.byte 0x1B, 0x88, 0x4B, 0xCE, 0x9F, 0x53, 0xDF, 0xE4, 0xF6, 0xAD, 0xC3, 0x78, 0xD7, 0x3C, 0xD1, 0xDB
|
||||
.byte 0x27, 0x21, 0xA0, 0x24, 0x30, 0x2D, 0x98, 0x41, 0xA8, 0xDF, 0x50, 0x7D, 0xAB, 0xCE, 0x00, 0xD9
|
||||
.byte 0xCB, 0xAC, 0x8F, 0x37, 0xF5, 0x53, 0xE4, 0x97, 0x1F, 0x13, 0x3C, 0x19, 0xFF, 0x05, 0xA7, 0x3B
|
||||
.byte 0xF6, 0xF4, 0x01, 0xDE, 0xF0, 0xC3, 0x77, 0x7B, 0x83, 0xBA, 0xAF, 0x99, 0x30, 0x94, 0x87, 0x25
|
||||
.byte 0x4E, 0x54, 0x42, 0x3F, 0xAC, 0x27, 0xF9, 0xCC, 0x87, 0xDD, 0xAE, 0xF2, 0x54, 0xF3, 0x97, 0x49
|
||||
.byte 0xF4, 0xB0, 0xF8, 0x6D, 0xDA, 0x60, 0xE0, 0xFD, 0x57, 0xAE, 0x55, 0xA9, 0x76, 0xEA, 0x80, 0x24
|
||||
.byte 0xA0, 0x04, 0x7D, 0xBE, 0xD1, 0x81, 0xD3, 0x0C, 0x95, 0xCF, 0xB7, 0xE0, 0x2D, 0x21, 0x21, 0xFF
|
||||
.byte 0x97, 0x1E, 0xB3, 0xD7, 0x9F, 0xBB, 0x33, 0x0C, 0x23, 0xC5, 0x88, 0x4A, 0x33, 0xB9, 0xC9, 0x4E
|
||||
.byte 0x1E, 0x65, 0x51, 0x45, 0xDE, 0xF9, 0x64, 0x7C, 0xF0, 0xBF, 0x11, 0xB4, 0x93, 0x8D, 0x5D, 0xC6
|
||||
.byte 0xAB, 0x37, 0x9E, 0xE9, 0x39, 0xC1, 0xC8, 0xDB, 0xB9, 0xFE, 0x45, 0xCE, 0x7B, 0xDD, 0x72, 0xD9
|
||||
.byte 0x6F, 0x68, 0x13, 0xC0, 0x4B, 0xBA, 0x00, 0xF4, 0x1E, 0x89, 0x71, 0x91, 0x26, 0xA6, 0x46, 0x12
|
||||
.byte 0xDF, 0x29, 0x6B, 0xC2, 0x5A, 0x53, 0xAF, 0xB9, 0x5B, 0xFD, 0x13, 0x9F, 0xD1, 0x8A, 0x7C, 0xB5
|
||||
.byte 0x04, 0xFD, 0x69, 0xEA, 0x23, 0xB4, 0x6D, 0x16, 0x21, 0x98, 0x54, 0xB4, 0xDF, 0xE6, 0xAB, 0x93
|
||||
.byte 0x36, 0xB6, 0xD2, 0x43, 0xCF, 0x2B, 0x98, 0x1D, 0x45, 0xC9, 0xBB, 0x20, 0x42, 0xB1, 0x9D, 0x1D
|
||||
|
||||
/* Package2 Development Rsa Modulus. */
|
||||
.byte 0xB3, 0x65, 0x54, 0xFB, 0x0A, 0xB0, 0x1E, 0x85, 0xA7, 0xF6, 0xCF, 0x91, 0x8E, 0xBA, 0x96, 0x99
|
||||
.byte 0x0D, 0x8B, 0x91, 0x69, 0x2A, 0xEE, 0x01, 0x20, 0x4F, 0x34, 0x5C, 0x2C, 0x4F, 0x4E, 0x37, 0xC7
|
||||
.byte 0xF1, 0x0B, 0xD4, 0xCD, 0xA1, 0x7F, 0x93, 0xF1, 0x33, 0x59, 0xCE, 0xB1, 0xE9, 0xDD, 0x26, 0xE6
|
||||
.byte 0xF3, 0xBB, 0x77, 0x87, 0x46, 0x7A, 0xD6, 0x4E, 0x47, 0x4A, 0xD1, 0x41, 0xB7, 0x79, 0x4A, 0x38
|
||||
.byte 0x06, 0x6E, 0xCF, 0x61, 0x8F, 0xCD, 0xC1, 0x40, 0x0B, 0xFA, 0x26, 0xDC, 0xC0, 0x34, 0x51, 0x83
|
||||
.byte 0xD9, 0x3B, 0x11, 0x54, 0x3B, 0x96, 0x27, 0x32, 0x9A, 0x95, 0xBE, 0x1E, 0x68, 0x11, 0x50, 0xA0
|
||||
.byte 0x6B, 0x10, 0xA8, 0x83, 0x8B, 0xF5, 0xFC, 0xBC, 0x90, 0x84, 0x7A, 0x5A, 0x5C, 0x43, 0x52, 0xE6
|
||||
.byte 0xC8, 0x26, 0xE9, 0xFE, 0x06, 0xA0, 0x8B, 0x53, 0x0F, 0xAF, 0x1E, 0xC4, 0x1C, 0x0B, 0xCF, 0x50
|
||||
.byte 0x1A, 0xA4, 0xF3, 0x5C, 0xFB, 0xF0, 0x97, 0xE4, 0xDE, 0x32, 0x0A, 0x9F, 0xE3, 0x5A, 0xAA, 0xB7
|
||||
.byte 0x44, 0x7F, 0x5C, 0x33, 0x60, 0xB9, 0x0F, 0x22, 0x2D, 0x33, 0x2A, 0xE9, 0x69, 0x79, 0x31, 0x42
|
||||
.byte 0x8F, 0xE4, 0x3A, 0x13, 0x8B, 0xE7, 0x26, 0xBD, 0x08, 0x87, 0x6C, 0xA6, 0xF2, 0x73, 0xF6, 0x8E
|
||||
.byte 0xA7, 0xF2, 0xFE, 0xFB, 0x6C, 0x28, 0x66, 0x0D, 0xBD, 0xD7, 0xEB, 0x42, 0xA8, 0x78, 0xE6, 0xB8
|
||||
.byte 0x6B, 0xAE, 0xC7, 0xA9, 0xE2, 0x40, 0x6E, 0x89, 0x20, 0x82, 0x25, 0x8E, 0x3C, 0x6A, 0x60, 0xD7
|
||||
.byte 0xF3, 0x56, 0x8E, 0xEC, 0x8D, 0x51, 0x8A, 0x63, 0x3C, 0x04, 0x78, 0x23, 0x0E, 0x90, 0x0C, 0xB4
|
||||
.byte 0xE7, 0x86, 0x3B, 0x4F, 0x8E, 0x13, 0x09, 0x47, 0x32, 0x0E, 0x04, 0xB8, 0x4D, 0x5B, 0xB0, 0x46
|
||||
.byte 0x71, 0xB0, 0x5C, 0xF4, 0xAD, 0x63, 0x4F, 0xC5, 0xE2, 0xAC, 0x1E, 0xC4, 0x33, 0x96, 0x09, 0x7B
|
||||
|
||||
/* Package2 Production Rsa Modulus. */
|
||||
.byte 0x8D, 0x13, 0xA7, 0x77, 0x6A, 0xE5, 0xDC, 0xC0, 0x3B, 0x25, 0xD0, 0x58, 0xE4, 0x20, 0x69, 0x59
|
||||
.byte 0x55, 0x4B, 0xAB, 0x70, 0x40, 0x08, 0x28, 0x07, 0xA8, 0xA7, 0xFD, 0x0F, 0x31, 0x2E, 0x11, 0xFE
|
||||
.byte 0x47, 0xA0, 0xF9, 0x9D, 0xDF, 0x80, 0xDB, 0x86, 0x5A, 0x27, 0x89, 0xCD, 0x97, 0x6C, 0x85, 0xC5
|
||||
.byte 0x6C, 0x39, 0x7F, 0x41, 0xF2, 0xFF, 0x24, 0x20, 0xC3, 0x95, 0xA6, 0xF7, 0x9D, 0x4A, 0x45, 0x74
|
||||
.byte 0x8B, 0x5D, 0x28, 0x8A, 0xC6, 0x99, 0x35, 0x68, 0x85, 0xA5, 0x64, 0x32, 0x80, 0x9F, 0xD3, 0x48
|
||||
.byte 0x39, 0xA2, 0x1D, 0x24, 0x67, 0x69, 0xDF, 0x75, 0xAC, 0x12, 0xB5, 0xBD, 0xC3, 0x29, 0x90, 0xBE
|
||||
.byte 0x37, 0xE4, 0xA0, 0x80, 0x9A, 0xBE, 0x36, 0xBF, 0x1F, 0x2C, 0xAB, 0x2B, 0xAD, 0xF5, 0x97, 0x32
|
||||
.byte 0x9A, 0x42, 0x9D, 0x09, 0x8B, 0x08, 0xF0, 0x63, 0x47, 0xA3, 0xE9, 0x1B, 0x36, 0xD8, 0x2D, 0x8A
|
||||
.byte 0xD7, 0xE1, 0x54, 0x11, 0x95, 0xE4, 0x45, 0x88, 0x69, 0x8A, 0x2B, 0x35, 0xCE, 0xD0, 0xA5, 0x0B
|
||||
.byte 0xD5, 0x5D, 0xAC, 0xDB, 0xAF, 0x11, 0x4D, 0xCA, 0xB8, 0x1E, 0xE7, 0x01, 0x9E, 0xF4, 0x46, 0xA3
|
||||
.byte 0x8A, 0x94, 0x6D, 0x76, 0xBD, 0x8A, 0xC8, 0x3B, 0xD2, 0x31, 0x58, 0x0C, 0x79, 0xA8, 0x26, 0xE9
|
||||
.byte 0xD1, 0x79, 0x9C, 0xCB, 0xD4, 0x2B, 0x6A, 0x4F, 0xC6, 0xCC, 0xCF, 0x90, 0xA7, 0xB9, 0x98, 0x47
|
||||
.byte 0xFD, 0xFA, 0x4C, 0x6C, 0x6F, 0x81, 0x87, 0x3B, 0xCA, 0xB8, 0x50, 0xF6, 0x3E, 0x39, 0x5D, 0x4D
|
||||
.byte 0x97, 0x3F, 0x0F, 0x35, 0x39, 0x53, 0xFB, 0xFA, 0xCD, 0xAB, 0xA8, 0x7A, 0x62, 0x9A, 0x3F, 0xF2
|
||||
.byte 0x09, 0x27, 0x96, 0x3F, 0x07, 0x9A, 0x91, 0xF7, 0x16, 0xBF, 0xC6, 0x3A, 0x82, 0x5A, 0x4B, 0xCF
|
||||
.byte 0x49, 0x50, 0x95, 0x8C, 0x55, 0x80, 0x7E, 0x39, 0xB1, 0x48, 0x05, 0x1E, 0x21, 0xC7, 0x24, 0x4F
|
||||
|
||||
/* Package2 Aes Key Source. */
|
||||
.byte 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7
|
159
exosphere/program/source/boot/secmon_boot_rsa.cpp
Normal file
159
exosphere/program/source/boot/secmon_boot_rsa.cpp
Normal file
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* 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"
|
||||
|
||||
namespace ams::secmon::boot {
|
||||
|
||||
namespace {
|
||||
|
||||
constinit const u8 RsaPublicKeyExponent[] = {
|
||||
0x00, 0x01, 0x00, 0x01,
|
||||
};
|
||||
|
||||
constexpr inline u8 TailMagic = 0xBC;
|
||||
|
||||
bool VerifyRsaPssSha256(const u8 *sig, const void *msg, size_t msg_size) {
|
||||
/* Define constants. */
|
||||
constexpr int EmBits = 2047;
|
||||
constexpr int EmLen = util::DivideUp(EmBits, BITSIZEOF(u8));
|
||||
constexpr int SaltLen = 0x20;
|
||||
constexpr int HashLen = se::Sha256HashSize;
|
||||
|
||||
/* Define a work buffer. */
|
||||
u8 work[EmLen];
|
||||
ON_SCOPE_EXIT { util::ClearMemory(work, sizeof(work)); };
|
||||
|
||||
/* Calculate the message hash, first flushing cache to ensure SE sees correct data. */
|
||||
se::Sha256Hash msg_hash;
|
||||
hw::FlushDataCache(msg, msg_size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
se::CalculateSha256(std::addressof(msg_hash), msg, msg_size);
|
||||
|
||||
/* Verify the tail magic. */
|
||||
bool is_valid = sig[EmLen - 1] == TailMagic;
|
||||
|
||||
/* Determine extents of masked db and h. */
|
||||
const u8 *masked_db = std::addressof(sig[0]);
|
||||
const u8 *h = std::addressof(sig[EmLen - HashLen - 1]);
|
||||
|
||||
/* Verify the extra bits are zero. */
|
||||
is_valid &= (masked_db[0] >> (BITSIZEOF(u8) - (BITSIZEOF(u8) * EmLen - EmBits))) == 0;
|
||||
|
||||
/* Calculate the db mask. */
|
||||
{
|
||||
constexpr int MaskLen = EmLen - HashLen - 1;
|
||||
constexpr int HashIters = util::DivideUp(MaskLen, HashLen);
|
||||
|
||||
u8 mgf1_buf[sizeof(u32) + HashLen];
|
||||
|
||||
std::memcpy(std::addressof(mgf1_buf[0]), h, HashLen);
|
||||
std::memset(std::addressof(mgf1_buf[HashLen]), 0, sizeof(u32));
|
||||
|
||||
for (int i = 0; i < HashIters; ++i) {
|
||||
/* Set the counter for this iteration. */
|
||||
mgf1_buf[sizeof(mgf1_buf) - 1] = i;
|
||||
|
||||
/* Calculate the sha256 to the appropriate place in the work buffer. */
|
||||
auto *mgf1_dst = reinterpret_cast<se::Sha256Hash *>(std::addressof(work[HashLen * i]));
|
||||
|
||||
hw::FlushDataCache(mgf1_buf, sizeof(mgf1_buf));
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
se::CalculateSha256(mgf1_dst, mgf1_buf, sizeof(mgf1_buf));
|
||||
}
|
||||
}
|
||||
|
||||
/* Decrypt masked db using the mask we just generated. */
|
||||
for (int i = 0; i < EmLen - HashLen - 1; ++i) {
|
||||
work[i] ^= masked_db[i];
|
||||
}
|
||||
|
||||
/* Mask out the top bits. */
|
||||
u8 *db = work;
|
||||
db[0] &= 0xFF >> (BITSIZEOF(u8) * EmLen - EmBits);
|
||||
|
||||
/* Verify that DB is of the form 0000...0001 */
|
||||
constexpr int DbLen = EmLen - HashLen - 1;
|
||||
int salt_ofs = 0;
|
||||
{
|
||||
int looking_for_one = 1;
|
||||
int invalid_db_padding = 0;
|
||||
int is_zero;
|
||||
int is_one;
|
||||
for (size_t i = 0; i < DbLen; /* ... */) {
|
||||
is_zero = (db[i] == 0);
|
||||
is_one = (db[i] == 1);
|
||||
salt_ofs += (looking_for_one & is_one) * (static_cast<s32>(++i));
|
||||
looking_for_one &= ~is_one;
|
||||
invalid_db_padding |= (looking_for_one & ~is_zero);
|
||||
}
|
||||
|
||||
is_valid &= (invalid_db_padding == 0);
|
||||
}
|
||||
|
||||
/* Verify salt. */
|
||||
is_valid &= (DbLen - salt_ofs) == SaltLen;
|
||||
|
||||
/* Setup the message to verify. */
|
||||
const u8 *salt = std::addressof(db[DbLen - SaltLen]);
|
||||
u8 verif_msg[8 + HashLen + SaltLen];
|
||||
ON_SCOPE_EXIT { util::ClearMemory(verif_msg, sizeof(verif_msg)); };
|
||||
|
||||
util::ClearMemory(std::addressof(verif_msg[0]), 8);
|
||||
std::memcpy(std::addressof(verif_msg[8]), std::addressof(msg_hash), HashLen);
|
||||
std::memcpy(std::addressof(verif_msg[8 + HashLen]), salt, SaltLen);
|
||||
|
||||
/* Verify the final hash. */
|
||||
return VerifyHash(h, reinterpret_cast<uintptr_t>(std::addressof(verif_msg[0])), sizeof(verif_msg));
|
||||
}
|
||||
|
||||
bool VerifyRsaPssSha256(int slot, void *sig, size_t sig_size, const void *msg, size_t msg_size) {
|
||||
/* Exponentiate the signature, using the signature as the destination buffer. */
|
||||
se::ModularExponentiate(sig, sig_size, slot, sig, sig_size);
|
||||
|
||||
/* Verify the pss padding. */
|
||||
return VerifyRsaPssSha256(static_cast<const u8 *>(sig), msg, msg_size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool VerifySignature(void *sig, size_t sig_size, const void *mod, size_t mod_size, const void *msg, size_t msg_size) {
|
||||
/* Load the public key into a temporary keyslot. */
|
||||
const int slot = pkg1::RsaKeySlot_Temporary;
|
||||
se::SetRsaKey(slot, mod, mod_size, RsaPublicKeyExponent, util::size(RsaPublicKeyExponent));
|
||||
|
||||
return VerifyRsaPssSha256(slot, sig, sig_size, msg, msg_size);
|
||||
}
|
||||
|
||||
bool VerifyHash(const void *hash, uintptr_t msg, size_t msg_size) {
|
||||
/* Zero-sized messages are always valid. */
|
||||
if (msg_size == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Ensure that the SE sees correct data for the message. */
|
||||
hw::FlushDataCache(reinterpret_cast<void *>(msg), msg_size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Calculate the hash. */
|
||||
se::Sha256Hash calc_hash;
|
||||
se::CalculateSha256(std::addressof(calc_hash), reinterpret_cast<void *>(msg), msg_size);
|
||||
|
||||
/* Verify the result. */
|
||||
return crypto::IsSameBytes(std::addressof(calc_hash), hash, sizeof(calc_hash));
|
||||
}
|
||||
|
||||
}
|
386
exosphere/program/source/boot/secmon_boot_setup.cpp
Normal file
386
exosphere/program/source/boot/secmon_boot_setup.cpp
Normal file
|
@ -0,0 +1,386 @@
|
|||
/*
|
||||
* 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_cache.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(i - 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 = IsProduction();
|
||||
|
||||
/* 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace ams::mmu;
|
||||
|
||||
constexpr void UnmapPhysicalIdentityMappingImpl(u64 *l1, u64 *l2, u64 *l3) {
|
||||
/* Invalidate the L3 entries for the tzram and iram boot code regions. */
|
||||
InvalidateL3Entries(l3, MemoryRegionPhysicalTzram.GetAddress(), MemoryRegionPhysicalTzram.GetSize());
|
||||
InvalidateL3Entries(l3, MemoryRegionPhysicalIramBootCode.GetAddress(), MemoryRegionPhysicalIramBootCode.GetSize());
|
||||
|
||||
/* Unmap the L2 entries corresponding to those L3 entries. */
|
||||
InvalidateL2Entries(l2, MemoryRegionPhysicalIramL2.GetAddress(), MemoryRegionPhysicalIramL2.GetSize());
|
||||
InvalidateL2Entries(l2, MemoryRegionPhysicalTzramL2.GetAddress(), MemoryRegionPhysicalTzramL2.GetSize());
|
||||
|
||||
/* Unmap the L1 entry corresponding to to those L2 entries. */
|
||||
InvalidateL1Entries(l1, MemoryRegionPhysical.GetAddress(), MemoryRegionPhysical.GetSize());
|
||||
}
|
||||
|
||||
constexpr void UnmapDramImpl(u64 *l1, u64 *l2, u64 *l3) {
|
||||
/* Unmap the L1 entry corresponding to to the Dram entries. */
|
||||
InvalidateL1Entries(l1, MemoryRegionDram.GetAddress(), MemoryRegionDram.GetSize());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void UnmapPhysicalIdentityMapping() {
|
||||
/* Get the tables. */
|
||||
u64 * const l1 = MemoryRegionVirtualTzramL1PageTable.GetPointer<u64>();
|
||||
u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer<u64>();
|
||||
|
||||
/* Unmap. */
|
||||
UnmapPhysicalIdentityMappingImpl(l1, l2_l3, l2_l3);
|
||||
|
||||
/* Ensure the mappings are consistent. */
|
||||
secmon::boot::EnsureMappingConsistency();
|
||||
}
|
||||
|
||||
void UnmapDram() {
|
||||
/* Get the tables. */
|
||||
u64 * const l1 = MemoryRegionVirtualTzramL1PageTable.GetPointer<u64>();
|
||||
u64 * const l2_l3 = MemoryRegionVirtualTzramL2L3PageTable.GetPointer<u64>();
|
||||
|
||||
/* Unmap. */
|
||||
UnmapDramImpl(l1, l2_l3, l2_l3);
|
||||
|
||||
/* Ensure the mappings are consistent. */
|
||||
secmon::boot::EnsureMappingConsistency();
|
||||
}
|
||||
|
||||
}
|
37
exosphere/program/source/boot/secmon_crt0.s
Normal file
37
exosphere/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
exosphere/program/source/boot/secmon_crt0_cpp.cpp
Normal file
46
exosphere/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();
|
||||
}
|
||||
|
||||
}
|
185
exosphere/program/source/boot/secmon_main.cpp
Normal file
185
exosphere/program/source/boot/secmon_main.cpp
Normal file
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* 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 "../smc/secmon_random_cache.hpp"
|
||||
#include "../secmon_cache.hpp"
|
||||
#include "../secmon_cpu_context.hpp"
|
||||
#include "../secmon_misc.hpp"
|
||||
#include "../secmon_setup.hpp"
|
||||
|
||||
namespace ams::secmon {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline const uintptr_t Package2LoadAddress = MemoryRegionDramPackage2Payloads.GetAddress();
|
||||
|
||||
}
|
||||
|
||||
void Main() {
|
||||
/* Set library register addresses. */
|
||||
actmon::SetRegisterAddress(MemoryRegionVirtualDeviceActivityMonitor.GetAddress());
|
||||
clkrst::SetRegisterAddress(MemoryRegionVirtualDeviceClkRst.GetAddress());
|
||||
flow::SetRegisterAddress(MemoryRegionVirtualDeviceFlowController.GetAddress());
|
||||
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(MemoryRegionVirtualDeviceApbMisc.GetAddress(), MemoryRegionVirtualDeviceGpio.GetAddress());
|
||||
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();
|
||||
|
||||
/* Setup the Cpu core context. */
|
||||
secmon::SetupCpuCoreContext();
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* Wait for NX Bootloader to finish loading the BootConfig. */
|
||||
secmon::boot::WaitForNxBootloader(secmon_params, pkg1::BootloaderState_LoadedBootConfig);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Load the bootconfig. */
|
||||
secmon::boot::LoadBootConfig(MemoryRegionPhysicalIramBootConfig.GetPointer());
|
||||
|
||||
/* Verify or clear the boot config. */
|
||||
secmon::boot::VerifyOrClearBootConfig();
|
||||
|
||||
/* Get the boot config. */
|
||||
const auto &bc = secmon::GetBootConfig();
|
||||
|
||||
/* Set the tsc value by the boot config. */
|
||||
{
|
||||
constexpr u64 TscMask = (static_cast<u64>(1) << 55) - 1;
|
||||
|
||||
secmon::boot::EnableTsc(bc.data.GetInitialTscValue() & TscMask);
|
||||
}
|
||||
|
||||
/* Wait for NX Bootloader to initialize DRAM. */
|
||||
secmon::boot::WaitForNxBootloader(secmon_params, pkg1::BootloaderState_InitializedDram);
|
||||
|
||||
/* Secure the PMC and MC. */
|
||||
secmon::SetupPmcAndMcSecure();
|
||||
|
||||
/* Copy warmboot to dram. */
|
||||
{
|
||||
/* Define warmboot extents. */
|
||||
const void * const src = MemoryRegionPhysicalIramWarmbootBin.GetPointer();
|
||||
void * const dst = MemoryRegionVirtualDramSecureDataStoreWarmbootFirmware.GetPointer();
|
||||
const size_t size = MemoryRegionPhysicalIramWarmbootBin.GetSize();
|
||||
|
||||
/* Ensure we copy the correct data. */
|
||||
hw::FlushDataCache(src, size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Copy warmboot.bin to its secure dram location. */
|
||||
std::memcpy(dst, src, size);
|
||||
}
|
||||
|
||||
/* Unmap the identity mapping. */
|
||||
secmon::boot::UnmapPhysicalIdentityMapping();
|
||||
|
||||
/* Setup the GPU carveout's magic numbers. */
|
||||
secmon::boot::WriteGpuCarveoutMagicNumbers();
|
||||
|
||||
/* Wait for NX bootloader to load Package2. */
|
||||
secmon::boot::WaitForNxBootloader(secmon_params, pkg1::BootloaderState_LoadedPackage2);
|
||||
|
||||
/* Parse and decrypt the package2 header. */
|
||||
pkg2::Package2Meta &pkg2_meta = secmon::boot::GetEphemeralPackage2Meta();
|
||||
const uintptr_t pkg2_payloads_start = MemoryRegionDramPackage2.GetAddress() + sizeof(pkg2::Package2Header);
|
||||
{
|
||||
/* Read the encrypred header. */
|
||||
pkg2::Package2Header encrypted_header;
|
||||
|
||||
const auto *dram_header = MemoryRegionDramPackage2.GetPointer<pkg2::Package2Header>();
|
||||
hw::FlushDataCache(dram_header, sizeof(*dram_header));
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
std::memcpy(std::addressof(encrypted_header), dram_header, sizeof(encrypted_header));
|
||||
|
||||
/* Atmosphere extension: support plaintext package2, identified by all-zeroes signature and decrypted header. */
|
||||
secmon::boot::UpdateBootConfigForPackage2Header(encrypted_header);
|
||||
|
||||
/* Verify the package2 header's signature. */
|
||||
secmon::boot::VerifyPackage2HeaderSignature(encrypted_header, !bc.signed_data.IsPackage2SignatureVerificationDisabled());
|
||||
|
||||
/* Decrypt the package2 header. */
|
||||
secmon::boot::DecryptPackage2Header(std::addressof(pkg2_meta), encrypted_header.meta, !bc.signed_data.IsPackage2EncryptionDisabled());
|
||||
}
|
||||
|
||||
/* Verify the package2 header. */
|
||||
secmon::boot::VerifyPackage2Header(pkg2_meta);
|
||||
|
||||
/* Save the package2 hash if in recovery boot. */
|
||||
if (secmon::IsRecoveryBoot()) {
|
||||
se::Sha256Hash hash;
|
||||
secmon::boot::CalculatePackage2Hash(std::addressof(hash), pkg2_meta, MemoryRegionDramPackage2.GetAddress());
|
||||
secmon::SetPackage2Hash(hash);
|
||||
}
|
||||
|
||||
/* Verify the package2 payloads. */
|
||||
secmon::boot::CheckVerifyResult(secmon::boot::VerifyPackage2Payloads(pkg2_meta, pkg2_payloads_start), pkg1::ErrorInfo_InvalidPackage2Payload, "package2 payload verification failed");
|
||||
|
||||
/* Decrypt/Move the package2 payloads to the right places. */
|
||||
secmon::boot::DecryptAndLoadPackage2Payloads(Package2LoadAddress, pkg2_meta, pkg2_payloads_start, !bc.signed_data.IsPackage2EncryptionDisabled());
|
||||
|
||||
/* Ensure that the CPU sees correct package2 data. */
|
||||
secmon::FlushEntireDataCache();
|
||||
secmon::EnsureInstructionConsistency();
|
||||
|
||||
/* Set the core's entrypoint and argument. */
|
||||
secmon::SetEntryContext(0, Package2LoadAddress + pkg2_meta.entrypoint, 0);
|
||||
|
||||
/* Unmap DRAM. */
|
||||
secmon::boot::UnmapDram();
|
||||
|
||||
/* Wait for NX bootloader to be done. */
|
||||
secmon::boot::WaitForNxBootloader(secmon_params, pkg1::BootloaderState_Done);
|
||||
|
||||
/* Perform final initialization. */
|
||||
secmon::SetupSocProtections();
|
||||
secmon::SetupCpuSErrorDebug();
|
||||
}
|
||||
|
||||
}
|
152
exosphere/program/source/boot/secmon_make_page_table.cpp
Normal file
152
exosphere/program/source/boot/secmon_make_page_table.cpp
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* 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 Debug region. */
|
||||
/* NOTE: This region is reserved for debug. By default it will be the last 0x8000 bytes of IRAM, but this is subject to change. */
|
||||
/* If you are doing development work for exosphere, feel free to locally change this to whatever is useful. */
|
||||
SetL3BlockEntry(l3, MemoryRegionVirtualDebug.GetAddress(), MemoryRegionPhysicalIram.GetEndAddress() - 0x8000, 0x8000, MappingAttributesEl3SecureDevice);
|
||||
|
||||
/* 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, MappingAttributesEl3SecureRwData);
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
151
exosphere/program/source/boot/secmon_package2.cpp
Normal file
151
exosphere/program/source/boot/secmon_package2.cpp
Normal file
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* 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_key_storage.hpp"
|
||||
#include "secmon_boot.hpp"
|
||||
|
||||
namespace ams::secmon::boot {
|
||||
|
||||
void CalculatePackage2Hash(se::Sha256Hash *dst, const pkg2::Package2Meta &meta, uintptr_t package2_start) {
|
||||
/* Determine the region to hash. */
|
||||
const void *data = reinterpret_cast<const void *>(package2_start);
|
||||
const size_t size = meta.GetSize();
|
||||
|
||||
/* Flush to ensure the SE sees the correct data. */
|
||||
hw::FlushDataCache(data, size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Calculate the hash. */
|
||||
se::CalculateSha256(dst, data, size);
|
||||
}
|
||||
|
||||
bool VerifyPackage2Signature(pkg2::Package2Header &header, const void *mod, size_t mod_size) {
|
||||
return VerifySignature(header.signature, sizeof(header.signature), mod, mod_size, std::addressof(header.meta), sizeof(header.meta));
|
||||
}
|
||||
|
||||
void DecryptPackage2(void *dst, size_t dst_size, const void *src, size_t src_size, const void *key, size_t key_size, const void *iv, size_t iv_size, u8 key_generation) {
|
||||
/* Ensure that the SE sees consistent data. */
|
||||
hw::FlushDataCache(key, key_size);
|
||||
hw::FlushDataCache(src, src_size);
|
||||
hw::FlushDataCache(dst, dst_size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Load the needed master key into the temporary keyslot. */
|
||||
secmon::LoadMasterKey(pkg1::AesKeySlot_Temporary, key_generation);
|
||||
|
||||
/* Load the package2 key into the temporary keyslot. */
|
||||
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Temporary, pkg1::AesKeySlot_Temporary, key, key_size);
|
||||
|
||||
/* Decrypt the data. */
|
||||
se::ComputeAes128Ctr(dst, dst_size, pkg1::AesKeySlot_Temporary, src, src_size, iv, iv_size);
|
||||
|
||||
/* Clear the keyslot we just used. */
|
||||
se::ClearAesKeySlot(pkg1::AesKeySlot_Temporary);
|
||||
|
||||
/* Ensure that the cpu sees consistent data. */
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
hw::FlushDataCache(dst, dst_size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
|
||||
bool VerifyPackage2Meta(const pkg2::Package2Meta &meta) {
|
||||
/* Get the obfuscated metadata. */
|
||||
const size_t size = meta.GetSize();
|
||||
const u8 key_generation = meta.GetKeyGeneration();
|
||||
|
||||
/* Check that size is big enough for the header. */
|
||||
if (size <= sizeof(pkg2::Package2Header)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check that the size isn't larger than what we allow. */
|
||||
if (size > pkg2::Package2SizeMax) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check that the key generation is one that we can use. */
|
||||
static_assert(pkg1::KeyGeneration_Count == 11);
|
||||
if (key_generation >= pkg1::KeyGeneration_Count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check the magic number. */
|
||||
if (!crypto::IsSameBytes(meta.magic, pkg2::Package2Meta::Magic::String, sizeof(meta.magic))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check the payload alignments. */
|
||||
if ((meta.entrypoint % pkg2::PayloadAlignment) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < pkg2::PayloadCount; ++i) {
|
||||
if ((meta.payload_sizes[i] % pkg2::PayloadAlignment) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that the sizes sum to the total. */
|
||||
if (size != sizeof(pkg2::Package2Header) + meta.payload_sizes[0] + meta.payload_sizes[1] + meta.payload_sizes[2]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check that the payloads do not overflow. */
|
||||
for (int i = 0; i < pkg2::PayloadCount; ++i) {
|
||||
if (meta.payload_offsets[i] > meta.payload_offsets[i] + meta.payload_sizes[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Verify that no payloads overlap. */
|
||||
for (int i = 0; i < pkg2::PayloadCount - 1; ++i) {
|
||||
for (int j = i + 1; j < pkg2::PayloadCount; ++j) {
|
||||
if (util::HasOverlap(meta.payload_offsets[i], meta.payload_sizes[i], meta.payload_offsets[j], meta.payload_sizes[j])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check whether any payload contains the entrypoint. */
|
||||
for (int i = 0; i < pkg2::PayloadCount; ++i) {
|
||||
if (util::Contains(meta.payload_offsets[i], meta.payload_sizes[i], meta.entrypoint)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* No payload contains the entrypoint, so we're not valid. */
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VerifyPackage2Version(const pkg2::Package2Meta &meta) {
|
||||
return meta.bootloader_version <= pkg2::CurrentBootloaderVersion && meta.package2_version >= pkg2::MinimumValidDataVersion;
|
||||
}
|
||||
|
||||
bool VerifyPackage2Payloads(const pkg2::Package2Meta &meta, uintptr_t payload_address) {
|
||||
/* Verify hashes match for all payloads. */
|
||||
for (int i = 0; i < pkg2::PayloadCount; ++i) {
|
||||
if (!VerifyHash(meta.payload_hashes[i], payload_address, meta.payload_sizes[i])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
payload_address += meta.payload_sizes[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
26
exosphere/program/source/boot/secmon_size_data.s
Normal file
26
exosphere/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
|
Loading…
Add table
Add a link
Reference in a new issue