From 89f8bee3b676e6566ad646d03fbae2231c6bf89b Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 21 Feb 2023 08:53:17 -0700 Subject: [PATCH] kern: update KSystemControl::InitializePhase1, dynamically scale 39-bit address space regions --- .../mesosphere/kern_k_address_space_info.hpp | 4 ++ .../mesosphere/kern_k_system_control_base.hpp | 4 +- .../nintendo/nx/kern_k_system_control.cpp | 66 +++++++++--------- .../source/kern_k_address_space_info.cpp | 68 ++++--------------- .../source/kern_k_system_control_base.cpp | 41 ++++++++--- 5 files changed, 83 insertions(+), 100 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp index 6f1507ddb..9e20dd254 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_address_space_info.hpp @@ -40,12 +40,16 @@ namespace ams::kern { static uintptr_t GetAddressSpaceStart(size_t width, Type type); static size_t GetAddressSpaceSize(size_t width, Type type); + static void SetAddressSpaceSize(size_t width, Type type, size_t size); + constexpr KAddressSpaceInfo(size_t bw, size_t a, size_t s, Type t) : m_bit_width(bw), m_address(a), m_size(s), m_type(t) { /* ... */ } constexpr size_t GetWidth() const { return m_bit_width; } constexpr size_t GetAddress() const { return m_address; } constexpr size_t GetSize() const { return m_size; } constexpr Type GetType() const { return m_type; } + + constexpr void SetSize(size_t size) { m_size = size; } }; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_system_control_base.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_system_control_base.hpp index 2448c384b..d169079ac 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_system_control_base.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_system_control_base.hpp @@ -57,9 +57,11 @@ namespace ams::kern { static void GenerateRandom(u64 *dst, size_t count); static u64 GenerateRandomRange(u64 min, u64 max); }; + protected: + static NOINLINE void InitializePhase1Base(u64 seed); public: /* Initialization. */ - static NOINLINE void InitializePhase1(bool skip_target_system = false); + static NOINLINE void InitializePhase1(); static NOINLINE void InitializePhase2(); static NOINLINE u32 GetCreateProcessMemoryPool(); 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 c2f73e31d..ea67d3b9a 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 @@ -398,40 +398,41 @@ namespace ams::kern::board::nintendo::nx { /* System Initialization. */ void KSystemControl::InitializePhase1() { - /* Initialize our random generator. */ + /* Configure KTargetSystem. */ + { + /* Set IsDebugMode. */ + { + KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode)); + + /* If debug mode, we want to initialize uart logging. */ + KTargetSystem::EnableDebugLogging(KTargetSystem::IsDebugMode()); + } + + /* Set Kernel Configuration. */ + { + const auto kernel_config = util::BitPack32{GetConfigU32(smc::ConfigItem::KernelConfiguration)}; + + KTargetSystem::EnableDebugMemoryFill(kernel_config.Get()); + KTargetSystem::EnableUserExceptionHandlers(kernel_config.Get()); + KTargetSystem::EnableDynamicResourceLimits(!kernel_config.Get()); + KTargetSystem::EnableUserPmuAccess(kernel_config.Get()); + + g_call_smc_on_panic = kernel_config.Get(); + } + + /* Set Kernel Debugging. */ + { + /* NOTE: This is used to restrict access to SvcKernelDebug/SvcChangeKernelTraceState. */ + /* Mesosphere may wish to not require this, as we'd ideally keep ProgramVerification enabled for userland. */ + KTargetSystem::EnableKernelDebugging(GetConfigBool(smc::ConfigItem::DisableProgramVerification)); + } + } + + /* Initialize random and resource limit. */ { u64 seed; smc::GenerateRandomBytes(std::addressof(seed), sizeof(seed)); - s_random_generator.Initialize(reinterpret_cast(std::addressof(seed)), sizeof(seed) / sizeof(u32)); - s_initialized_random_generator = true; - } - - /* Set IsDebugMode. */ - { - KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode)); - - /* If debug mode, we want to initialize uart logging. */ - KTargetSystem::EnableDebugLogging(KTargetSystem::IsDebugMode()); - KDebugLog::Initialize(); - } - - /* Set Kernel Configuration. */ - { - const auto kernel_config = util::BitPack32{GetConfigU32(smc::ConfigItem::KernelConfiguration)}; - - KTargetSystem::EnableDebugMemoryFill(kernel_config.Get()); - KTargetSystem::EnableUserExceptionHandlers(kernel_config.Get()); - KTargetSystem::EnableDynamicResourceLimits(!kernel_config.Get()); - KTargetSystem::EnableUserPmuAccess(kernel_config.Get()); - - g_call_smc_on_panic = kernel_config.Get(); - } - - /* Set Kernel Debugging. */ - { - /* NOTE: This is used to restrict access to SvcKernelDebug/SvcChangeKernelTraceState. */ - /* Mesosphere may wish to not require this, as we'd ideally keep ProgramVerification enabled for userland. */ - KTargetSystem::EnableKernelDebugging(GetConfigBool(smc::ConfigItem::DisableProgramVerification)); + KSystemControlBase::InitializePhase1Base(seed); } /* Configure the Kernel Carveout region. */ @@ -441,9 +442,6 @@ namespace ams::kern::board::nintendo::nx { smc::ConfigureCarveout(0, carveout.GetAddress(), carveout.GetSize()); } - - /* Initialize the system resource limit (and potentially other things). */ - KSystemControlBase::InitializePhase1(true); } void KSystemControl::InitializePhase2() { diff --git a/libraries/libmesosphere/source/kern_k_address_space_info.cpp b/libraries/libmesosphere/source/kern_k_address_space_info.cpp index 46a85ec89..ef585eba8 100644 --- a/libraries/libmesosphere/source/kern_k_address_space_info.cpp +++ b/libraries/libmesosphere/source/kern_k_address_space_info.cpp @@ -21,7 +21,7 @@ namespace ams::kern { constexpr uintptr_t Invalid = std::numeric_limits::max(); - constexpr KAddressSpaceInfo AddressSpaceInfos[] = { + constinit KAddressSpaceInfo AddressSpaceInfos[] = { { 32, ams::svc::AddressSmallMap32Start, ams::svc::AddressSmallMap32Size, KAddressSpaceInfo::Type_MapSmall, }, { 32, ams::svc::AddressLargeMap32Start, ams::svc::AddressLargeMap32Size, KAddressSpaceInfo::Type_MapLarge, }, { 32, Invalid, ams::svc::AddressMemoryRegionHeap32Size, KAddressSpaceInfo::Type_Heap, }, @@ -37,67 +37,27 @@ namespace ams::kern { { 39, Invalid, ams::svc::AddressMemoryRegionStack39Size, KAddressSpaceInfo::Type_Stack, }, }; - constexpr bool IsAllowedIndexForAddress(size_t index) { - return index < util::size(AddressSpaceInfos) && AddressSpaceInfos[index].GetAddress() != Invalid; - } - - constexpr size_t AddressSpaceIndices32Bit[KAddressSpaceInfo::Type_Count] = { - 0, 1, 0, 2, 0, 3, - }; - - constexpr size_t AddressSpaceIndices36Bit[KAddressSpaceInfo::Type_Count] = { - 4, 5, 4, 6, 4, 7, - }; - - constexpr size_t AddressSpaceIndices39Bit[KAddressSpaceInfo::Type_Count] = { - 9, 8, 8, 10, 12, 11, - }; - - constexpr bool IsAllowed32BitType(KAddressSpaceInfo::Type type) { - return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_Map39Bit && type != KAddressSpaceInfo::Type_Stack; - } - - constexpr bool IsAllowed36BitType(KAddressSpaceInfo::Type type) { - return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_Map39Bit && type != KAddressSpaceInfo::Type_Stack; - } - - constexpr bool IsAllowed39BitType(KAddressSpaceInfo::Type type) { - return type < KAddressSpaceInfo::Type_Count && type != KAddressSpaceInfo::Type_MapLarge; + KAddressSpaceInfo &GetAddressSpaceInfo(size_t width, KAddressSpaceInfo::Type type) { + for (auto &info : AddressSpaceInfos) { + if (info.GetWidth() == width && info.GetType() == type) { + return info; + } + } + MESOSPHERE_PANIC("Could not find AddressSpaceInfo"); } } uintptr_t KAddressSpaceInfo::GetAddressSpaceStart(size_t width, KAddressSpaceInfo::Type type) { - switch (width) { - case 32: - MESOSPHERE_ABORT_UNLESS(IsAllowed32BitType(type)); - MESOSPHERE_ABORT_UNLESS(IsAllowedIndexForAddress(AddressSpaceIndices32Bit[type])); - return AddressSpaceInfos[AddressSpaceIndices32Bit[type]].GetAddress(); - case 36: - MESOSPHERE_ABORT_UNLESS(IsAllowed36BitType(type)); - MESOSPHERE_ABORT_UNLESS(IsAllowedIndexForAddress(AddressSpaceIndices36Bit[type])); - return AddressSpaceInfos[AddressSpaceIndices36Bit[type]].GetAddress(); - case 39: - MESOSPHERE_ABORT_UNLESS(IsAllowed39BitType(type)); - MESOSPHERE_ABORT_UNLESS(IsAllowedIndexForAddress(AddressSpaceIndices39Bit[type])); - return AddressSpaceInfos[AddressSpaceIndices39Bit[type]].GetAddress(); - MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); - } + return GetAddressSpaceInfo(width, type).GetAddress(); } size_t KAddressSpaceInfo::GetAddressSpaceSize(size_t width, KAddressSpaceInfo::Type type) { - switch (width) { - case 32: - MESOSPHERE_ABORT_UNLESS(IsAllowed32BitType(type)); - return AddressSpaceInfos[AddressSpaceIndices32Bit[type]].GetSize(); - case 36: - MESOSPHERE_ABORT_UNLESS(IsAllowed36BitType(type)); - return AddressSpaceInfos[AddressSpaceIndices36Bit[type]].GetSize(); - case 39: - MESOSPHERE_ABORT_UNLESS(IsAllowed39BitType(type)); - return AddressSpaceInfos[AddressSpaceIndices39Bit[type]].GetSize(); - MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); - } + return GetAddressSpaceInfo(width, type).GetSize(); + } + + void KAddressSpaceInfo::SetAddressSpaceSize(size_t width, Type type, size_t size) { + GetAddressSpaceInfo(width, type).SetSize(size); } } diff --git a/libraries/libmesosphere/source/kern_k_system_control_base.cpp b/libraries/libmesosphere/source/kern_k_system_control_base.cpp index ce8e32f9e..f04f896bc 100644 --- a/libraries/libmesosphere/source/kern_k_system_control_base.cpp +++ b/libraries/libmesosphere/source/kern_k_system_control_base.cpp @@ -100,23 +100,15 @@ namespace ams::kern { } /* System Initialization. */ - void KSystemControlBase::InitializePhase1(bool skip_target_system) { - /* Initialize the rng, if we somehow haven't already. */ - if (AMS_UNLIKELY(!s_initialized_random_generator)) { - const u64 seed = KHardwareTimer::GetTick(); - s_random_generator.Initialize(reinterpret_cast(std::addressof(seed)), sizeof(seed) / sizeof(u32)); - s_initialized_random_generator = true; - } - - /* Configure KTargetSystem, if we haven't already by an implementation SystemControl. */ - if (!skip_target_system) { + void KSystemControlBase::InitializePhase1() { + /* Configure KTargetSystem. */ + { /* Set IsDebugMode. */ { KTargetSystem::SetIsDebugMode(true); /* If debug mode, we want to initialize uart logging. */ KTargetSystem::EnableDebugLogging(true); - KDebugLog::Initialize(); } /* Set Kernel Configuration. */ @@ -135,6 +127,20 @@ namespace ams::kern { } } + /* Initialize random and resource limit. */ + KSystemControlBase::InitializePhase1Base(KHardwareTimer::GetTick()); + } + + void KSystemControlBase::InitializePhase1Base(u64 seed) { + /* Initialize the rng, if we somehow haven't already. */ + if (AMS_UNLIKELY(!s_initialized_random_generator)) { + s_random_generator.Initialize(reinterpret_cast(std::addressof(seed)), sizeof(seed) / sizeof(u32)); + s_initialized_random_generator = true; + } + + /* Initialize debug logging. */ + KDebugLog::Initialize(); + /* System ResourceLimit initialization. */ { /* Construct the resource limit object. */ @@ -144,6 +150,19 @@ namespace ams::kern { /* Set the initial limits. */ const auto [total_memory_size, kernel_memory_size] = KMemoryLayout::GetTotalAndKernelMemorySizes(); + + /* Update 39-bit address space infos. */ + { + /* Heap should be equal to the total memory size, minimum 8 GB, maximum 32 GB. */ + /* Alias should be equal to 8 * heap size, maximum 128 GB. */ + const size_t heap_size = std::max(std::min(util::AlignUp(total_memory_size, 1_GB), 32_GB), 8_GB); + const size_t alias_size = std::min(heap_size * 8, 128_GB); + + /* Set the address space sizes. */ + KAddressSpaceInfo::SetAddressSpaceSize(39, KAddressSpaceInfo::Type_Heap, heap_size); + KAddressSpaceInfo::SetAddressSpaceSize(39, KAddressSpaceInfo::Type_Alias, alias_size); + } + 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));