From ecbe5cd406ca67d7fa9dc96420ec6bfb023aa9f9 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 28 Mar 2024 03:42:37 -0700 Subject: [PATCH] kern: refactor smc helpers to share more common logic --- .../arch/arm64/kern_secure_monitor_base.hpp | 47 ++-- .../nintendo/nx/kern_k_system_control.cpp | 7 +- .../board/nintendo/nx/kern_secure_monitor.cpp | 201 ++++++++++++------ .../board/nintendo/nx/kern_secure_monitor.hpp | 4 +- .../source/kern_k_system_control_base.cpp | 2 +- 5 files changed, 155 insertions(+), 106 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_secure_monitor_base.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_secure_monitor_base.hpp index 76ec13937..a3e8f080b 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_secure_monitor_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/arch/arm64/kern_secure_monitor_base.hpp @@ -16,11 +16,10 @@ #pragma once #include #include -#include namespace ams::kern::arch::arm64::smc { - template + template void SecureMonitorCall(u64 *buf) { /* Load arguments into registers. */ register u64 x0 asm("x0") = buf[0]; @@ -32,34 +31,18 @@ namespace ams::kern::arch::arm64::smc { register u64 x6 asm("x6") = buf[6]; register u64 x7 asm("x7") = buf[7]; + /* Backup the current thread pointer. */ + const uintptr_t current_thread_pointer_value = cpu::GetCurrentThreadPointerValue(); + /* Perform the call. */ - if constexpr (DisableInterrupt) { - KScopedInterruptDisable di; + __asm__ __volatile__("smc %c[smc_id]" + : "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7) + : [smc_id]"i"(SmcId) + : "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory" + ); - /* Backup the current thread pointer. */ - const uintptr_t current_thread_pointer_value = cpu::GetCurrentThreadPointerValue(); - - __asm__ __volatile__("smc %c[smc_id]" - : "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7) - : [smc_id]"i"(SmcId) - : "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); - } else { - /* Backup the current thread pointer. */ - const uintptr_t current_thread_pointer_value = cpu::GetCurrentThreadPointerValue(); - - __asm__ __volatile__("smc %c[smc_id]" - : "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7) - : [smc_id]"i"(SmcId) - : "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); - } + /* Restore the current thread pointer into X18. */ + cpu::SetCurrentThreadPointerValue(current_thread_pointer_value); /* Store arguments to output. */ buf[0] = x0; @@ -78,18 +61,18 @@ namespace ams::kern::arch::arm64::smc { PsciFunction_CpuOn = 0xC4000003, }; - template + template u64 PsciCall(PsciFunction function, u64 x1 = 0, u64 x2 = 0, u64 x3 = 0, u64 x4 = 0, u64 x5 = 0, u64 x6 = 0, u64 x7 = 0) { ams::svc::lp64::SecureMonitorArguments args = { { function, x1, x2, x3, x4, x5, x6, x7 } }; - SecureMonitorCall(args.r); + SecureMonitorCall(args.r); return args.r[0]; } - template + template u64 CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) { - return PsciCall(PsciFunction_CpuOn, core_id, entrypoint, arg); + return PsciCall(PsciFunction_CpuOn, core_id, entrypoint, arg); } } diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp index e3ac52278..52a894d1c 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_system_control.cpp @@ -296,7 +296,7 @@ namespace ams::kern::board::nintendo::nx { /* 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)); + smc::init::ReadWriteRegister(std::addressof(config_value), MemoryControllerConfigurationRegister, 0, 0); return static_cast(config_value & 0x3FFF) << 20; } @@ -387,7 +387,7 @@ namespace ams::kern::board::nintendo::nx { } void KSystemControl::Init::CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg) { - MESOSPHERE_INIT_ABORT_UNLESS((::ams::kern::arch::arm64::smc::CpuOn(core_id, entrypoint, arg)) == 0); + MESOSPHERE_INIT_ABORT_UNLESS((::ams::kern::arch::arm64::smc::CpuOn(core_id, entrypoint, arg)) == 0); } /* Randomness for Initialization. */ @@ -601,8 +601,9 @@ namespace ams::kern::board::nintendo::nx { if (g_call_smc_on_panic) { /* If we should, instruct the secure monitor to display a panic screen. */ - smc::Panic(0xF00); + smc::ShowError(0xF00); } + AMS_INFINITE_LOOP(); } diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.cpp index 6b1e3923f..d55eb2c70 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.cpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.cpp @@ -43,7 +43,7 @@ namespace ams::kern::board::nintendo::nx::smc { enum FunctionId : u32 { FunctionId_GetConfig = 0xC3000004, FunctionId_GenerateRandomBytes = 0xC3000005, - FunctionId_Panic = 0xC3000006, + FunctionId_ShowError = 0xC3000006, FunctionId_ConfigureCarveout = 0xC3000007, FunctionId_ReadWriteRegister = 0xC3000008, @@ -51,122 +51,187 @@ namespace ams::kern::board::nintendo::nx::smc { FunctionId_SetConfig = 0xC3000409, }; + constexpr size_t GenerateRandomBytesSizeMax = sizeof(::ams::svc::lp64::SecureMonitorArguments) - sizeof(::ams::svc::lp64::SecureMonitorArguments{}.r[0]); + /* Global lock for generate random bytes. */ constinit KSpinLock g_generate_random_lock; + bool TryGetConfigImpl(u64 *out, size_t num_qwords, ConfigItem config_item) { + /* Create the arguments .*/ + ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_GetConfig, static_cast(config_item) } }; + + /* Call into the secure monitor. */ + ::ams::kern::arch::arm64::smc::SecureMonitorCall(args.r); + + /* If successful, copy the output. */ + const bool success = static_cast(args.r[0]) == SmcResult::Success; + if (AMS_LIKELY(success)) { + for (size_t i = 0; i < num_qwords && i < 7; i++) { + out[i] = args.r[1 + i]; + } + } + + return success; + } + + bool SetConfigImpl(ConfigItem config_item, u64 value) { + /* Create the arguments .*/ + ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_SetConfig, static_cast(config_item), 0, value } }; + + /* Call into the secure monitor. */ + ::ams::kern::arch::arm64::smc::SecureMonitorCall(args.r); + + /* Return whether the call was successful. */ + return static_cast(args.r[0]) == SmcResult::Success; + } + + bool ReadWriteRegisterImpl(u32 *out, u64 address, u32 mask, u32 value) { + /* Create the arguments .*/ + ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_ReadWriteRegister, address, mask, value } }; + + /* Call into the secure monitor. */ + ::ams::kern::arch::arm64::smc::SecureMonitorCall(args.r); + + /* Unconditionally write the output. */ + *out = static_cast(args.r[1]); + + /* Return whether the call was successful. */ + return static_cast(args.r[0]) == SmcResult::Success; + } + + bool GenerateRandomBytesImpl(void *dst, size_t size) { + /* Create the arguments. */ + ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_GenerateRandomBytes, size } }; + + /* Call into the secure monitor. */ + ::ams::kern::arch::arm64::smc::SecureMonitorCall(args.r); + + /* If successful, copy the output. */ + const bool success = static_cast(args.r[0]) == SmcResult::Success; + if (AMS_LIKELY(success)) { + std::memcpy(dst, std::addressof(args.r[1]), size); + } + + return success; + } + + bool ConfigureCarveoutImpl(size_t which, uintptr_t address, size_t size) { + /* Create the arguments .*/ + ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_ConfigureCarveout, static_cast(which), static_cast(address), static_cast(size) } }; + + /* Call into the secure monitor. */ + ::ams::kern::arch::arm64::smc::SecureMonitorCall(args.r); + + /* Return whether the call was successful. */ + return static_cast(args.r[0]) == SmcResult::Success; + } + + bool ShowErrorImpl(u32 color) { + /* Create the arguments .*/ + ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_ShowError, color } }; + + /* Call into the secure monitor. */ + ::ams::kern::arch::arm64::smc::SecureMonitorCall(args.r); + + /* Return whether the call was successful. */ + return static_cast(args.r[0]) == SmcResult::Success; + } + + void CallSecureMonitorFromUserImpl(ams::svc::lp64::SecureMonitorArguments *args) { + /* Call into the secure monitor. */ + ::ams::kern::arch::arm64::smc::SecureMonitorCall(args->r); + } + } /* SMC functionality needed for init. */ namespace init { void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) { - ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_GetConfig, static_cast(config_item) } }; - - ::ams::kern::arch::arm64::smc::SecureMonitorCall(args.r); - MESOSPHERE_INIT_ABORT_UNLESS((static_cast(args.r[0]) == SmcResult::Success)); - - for (size_t i = 0; i < num_qwords && i < 7; i++) { - out[i] = args.r[1 + i]; - } + /* Ensure we successfully get the config. */ + MESOSPHERE_INIT_ABORT_UNLESS(TryGetConfigImpl(out, num_qwords, config_item)); } void GenerateRandomBytes(void *dst, size_t size) { - /* Call SmcGenerateRandomBytes() */ - ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_GenerateRandomBytes, size } }; - MESOSPHERE_INIT_ABORT_UNLESS(size <= sizeof(args) - sizeof(args.r[0])); + /* Check that the size is valid. */ + MESOSPHERE_INIT_ABORT_UNLESS(0 < size && size <= GenerateRandomBytesSizeMax); - ::ams::kern::arch::arm64::smc::SecureMonitorCall(args.r); - MESOSPHERE_INIT_ABORT_UNLESS((static_cast(args.r[0]) == SmcResult::Success)); - - /* Copy output. */ - std::memcpy(dst, std::addressof(args.r[1]), size); + /* Ensure we successfully generate the random bytes. */ + MESOSPHERE_INIT_ABORT_UNLESS(GenerateRandomBytesImpl(dst, size)); } - bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value) { - ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_ReadWriteRegister, address, mask, value } }; - - ::ams::kern::arch::arm64::smc::SecureMonitorCall(args.r); - MESOSPHERE_INIT_ABORT_UNLESS((static_cast(args.r[0]) == SmcResult::Success)); - - *out = args.r[1]; - - return static_cast(args.r[0]) == SmcResult::Success; + void ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value) { + /* Ensure we successfully access the register. */ + MESOSPHERE_INIT_ABORT_UNLESS(ReadWriteRegisterImpl(out, address, mask, value)); } } bool TryGetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) { - ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_GetConfig, static_cast(config_item) } }; + /* Disable interrupts. */ + KScopedInterruptDisable di; - ::ams::kern::arch::arm64::smc::SecureMonitorCall(args.r); - if (AMS_UNLIKELY(static_cast(args.r[0]) != SmcResult::Success)) { - return false; - } - - for (size_t i = 0; i < num_qwords && i < 7; i++) { - out[i] = args.r[1 + i]; - } - - return true; + /* Get the config. */ + return TryGetConfigImpl(out, num_qwords, config_item); } void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) { + /* Ensure we successfully get the config. */ MESOSPHERE_ABORT_UNLESS(TryGetConfig(out, num_qwords, config_item)); } bool SetConfig(ConfigItem config_item, u64 value) { - ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_SetConfig, static_cast(config_item), 0, value } }; + /* Disable interrupts. */ + KScopedInterruptDisable di; - ::ams::kern::arch::arm64::smc::SecureMonitorCall(args.r); - - return static_cast(args.r[0]) == SmcResult::Success; + /* Set the config. */ + return SetConfigImpl(config_item, value); } bool ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value) { - ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_ReadWriteRegister, address, mask, value } }; + /* Disable interrupts. */ + KScopedInterruptDisable di; - ::ams::kern::arch::arm64::smc::SecureMonitorCall(args.r); - - *out = static_cast(args.r[1]); - return static_cast(args.r[0]) == SmcResult::Success; + /* Access the register. */ + return ReadWriteRegisterImpl(out, address, mask, value); } void ConfigureCarveout(size_t which, uintptr_t address, size_t size) { - ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_ConfigureCarveout, static_cast(which), static_cast(address), static_cast(size) } }; + /* Disable interrupts. */ + KScopedInterruptDisable di; - ::ams::kern::arch::arm64::smc::SecureMonitorCall(args.r); - - MESOSPHERE_ABORT_UNLESS((static_cast(args.r[0]) == SmcResult::Success)); + /* Ensure that we successfully configure the carveout. */ + MESOSPHERE_ABORT_UNLESS(ConfigureCarveoutImpl(which, address, size)); } void GenerateRandomBytes(void *dst, size_t size) { - /* Setup for call. */ - ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_GenerateRandomBytes, size } }; - MESOSPHERE_ABORT_UNLESS(size <= sizeof(args) - sizeof(args.r[0])); + /* Check that the size is valid. */ + MESOSPHERE_ABORT_UNLESS(0 < size && size <= GenerateRandomBytesSizeMax); - /* Make call. */ - { - KScopedInterruptDisable intr_disable; - KScopedSpinLock lk(g_generate_random_lock); + /* Disable interrupts. */ + KScopedInterruptDisable di; - ::ams::kern::arch::arm64::smc::SecureMonitorCall(args.r); - } - MESOSPHERE_ABORT_UNLESS((static_cast(args.r[0]) == SmcResult::Success)); + /* Acquire the exclusive right to generate random bytes. */ + KScopedSpinLock lk(g_generate_random_lock); - /* Copy output. */ - std::memcpy(dst, std::addressof(args.r[1]), size); + /* Ensure we successfully generate the random bytes. */ + MESOSPHERE_ABORT_UNLESS(GenerateRandomBytesImpl(dst, size)); } - void NORETURN Panic(u32 color) { - ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_Panic, color } }; + void ShowError(u32 color) { + /* Disable interrupts. */ + KScopedInterruptDisable di; - ::ams::kern::arch::arm64::smc::SecureMonitorCall(args.r); - - AMS_INFINITE_LOOP(); + /* Ensure we successfully show the error. */ + MESOSPHERE_ABORT_UNLESS(ShowErrorImpl(color)); } void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args) { - ::ams::kern::arch::arm64::smc::SecureMonitorCall(args->r); + /* Disable interrupts. */ + KScopedInterruptDisable di; + + /* Perform the call. */ + CallSecureMonitorFromUserImpl(args); } } \ No newline at end of file diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp index b172fa540..1e64d11f9 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_secure_monitor.hpp @@ -111,7 +111,7 @@ namespace ams::kern::board::nintendo::nx::smc { bool SetConfig(ConfigItem config_item, u64 value); - void NORETURN Panic(u32 color); + void ShowError(u32 color); void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args); @@ -119,7 +119,7 @@ namespace ams::kern::board::nintendo::nx::smc { 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); + void ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value); } diff --git a/libraries/libmesosphere/source/kern_k_system_control_base.cpp b/libraries/libmesosphere/source/kern_k_system_control_base.cpp index 6764662d9..8412fbf75 100644 --- a/libraries/libmesosphere/source/kern_k_system_control_base.cpp +++ b/libraries/libmesosphere/source/kern_k_system_control_base.cpp @@ -78,7 +78,7 @@ namespace ams::kern { void KSystemControlBase::Init::CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg) { #if defined(ATMOSPHERE_ARCH_ARM64) - MESOSPHERE_INIT_ABORT_UNLESS((::ams::kern::arch::arm64::smc::CpuOn<0, false>(core_id, entrypoint, arg)) == 0); + MESOSPHERE_INIT_ABORT_UNLESS((::ams::kern::arch::arm64::smc::CpuOn<0>(core_id, entrypoint, arg)) == 0); #else AMS_INFINITE_LOOP(); #endif