mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-06-03 08:08:39 -04:00
kern: add (and use) generic KSystemControlBase
This commit is contained in:
parent
1f8bf41f0b
commit
273f4a87ae
23 changed files with 704 additions and 988 deletions
|
@ -1130,7 +1130,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||
size_t cur_size;
|
||||
{
|
||||
/* Get the current contiguous range. */
|
||||
KPageTableBase::MemoryRange contig_range = {};
|
||||
KPageTableBase::MemoryRange contig_range = { .address = Null<KPhysicalAddress>, .size = 0 };
|
||||
R_TRY(page_table->OpenMemoryRangeForMapDeviceAddressSpace(std::addressof(contig_range), process_address + mapped_size, size - mapped_size, ConvertToKMemoryPermission(device_perm), is_aligned));
|
||||
|
||||
/* Ensure we close the range when we're done. */
|
||||
|
@ -1288,7 +1288,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||
MESOSPHERE_ASSERT(((device_address + size - 1) & ~DeviceVirtualAddressMask) == 0);
|
||||
|
||||
/* We need to traverse the ranges that make up our mapping, to make sure they're all good. Start by getting a contiguous range. */
|
||||
KPageTableBase::MemoryRange contig_range = {};
|
||||
KPageTableBase::MemoryRange contig_range = { .address = Null<KPhysicalAddress>, .size = 0 };
|
||||
if (R_FAILED(page_table->OpenMemoryRangeForUnmapDeviceAddressSpace(std::addressof(contig_range), process_address, size))) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||
|
||||
void PowerOnCpu(int core_id, KPhysicalAddress entry_phys_addr, u64 context_id) {
|
||||
/* Request the secure monitor power on the core. */
|
||||
smc::CpuOn(cpu::MultiprocessorAffinityRegisterAccessor().GetCpuOnArgument() | core_id, GetInteger(entry_phys_addr), context_id);
|
||||
::ams::kern::arch::arm64::smc::CpuOn<smc::SmcId_Supervisor, true>(cpu::MultiprocessorAffinityRegisterAccessor().GetCpuOnArgument() | core_id, GetInteger(entry_phys_addr), context_id);
|
||||
}
|
||||
|
||||
void WaitOtherCpuPowerOff() {
|
||||
|
|
|
@ -21,8 +21,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||
|
||||
namespace {
|
||||
|
||||
constexpr uintptr_t DramPhysicalAddress = 0x80000000;
|
||||
constexpr size_t SecureAlignment = 128_KB;
|
||||
constexpr size_t SecureAlignment = 128_KB;
|
||||
|
||||
/* Global variables for panic. */
|
||||
constinit bool g_call_smc_on_panic;
|
||||
|
@ -38,22 +37,6 @@ namespace ams::kern::board::nintendo::nx {
|
|||
constinit KPhysicalAddress g_secure_region_phys_addr = Null<KPhysicalAddress>;
|
||||
constinit size_t g_secure_region_size = 0;
|
||||
|
||||
/* Global variables for randomness. */
|
||||
/* Nintendo uses std::mt19937_t for randomness. */
|
||||
/* To save space (and because mt19337_t isn't secure anyway), */
|
||||
/* We will use TinyMT. */
|
||||
constinit bool g_initialized_random_generator;
|
||||
constinit util::TinyMT g_random_generator{util::ConstantInitialize};
|
||||
constinit KSpinLock g_random_lock;
|
||||
|
||||
ALWAYS_INLINE size_t GetRealMemorySizeForInit() {
|
||||
/* TODO: Move this into a header for the MC in general. */
|
||||
constexpr u32 MemoryControllerConfigurationRegister = 0x70019050;
|
||||
u32 config_value;
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(smc::init::ReadWriteRegister(&config_value, MemoryControllerConfigurationRegister, 0, 0));
|
||||
return static_cast<size_t>(config_value & 0x3FFF) << 20;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE util::BitPack32 GetKernelConfigurationForInit() {
|
||||
u64 value = 0;
|
||||
smc::init::GetConfig(&value, 1, smc::ConfigItem::KernelConfiguration);
|
||||
|
@ -86,7 +69,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||
|
||||
ALWAYS_INLINE u64 GenerateRandomU64ForInit() {
|
||||
u64 value;
|
||||
smc::init::GenerateRandomBytes(&value, sizeof(value));
|
||||
smc::init::GenerateRandomBytes(std::addressof(value), sizeof(value));
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -96,27 +79,6 @@ namespace ams::kern::board::nintendo::nx {
|
|||
return value;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE u64 GenerateRandomU64FromGenerator() {
|
||||
return g_random_generator.GenerateRandomU64();
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
ALWAYS_INLINE u64 GenerateUniformRange(u64 min, u64 max, F f) {
|
||||
/* Handle the case where the difference is too large to represent. */
|
||||
if (max == std::numeric_limits<u64>::max() && min == std::numeric_limits<u64>::min()) {
|
||||
return f();
|
||||
}
|
||||
|
||||
/* Iterate until we get a value in range. */
|
||||
const u64 range_size = ((max + 1) - min);
|
||||
const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size;
|
||||
while (true) {
|
||||
if (const u64 rnd = f(); rnd < effective_max) {
|
||||
return min + (rnd % range_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYS_INLINE u64 GetConfigU64(smc::ConfigItem which) {
|
||||
u64 value;
|
||||
smc::GetConfig(&value, 1, which);
|
||||
|
@ -324,6 +286,14 @@ namespace ams::kern::board::nintendo::nx {
|
|||
}
|
||||
|
||||
/* Initialization. */
|
||||
size_t KSystemControl::Init::GetRealMemorySize() {
|
||||
/* TODO: Move this into a header for the MC in general. */
|
||||
constexpr u32 MemoryControllerConfigurationRegister = 0x70019050;
|
||||
u32 config_value;
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(smc::init::ReadWriteRegister(&config_value, MemoryControllerConfigurationRegister, 0, 0));
|
||||
return static_cast<size_t>(config_value & 0x3FFF) << 20;
|
||||
}
|
||||
|
||||
size_t KSystemControl::Init::GetIntendedMemorySize() {
|
||||
switch (GetKernelConfigurationForInit().Get<smc::KernelConfiguration::MemorySize>()) {
|
||||
case smc::MemorySize_4GB:
|
||||
|
@ -336,23 +306,6 @@ namespace ams::kern::board::nintendo::nx {
|
|||
}
|
||||
}
|
||||
|
||||
KPhysicalAddress KSystemControl::Init::GetKernelPhysicalBaseAddress(uintptr_t base_address) {
|
||||
const size_t real_dram_size = GetRealMemorySizeForInit();
|
||||
const size_t intended_dram_size = KSystemControl::Init::GetIntendedMemorySize();
|
||||
if (intended_dram_size * 2 < real_dram_size) {
|
||||
return base_address;
|
||||
} else {
|
||||
return base_address + ((real_dram_size - intended_dram_size) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
void KSystemControl::Init::GetInitialProcessBinaryLayout(InitialProcessBinaryLayout *out) {
|
||||
*out = {
|
||||
.address = GetInteger(GetKernelPhysicalBaseAddress(DramPhysicalAddress)) + GetIntendedMemorySize() - KTraceBufferSize - InitialProcessBinarySizeMax,
|
||||
._08 = 0,
|
||||
};
|
||||
}
|
||||
|
||||
bool KSystemControl::Init::ShouldIncreaseThreadResourceLimit() {
|
||||
return GetKernelConfigurationForInit().Get<smc::KernelConfiguration::IncreaseThreadResourceLimit>();
|
||||
}
|
||||
|
@ -424,17 +377,17 @@ namespace ams::kern::board::nintendo::nx {
|
|||
}
|
||||
|
||||
void KSystemControl::Init::CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
|
||||
smc::init::CpuOn(core_id, entrypoint, arg);
|
||||
MESOSPHERE_INIT_ABORT_UNLESS((::ams::kern::arch::arm64::smc::CpuOn<smc::SmcId_Supervisor, false>(core_id, entrypoint, arg)) == 0);
|
||||
}
|
||||
|
||||
/* Randomness for Initialization. */
|
||||
void KSystemControl::Init::GenerateRandomBytes(void *dst, size_t size) {
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(size <= 0x38);
|
||||
smc::init::GenerateRandomBytes(dst, size);
|
||||
void KSystemControl::Init::GenerateRandom(u64 *dst, size_t count) {
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(count <= 7);
|
||||
smc::init::GenerateRandomBytes(dst, count * sizeof(u64));
|
||||
}
|
||||
|
||||
u64 KSystemControl::Init::GenerateRandomRange(u64 min, u64 max) {
|
||||
return GenerateUniformRange(min, max, GenerateRandomU64ForInit);
|
||||
return KSystemControlBase::GenerateUniformRange(min, max, GenerateRandomU64ForInit);
|
||||
}
|
||||
|
||||
/* System Initialization. */
|
||||
|
@ -443,8 +396,8 @@ namespace ams::kern::board::nintendo::nx {
|
|||
{
|
||||
u64 seed;
|
||||
smc::GenerateRandomBytes(std::addressof(seed), sizeof(seed));
|
||||
g_random_generator.Initialize(reinterpret_cast<u32*>(std::addressof(seed)), sizeof(seed) / sizeof(u32));
|
||||
g_initialized_random_generator = true;
|
||||
s_random_generator.Initialize(reinterpret_cast<const u32*>(std::addressof(seed)), sizeof(seed) / sizeof(u32));
|
||||
s_initialized_random_generator = true;
|
||||
}
|
||||
|
||||
/* Set IsDebugMode. */
|
||||
|
@ -483,25 +436,8 @@ namespace ams::kern::board::nintendo::nx {
|
|||
smc::ConfigureCarveout(0, carveout.GetAddress(), carveout.GetSize());
|
||||
}
|
||||
|
||||
/* System ResourceLimit initialization. */
|
||||
{
|
||||
/* Construct the resource limit object. */
|
||||
KResourceLimit &sys_res_limit = Kernel::GetSystemResourceLimit();
|
||||
KAutoObject::Create<KResourceLimit>(std::addressof(sys_res_limit));
|
||||
sys_res_limit.Initialize();
|
||||
|
||||
/* Set the initial limits. */
|
||||
const auto [total_memory_size, kernel_memory_size] = KMemoryLayout::GetTotalAndKernelMemorySizes();
|
||||
const auto &slab_counts = init::GetSlabResourceCounts();
|
||||
MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_PhysicalMemoryMax, total_memory_size));
|
||||
MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_ThreadCountMax, slab_counts.num_KThread));
|
||||
MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_EventCountMax, slab_counts.num_KEvent));
|
||||
MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_TransferMemoryCountMax, slab_counts.num_KTransferMemory));
|
||||
MESOSPHERE_R_ABORT_UNLESS(sys_res_limit.SetLimitValue(ams::svc::LimitableResource_SessionCountMax, slab_counts.num_KSession));
|
||||
|
||||
/* Reserve system memory. */
|
||||
MESOSPHERE_ABORT_UNLESS(sys_res_limit.Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, kernel_memory_size));
|
||||
}
|
||||
/* Initialize the system resource limit (and potentially other things). */
|
||||
KSystemControlBase::InitializePhase1(true);
|
||||
}
|
||||
|
||||
void KSystemControl::InitializePhase2() {
|
||||
|
@ -520,11 +456,8 @@ namespace ams::kern::board::nintendo::nx {
|
|||
g_secure_applet_memory_address = KMemoryLayout::GetLinearVirtualAddress(secure_applet_memory_phys_addr);
|
||||
}
|
||||
|
||||
/* Initialize KTrace. */
|
||||
if constexpr (IsKTraceEnabled) {
|
||||
const auto &ktrace = KMemoryLayout::GetKernelTraceBufferRegion();
|
||||
KTrace::Initialize(ktrace.GetAddress(), ktrace.GetSize());
|
||||
}
|
||||
/* Initialize KTrace (and potentially other init). */
|
||||
KSystemControlBase::InitializePhase2();
|
||||
}
|
||||
|
||||
u32 KSystemControl::GetCreateProcessMemoryPool() {
|
||||
|
@ -546,29 +479,29 @@ namespace ams::kern::board::nintendo::nx {
|
|||
}
|
||||
|
||||
/* Randomness. */
|
||||
void KSystemControl::GenerateRandomBytes(void *dst, size_t size) {
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(size <= 0x38);
|
||||
smc::GenerateRandomBytes(dst, size);
|
||||
void KSystemControl::GenerateRandom(u64 *dst, size_t count) {
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(count <= 7);
|
||||
smc::GenerateRandomBytes(dst, count * sizeof(u64));
|
||||
}
|
||||
|
||||
u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) {
|
||||
KScopedInterruptDisable intr_disable;
|
||||
KScopedSpinLock lk(g_random_lock);
|
||||
KScopedSpinLock lk(s_random_lock);
|
||||
|
||||
|
||||
if (AMS_LIKELY(g_initialized_random_generator)) {
|
||||
return GenerateUniformRange(min, max, GenerateRandomU64FromGenerator);
|
||||
if (AMS_LIKELY(s_initialized_random_generator)) {
|
||||
return KSystemControlBase::GenerateUniformRange(min, max, [] ALWAYS_INLINE_LAMBDA () -> u64 { return s_random_generator.GenerateRandomU64(); });
|
||||
} else {
|
||||
return GenerateUniformRange(min, max, GenerateRandomU64FromSmc);
|
||||
return KSystemControlBase::GenerateUniformRange(min, max, GenerateRandomU64FromSmc);
|
||||
}
|
||||
}
|
||||
|
||||
u64 KSystemControl::GenerateRandomU64() {
|
||||
KScopedInterruptDisable intr_disable;
|
||||
KScopedSpinLock lk(g_random_lock);
|
||||
KScopedSpinLock lk(s_random_lock);
|
||||
|
||||
if (AMS_LIKELY(g_initialized_random_generator)) {
|
||||
return GenerateRandomU64FromGenerator();
|
||||
if (AMS_LIKELY(s_initialized_random_generator)) {
|
||||
return s_random_generator.GenerateRandomU64();
|
||||
} else {
|
||||
return GenerateRandomU64FromSmc();
|
||||
}
|
||||
|
@ -672,52 +605,18 @@ namespace ams::kern::board::nintendo::nx {
|
|||
}
|
||||
|
||||
/* User access. */
|
||||
void KSystemControl::CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args) {
|
||||
/* Get the function id for the current call. */
|
||||
u64 function_id = args->r[0];
|
||||
|
||||
/* We'll need to map in pages if arguments are pointers. Prepare page groups to do so. */
|
||||
auto &page_table = GetCurrentProcess().GetPageTable();
|
||||
auto *bim = page_table.GetBlockInfoManager();
|
||||
|
||||
constexpr size_t MaxMappedRegisters = 7;
|
||||
std::array<KPageGroup, MaxMappedRegisters> page_groups = { KPageGroup(bim), KPageGroup(bim), KPageGroup(bim), KPageGroup(bim), KPageGroup(bim), KPageGroup(bim), KPageGroup(bim), };
|
||||
|
||||
for (size_t i = 0; i < MaxMappedRegisters; i++) {
|
||||
const size_t reg_id = i + 1;
|
||||
if (function_id & (1ul << (8 + reg_id))) {
|
||||
/* Create and open a new page group for the address. */
|
||||
KVirtualAddress virt_addr = args->r[reg_id];
|
||||
|
||||
if (R_SUCCEEDED(page_table.MakeAndOpenPageGroup(std::addressof(page_groups[i]), util::AlignDown(GetInteger(virt_addr), PageSize), 1, KMemoryState_None, KMemoryState_None, KMemoryPermission_UserReadWrite, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, KMemoryAttribute_None))) {
|
||||
/* Translate the virtual address to a physical address. */
|
||||
const auto it = page_groups[i].begin();
|
||||
MESOSPHERE_ASSERT(it != page_groups[i].end());
|
||||
MESOSPHERE_ASSERT(it->GetNumPages() == 1);
|
||||
|
||||
args->r[reg_id] = GetInteger(it->GetAddress()) | (GetInteger(virt_addr) & (PageSize - 1));
|
||||
} else {
|
||||
/* If we couldn't map, we should clear the address. */
|
||||
args->r[reg_id] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KSystemControl::CallSecureMonitorFromUserImpl(ams::svc::lp64::SecureMonitorArguments *args) {
|
||||
/* Invoke the secure monitor. */
|
||||
smc::CallSecureMonitorFromUser(args);
|
||||
|
||||
/* Make sure that we close any pages that we opened. */
|
||||
for (size_t i = 0; i < MaxMappedRegisters; i++) {
|
||||
page_groups[i].Close();
|
||||
}
|
||||
return smc::CallSecureMonitorFromUser(args);
|
||||
}
|
||||
|
||||
/* Secure Memory. */
|
||||
size_t KSystemControl::CalculateRequiredSecureMemorySize(size_t size, u32 pool) {
|
||||
if (pool == KMemoryManager::Pool_Applet) {
|
||||
return 0;
|
||||
} else {
|
||||
return KSystemControlBase::CalculateRequiredSecureMemorySize(size, pool);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
Result KSystemControl::AllocateSecureMemory(KVirtualAddress *out, size_t size, u32 pool) {
|
||||
|
|
|
@ -20,10 +20,6 @@ namespace ams::kern::board::nintendo::nx::smc {
|
|||
|
||||
namespace {
|
||||
|
||||
struct SecureMonitorArguments {
|
||||
u64 x[8];
|
||||
};
|
||||
|
||||
enum UserFunctionId : u32 {
|
||||
UserFunctionId_SetConfig = 0xC3000401,
|
||||
UserFunctionId_GetConfigUser = 0xC3000002,
|
||||
|
@ -45,9 +41,6 @@ namespace ams::kern::board::nintendo::nx::smc {
|
|||
};
|
||||
|
||||
enum FunctionId : u32 {
|
||||
FunctionId_CpuSuspend = 0xC4000001,
|
||||
FunctionId_CpuOff = 0x84000002,
|
||||
FunctionId_CpuOn = 0xC4000003,
|
||||
FunctionId_GetConfig = 0xC3000004,
|
||||
FunctionId_GenerateRandomBytes = 0xC3000005,
|
||||
FunctionId_Panic = 0xC3000006,
|
||||
|
@ -58,171 +51,60 @@ namespace ams::kern::board::nintendo::nx::smc {
|
|||
FunctionId_SetConfig = 0xC3000409,
|
||||
};
|
||||
|
||||
void CallPrivilegedSecureMonitorFunction(SecureMonitorArguments &args) {
|
||||
/* Load arguments into registers. */
|
||||
register u64 x0 asm("x0") = args.x[0];
|
||||
register u64 x1 asm("x1") = args.x[1];
|
||||
register u64 x2 asm("x2") = args.x[2];
|
||||
register u64 x3 asm("x3") = args.x[3];
|
||||
register u64 x4 asm("x4") = args.x[4];
|
||||
register u64 x5 asm("x5") = args.x[5];
|
||||
register u64 x6 asm("x6") = args.x[6];
|
||||
register u64 x7 asm("x7") = args.x[7];
|
||||
|
||||
/* Actually make the call. */
|
||||
{
|
||||
/* Disable interrupts while making the call. */
|
||||
KScopedInterruptDisable intr_disable;
|
||||
|
||||
{
|
||||
/* Backup the current thread pointer. */
|
||||
const uintptr_t current_thread_pointer_value = cpu::GetCurrentThreadPointerValue();
|
||||
|
||||
__asm__ __volatile__("smc #1"
|
||||
: "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7)
|
||||
:
|
||||
: "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory"
|
||||
);
|
||||
|
||||
/* Restore the current thread pointer into X18. */
|
||||
cpu::SetCurrentThreadPointerValue(current_thread_pointer_value);
|
||||
|
||||
/* Store arguments to output. */
|
||||
args.x[0] = x0;
|
||||
args.x[1] = x1;
|
||||
args.x[2] = x2;
|
||||
args.x[3] = x3;
|
||||
args.x[4] = x4;
|
||||
args.x[5] = x5;
|
||||
args.x[6] = x6;
|
||||
args.x[7] = x7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CallUserSecureMonitorFunction(ams::svc::lp64::SecureMonitorArguments *args) {
|
||||
/* Load arguments into registers. */
|
||||
register u64 x0 asm("x0") = args->r[0];
|
||||
register u64 x1 asm("x1") = args->r[1];
|
||||
register u64 x2 asm("x2") = args->r[2];
|
||||
register u64 x3 asm("x3") = args->r[3];
|
||||
register u64 x4 asm("x4") = args->r[4];
|
||||
register u64 x5 asm("x5") = args->r[5];
|
||||
register u64 x6 asm("x6") = args->r[6];
|
||||
register u64 x7 asm("x7") = args->r[7];
|
||||
|
||||
/* Actually make the call. */
|
||||
{
|
||||
/* Disable interrupts while making the call. */
|
||||
KScopedInterruptDisable intr_disable;
|
||||
|
||||
{
|
||||
/* Backup the current thread pointer. */
|
||||
const uintptr_t current_thread_pointer_value = cpu::GetCurrentThreadPointerValue();
|
||||
|
||||
__asm__ __volatile__("smc #0"
|
||||
: "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7)
|
||||
:
|
||||
: "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory"
|
||||
);
|
||||
|
||||
/* Restore the current thread pointer into X18. */
|
||||
cpu::SetCurrentThreadPointerValue(current_thread_pointer_value);
|
||||
|
||||
/* Store arguments to output. */
|
||||
args->r[0] = x0;
|
||||
args->r[1] = x1;
|
||||
args->r[2] = x2;
|
||||
args->r[3] = x3;
|
||||
args->r[4] = x4;
|
||||
args->r[5] = x5;
|
||||
args->r[6] = x6;
|
||||
args->r[7] = x7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CallPrivilegedSecureMonitorFunctionForInit(SecureMonitorArguments &args) {
|
||||
/* Load arguments into registers. */
|
||||
register u64 x0 asm("x0") = args.x[0];
|
||||
register u64 x1 asm("x1") = args.x[1];
|
||||
register u64 x2 asm("x2") = args.x[2];
|
||||
register u64 x3 asm("x3") = args.x[3];
|
||||
register u64 x4 asm("x4") = args.x[4];
|
||||
register u64 x5 asm("x5") = args.x[5];
|
||||
register u64 x6 asm("x6") = args.x[6];
|
||||
register u64 x7 asm("x7") = args.x[7];
|
||||
|
||||
/* Actually make the call. */
|
||||
__asm__ __volatile__("smc #1"
|
||||
: "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7)
|
||||
:
|
||||
: "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory"
|
||||
);
|
||||
|
||||
/* Store arguments to output. */
|
||||
args.x[0] = x0;
|
||||
args.x[1] = x1;
|
||||
args.x[2] = x2;
|
||||
args.x[3] = x3;
|
||||
args.x[4] = x4;
|
||||
args.x[5] = x5;
|
||||
args.x[6] = x6;
|
||||
args.x[7] = x7;
|
||||
}
|
||||
|
||||
/* Global lock for generate random bytes. */
|
||||
KSpinLock g_generate_random_lock;
|
||||
constinit KSpinLock g_generate_random_lock;
|
||||
|
||||
}
|
||||
|
||||
/* SMC functionality needed for init. */
|
||||
namespace init {
|
||||
|
||||
void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
|
||||
SecureMonitorArguments args = { FunctionId_CpuOn, core_id, entrypoint, arg };
|
||||
CallPrivilegedSecureMonitorFunctionForInit(args);
|
||||
}
|
||||
|
||||
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) {
|
||||
SecureMonitorArguments args = { FunctionId_GetConfig, static_cast<u32>(config_item) };
|
||||
CallPrivilegedSecureMonitorFunctionForInit(args);
|
||||
MESOSPHERE_INIT_ABORT_UNLESS((static_cast<SmcResult>(args.x[0]) == SmcResult::Success));
|
||||
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_GetConfig, static_cast<u32>(config_item) } };
|
||||
|
||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor, false>(args.r);
|
||||
MESOSPHERE_INIT_ABORT_UNLESS((static_cast<SmcResult>(args.r[0]) == SmcResult::Success));
|
||||
|
||||
for (size_t i = 0; i < num_qwords && i < 7; i++) {
|
||||
out[i] = args.x[1 + i];
|
||||
out[i] = args.r[1 + i];
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateRandomBytes(void *dst, size_t size) {
|
||||
/* Call SmcGenerateRandomBytes() */
|
||||
SecureMonitorArguments args = { FunctionId_GenerateRandomBytes, size };
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(size <= sizeof(args) - sizeof(args.x[0]));
|
||||
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_GenerateRandomBytes, size } };
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(size <= sizeof(args) - sizeof(args.r[0]));
|
||||
|
||||
CallPrivilegedSecureMonitorFunctionForInit(args);
|
||||
MESOSPHERE_INIT_ABORT_UNLESS((static_cast<SmcResult>(args.x[0]) == SmcResult::Success));
|
||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor, false>(args.r);
|
||||
MESOSPHERE_INIT_ABORT_UNLESS((static_cast<SmcResult>(args.r[0]) == SmcResult::Success));
|
||||
|
||||
/* Copy output. */
|
||||
std::memcpy(dst, std::addressof(args.x[1]), size);
|
||||
std::memcpy(dst, std::addressof(args.r[1]), size);
|
||||
}
|
||||
|
||||
bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value) {
|
||||
SecureMonitorArguments args = { FunctionId_ReadWriteRegister, address, mask, value };
|
||||
CallPrivilegedSecureMonitorFunctionForInit(args);
|
||||
*out = args.x[1];
|
||||
return static_cast<SmcResult>(args.x[0]) == SmcResult::Success;
|
||||
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_ReadWriteRegister, address, mask, value } };
|
||||
|
||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor, false>(args.r);
|
||||
MESOSPHERE_INIT_ABORT_UNLESS((static_cast<SmcResult>(args.r[0]) == SmcResult::Success));
|
||||
|
||||
*out = args.r[1];
|
||||
|
||||
return static_cast<SmcResult>(args.r[0]) == SmcResult::Success;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool TryGetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) {
|
||||
SecureMonitorArguments args = { FunctionId_GetConfig, static_cast<u32>(config_item) };
|
||||
CallPrivilegedSecureMonitorFunction(args);
|
||||
if (static_cast<SmcResult>(args.x[0]) != SmcResult::Success) {
|
||||
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_GetConfig, static_cast<u32>(config_item) } };
|
||||
|
||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor, true>(args.r);
|
||||
if (AMS_UNLIKELY(static_cast<SmcResult>(args.r[0]) != SmcResult::Success)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_qwords && i < 7; i++) {
|
||||
out[i] = args.x[1 + i];
|
||||
out[i] = args.r[1 + i];
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -233,55 +115,58 @@ namespace ams::kern::board::nintendo::nx::smc {
|
|||
}
|
||||
|
||||
bool SetConfig(ConfigItem config_item, u64 value) {
|
||||
SecureMonitorArguments args = { FunctionId_SetConfig, static_cast<u32>(config_item), 0, value };
|
||||
CallPrivilegedSecureMonitorFunction(args);
|
||||
return static_cast<SmcResult>(args.x[0]) == SmcResult::Success;
|
||||
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_SetConfig, static_cast<u32>(config_item), 0, value } };
|
||||
|
||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor, true>(args.r);
|
||||
|
||||
return static_cast<SmcResult>(args.r[0]) == SmcResult::Success;
|
||||
}
|
||||
|
||||
bool ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value) {
|
||||
SecureMonitorArguments args = { FunctionId_ReadWriteRegister, address, mask, value };
|
||||
CallPrivilegedSecureMonitorFunction(args);
|
||||
*out = static_cast<u32>(args.x[1]);
|
||||
return static_cast<SmcResult>(args.x[0]) == SmcResult::Success;
|
||||
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_ReadWriteRegister, address, mask, value } };
|
||||
|
||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor, true>(args.r);
|
||||
|
||||
*out = static_cast<u32>(args.r[1]);
|
||||
return static_cast<SmcResult>(args.r[0]) == SmcResult::Success;
|
||||
}
|
||||
|
||||
void ConfigureCarveout(size_t which, uintptr_t address, size_t size) {
|
||||
SecureMonitorArguments args = { FunctionId_ConfigureCarveout, static_cast<u64>(which), static_cast<u64>(address), static_cast<u64>(size) };
|
||||
CallPrivilegedSecureMonitorFunction(args);
|
||||
MESOSPHERE_ABORT_UNLESS((static_cast<SmcResult>(args.x[0]) == SmcResult::Success));
|
||||
}
|
||||
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_ConfigureCarveout, static_cast<u64>(which), static_cast<u64>(address), static_cast<u64>(size) } };
|
||||
|
||||
void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
|
||||
SecureMonitorArguments args = { FunctionId_CpuOn, core_id, static_cast<u64>(entrypoint), static_cast<u64>(arg) };
|
||||
CallPrivilegedSecureMonitorFunction(args);
|
||||
MESOSPHERE_ABORT_UNLESS((static_cast<SmcResult>(args.x[0]) == SmcResult::Success));
|
||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor, true>(args.r);
|
||||
|
||||
MESOSPHERE_ABORT_UNLESS((static_cast<SmcResult>(args.r[0]) == SmcResult::Success));
|
||||
}
|
||||
|
||||
void GenerateRandomBytes(void *dst, size_t size) {
|
||||
/* Setup for call. */
|
||||
SecureMonitorArguments args = { FunctionId_GenerateRandomBytes, size };
|
||||
MESOSPHERE_ABORT_UNLESS(size <= sizeof(args) - sizeof(args.x[0]));
|
||||
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_GenerateRandomBytes, size } };
|
||||
MESOSPHERE_ABORT_UNLESS(size <= sizeof(args) - sizeof(args.r[0]));
|
||||
|
||||
/* Make call. */
|
||||
{
|
||||
KScopedInterruptDisable intr_disable;
|
||||
KScopedSpinLock lk(g_generate_random_lock);
|
||||
CallPrivilegedSecureMonitorFunction(args);
|
||||
|
||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor, true>(args.r);
|
||||
}
|
||||
MESOSPHERE_ABORT_UNLESS((static_cast<SmcResult>(args.x[0]) == SmcResult::Success));
|
||||
MESOSPHERE_ABORT_UNLESS((static_cast<SmcResult>(args.r[0]) == SmcResult::Success));
|
||||
|
||||
/* Copy output. */
|
||||
std::memcpy(dst, std::addressof(args.x[1]), size);
|
||||
std::memcpy(dst, std::addressof(args.r[1]), size);
|
||||
}
|
||||
|
||||
void NORETURN Panic(u32 color) {
|
||||
SecureMonitorArguments args = { FunctionId_Panic, color };
|
||||
CallPrivilegedSecureMonitorFunction(args);
|
||||
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_Panic, color } };
|
||||
|
||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor, true>(args.r);
|
||||
|
||||
AMS_INFINITE_LOOP();
|
||||
}
|
||||
|
||||
void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args) {
|
||||
CallUserSecureMonitorFunction(args);
|
||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_User, true>(args->r);
|
||||
}
|
||||
|
||||
}
|
|
@ -15,10 +15,16 @@
|
|||
*/
|
||||
#pragma once
|
||||
#include <mesosphere.hpp>
|
||||
#include <mesosphere/arch/arm64/kern_secure_monitor_base.hpp>
|
||||
|
||||
namespace ams::kern::board::nintendo::nx::smc {
|
||||
|
||||
/* Types. */
|
||||
enum SmcId {
|
||||
SmcId_User = 0,
|
||||
SmcId_Supervisor = 1,
|
||||
};
|
||||
|
||||
enum MemorySize {
|
||||
MemorySize_4GB = 0,
|
||||
MemorySize_6GB = 1,
|
||||
|
@ -105,15 +111,12 @@ namespace ams::kern::board::nintendo::nx::smc {
|
|||
|
||||
bool SetConfig(ConfigItem config_item, u64 value);
|
||||
|
||||
void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
|
||||
|
||||
void NORETURN Panic(u32 color);
|
||||
|
||||
void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args);
|
||||
|
||||
namespace init {
|
||||
|
||||
void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
|
||||
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item);
|
||||
void GenerateRandomBytes(void *dst, size_t size);
|
||||
bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue