From 5bc3307ffa5f953aa853aaef55b46dac54db59c7 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 17 Aug 2020 16:45:41 -0700 Subject: [PATCH] kern: improve resource region size definitions/calculations --- .../arch/arm64/init/kern_k_init_page_table.hpp | 4 ++++ .../include/mesosphere/kern_initial_process.hpp | 2 +- .../include/mesosphere/kern_k_memory_layout.hpp | 14 ++++++++++++++ .../source/init/kern_init_slab_setup.cpp | 17 +++++++++++++---- libmesosphere/source/kern_k_memory_layout.cpp | 13 +++++++++++++ 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_page_table.hpp b/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_page_table.hpp index a0952347..357a2ae5 100644 --- a/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_page_table.hpp +++ b/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_page_table.hpp @@ -74,6 +74,10 @@ namespace ams::kern::arch::arm64::init { static ALWAYS_INLINE void ClearNewPageTable(KPhysicalAddress address) { ClearPhysicalMemory(address, PageSize); } + public: + static consteval size_t GetMaximumOverheadSize(size_t size) { + return (util::DivideUp(size, L1BlockSize) + util::DivideUp(size, L2BlockSize)) * PageSize; + } private: size_t NOINLINE GetBlockCount(KVirtualAddress virt_addr, size_t size, size_t block_size) { const KVirtualAddress end_virt_addr = virt_addr + size; diff --git a/libmesosphere/include/mesosphere/kern_initial_process.hpp b/libmesosphere/include/mesosphere/kern_initial_process.hpp index e5e6c2f4..7e87cca9 100644 --- a/libmesosphere/include/mesosphere/kern_initial_process.hpp +++ b/libmesosphere/include/mesosphere/kern_initial_process.hpp @@ -20,7 +20,7 @@ namespace ams::kern { constexpr u32 InitialProcessBinaryMagic = util::FourCC<'I','N','I','1'>::Code; - constexpr size_t InitialProcessBinarySizeMax = 0xC00000; + constexpr size_t InitialProcessBinarySizeMax = 12_MB; struct InitialProcessBinaryHeader { u32 magic; diff --git a/libmesosphere/include/mesosphere/kern_k_memory_layout.hpp b/libmesosphere/include/mesosphere/kern_k_memory_layout.hpp index fe6928a6..bf03aa26 100644 --- a/libmesosphere/include/mesosphere/kern_k_memory_layout.hpp +++ b/libmesosphere/include/mesosphere/kern_k_memory_layout.hpp @@ -39,6 +39,19 @@ namespace ams::kern { constexpr size_t KernelPhysicalAddressSpaceLast = KernelPhysicalAddressSpaceEnd - 1ul; constexpr size_t KernelPhysicalAddressSpaceSize = KernelPhysicalAddressSpaceEnd - KernelPhysicalAddressSpaceBase; + constexpr size_t KernelPageTableHeapSize = init::KInitialPageTable::GetMaximumOverheadSize(8_GB); + constexpr size_t KernelInitialPageHeapSize = 128_KB; + + constexpr size_t KernelSlabHeapDataSize = 5_MB; + constexpr size_t KernelSlabHeapGapsSize = 2_MB - 64_KB; + constexpr size_t KernelSlabHeapGapsSizeDeprecated = 2_MB; + constexpr size_t KernelSlabHeapSize = KernelSlabHeapDataSize + KernelSlabHeapGapsSize; + + /* NOTE: This is calculated from KThread slab counts, assuming KThread size <= 0x860. */ + constexpr size_t KernelSlabHeapAdditionalSize = 0x68000; + + constexpr size_t KernelResourceSize = KernelPageTableHeapSize + KernelInitialPageHeapSize + KernelSlabHeapSize; + enum KMemoryRegionType : u32 { KMemoryRegionAttr_CarveoutProtected = 0x04000000, KMemoryRegionAttr_DidKernelMap = 0x08000000, @@ -544,6 +557,7 @@ namespace ams::kern { } static void InitializeLinearMemoryRegionTrees(KPhysicalAddress aligned_linear_phys_start, KVirtualAddress linear_virtual_start); + static size_t GetResourceRegionSizeForInit(); static NOINLINE auto GetKernelRegionExtents() { return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Kernel); } static NOINLINE auto GetKernelCodeRegionExtents() { return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelCode); } diff --git a/libmesosphere/source/init/kern_init_slab_setup.cpp b/libmesosphere/source/init/kern_init_slab_setup.cpp index 0a8ecce8..87199c43 100644 --- a/libmesosphere/source/init/kern_init_slab_setup.cpp +++ b/libmesosphere/source/init/kern_init_slab_setup.cpp @@ -71,8 +71,12 @@ namespace ams::kern::init { constexpr size_t SlabCountExtraKThread = 160; - /* This is used for gaps between the slab allocators. */ - constexpr size_t SlabRegionReservedSize = 2_MB - 64_KB; + namespace test { + + constexpr size_t RequiredSizeForExtraThreadCount = SlabCountExtraKThread * (sizeof(KThread) + (sizeof(KLinkedListNode) * 17) + (sizeof(KThreadLocalPage) / 8) + sizeof(KEventInfo)); + static_assert(RequiredSizeForExtraThreadCount <= KernelSlabHeapAdditionalSize); + + } /* Global to hold our resource counts. */ KSlabResourceCounts g_slab_resource_counts = { @@ -121,6 +125,10 @@ namespace ams::kern::init { } } + size_t CalculateSlabHeapGapSize() { + return (kern::GetTargetFirmware() >= TargetFirmware_10_0_0) ? KernelSlabHeapGapsSize : KernelSlabHeapGapsSizeDeprecated; + } + size_t CalculateTotalSlabHeapSize() { size_t size = 0; @@ -135,7 +143,7 @@ namespace ams::kern::init { #undef ADD_SLAB_SIZE /* Add the reserved size. */ - size += SlabRegionReservedSize; + size += CalculateSlabHeapGapSize(); return size; } @@ -175,11 +183,12 @@ namespace ams::kern::init { } /* Create an array to represent the gaps between the slabs. */ + const size_t total_gap_size = CalculateSlabHeapGapSize(); size_t slab_gaps[util::size(slab_types)]; for (size_t i = 0; i < util::size(slab_gaps); i++) { /* Note: This is an off-by-one error from Nintendo's intention, because GenerateRandomRange is inclusive. */ /* However, Nintendo also has the off-by-one error, and it's "harmless", so we will include it ourselves. */ - slab_gaps[i] = KSystemControl::GenerateRandomRange(0, SlabRegionReservedSize); + slab_gaps[i] = KSystemControl::GenerateRandomRange(0, total_gap_size); } /* Sort the array, so that we can treat differences between values as offsets to the starts of slabs. */ diff --git a/libmesosphere/source/kern_k_memory_layout.cpp b/libmesosphere/source/kern_k_memory_layout.cpp index 88c83563..7e904761 100644 --- a/libmesosphere/source/kern_k_memory_layout.cpp +++ b/libmesosphere/source/kern_k_memory_layout.cpp @@ -168,6 +168,19 @@ namespace ams::kern { } } + size_t KMemoryLayout::GetResourceRegionSizeForInit() { + /* Calculate resource region size based on whether we allow extra threads. */ + const bool use_extra_resources = KSystemControl::Init::ShouldIncreaseThreadResourceLimit(); + size_t resource_region_size = KernelResourceSize + (use_extra_resources ? KernelSlabHeapAdditionalSize : 0); + + /* 10.0.0 reduced the slab heap gaps by 64K. */ + if (kern::GetTargetFirmware() < ams::TargetFirmware_10_0_0) { + resource_region_size += (KernelSlabHeapGapsSizeDeprecated - KernelSlabHeapGapsSize); + } + + return resource_region_size; + } + namespace init { namespace {