diff --git a/libraries/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_page_table.hpp b/libraries/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_page_table.hpp index a09523477..357a2ae5f 100644 --- a/libraries/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_page_table.hpp +++ b/libraries/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/libraries/libmesosphere/include/mesosphere/kern_initial_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_initial_process.hpp index e5e6c2f40..7e87cca96 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_initial_process.hpp +++ b/libraries/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/libraries/libmesosphere/include/mesosphere/kern_k_memory_layout.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_memory_layout.hpp index fe6928a69..bf03aa26a 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_memory_layout.hpp +++ b/libraries/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/libraries/libmesosphere/source/init/kern_init_slab_setup.cpp b/libraries/libmesosphere/source/init/kern_init_slab_setup.cpp index 0a8ecce88..87199c431 100644 --- a/libraries/libmesosphere/source/init/kern_init_slab_setup.cpp +++ b/libraries/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/libraries/libmesosphere/source/kern_k_memory_layout.cpp b/libraries/libmesosphere/source/kern_k_memory_layout.cpp index 88c835631..7e9047611 100644 --- a/libraries/libmesosphere/source/kern_k_memory_layout.cpp +++ b/libraries/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 { diff --git a/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp b/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp index f892f7cb3..090a9a802 100644 --- a/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp +++ b/mesosphere/kernel/source/arch/arm64/init/kern_init_core.cpp @@ -31,31 +31,12 @@ namespace ams::kern::init { namespace { - constexpr size_t KernelResourceRegionSize = 0x1728000; - constexpr size_t ExtraKernelResourceSize = 0x68000; - static_assert(ExtraKernelResourceSize + KernelResourceRegionSize == 0x1790000); - constexpr size_t KernelResourceReduction_10_0_0 = 0x10000; - /* Global Allocator. */ KInitialPageAllocator g_initial_page_allocator; /* Global initial arguments array. */ KPhysicalAddress g_init_arguments_phys_addr[cpu::NumCores]; - size_t GetResourceRegionSize() { - /* Decide if Kernel should have enlarged resource region. */ - const bool use_extra_resources = KSystemControl::Init::ShouldIncreaseThreadResourceLimit(); - size_t resource_region_size = KernelResourceRegionSize + (use_extra_resources ? ExtraKernelResourceSize : 0); - static_assert(KernelResourceRegionSize > InitialProcessBinarySizeMax); - static_assert(KernelResourceRegionSize + ExtraKernelResourceSize > InitialProcessBinarySizeMax); - - /* 10.0.0 reduced the kernel resource region size by 64K. */ - if (kern::GetTargetFirmware() >= ams::TargetFirmware_10_0_0) { - resource_region_size -= KernelResourceReduction_10_0_0; - } - return resource_region_size; - } - /* Page table attributes. */ constexpr PageTableEntry KernelRoDataAttribute(PageTableEntry::Permission_KernelR, PageTableEntry::PageAttribute_NormalMemory, PageTableEntry::Shareable_InnerShareable, PageTableEntry::MappingFlag_Mapped); constexpr PageTableEntry KernelRwDataAttribute(PageTableEntry::Permission_KernelRW, PageTableEntry::PageAttribute_NormalMemory, PageTableEntry::Shareable_InnerShareable, PageTableEntry::MappingFlag_Mapped); @@ -152,8 +133,8 @@ namespace ams::kern::init { const KVirtualAddress stack_region_start = KMemoryLayout::GetVirtualMemoryRegionTree().GetRandomAlignedRegion(StackRegionSize, StackRegionAlign, KMemoryRegionType_Kernel); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetVirtualMemoryRegionTree().Insert(GetInteger(stack_region_start), StackRegionSize, KMemoryRegionType_KernelStack)); - /* Decide if Kernel should have enlarged resource region (slab region + page table heap region). */ - const size_t resource_region_size = GetResourceRegionSize(); + /* Determine the size of the resource region. */ + const size_t resource_region_size = KMemoryLayout::GetResourceRegionSizeForInit(); /* Determine the size of the slab region. */ const size_t slab_region_size = util::AlignUp(CalculateTotalSlabHeapSize(), PageSize); diff --git a/mesosphere/kernel_ldr/source/kern_init_loader.cpp b/mesosphere/kernel_ldr/source/kern_init_loader.cpp index fb25f4890..7bd7667e5 100644 --- a/mesosphere/kernel_ldr/source/kern_init_loader.cpp +++ b/mesosphere/kernel_ldr/source/kern_init_loader.cpp @@ -28,32 +28,16 @@ namespace ams::kern::init::loader { namespace { - constexpr size_t KernelResourceRegionSize = 0x1728000; - constexpr size_t ExtraKernelResourceSize = 0x68000; - static_assert(ExtraKernelResourceSize + KernelResourceRegionSize == 0x1790000); - constexpr size_t KernelResourceReduction_10_0_0 = 0x10000; + static_assert(InitialProcessBinarySizeMax <= KernelResourceSize); - constexpr size_t InitialPageTableRegionSize = 0x200000; + constexpr size_t InitialPageTableRegionSizeMax = 2_MB; + static_assert(InitialPageTableRegionSizeMax < KernelPageTableHeapSize + KernelInitialPageHeapSize); /* Global Allocator. */ KInitialPageAllocator g_initial_page_allocator; KInitialPageAllocator::State g_final_page_allocator_state; - size_t GetResourceRegionSize() { - /* Decide if Kernel should have enlarged resource region. */ - const bool use_extra_resources = KSystemControl::Init::ShouldIncreaseThreadResourceLimit(); - size_t resource_region_size = KernelResourceRegionSize + (use_extra_resources ? ExtraKernelResourceSize : 0); - static_assert(KernelResourceRegionSize > InitialProcessBinarySizeMax); - static_assert(KernelResourceRegionSize + ExtraKernelResourceSize > InitialProcessBinarySizeMax); - - /* 10.0.0 reduced the kernel resource region size by 64K. */ - if (kern::GetTargetFirmware() >= ams::TargetFirmware_10_0_0) { - resource_region_size -= KernelResourceReduction_10_0_0; - } - return resource_region_size; - } - void RelocateKernelPhysically(uintptr_t &base_address, KernelLayout *&layout) { KPhysicalAddress correct_base = KSystemControl::Init::GetKernelPhysicalBaseAddress(base_address); if (correct_base != base_address) { @@ -276,7 +260,7 @@ namespace ams::kern::init::loader { const uintptr_t init_array_end_offset = layout->init_array_end_offset; /* Determine the size of the resource region. */ - const size_t resource_region_size = GetResourceRegionSize(); + const size_t resource_region_size = KMemoryLayout::GetResourceRegionSizeForInit(); /* Setup the INI1 header in memory for the kernel. */ const uintptr_t ini_end_address = base_address + ini_load_offset + resource_region_size; @@ -300,7 +284,7 @@ namespace ams::kern::init::loader { KInitialPageTable ttbr1_table(g_initial_page_allocator.Allocate()); /* Setup initial identity mapping. TTBR1 table passed by reference. */ - SetupInitialIdentityMapping(ttbr1_table, base_address, bss_end_offset, ini_end_address, InitialPageTableRegionSize, g_initial_page_allocator); + SetupInitialIdentityMapping(ttbr1_table, base_address, bss_end_offset, ini_end_address, InitialPageTableRegionSizeMax, g_initial_page_allocator); /* Generate a random slide for the kernel's base address. */ const KVirtualAddress virtual_base_address = GetRandomKernelBaseAddress(ttbr1_table, base_address, bss_end_offset);