From 5e85bc3d230e87fd323d1eb0c90816eaf7964a0d Mon Sep 17 00:00:00 2001
From: ameerj <52414509+ameerj@users.noreply.github.com>
Date: Mon, 12 Apr 2021 16:14:19 -0400
Subject: [PATCH] kernel/process: Replace process resource limit instance with
 the kernel's resource limit

This commit addresses the inaccurate behavior of kernel processes creating their own resource limit, rather than utilizing the kernel's system-wide resource limit instance.
---
 src/core/hle/kernel/kernel.cpp  | 41 ++++++++++++++++++++-------------
 src/core/hle/kernel/process.cpp | 24 ++-----------------
 2 files changed, 27 insertions(+), 38 deletions(-)

diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 8fd9905775..f7d3f218ae 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -67,8 +67,13 @@ struct KernelCore::Impl {
         is_phantom_mode_for_singlecore = false;
 
         InitializePhysicalCores();
-        InitializeSystemResourceLimit(kernel, system);
-        InitializeMemoryLayout();
+
+        // Derive the initial memory layout from the emulated board
+        KMemoryLayout memory_layout;
+        DeriveInitialMemoryLayout(memory_layout);
+        InitializeMemoryLayout(memory_layout);
+        InitializeSystemResourceLimit(kernel, system, memory_layout);
+        InitializeSlabHeaps();
         InitializeSchedulers();
         InitializeSuspendThreads();
         InitializePreemption(kernel);
@@ -137,27 +142,32 @@ struct KernelCore::Impl {
     }
 
     // Creates the default system resource limit
-    void InitializeSystemResourceLimit(KernelCore& kernel, Core::System& system) {
+    void InitializeSystemResourceLimit(KernelCore& kernel, Core::System& system,
+                                       const KMemoryLayout& memory_layout) {
         system_resource_limit = std::make_shared<KResourceLimit>(kernel, system);
+        const auto [total_size, kernel_size] = memory_layout.GetTotalAndKernelMemorySizes();
 
         // If setting the default system values fails, then something seriously wrong has occurred.
-        ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, 0x100000000)
+        ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, total_size)
                    .IsSuccess());
         ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess());
         ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 900).IsSuccess());
         ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200)
                    .IsSuccess());
         ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 1133).IsSuccess());
+        system_resource_limit->Reserve(LimitableResource::PhysicalMemory, kernel_size);
 
-        // Derived from recent software updates. The kernel reserves 27MB
-        constexpr u64 kernel_size{0x1b00000};
-        if (!system_resource_limit->Reserve(LimitableResource::PhysicalMemory, kernel_size)) {
-            UNREACHABLE();
-        }
         // Reserve secure applet memory, introduced in firmware 5.0.0
-        constexpr u64 secure_applet_memory_size{0x400000};
+        constexpr u64 secure_applet_memory_size{Common::Size_4_MB};
         ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory,
                                               secure_applet_memory_size));
+
+        // This memory seems to be reserved on hardware, but is not reserved/used by yuzu.
+        // Likely Horizon OS reserved memory
+        // TODO(ameerj): Derive the memory rather than hardcode it.
+        constexpr u64 unknown_reserved_memory{0x2f896000};
+        ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory,
+                                              unknown_reserved_memory));
     }
 
     void InitializePreemption(KernelCore& kernel) {
@@ -531,11 +541,7 @@ struct KernelCore::Impl {
                                                         linear_region_start);
     }
 
-    void InitializeMemoryLayout() {
-        // Derive the initial memory layout from the emulated board
-        KMemoryLayout memory_layout;
-        DeriveInitialMemoryLayout(memory_layout);
-
+    void InitializeMemoryLayout(const KMemoryLayout& memory_layout) {
         const auto system_pool = memory_layout.GetKernelSystemPoolRegionPhysicalExtents();
         const auto applet_pool = memory_layout.GetKernelAppletPoolRegionPhysicalExtents();
         const auto application_pool = memory_layout.GetKernelApplicationPoolRegionPhysicalExtents();
@@ -578,11 +584,14 @@ struct KernelCore::Impl {
             system.Kernel(), system.DeviceMemory(), nullptr, {time_phys_addr, time_size / PageSize},
             KMemoryPermission::None, KMemoryPermission::Read, time_phys_addr, time_size,
             "Time:SharedMemory");
+    }
 
+    void InitializeSlabHeaps() {
         // Allocate slab heaps
         user_slab_heap_pages = std::make_unique<KSlabHeap<Page>>();
 
-        constexpr u64 user_slab_heap_size{0x1ef000};
+        // TODO(ameerj): This should be derived, not hardcoded within the kernel
+        constexpr u64 user_slab_heap_size{0x3de000};
         // Reserve slab heaps
         ASSERT(
             system_resource_limit->Reserve(LimitableResource::PhysicalMemory, user_slab_heap_size));
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 9d5956ead7..dd01f39245 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -120,9 +120,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
     std::shared_ptr<Process> process = std::make_shared<Process>(system);
     process->name = std::move(name);
 
-    // TODO: This is inaccurate
-    // The process should hold a reference to the kernel-wide resource limit.
-    process->resource_limit = std::make_shared<KResourceLimit>(kernel, system);
+    process->resource_limit = kernel.GetSystemResourceLimit();
     process->status = ProcessStatus::Created;
     process->program_id = 0;
     process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
@@ -160,17 +158,13 @@ void Process::DecrementThreadCount() {
 }
 
 u64 Process::GetTotalPhysicalMemoryAvailable() const {
-    // TODO: This is expected to always return the application memory pool size after accurately
-    // reserving kernel resources. The current workaround uses a process-local resource limit of
-    // application memory pool size, which is inaccurate.
     const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) +
                        page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
                        main_thread_stack_size};
-
+    ASSERT(capacity == kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application));
     if (capacity < memory_usage_capacity) {
         return capacity;
     }
-
     return memory_usage_capacity;
 }
 
@@ -272,10 +266,6 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
     system_resource_size = metadata.GetSystemResourceSize();
     image_size = code_size;
 
-    // Set initial resource limits
-    resource_limit->SetLimitValue(
-        LimitableResource::PhysicalMemory,
-        kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application));
     KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory,
                                                   code_size + system_resource_size);
     if (!memory_reservation.Succeeded()) {
@@ -324,16 +314,6 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
         UNREACHABLE();
     }
 
-    // Set initial resource limits
-    resource_limit->SetLimitValue(
-        LimitableResource::PhysicalMemory,
-        kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application));
-
-    resource_limit->SetLimitValue(LimitableResource::Threads, 608);
-    resource_limit->SetLimitValue(LimitableResource::Events, 700);
-    resource_limit->SetLimitValue(LimitableResource::TransferMemory, 128);
-    resource_limit->SetLimitValue(LimitableResource::Sessions, 894);
-
     // Create TLS region
     tls_region_address = CreateTLSRegion();
     memory_reservation.Commit();