kernel: Add 12 GiB heap support

- Increased heap region from 8 GiB to 12 GiB
- Fixed memory manager page reference count allocation
- Made resource region sizing dynamic for >8GB DRAM
- Increased physical address space bits to support 16GB

Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
Zephyron
2025-10-22 15:06:47 +10:00
parent 8cc5aa143f
commit 9c13799b49
6 changed files with 34 additions and 9 deletions

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
@@ -120,8 +121,8 @@ public:
private: private:
static constexpr size_t device_virtual_bits = Traits::device_virtual_bits; static constexpr size_t device_virtual_bits = Traits::device_virtual_bits;
static constexpr size_t device_as_size = 1ULL << device_virtual_bits; static constexpr size_t device_as_size = 1ULL << device_virtual_bits;
static constexpr size_t physical_min_bits = 32; static constexpr size_t physical_min_bits = 32; // 4GB
static constexpr size_t physical_max_bits = 33; static constexpr size_t physical_max_bits = 34; // 16GB (increased to support 12GB+ DRAM)
static constexpr size_t page_bits = 12; static constexpr size_t page_bits = 12;
static constexpr size_t page_size = 1ULL << page_bits; static constexpr size_t page_size = 1ULL << page_bits;
static constexpr size_t page_mask = page_size - 1ULL; static constexpr size_t page_mask = page_size - 1ULL;

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <array> #include <array>
@@ -16,6 +17,8 @@ using namespace Common::Literals;
constexpr u64 Size_Invalid = UINT64_MAX; constexpr u64 Size_Invalid = UINT64_MAX;
// clang-format off // clang-format off
// Address space layout information for different process address space configurations.
// Heap size increased from 8_GiB to 12_GiB to support games that require larger heap allocations
constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{ constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{
{ .bit_width = 32, .address = 2_MiB , .size = 1_GiB - 2_MiB , .type = KAddressSpaceInfo::Type::MapSmall, }, { .bit_width = 32, .address = 2_MiB , .size = 1_GiB - 2_MiB , .type = KAddressSpaceInfo::Type::MapSmall, },
{ .bit_width = 32, .address = 1_GiB , .size = 4_GiB - 1_GiB , .type = KAddressSpaceInfo::Type::MapLarge, }, { .bit_width = 32, .address = 1_GiB , .size = 4_GiB - 1_GiB , .type = KAddressSpaceInfo::Type::MapLarge, },
@@ -23,7 +26,7 @@ constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{
{ .bit_width = 32, .address = Size_Invalid, .size = 1_GiB , .type = KAddressSpaceInfo::Type::Heap, }, { .bit_width = 32, .address = Size_Invalid, .size = 1_GiB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 36, .address = 128_MiB , .size = 2_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::MapSmall, }, { .bit_width = 36, .address = 128_MiB , .size = 2_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::MapSmall, },
{ .bit_width = 36, .address = 2_GiB , .size = 64_GiB - 2_GiB , .type = KAddressSpaceInfo::Type::MapLarge, }, { .bit_width = 36, .address = 2_GiB , .size = 64_GiB - 2_GiB , .type = KAddressSpaceInfo::Type::MapLarge, },
{ .bit_width = 36, .address = Size_Invalid, .size = 8_GiB , .type = KAddressSpaceInfo::Type::Heap, }, { .bit_width = 36, .address = Size_Invalid, .size = 12_GiB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 36, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Alias, }, { .bit_width = 36, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Alias, },
#ifdef HAS_NCE #ifdef HAS_NCE
// With NCE, we use a 38-bit address space due to memory limitations. This should (safely) truncate ASLR region. // With NCE, we use a 38-bit address space due to memory limitations. This should (safely) truncate ASLR region.
@@ -32,7 +35,7 @@ constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{
{ .bit_width = 39, .address = 128_MiB , .size = 512_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::Map39Bit, }, { .bit_width = 39, .address = 128_MiB , .size = 512_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::Map39Bit, },
#endif #endif
{ .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::MapSmall }, { .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::MapSmall },
{ .bit_width = 39, .address = Size_Invalid, .size = 8_GiB , .type = KAddressSpaceInfo::Type::Heap, }, { .bit_width = 39, .address = Size_Invalid, .size = 12_GiB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::Alias, }, { .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 39, .address = Size_Invalid, .size = 2_GiB , .type = KAddressSpaceInfo::Type::Stack, }, { .bit_width = 39, .address = Size_Invalid, .size = 2_GiB , .type = KAddressSpaceInfo::Type::Stack, },
}}; }};

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <array> #include <array>
@@ -158,7 +159,17 @@ void KMemoryLayout::InitializeLinearMemoryRegionTrees(KPhysicalAddress aligned_l
} }
size_t KMemoryLayout::GetResourceRegionSizeForInit(bool use_extra_resource) { size_t KMemoryLayout::GetResourceRegionSizeForInit(bool use_extra_resource) {
return KernelResourceSize + KSystemControl::SecureAppletMemorySize + // Calculate kernel page table heap size based on actual memory size to support > 8GB DRAM
const size_t actual_memory_size = KSystemControl::Init::GetIntendedMemorySize();
const size_t actual_pt_heap_size = GetMaximumOverheadSize(actual_memory_size);
// Use the larger of static or dynamic calculation to ensure sufficient space
const size_t kernel_pt_heap = std::max(KernelPageTableHeapSize, actual_pt_heap_size);
const size_t base_resource_size = kernel_pt_heap + KernelInitialPageHeapSize +
KernelSlabHeapSize + KernelPageBufferHeapSize;
return base_resource_size + KSystemControl::SecureAppletMemorySize +
(use_extra_resource ? KernelSlabHeapAdditionalSize + KernelPageBufferAdditionalSize : 0); (use_extra_resource ? KernelSlabHeapAdditionalSize + KernelPageBufferAdditionalSize : 0);
} }

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
@@ -27,6 +28,9 @@ constexpr std::size_t GetMaximumOverheadSize(std::size_t size) {
constexpr std::size_t MainMemorySize = 4_GiB; constexpr std::size_t MainMemorySize = 4_GiB;
constexpr std::size_t MainMemorySizeMax = 8_GiB; constexpr std::size_t MainMemorySizeMax = 8_GiB;
// Maximum heap size that can be allocated by applications (increased to support large games)
constexpr std::size_t MaxHeapSize = 12_GiB;
constexpr std::size_t ReservedEarlyDramSize = 384_KiB; constexpr std::size_t ReservedEarlyDramSize = 384_KiB;
constexpr std::size_t DramPhysicalAddress = 0x80000000; constexpr std::size_t DramPhysicalAddress = 0x80000000;
@@ -53,6 +57,8 @@ constexpr std::size_t KernelPhysicalAddressSpaceSize =
KernelPhysicalAddressSpaceEnd - KernelPhysicalAddressSpaceBase; KernelPhysicalAddressSpaceEnd - KernelPhysicalAddressSpaceBase;
constexpr std::size_t KernelPhysicalAddressCodeBase = DramPhysicalAddress + ReservedEarlyDramSize; constexpr std::size_t KernelPhysicalAddressCodeBase = DramPhysicalAddress + ReservedEarlyDramSize;
// Use MainMemorySizeMax for conservative page table heap allocation
// This keeps kernel overhead reasonable while supporting up to 16GB DRAM
constexpr std::size_t KernelPageTableHeapSize = GetMaximumOverheadSize(MainMemorySizeMax); constexpr std::size_t KernelPageTableHeapSize = GetMaximumOverheadSize(MainMemorySizeMax);
constexpr std::size_t KernelInitialPageHeapSize = 128_KiB; constexpr std::size_t KernelInitialPageHeapSize = 128_KiB;

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm> #include <algorithm>
@@ -446,8 +447,8 @@ size_t KMemoryManager::Impl::Initialize(KPhysicalAddress address, size_t size,
// Setup region. // Setup region.
m_pool = p; m_pool = p;
m_management_region = management; m_management_region = management;
m_page_reference_counts.resize( // Allocate page reference counts based on actual managed size, not total memory size
Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize() / PageSize); m_page_reference_counts.resize(size / PageSize);
ASSERT(Common::IsAligned(GetInteger(m_management_region), PageSize)); ASSERT(Common::IsAligned(GetInteger(m_management_region), PageSize));
// Initialize the manager's KPageHeap. // Initialize the manager's KPageHeap.

View File

@@ -1,7 +1,9 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h" #include "core/core.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/svc.h" #include "core/hle/kernel/svc.h"
@@ -12,8 +14,9 @@ Result SetHeapSize(Core::System& system, u64* out_address, u64 size) {
LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", size); LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", size);
// Validate size. // Validate size.
R_UNLESS(Common::IsAligned(size, HeapSizeAlignment), ResultInvalidSize); // Check alignment and size limits for 12GiB heap support.
R_UNLESS(size < MainMemorySizeMax, ResultInvalidSize); R_UNLESS((size & 0xfffffffc001fffff) == 0, ResultInvalidSize);
R_UNLESS(size < MaxHeapSize, ResultInvalidSize);
// Set the heap size. // Set the heap size.
KProcessAddress address{}; KProcessAddress address{};