diff --git a/exosphere2/program/source/boot/secmon_boot.hpp b/exosphere2/program/source/boot/secmon_boot.hpp
index dca6d0091..d82c67cac 100644
--- a/exosphere2/program/source/boot/secmon_boot.hpp
+++ b/exosphere2/program/source/boot/secmon_boot.hpp
@@ -22,4 +22,10 @@ namespace ams::secmon::boot {
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);
+
}
\ No newline at end of file
diff --git a/exosphere2/program/source/boot/secmon_boot_config.cpp b/exosphere2/program/source/boot/secmon_boot_config.cpp
index ad0649c3e..c4448624a 100644
--- a/exosphere2/program/source/boot/secmon_boot_config.cpp
+++ b/exosphere2/program/source/boot/secmon_boot_config.cpp
@@ -14,9 +14,21 @@
* along with this program. If not, see .
*/
#include
+#include "secmon_boot.hpp"
namespace ams::secmon::boot {
- /* TODO */
+ 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));
+ }
-}
\ No newline at end of file
+ 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));
+ }
+
+}
diff --git a/exosphere2/program/source/boot/secmon_boot_functions.cpp b/exosphere2/program/source/boot/secmon_boot_functions.cpp
index 3095f2f77..a9488e44e 100644
--- a/exosphere2/program/source/boot/secmon_boot_functions.cpp
+++ b/exosphere2/program/source/boot/secmon_boot_functions.cpp
@@ -14,13 +14,94 @@
* along with this program. If not, see .
*/
#include
+#include "secmon_boot.hpp"
#include "secmon_boot_functions.hpp"
namespace ams::secmon::boot {
+ namespace {
+
+ constexpr inline uintptr_t SYSCTR0 = MemoryRegionVirtualDeviceSysCtr0.GetAddress();
+
+ constinit const u8 BootConfigRsaPublicModulus[se::RsaSize] = {
+ 0xB5, 0x96, 0x87, 0x31, 0x39, 0xAA, 0xBB, 0x3C, 0x28, 0xF3, 0xF0, 0x65, 0xF1, 0x50, 0x70, 0x64,
+ 0xE6, 0x6C, 0x97, 0x50, 0xCD, 0xA6, 0xEE, 0xEA, 0xC3, 0x8F, 0xE6, 0xB5, 0x81, 0x54, 0x65, 0x33,
+ 0x1B, 0x88, 0x4B, 0xCE, 0x9F, 0x53, 0xDF, 0xE4, 0xF6, 0xAD, 0xC3, 0x78, 0xD7, 0x3C, 0xD1, 0xDB,
+ 0x27, 0x21, 0xA0, 0x24, 0x30, 0x2D, 0x98, 0x41, 0xA8, 0xDF, 0x50, 0x7D, 0xAB, 0xCE, 0x00, 0xD9,
+ 0xCB, 0xAC, 0x8F, 0x37, 0xF5, 0x53, 0xE4, 0x97, 0x1F, 0x13, 0x3C, 0x19, 0xFF, 0x05, 0xA7, 0x3B,
+ 0xF6, 0xF4, 0x01, 0xDE, 0xF0, 0xC3, 0x77, 0x7B, 0x83, 0xBA, 0xAF, 0x99, 0x30, 0x94, 0x87, 0x25,
+ 0x4E, 0x54, 0x42, 0x3F, 0xAC, 0x27, 0xF9, 0xCC, 0x87, 0xDD, 0xAE, 0xF2, 0x54, 0xF3, 0x97, 0x49,
+ 0xF4, 0xB0, 0xF8, 0x6D, 0xDA, 0x60, 0xE0, 0xFD, 0x57, 0xAE, 0x55, 0xA9, 0x76, 0xEA, 0x80, 0x24,
+ 0xA0, 0x04, 0x7D, 0xBE, 0xD1, 0x81, 0xD3, 0x0C, 0x95, 0xCF, 0xB7, 0xE0, 0x2D, 0x21, 0x21, 0xFF,
+ 0x97, 0x1E, 0xB3, 0xD7, 0x9F, 0xBB, 0x33, 0x0C, 0x23, 0xC5, 0x88, 0x4A, 0x33, 0xB9, 0xC9, 0x4E,
+ 0x1E, 0x65, 0x51, 0x45, 0xDE, 0xF9, 0x64, 0x7C, 0xF0, 0xBF, 0x11, 0xB4, 0x93, 0x8D, 0x5D, 0xC6,
+ 0xAB, 0x37, 0x9E, 0xE9, 0x39, 0xC1, 0xC8, 0xDB, 0xB9, 0xFE, 0x45, 0xCE, 0x7B, 0xDD, 0x72, 0xD9,
+ 0x6F, 0x68, 0x13, 0xC0, 0x4B, 0xBA, 0x00, 0xF4, 0x1E, 0x89, 0x71, 0x91, 0x26, 0xA6, 0x46, 0x12,
+ 0xDF, 0x29, 0x6B, 0xC2, 0x5A, 0x53, 0xAF, 0xB9, 0x5B, 0xFD, 0x13, 0x9F, 0xD1, 0x8A, 0x7C, 0xB5,
+ 0x04, 0xFD, 0x69, 0xEA, 0x23, 0xB4, 0x6D, 0x16, 0x21, 0x98, 0x54, 0xB4, 0xDF, 0xE6, 0xAB, 0x93,
+ 0x36, 0xB6, 0xD2, 0x43, 0xCF, 0x2B, 0x98, 0x1D, 0x45, 0xC9, 0xBB, 0x20, 0x42, 0xB1, 0x9D, 0x1D
+ };
+
+ }
+
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, BootConfigRsaPublicModulus, util::size(BootConfigRsaPublicModulus));
+ 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(initial_tsc_value >> 0);
+ const u32 hi = static_cast(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));
+ }
+
}
\ No newline at end of file
diff --git a/exosphere2/program/source/boot/secmon_boot_functions.hpp b/exosphere2/program/source/boot/secmon_boot_functions.hpp
index 5ec201add..83ac091db 100644
--- a/exosphere2/program/source/boot/secmon_boot_functions.hpp
+++ b/exosphere2/program/source/boot/secmon_boot_functions.hpp
@@ -20,4 +20,11 @@ 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);
+
}
\ No newline at end of file
diff --git a/exosphere2/program/source/boot/secmon_boot_rsa.cpp b/exosphere2/program/source/boot/secmon_boot_rsa.cpp
new file mode 100644
index 000000000..344196c05
--- /dev/null
+++ b/exosphere2/program/source/boot/secmon_boot_rsa.cpp
@@ -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 .
+ */
+#include
+#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(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(++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(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(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(msg), msg_size);
+ hw::DataSynchronizationBarrierInnerShareable();
+
+ /* Calculate the hash. */
+ se::Sha256Hash calc_hash;
+ se::CalculateSha256(std::addressof(calc_hash), reinterpret_cast(msg), msg_size);
+
+ /* Verify the result. */
+ return crypto::IsSameBytes(std::addressof(calc_hash), hash, sizeof(calc_hash));
+ }
+
+}
diff --git a/exosphere2/program/source/boot/secmon_main.cpp b/exosphere2/program/source/boot/secmon_main.cpp
index 9818f7ef7..93b9f9c93 100644
--- a/exosphere2/program/source/boot/secmon_main.cpp
+++ b/exosphere2/program/source/boot/secmon_main.cpp
@@ -26,7 +26,7 @@ namespace ams::secmon {
/* Set library register addresses. */
/* actmon::SetRegisterAddress(MemoryRegionVirtualDeviceActivityMonitor.GetAddress()); */
clkrst::SetRegisterAddress(MemoryRegionVirtualDeviceClkRst.GetAddress());
- /* flowctrl::SetRegisterAddress(); */
+ flow::SetRegisterAddress(MemoryRegionVirtualDeviceFlowController.GetAddress());
fuse::SetRegisterAddress(MemoryRegionVirtualDeviceFuses.GetAddress());
gic::SetRegisterAddress(MemoryRegionVirtualDeviceGicDistributor.GetAddress(), MemoryRegionVirtualDeviceGicCpuInterface.GetAddress());
i2c::SetRegisterAddress(i2c::Port_1, MemoryRegionVirtualDeviceI2c1.GetAddress());
@@ -69,6 +69,26 @@ namespace ams::secmon {
/* Initialize the random cache. */
secmon::smc::FillRandomCache();
}
+
+ /* 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(1) << 55) - 1;
+
+ secmon::boot::EnableTsc(bc.data.GetInitialTscValue() & TscMask);
+ }
}
}
\ No newline at end of file
diff --git a/libraries/libexosphere/include/exosphere.hpp b/libraries/libexosphere/include/exosphere.hpp
index c92a382d9..b320a52e5 100644
--- a/libraries/libexosphere/include/exosphere.hpp
+++ b/libraries/libexosphere/include/exosphere.hpp
@@ -21,6 +21,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/libraries/libexosphere/include/exosphere/br.hpp b/libraries/libexosphere/include/exosphere/br.hpp
new file mode 100644
index 000000000..089713a08
--- /dev/null
+++ b/libraries/libexosphere/include/exosphere/br.hpp
@@ -0,0 +1,19 @@
+/*
+ * 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 .
+ */
+#pragma once
+#include
+
+#include
diff --git a/libraries/libexosphere/include/exosphere/br/br_types.hpp b/libraries/libexosphere/include/exosphere/br/br_types.hpp
new file mode 100644
index 000000000..382010755
--- /dev/null
+++ b/libraries/libexosphere/include/exosphere/br/br_types.hpp
@@ -0,0 +1,30 @@
+/*
+ * 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 .
+ */
+#pragma once
+#include
+
+#include
+#include
+
+namespace ams::br {
+
+ struct BootEcid {
+ u32 ecid[4];
+ };
+ static_assert(util::is_pod::value);
+ static_assert(sizeof(BootEcid) == 0x10);
+
+}
diff --git a/libraries/libexosphere/include/exosphere/br/impl/br_erista_types.hpp b/libraries/libexosphere/include/exosphere/br/impl/br_erista_types.hpp
new file mode 100644
index 000000000..ee26f5b9e
--- /dev/null
+++ b/libraries/libexosphere/include/exosphere/br/impl/br_erista_types.hpp
@@ -0,0 +1,21 @@
+/*
+ * 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 .
+ */
+#pragma once
+#include
+
+namespace ams::br::erista {
+
+}
diff --git a/libraries/libexosphere/include/exosphere/br/impl/br_mariko_types.hpp b/libraries/libexosphere/include/exosphere/br/impl/br_mariko_types.hpp
new file mode 100644
index 000000000..8210479c2
--- /dev/null
+++ b/libraries/libexosphere/include/exosphere/br/impl/br_mariko_types.hpp
@@ -0,0 +1,21 @@
+/*
+ * 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 .
+ */
+#pragma once
+#include
+
+namespace ams::br::mariko {
+
+}
diff --git a/libraries/libexosphere/include/exosphere/fuse.hpp b/libraries/libexosphere/include/exosphere/fuse.hpp
index 3df44b8a3..55efdb334 100644
--- a/libraries/libexosphere/include/exosphere/fuse.hpp
+++ b/libraries/libexosphere/include/exosphere/fuse.hpp
@@ -15,6 +15,7 @@
*/
#pragma once
#include
+#include
#include
namespace ams::fuse {
@@ -45,5 +46,6 @@ namespace ams::fuse {
HardwareType GetHardwareType();
HardwareState GetHardwareState();
pmic::Regulator GetRegulator();
+ void GetEcid(br::BootEcid *out);
}
\ No newline at end of file
diff --git a/libraries/libexosphere/include/exosphere/pkg1.hpp b/libraries/libexosphere/include/exosphere/pkg1.hpp
index d7dbad6af..90a61cb17 100644
--- a/libraries/libexosphere/include/exosphere/pkg1.hpp
+++ b/libraries/libexosphere/include/exosphere/pkg1.hpp
@@ -20,3 +20,4 @@
#include
#include
#include
+#include
diff --git a/libraries/libexosphere/include/exosphere/pkg1/pkg1_api.hpp b/libraries/libexosphere/include/exosphere/pkg1/pkg1_api.hpp
new file mode 100644
index 000000000..632a122ac
--- /dev/null
+++ b/libraries/libexosphere/include/exosphere/pkg1/pkg1_api.hpp
@@ -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 .
+ */
+#pragma once
+#include
+
+namespace ams::pkg1 {
+
+ bool IsProduction();
+ bool IsProductionForVersionCheck();
+ bool IsProductionForPublicKey();
+
+}
diff --git a/libraries/libexosphere/include/exosphere/pkg1/pkg1_boot_config.hpp b/libraries/libexosphere/include/exosphere/pkg1/pkg1_boot_config.hpp
index da73f0112..8cef0c823 100644
--- a/libraries/libexosphere/include/exosphere/pkg1/pkg1_boot_config.hpp
+++ b/libraries/libexosphere/include/exosphere/pkg1/pkg1_boot_config.hpp
@@ -90,9 +90,13 @@ namespace ams::pkg1 {
return static_cast(this->flags0[3]);
}
- bool IsTscInitialValueValid() const {
+ constexpr bool IsInitialTscValueValid() const {
return (this->flags0[4] & (1 << 0)) != 0;
}
+
+ constexpr u64 GetInitialTscValue() const {
+ return this->IsInitialTscValueValid() ? this->initial_tsc_value : 0;
+ }
};
static_assert(util::is_pod::value);
static_assert(sizeof(BootConfigData) == 0x200);
diff --git a/libraries/libexosphere/include/exosphere/se.hpp b/libraries/libexosphere/include/exosphere/se.hpp
index ad9abd632..c46693815 100644
--- a/libraries/libexosphere/include/exosphere/se.hpp
+++ b/libraries/libexosphere/include/exosphere/se.hpp
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/libraries/libexosphere/include/exosphere/se/se_hash.hpp b/libraries/libexosphere/include/exosphere/se/se_hash.hpp
new file mode 100644
index 000000000..934ced609
--- /dev/null
+++ b/libraries/libexosphere/include/exosphere/se/se_hash.hpp
@@ -0,0 +1,30 @@
+/*
+ * 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 .
+ */
+#pragma once
+#include
+
+namespace ams::se {
+
+ constexpr inline int Sha256HashSize = crypto::Sha256Generator::HashSize;
+
+ union Sha256Hash {
+ u8 bytes[Sha256HashSize / sizeof( u8)];
+ u32 words[Sha256HashSize / sizeof(u32)];
+ };
+
+ void CalculateSha256(Sha256Hash *dst, const void *src, size_t src_size);
+
+}
diff --git a/libraries/libexosphere/include/exosphere/se/se_rsa.hpp b/libraries/libexosphere/include/exosphere/se/se_rsa.hpp
index e16b99c66..e632f67a9 100644
--- a/libraries/libexosphere/include/exosphere/se/se_rsa.hpp
+++ b/libraries/libexosphere/include/exosphere/se/se_rsa.hpp
@@ -26,4 +26,6 @@ namespace ams::se {
void SetRsaKey(int slot, const void *mod, size_t mod_size, const void *exp, size_t exp_size);
+ void ModularExponentiate(void *dst, size_t dst_size, int slot, const void *src, size_t src_size);
+
}
diff --git a/libraries/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp b/libraries/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp
index 7f094a14b..bf8515650 100644
--- a/libraries/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp
+++ b/libraries/libexosphere/include/exosphere/secmon/secmon_configuration_context.arch.arm64.hpp
@@ -70,6 +70,10 @@ namespace ams::secmon {
GetConfigurationContext().secmon_cfg.key_generation = generation;
}
+ ALWAYS_INLINE pkg1::BootConfig *GetBootConfigStorage() {
+ return std::addressof(GetConfigurationContext().boot_config);
+ }
+
}
ALWAYS_INLINE const ConfigurationContext &GetConfigurationContext() {
diff --git a/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp b/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp
index c40368a3c..1e25108c5 100644
--- a/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp
+++ b/libraries/libexosphere/include/exosphere/secmon/secmon_memory_layout.hpp
@@ -271,7 +271,9 @@ namespace ams::secmon {
static_assert(MemoryRegionVirtual.Contains(MemoryRegionVirtualTzramL2L3PageTable));
static_assert(MemoryRegionPhysicalTzramNonVolatile.Contains(MemoryRegionPhysicalTzramL2L3PageTable));
- constexpr inline const MemoryRegion MemoryRegionPhysicalTzramFullProgramImage = MemoryRegion(0x7C010800, 0xD800);
- constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCodeImage = MemoryRegion(0x40032000, 0xC000);
+ constexpr inline const MemoryRegion MemoryRegionPhysicalTzramFullProgramImage = MemoryRegion(UINT64_C(0x7C010800), 0xD800);
+ constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCodeImage = MemoryRegion(UINT64_C(0x40032000), 0xC000);
-}
\ No newline at end of file
+ constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootConfig = MemoryRegion(UINT64_C(0x4003F800), 0x400);
+
+}
diff --git a/libraries/libexosphere/include/exosphere/tegra/tegra_sysctr0.hpp b/libraries/libexosphere/include/exosphere/tegra/tegra_sysctr0.hpp
index a191641f9..d7e7fd497 100644
--- a/libraries/libexosphere/include/exosphere/tegra/tegra_sysctr0.hpp
+++ b/libraries/libexosphere/include/exosphere/tegra/tegra_sysctr0.hpp
@@ -16,6 +16,9 @@
#pragma once
#include
+#define SYSCTR0_CNTCR (0x00C)
+#define SYSCTR0_CNTCV0 (0x008)
+#define SYSCTR0_CNTCV1 (0x00C)
#define SYSCTR0_CNTFID0 (0x020)
#define SYSCTR0_CNTFID1 (0x024)
@@ -33,4 +36,18 @@
#define SYSCTR0_COUNTERID10 (0xFF8)
#define SYSCTR0_COUNTERID11 (0xFFC)
-#define SYSCTR0_COUNTERID(n) SYSCTR0_COUNTERID##n
\ No newline at end of file
+#define SYSCTR0_COUNTERID(n) SYSCTR0_COUNTERID##n
+
+#define SYSCTR0_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (SYSCTR0, NAME)
+#define SYSCTR0_REG_BITS_VALUE(NAME, VALUE) REG_NAMED_BITS_VALUE (SYSCTR0, NAME, VALUE)
+#define SYSCTR0_REG_BITS_ENUM(NAME, ENUM) REG_NAMED_BITS_ENUM (SYSCTR0, NAME, ENUM)
+#define SYSCTR0_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(SYSCTR0, NAME, __COND__, TRUE_ENUM, FALSE_ENUM)
+
+#define DEFINE_SYSCTR0_REG(NAME, __OFFSET__, __WIDTH__) REG_DEFINE_NAMED_REG (SYSCTR0, NAME, __OFFSET__, __WIDTH__)
+#define DEFINE_SYSCTR0_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE) REG_DEFINE_NAMED_BIT_ENUM (SYSCTR0, NAME, __OFFSET__, ZERO, ONE)
+#define DEFINE_SYSCTR0_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE) REG_DEFINE_NAMED_TWO_BIT_ENUM (SYSCTR0, NAME, __OFFSET__, ZERO, ONE, TWO, THREE)
+#define DEFINE_SYSCTR0_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN) REG_DEFINE_NAMED_THREE_BIT_ENUM(SYSCTR0, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN)
+#define DEFINE_SYSCTR0_REG_FOUR_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (SYSCTR0, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN)
+
+DEFINE_SYSCTR0_REG_BIT_ENUM(CNTCR_EN, 0, DISABLE, ENABLE);
+DEFINE_SYSCTR0_REG_BIT_ENUM(CNTCR_HDBG, 1, DISABLE, ENABLE);
\ No newline at end of file
diff --git a/libraries/libexosphere/source/fuse/fuse_api.cpp b/libraries/libexosphere/source/fuse/fuse_api.cpp
index 73f48494d..32d491393 100644
--- a/libraries/libexosphere/source/fuse/fuse_api.cpp
+++ b/libraries/libexosphere/source/fuse/fuse_api.cpp
@@ -118,4 +118,28 @@ namespace ams::fuse {
return pmic::Regulator_Erista_Max77621;
}
-}
\ No newline at end of file
+ void GetEcid(br::BootEcid *out) {
+ /* Get the registers. */
+ const volatile auto &chip = GetChipRegisters();
+
+ /* Read the ecid components. */
+ const u32 vendor = reg::Read(chip.FUSE_OPT_VENDOR_CODE);
+ const u32 fab = reg::Read(chip.FUSE_OPT_FAB_CODE);
+ const u32 lot0 = reg::Read(chip.FUSE_OPT_LOT_CODE_0);
+ const u32 lot1 = reg::Read(chip.FUSE_OPT_LOT_CODE_1);
+ const u32 wafer = reg::Read(chip.FUSE_OPT_WAFER_ID);
+ const u32 x_coord = reg::Read(chip.FUSE_OPT_X_COORDINATE);
+ const u32 y_coord = reg::Read(chip.FUSE_OPT_Y_COORDINATE);
+ const u32 reserved = reg::Read(chip.FUSE_OPT_OPS_RESERVED);
+
+ /* Clear the output. */
+ util::ClearMemory(out, sizeof(*out));
+
+ /* Copy the component bits. */
+ out->ecid[0] = static_cast((lot1 << 30) | (wafer << 24) | (x_coord << 15) | (y_coord << 6) | (reserved));
+ out->ecid[1] = static_cast((lot0 << 26) | (lot1 >> 2));
+ out->ecid[2] = static_cast((fab << 26) | (lot0 >> 6));
+ out->ecid[3] = static_cast(vendor);
+ }
+
+}
diff --git a/libraries/libexosphere/source/pkg1/pkg1_api.cpp b/libraries/libexosphere/source/pkg1/pkg1_api.cpp
new file mode 100644
index 000000000..035b4d087
--- /dev/null
+++ b/libraries/libexosphere/source/pkg1/pkg1_api.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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 .
+ */
+#include
+
+namespace ams::pkg1 {
+
+ namespace {
+
+ bool IsProductionImpl() {
+ return fuse::GetHardwareState() != fuse::HardwareState_Development;
+ }
+
+ }
+
+ bool IsProduction() {
+ return IsProductionImpl();
+ }
+
+ bool IsProductionForVersionCheck() {
+ return IsProductionImpl();
+ }
+
+ bool IsProductionForPublicKey() {
+ return IsProductionImpl();
+ }
+
+}
diff --git a/libraries/libexosphere/source/se/se_hash.cpp b/libraries/libexosphere/source/se/se_hash.cpp
new file mode 100644
index 000000000..2ef38deb2
--- /dev/null
+++ b/libraries/libexosphere/source/se/se_hash.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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 .
+ */
+#include
+#include "se_execute.hpp"
+
+namespace ams::se {
+
+ namespace {
+
+ void SetMessageSize(volatile SecurityEngineRegisters *SE, size_t src_size) {
+ /* Set the message size. */
+ reg::Write(SE->SE_SHA_MSG_LENGTH[0], src_size * BITSIZEOF(u8));
+ reg::Write(SE->SE_SHA_MSG_LENGTH[1], 0);
+ reg::Write(SE->SE_SHA_MSG_LENGTH[2], 0);
+ reg::Write(SE->SE_SHA_MSG_LENGTH[3], 0);
+
+ /* Set the message remaining size. */
+ reg::Write(SE->SE_SHA_MSG_LEFT[0], src_size * BITSIZEOF(u8));
+ reg::Write(SE->SE_SHA_MSG_LEFT[1], 0);
+ reg::Write(SE->SE_SHA_MSG_LEFT[2], 0);
+ reg::Write(SE->SE_SHA_MSG_LEFT[3], 0);
+ }
+
+ void GetHashResult(volatile SecurityEngineRegisters *SE, void *dst, size_t dst_size) {
+ /* Copy out the words. */
+ const int num_words = dst_size / sizeof(u32);
+ for (int i = 0; i < num_words; ++i) {
+ const u32 word = reg::Read(SE->SE_HASH_RESULT[i]);
+ util::StoreBigEndian(static_cast(dst) + i, word);
+ }
+ }
+
+ }
+
+ void CalculateSha256(Sha256Hash *dst, const void *src, size_t src_size) {
+ /* Get the engine. */
+ auto *SE = GetRegisters();
+
+ /* Configure the engine to perform SHA256 "encryption". */
+ reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM(CONFIG_ENC_MODE, SHA256),
+ SE_REG_BITS_ENUM(CONFIG_DEC_MODE, AESMODE_KEY128),
+ SE_REG_BITS_ENUM(CONFIG_ENC_ALG, SHA),
+ SE_REG_BITS_ENUM(CONFIG_DEC_ALG, NOP),
+ SE_REG_BITS_ENUM(CONFIG_DST, HASH_REG));
+
+ /* Begin a hardware hash operation. */
+ reg::Write(SE->SE_SHA_CONFIG, SE_REG_BITS_VALUE(SHA_CONFIG_HW_INIT_HASH, 1));
+
+ /* Set the message size. */
+ SetMessageSize(SE, src_size);
+
+ /* Execute the operation. */
+ ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, src, src_size);
+
+ /* Get the result. */
+ GetHashResult(SE, dst, sizeof(*dst));
+ }
+
+}
diff --git a/libraries/libexosphere/source/se/se_registers.hpp b/libraries/libexosphere/source/se/se_registers.hpp
index d76e0571c..2a5e70352 100644
--- a/libraries/libexosphere/source/se/se_registers.hpp
+++ b/libraries/libexosphere/source/se/se_registers.hpp
@@ -133,32 +133,12 @@ namespace ams::se {
DEFINE_SE_REG_BIT_ENUM_WITH_SW_CLEAR(INT_STATUS_ERR_STAT, 16);
/* SE_CONFIG */
- DEFINE_SE_REG(CONFIG_DST, 2, 3);
- DEFINE_SE_REG(CONFIG_DEC_ALG, 8, 4);
- DEFINE_SE_REG(CONFIG_ENC_ALG, 12, 4);
DEFINE_SE_REG(CONFIG_DEC_MODE, 16, 8);
DEFINE_SE_REG(CONFIG_ENC_MODE, 24, 8);
- enum SE_CONFIG_DST {
- SE_CONFIG_DST_MEMORY = 0,
- SE_CONFIG_DST_HASH_REG = 1,
- SE_CONFIG_DST_KEYTABLE = 2,
- SE_CONFIG_DST_SRK = 3,
- SE_CONFIG_DST_RSA_REG = 4,
- };
-
- enum SE_CONFIG_DEC_ALG {
- SE_CONFIG_DEC_ALG_NOP = 0,
- SE_CONFIG_DEC_ALG_AES_DEC = 1,
- };
-
- enum SE_CONFIG_ENC_ALG {
- SE_CONFIG_ENC_ALG_NOP = 0,
- SE_CONFIG_ENC_ALG_AES_ENC = 1,
- SE_CONFIG_ENC_ALG_RNG = 2,
- SE_CONFIG_ENC_ALG_SHA = 3,
- SE_CONFIG_ENC_ALG_RSA = 4,
- };
+ DEFINE_SE_REG_THREE_BIT_ENUM(CONFIG_DST, 2, MEMORY, HASH_REG, KEYTABLE, SRK, RSA_REG, RESERVED5, RESERVED6, RESERVED7);
+ DEFINE_SE_REG_FOUR_BIT_ENUM(CONFIG_DEC_ALG, 8, NOP, AES_DEC, RESERVED2, RESERVED3, RESERVED4, RESERVED5, RESERVED6, RESERVED7, RESERVED8, RESERVED9, RESERVED10, RESERVED11, RESERVED12, RESERVED13, RESERVED14, RESERVED15);
+ DEFINE_SE_REG_FOUR_BIT_ENUM(CONFIG_ENC_ALG, 12, NOP, AES_ENC, RNG, SHA, RSA, RESERVED5, RESERVED6, RESERVED7, RESERVED8, RESERVED9, RESERVED10, RESERVED11, RESERVED12, RESERVED13, RESERVED14, RESERVED15);
enum SE_CONFIG_DEC_MODE {
SE_CONFIG_DEC_MODE_AESMODE_KEY128 = 0,
@@ -171,13 +151,16 @@ namespace ams::se {
SE_CONFIG_ENC_MODE_AESMODE_KEY192 = 1,
SE_CONFIG_ENC_MODE_AESMODE_KEY256 = 2,
- SE_CONFIG_ENC_MODE_AESMODE_SHA1 = 1,
- SE_CONFIG_ENC_MODE_AESMODE_SHA224 = 4,
- SE_CONFIG_ENC_MODE_AESMODE_SHA256 = 5,
- SE_CONFIG_ENC_MODE_AESMODE_SHA384 = 6,
- SE_CONFIG_ENC_MODE_AESMODE_SHA512 = 7,
+ SE_CONFIG_ENC_MODE_SHA1 = 1,
+ SE_CONFIG_ENC_MODE_SHA224 = 4,
+ SE_CONFIG_ENC_MODE_SHA256 = 5,
+ SE_CONFIG_ENC_MODE_SHA384 = 6,
+ SE_CONFIG_ENC_MODE_SHA512 = 7,
};
+ /* SE_SHA_CONFIG */
+ DEFINE_SE_REG(SHA_CONFIG_HW_INIT_HASH, 0, 1);
+
/* SE_CRYPTO_KEYTABLE_ADDR */
DEFINE_SE_REG(CRYPTO_KEYTABLE_ADDR_KEYIV_WORD, 0, 4);
@@ -208,6 +191,9 @@ namespace ams::se {
DEFINE_SE_REG(CRYPTO_KEYTABLE_ADDR_KEYIV_KEY_SLOT, 4, 4);
+ /* SE_RSA_CONFIG */
+ DEFINE_SE_REG(RSA_CONFIG_KEY_SLOT, 24, 1);
+
/* SE_RSA_KEYTABLE_ADDR */
DEFINE_SE_REG(RSA_KEYTABLE_ADDR_WORD_ADDR, 0, 6);
DEFINE_SE_REG_BIT_ENUM(RSA_KEYTABLE_ADDR_EXPMOD_SEL, 6, EXPONENT, MODULUS);
diff --git a/libraries/libexosphere/source/se/se_rsa.cpp b/libraries/libexosphere/source/se/se_rsa.cpp
index d39a040dc..99ec5e90a 100644
--- a/libraries/libexosphere/source/se/se_rsa.cpp
+++ b/libraries/libexosphere/source/se/se_rsa.cpp
@@ -27,10 +27,7 @@ namespace ams::se {
constinit RsaKeyInfo g_rsa_key_infos[RsaKeySlotCount] = {};
- void ClearRsaKeySlot(int slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL expmod) {
- /* Get the engine. */
- auto *SE = GetRegisters();
-
+ void ClearRsaKeySlot(volatile SecurityEngineRegisters *SE, int slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL expmod) {
constexpr int NumWords = se::RsaSize / sizeof(u32);
for (int i = 0; i < NumWords; ++i) {
/* Select the keyslot word. */
@@ -44,10 +41,7 @@ namespace ams::se {
}
}
- void SetRsaKey(int slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL expmod, const void *key, size_t key_size) {
- /* Get the engine. */
- auto *SE = GetRegisters();
-
+ void SetRsaKey(volatile SecurityEngineRegisters *SE, int slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL expmod, const void *key, size_t key_size) {
const int num_words = key_size / sizeof(u32);
for (int i = 0; i < num_words; ++i) {
/* Select the keyslot word. */
@@ -64,6 +58,15 @@ namespace ams::se {
}
}
+ void GetRsaResult(volatile SecurityEngineRegisters *SE, void *dst, size_t size) {
+ /* Copy out the words. */
+ const int num_words = size / sizeof(u32);
+ for (int i = 0; i < num_words; ++i) {
+ const u32 word = reg::Read(SE->SE_RSA_OUTPUT[i]);
+ util::StoreBigEndian(static_cast(dst) + num_words - 1 - i, word);
+ }
+ }
+
}
void ClearRsaKeySlot(int slot) {
@@ -73,11 +76,14 @@ namespace ams::se {
/* Clear the info. */
g_rsa_key_infos[slot] = {};
+ /* Get the engine. */
+ auto *SE = GetRegisters();
+
/* Clear the modulus. */
- ClearRsaKeySlot(slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_MODULUS);
+ ClearRsaKeySlot(SE, slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_MODULUS);
/* Clear the exponent. */
- ClearRsaKeySlot(slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_EXPONENT);
+ ClearRsaKeySlot(SE, slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_EXPONENT);
}
void LockRsaKeySlot(int slot, u32 flags) {
@@ -117,9 +123,55 @@ namespace ams::se {
info.modulus_size_val = (mod_size / 64) - 1;
info.exponent_size_val = (exp_size / 4);
+ /* Get the engine. */
+ auto *SE = GetRegisters();
+
/* Set the modulus and exponent. */
- SetRsaKey(slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_MODULUS, mod, mod_size);
- SetRsaKey(slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_EXPONENT, exp, exp_size);
+ SetRsaKey(SE, slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_MODULUS, mod, mod_size);
+ SetRsaKey(SE, slot, SE_RSA_KEYTABLE_ADDR_EXPMOD_SEL_EXPONENT, exp, exp_size);
+ }
+
+ void ModularExponentiate(void *dst, size_t dst_size, int slot, const void *src, size_t src_size) {
+ /* Validate the slot and sizes. */
+ AMS_ABORT_UNLESS(0 <= slot && slot < RsaKeySlotCount);
+ AMS_ABORT_UNLESS(src_size <= RsaSize);
+ AMS_ABORT_UNLESS(dst_size <= RsaSize);
+
+ /* Get the engine. */
+ auto *SE = GetRegisters();
+
+ /* Create a work buffer. */
+ u8 work[RsaSize];
+ util::ClearMemory(work, sizeof(work));
+
+ /* Copy the input into the work buffer (reversing endianness). */
+ const u8 *src_u8 = static_cast(src);
+ for (size_t i = 0; i < src_size; ++i) {
+ work[src_size - 1 - i] = src_u8[i];
+ }
+
+ /* Flush the work buffer to ensure the SE sees correct results. */
+ hw::FlushDataCache(work, sizeof(work));
+ hw::DataSynchronizationBarrierInnerShareable();
+
+ /* Configure the engine to perform RSA encryption. */
+ reg::Write(SE->SE_CONFIG, SE_REG_BITS_ENUM(CONFIG_ENC_MODE, AESMODE_KEY128),
+ SE_REG_BITS_ENUM(CONFIG_DEC_MODE, AESMODE_KEY128),
+ SE_REG_BITS_ENUM(CONFIG_ENC_ALG, RSA),
+ SE_REG_BITS_ENUM(CONFIG_DEC_ALG, NOP),
+ SE_REG_BITS_ENUM(CONFIG_DST, RSA_REG));
+
+ /* Configure the engine to use the keyslot and correct modulus/exp sizes. */
+ const auto &info = g_rsa_key_infos[slot];
+ reg::Write(SE->SE_RSA_CONFIG, SE_REG_BITS_VALUE(RSA_CONFIG_KEY_SLOT, slot));
+ reg::Write(SE->SE_RSA_KEY_SIZE, info.modulus_size_val);
+ reg::Write(SE->SE_RSA_EXP_SIZE, info.exponent_size_val);
+
+ /* Execute the operation. */
+ ExecuteOperation(SE, SE_OPERATION_OP_START, nullptr, 0, work, src_size);
+
+ /* Copy out the result. */
+ GetRsaResult(SE, dst, dst_size);
}
}