From b57c5a9b54b23a348d7e80e51943f27a54fb8c2f Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Tue, 20 Apr 2021 21:28:11 -0700
Subject: [PATCH] hle: kernel: Migrate KResourceLimit to KAutoObject.

---
 src/core/hle/kernel/init/init_slab_setup.cpp  |   6 +-
 src/core/hle/kernel/k_resource_limit.cpp      |  14 +-
 src/core/hle/kernel/k_resource_limit.h        |  20 ++-
 .../kernel/k_scoped_resource_reservation.h    |   8 +-
 src/core/hle/kernel/k_shared_memory.cpp       |  28 +++-
 src/core/hle/kernel/k_shared_memory.h         |   2 +-
 src/core/hle/kernel/k_transfer_memory.h       |   5 +-
 src/core/hle/kernel/kernel.cpp                |  24 +++-
 src/core/hle/kernel/kernel.h                  |  40 +++---
 src/core/hle/kernel/process.cpp               |  20 ++-
 src/core/hle/kernel/process.h                 |   8 +-
 src/core/hle/kernel/svc.cpp                   | 127 +++++++++---------
 src/core/hle/kernel/svc_wrap.h                |  19 ++-
 13 files changed, 198 insertions(+), 123 deletions(-)

diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp
index ce7a24c405..a5ddd7344c 100644
--- a/src/core/hle/kernel/init/init_slab_setup.cpp
+++ b/src/core/hle/kernel/init/init_slab_setup.cpp
@@ -12,11 +12,12 @@
 #include "core/hle/kernel/k_event.h"
 #include "core/hle/kernel/k_memory_layout.h"
 #include "core/hle/kernel/k_memory_manager.h"
+#include "core/hle/kernel/k_resource_limit.h"
 #include "core/hle/kernel/k_session.h"
 #include "core/hle/kernel/k_shared_memory.h"
-#include "core/hle/kernel/k_transfer_memory.h"
 #include "core/hle/kernel/k_system_control.h"
 #include "core/hle/kernel/k_thread.h"
+#include "core/hle/kernel/k_transfer_memory.h"
 #include "core/hle/kernel/memory_types.h"
 #include "core/hle/kernel/process.h"
 #include "core/memory.h"
@@ -31,7 +32,8 @@ namespace Kernel::Init {
     HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__)                                           \
     HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__)                         \
     HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__VA_ARGS__)                             \
-    HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__)
+    HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__)                                       \
+    HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__)
 
 namespace {
 
diff --git a/src/core/hle/kernel/k_resource_limit.cpp b/src/core/hle/kernel/k_resource_limit.cpp
index d05b34ea33..ad5095bfd0 100644
--- a/src/core/hle/kernel/k_resource_limit.cpp
+++ b/src/core/hle/kernel/k_resource_limit.cpp
@@ -10,10 +10,16 @@
 namespace Kernel {
 constexpr s64 DefaultTimeout = 10000000000; // 10 seconds
 
-KResourceLimit::KResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing_)
-    : Object{kernel}, lock{kernel}, cond_var{kernel}, core_timing(core_timing_) {}
+KResourceLimit::KResourceLimit(KernelCore& kernel)
+    : KAutoObjectWithSlabHeapAndContainer{kernel}, lock{kernel}, cond_var{kernel} {}
 KResourceLimit::~KResourceLimit() = default;
 
+void KResourceLimit::Initialize(const Core::Timing::CoreTiming* core_timing_) {
+    core_timing = core_timing_;
+}
+
+void KResourceLimit::Finalize() {}
+
 s64 KResourceLimit::GetLimitValue(LimitableResource which) const {
     const auto index = static_cast<std::size_t>(which);
     s64 value{};
@@ -78,7 +84,7 @@ ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) {
 }
 
 bool KResourceLimit::Reserve(LimitableResource which, s64 value) {
-    return Reserve(which, value, core_timing.GetGlobalTimeNs().count() + DefaultTimeout);
+    return Reserve(which, value, core_timing->GetGlobalTimeNs().count() + DefaultTimeout);
 }
 
 bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
@@ -109,7 +115,7 @@ bool KResourceLimit::Reserve(LimitableResource which, s64 value, s64 timeout) {
         }
 
         if (current_hints[index] + value <= limit_values[index] &&
-            (timeout < 0 || core_timing.GetGlobalTimeNs().count() < timeout)) {
+            (timeout < 0 || core_timing->GetGlobalTimeNs().count() < timeout)) {
             waiter_count++;
             cond_var.Wait(&lock, timeout);
             waiter_count--;
diff --git a/src/core/hle/kernel/k_resource_limit.h b/src/core/hle/kernel/k_resource_limit.h
index 4542317d0c..483c66c336 100644
--- a/src/core/hle/kernel/k_resource_limit.h
+++ b/src/core/hle/kernel/k_resource_limit.h
@@ -32,10 +32,16 @@ constexpr bool IsValidResourceType(LimitableResource type) {
     return type < LimitableResource::Count;
 }
 
-class KResourceLimit final : public Object {
+class KResourceLimit final
+    : public KAutoObjectWithSlabHeapAndContainer<KResourceLimit, KAutoObjectWithList> {
+    KERNEL_AUTOOBJECT_TRAITS(KResourceLimit, KAutoObject);
+
 public:
-    explicit KResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing_);
-    ~KResourceLimit();
+    explicit KResourceLimit(KernelCore& kernel);
+    virtual ~KResourceLimit();
+
+    void Initialize(const Core::Timing::CoreTiming* core_timing_);
+    virtual void Finalize() override;
 
     s64 GetLimitValue(LimitableResource which) const;
     s64 GetCurrentValue(LimitableResource which) const;
@@ -49,6 +55,10 @@ public:
     void Release(LimitableResource which, s64 value);
     void Release(LimitableResource which, s64 value, s64 hint);
 
+    static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
+
+    // DEPRECATED
+
     std::string GetTypeName() const override {
         return "KResourceLimit";
     }
@@ -61,8 +71,6 @@ public:
         return HANDLE_TYPE;
     }
 
-    virtual void Finalize() override {}
-
 private:
     using ResourceArray = std::array<s64, static_cast<std::size_t>(LimitableResource::Count)>;
     ResourceArray limit_values{};
@@ -72,6 +80,6 @@ private:
     mutable KLightLock lock;
     s32 waiter_count{};
     KLightConditionVariable cond_var;
-    const Core::Timing::CoreTiming& core_timing;
+    const Core::Timing::CoreTiming* core_timing{};
 };
 } // namespace Kernel
diff --git a/src/core/hle/kernel/k_scoped_resource_reservation.h b/src/core/hle/kernel/k_scoped_resource_reservation.h
index c5deca00b3..b160587c5d 100644
--- a/src/core/hle/kernel/k_scoped_resource_reservation.h
+++ b/src/core/hle/kernel/k_scoped_resource_reservation.h
@@ -15,8 +15,7 @@ namespace Kernel {
 
 class KScopedResourceReservation {
 public:
-    explicit KScopedResourceReservation(std::shared_ptr<KResourceLimit> l, LimitableResource r,
-                                        s64 v, s64 timeout)
+    explicit KScopedResourceReservation(KResourceLimit* l, LimitableResource r, s64 v, s64 timeout)
         : resource_limit(std::move(l)), value(v), resource(r) {
         if (resource_limit && value) {
             success = resource_limit->Reserve(resource, value, timeout);
@@ -25,8 +24,7 @@ public:
         }
     }
 
-    explicit KScopedResourceReservation(std::shared_ptr<KResourceLimit> l, LimitableResource r,
-                                        s64 v = 1)
+    explicit KScopedResourceReservation(KResourceLimit* l, LimitableResource r, s64 v = 1)
         : resource_limit(std::move(l)), value(v), resource(r) {
         if (resource_limit && value) {
             success = resource_limit->Reserve(resource, value);
@@ -58,7 +56,7 @@ public:
     }
 
 private:
-    std::shared_ptr<KResourceLimit> resource_limit;
+    KResourceLimit* resource_limit{};
     s64 value;
     LimitableResource resource;
     bool success;
diff --git a/src/core/hle/kernel/k_shared_memory.cpp b/src/core/hle/kernel/k_shared_memory.cpp
index 9e20c2350d..e91bc94bd0 100644
--- a/src/core/hle/kernel/k_shared_memory.cpp
+++ b/src/core/hle/kernel/k_shared_memory.cpp
@@ -8,6 +8,7 @@
 #include "core/hle/kernel/k_scoped_resource_reservation.h"
 #include "core/hle/kernel/k_shared_memory.h"
 #include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/svc_results.h"
 
 namespace Kernel {
 
@@ -22,12 +23,7 @@ ResultCode KSharedMemory::Initialize(KernelCore& kernel_, Core::DeviceMemory& de
                                      KMemoryPermission owner_permission_,
                                      KMemoryPermission user_permission_, PAddr physical_address_,
                                      std::size_t size_, std::string name_) {
-
-    resource_limit = kernel_.GetSystemResourceLimit();
-    KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory,
-                                                  size_);
-    ASSERT(memory_reservation.Succeeded());
-
+    // Set members.
     owner_process = owner_process_;
     device_memory = &device_memory_;
     page_list = std::move(page_list_);
@@ -36,9 +32,27 @@ ResultCode KSharedMemory::Initialize(KernelCore& kernel_, Core::DeviceMemory& de
     physical_address = physical_address_;
     size = size_;
     name = name_;
+
+    // Get the resource limit.
+    KResourceLimit* reslimit = kernel.GetSystemResourceLimit();
+
+    // Reserve memory for ourselves.
+    KScopedResourceReservation memory_reservation(reslimit, LimitableResource::PhysicalMemory,
+                                                  size_);
+    R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
+
+    // Commit our reservation.
+    memory_reservation.Commit();
+
+    // Set our resource limit.
+    resource_limit = reslimit;
+    resource_limit->Open();
+
+    // Mark initialized.
     is_initialized = true;
 
-    memory_reservation.Commit();
+    // Clear all pages in the memory.
+    std::memset(device_memory_.GetPointer(physical_address_), 0, size_);
 
     return RESULT_SUCCESS;
 }
diff --git a/src/core/hle/kernel/k_shared_memory.h b/src/core/hle/kernel/k_shared_memory.h
index aaa773bfc3..93153ab203 100644
--- a/src/core/hle/kernel/k_shared_memory.h
+++ b/src/core/hle/kernel/k_shared_memory.h
@@ -88,7 +88,7 @@ private:
     KMemoryPermission user_permission{};
     PAddr physical_address{};
     std::size_t size{};
-    std::shared_ptr<KResourceLimit> resource_limit;
+    KResourceLimit* resource_limit{};
     bool is_initialized{};
 };
 
diff --git a/src/core/hle/kernel/k_transfer_memory.h b/src/core/hle/kernel/k_transfer_memory.h
index f43725c7fa..3c3fa401b4 100644
--- a/src/core/hle/kernel/k_transfer_memory.h
+++ b/src/core/hle/kernel/k_transfer_memory.h
@@ -27,9 +27,7 @@ class KTransferMemory final
 
 public:
     explicit KTransferMemory(KernelCore& kernel);
-    ~KTransferMemory() override;
-
-    static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory;
+    virtual ~KTransferMemory() override;
 
     ResultCode Initialize(VAddr address_, std::size_t size_, Svc::MemoryPermission owner_perm_);
 
@@ -67,6 +65,7 @@ public:
         return GetTypeName();
     }
 
+    static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory;
     HandleType GetHandleType() const override {
         return HANDLE_TYPE;
     }
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 472c71cf1d..ada993f46d 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -74,8 +74,8 @@ struct KernelCore::Impl {
         Init::InitializeSlabHeaps(system, memory_layout);
 
         // Initialize kernel memory and resources.
-        InitializeMemoryLayout(memory_layout);
         InitializeSystemResourceLimit(kernel, system.CoreTiming(), memory_layout);
+        InitializeMemoryLayout(memory_layout);
         InitializePageSlab();
         InitializeSchedulers();
         InitializeSuspendThreads();
@@ -126,11 +126,19 @@ struct KernelCore::Impl {
 
         exclusive_monitor.reset();
 
+        hid_shared_mem->Close();
         hid_shared_mem = nullptr;
+
+        font_shared_mem->Close();
         font_shared_mem = nullptr;
+
+        irs_shared_mem->Close();
         irs_shared_mem = nullptr;
+
+        time_shared_mem->Close();
         time_shared_mem = nullptr;
 
+        system_resource_limit->Close();
         system_resource_limit = nullptr;
 
         // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
@@ -156,7 +164,9 @@ struct KernelCore::Impl {
     void InitializeSystemResourceLimit(KernelCore& kernel,
                                        const Core::Timing::CoreTiming& core_timing,
                                        const KMemoryLayout& memory_layout) {
-        system_resource_limit = std::make_shared<KResourceLimit>(kernel, core_timing);
+        system_resource_limit = KResourceLimit::Create(system.Kernel());
+        system_resource_limit->Initialize(&core_timing);
+
         const auto [total_size, kernel_size] = memory_layout.GetTotalAndKernelMemorySizes();
 
         // If setting the default system values fails, then something seriously wrong has occurred.
@@ -627,11 +637,11 @@ struct KernelCore::Impl {
 
     // Lists all processes that exist in the current session.
     std::vector<Process*> process_list;
-    Process* current_process = nullptr;
+    Process* current_process{};
     std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
     Kernel::TimeManager time_manager;
 
-    std::shared_ptr<KResourceLimit> system_resource_limit;
+    KResourceLimit* system_resource_limit{};
 
     std::shared_ptr<Core::Timing::EventType> preemption_event;
 
@@ -704,7 +714,11 @@ void KernelCore::Shutdown() {
     impl->Shutdown();
 }
 
-std::shared_ptr<KResourceLimit> KernelCore::GetSystemResourceLimit() const {
+const KResourceLimit* KernelCore::GetSystemResourceLimit() const {
+    return impl->system_resource_limit;
+}
+
+KResourceLimit* KernelCore::GetSystemResourceLimit() {
     return impl->system_resource_limit;
 }
 
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index f07f0276ed..43e49603ba 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -92,7 +92,10 @@ public:
     void Shutdown();
 
     /// Retrieves a shared pointer to the system resource limit instance.
-    std::shared_ptr<KResourceLimit> GetSystemResourceLimit() const;
+    const KResourceLimit* GetSystemResourceLimit() const;
+
+    /// Retrieves a shared pointer to the system resource limit instance.
+    KResourceLimit* GetSystemResourceLimit();
 
     /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
     KScopedAutoObject<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
@@ -263,24 +266,26 @@ public:
     /// Gets the slab heap for the specified kernel object type.
     template <typename T>
     KSlabHeap<T>& SlabHeap() {
-        if constexpr (std::is_same_v<T, Process>) {
-            return slab_heap_container->process;
-        } else if constexpr (std::is_same_v<T, KThread>) {
-            return slab_heap_container->thread;
+        if constexpr (std::is_same_v<T, KClientSession>) {
+            return slab_heap_container->client_session;
         } else if constexpr (std::is_same_v<T, KEvent>) {
             return slab_heap_container->event;
-        } else if constexpr (std::is_same_v<T, KSharedMemory>) {
-            return slab_heap_container->shared_memory;
         } else if constexpr (std::is_same_v<T, KLinkedListNode>) {
             return slab_heap_container->linked_list_node;
-        } else if constexpr (std::is_same_v<T, KWritableEvent>) {
-            return slab_heap_container->writeable_event;
-        } else if constexpr (std::is_same_v<T, KClientSession>) {
-            return slab_heap_container->client_session;
+        } else if constexpr (std::is_same_v<T, Process>) {
+            return slab_heap_container->process;
+        } else if constexpr (std::is_same_v<T, KResourceLimit>) {
+            return slab_heap_container->resource_limit;
         } else if constexpr (std::is_same_v<T, KSession>) {
             return slab_heap_container->session;
+        } else if constexpr (std::is_same_v<T, KSharedMemory>) {
+            return slab_heap_container->shared_memory;
+        } else if constexpr (std::is_same_v<T, KThread>) {
+            return slab_heap_container->thread;
         } else if constexpr (std::is_same_v<T, KTransferMemory>) {
             return slab_heap_container->transfer_memory;
+        } else if constexpr (std::is_same_v<T, KWritableEvent>) {
+            return slab_heap_container->writeable_event;
         }
     }
 
@@ -315,15 +320,16 @@ private:
 private:
     /// Helper to encapsulate all slab heaps in a single heap allocated container
     struct SlabHeapContainer {
-        KSlabHeap<Process> process;
-        KSlabHeap<KThread> thread;
-        KSlabHeap<KEvent> event;
-        KSlabHeap<KSharedMemory> shared_memory;
-        KSlabHeap<KLinkedListNode> linked_list_node;
-        KSlabHeap<KWritableEvent> writeable_event;
         KSlabHeap<KClientSession> client_session;
+        KSlabHeap<KEvent> event;
+        KSlabHeap<KLinkedListNode> linked_list_node;
+        KSlabHeap<Process> process;
+        KSlabHeap<KResourceLimit> resource_limit;
         KSlabHeap<KSession> session;
+        KSlabHeap<KSharedMemory> shared_memory;
+        KSlabHeap<KThread> thread;
         KSlabHeap<KTransferMemory> transfer_memory;
+        KSlabHeap<KWritableEvent> writeable_event;
     };
 
     std::unique_ptr<SlabHeapContainer> slab_heap_container;
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 6780379231..315640bea8 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -138,10 +138,13 @@ ResultCode Process::Initialize(Process* process, Core::System& system, std::stri
 
     kernel.AppendNewProcess(process);
 
+    // Open a reference to the resource limit.
+    process->resource_limit->Open();
+
     return RESULT_SUCCESS;
 }
 
-std::shared_ptr<KResourceLimit> Process::GetResourceLimit() const {
+KResourceLimit* Process::GetResourceLimit() const {
     return resource_limit;
 }
 
@@ -166,7 +169,10 @@ u64 Process::GetTotalPhysicalMemoryAvailable() const {
     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 (const auto pool_size = kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application);
+        capacity != pool_size) {
+        LOG_WARNING(Kernel, "capacity {} != application pool size {}", capacity, pool_size);
+    }
     if (capacity < memory_usage_capacity) {
         return capacity;
     }
@@ -371,6 +377,16 @@ void Process::PrepareForTermination() {
     ChangeStatus(ProcessStatus::Exited);
 }
 
+void Process::Finalize() {
+    // Release memory to the resource limit.
+    if (resource_limit != nullptr) {
+        resource_limit->Close();
+    }
+
+    // Perform inherited finalization.
+    KAutoObjectWithSlabHeapAndContainer<Process, KSynchronizationObject>::Finalize();
+}
+
 /**
  * Attempts to find a TLS page that contains a free slot for
  * use by a thread.
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index df3c7997d6..35fe164338 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -171,7 +171,7 @@ public:
     }
 
     /// Gets the resource limit descriptor for this process
-    std::shared_ptr<KResourceLimit> GetResourceLimit() const;
+    KResourceLimit* GetResourceLimit() const;
 
     /// Gets the ideal CPU core ID for this process
     u8 GetIdealCoreId() const {
@@ -348,9 +348,7 @@ public:
 
     static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
 
-    virtual void Finalize() override {
-        UNIMPLEMENTED();
-    }
+    virtual void Finalize();
 
     virtual u64 GetId() const override final {
         return GetProcessID();
@@ -415,7 +413,7 @@ private:
     u32 system_resource_size = 0;
 
     /// Resource limit descriptor for this process
-    std::shared_ptr<KResourceLimit> resource_limit;
+    KResourceLimit* resource_limit{};
 
     /// The ideal CPU core for this process, threads are scheduled on this core by default.
     u8 ideal_core = 0;
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 9e8184758a..a78bfd1dab 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -153,9 +153,9 @@ ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_
     const auto* const current_process = system.Kernel().CurrentProcess();
     ASSERT(current_process != nullptr);
 
-    const auto resource_limit_object =
-        current_process->GetHandleTable().Get<KResourceLimit>(resource_limit);
-    if (!resource_limit_object) {
+    auto resource_limit_object =
+        current_process->GetHandleTable().GetObject<KResourceLimit>(resource_limit);
+    if (resource_limit_object.IsNull()) {
         LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
                   resource_limit);
         return ResultInvalidHandle;
@@ -843,12 +843,10 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle
             return RESULT_SUCCESS;
         }
 
-        const auto table_result = handle_table.Create(resource_limit.get());
-        if (table_result.Failed()) {
-            return table_result.Code();
-        }
+        Handle handle{};
+        R_TRY(handle_table.Add(&handle, resource_limit));
 
-        *result = *table_result;
+        *result = handle;
         return RESULT_SUCCESS;
     }
 
@@ -2093,83 +2091,86 @@ static ResultCode GetProcessInfo(Core::System& system, u64* out, Handle process_
 }
 
 static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle) {
-    std::lock_guard lock{HLE::g_hle_lock};
     LOG_DEBUG(Kernel_SVC, "called");
 
+    // Create a new resource limit.
     auto& kernel = system.Kernel();
-    auto resource_limit = std::make_shared<KResourceLimit>(kernel, system.CoreTiming());
+    KResourceLimit* resource_limit = KResourceLimit::Create(kernel);
+    R_UNLESS(resource_limit != nullptr, ResultOutOfResource);
 
-    auto* const current_process = kernel.CurrentProcess();
-    ASSERT(current_process != nullptr);
+    // Ensure we don't leak a reference to the limit.
+    SCOPE_EXIT({ resource_limit->Close(); });
 
-    const auto handle = current_process->GetHandleTable().Create(resource_limit.get());
-    if (handle.Failed()) {
-        return handle.Code();
-    }
+    // Initialize the resource limit.
+    resource_limit->Initialize(&system.CoreTiming());
+
+    // Register the limit.
+    KResourceLimit::Register(kernel, resource_limit);
+
+    // Add the limit to the handle table.
+    R_TRY(kernel.CurrentProcess()->GetHandleTable().Add(out_handle, resource_limit));
 
-    *out_handle = *handle;
     return RESULT_SUCCESS;
 }
 
-static ResultCode GetResourceLimitLimitValue(Core::System& system, u64* out_value,
-                                             Handle resource_limit, u32 resource_type) {
-    LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type);
+static ResultCode GetResourceLimitLimitValue(Core::System& system, u64* out_limit_value,
+                                             Handle resource_limit_handle,
+                                             LimitableResource which) {
+    LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle,
+              which);
 
-    const auto limit_value = RetrieveResourceLimitValue(system, resource_limit, resource_type,
-                                                        ResourceLimitValueType::LimitValue);
-    if (limit_value.Failed()) {
-        return limit_value.Code();
-    }
+    // Validate the resource.
+    R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
+
+    // Get the resource limit.
+    auto& kernel = system.Kernel();
+    KScopedAutoObject resource_limit =
+        kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle);
+    R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
+
+    // Get the limit value.
+    *out_limit_value = resource_limit->GetLimitValue(which);
 
-    *out_value = static_cast<u64>(*limit_value);
     return RESULT_SUCCESS;
 }
 
-static ResultCode GetResourceLimitCurrentValue(Core::System& system, u64* out_value,
-                                               Handle resource_limit, u32 resource_type) {
-    LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type);
+static ResultCode GetResourceLimitCurrentValue(Core::System& system, u64* out_current_value,
+                                               Handle resource_limit_handle,
+                                               LimitableResource which) {
+    LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}", resource_limit_handle,
+              which);
 
-    const auto current_value = RetrieveResourceLimitValue(system, resource_limit, resource_type,
-                                                          ResourceLimitValueType::CurrentValue);
-    if (current_value.Failed()) {
-        return current_value.Code();
-    }
+    // Validate the resource.
+    R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
+
+    // Get the resource limit.
+    auto& kernel = system.Kernel();
+    KScopedAutoObject resource_limit =
+        kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle);
+    R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
+
+    // Get the current value.
+    *out_current_value = resource_limit->GetCurrentValue(which);
 
-    *out_value = static_cast<u64>(*current_value);
     return RESULT_SUCCESS;
 }
 
-static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resource_limit,
-                                             u32 resource_type, u64 value) {
-    LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit,
-              resource_type, value);
+static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resource_limit_handle,
+                                             LimitableResource which, u64 limit_value) {
+    LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}, limit_value={}",
+              resource_limit_handle, which, limit_value);
 
-    const auto type = static_cast<LimitableResource>(resource_type);
-    if (!IsValidResourceType(type)) {
-        LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
-        return ResultInvalidEnumValue;
-    }
+    // Validate the resource.
+    R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
 
-    auto* const current_process = system.Kernel().CurrentProcess();
-    ASSERT(current_process != nullptr);
+    // Get the resource limit.
+    auto& kernel = system.Kernel();
+    KScopedAutoObject resource_limit =
+        kernel.CurrentProcess()->GetHandleTable().GetObject<KResourceLimit>(resource_limit_handle);
+    R_UNLESS(resource_limit.IsNotNull(), ResultInvalidHandle);
 
-    auto resource_limit_object =
-        current_process->GetHandleTable().Get<KResourceLimit>(resource_limit);
-    if (!resource_limit_object) {
-        LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
-                  resource_limit);
-        return ResultInvalidHandle;
-    }
-
-    const auto set_result = resource_limit_object->SetLimitValue(type, static_cast<s64>(value));
-    if (set_result.IsError()) {
-        LOG_ERROR(Kernel_SVC,
-                  "Attempted to lower resource limit ({}) for category '{}' below its current "
-                  "value ({})",
-                  resource_limit_object->GetLimitValue(type), resource_type,
-                  resource_limit_object->GetCurrentValue(type));
-        return set_result;
-    }
+    // Set the limit value.
+    R_TRY(resource_limit->SetLimitValue(which, limit_value));
 
     return RESULT_SUCCESS;
 }
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index 61986bb526..d3df25d0fa 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -154,15 +154,28 @@ void SvcWrap64(Core::System& system) {
     FuncReturn(system, retval);
 }
 
+// Used by GetResourceLimitLimitValue.
+template <ResultCode func(Core::System&, u64*, Handle, LimitableResource)>
+void SvcWrap64(Core::System& system) {
+    u64 param_1 = 0;
+    const u32 retval = func(system, &param_1, static_cast<Handle>(Param(system, 1)),
+                            static_cast<LimitableResource>(Param(system, 2)))
+                           .raw;
+
+    system.CurrentArmInterface().SetReg(1, param_1);
+    FuncReturn(system, retval);
+}
+
 template <ResultCode func(Core::System&, u32, u64)>
 void SvcWrap64(Core::System& system) {
     FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1)).raw);
 }
 
-template <ResultCode func(Core::System&, u32, u32, u64)>
+// Used by SetResourceLimitLimitValue
+template <ResultCode func(Core::System&, Handle, LimitableResource, u64)>
 void SvcWrap64(Core::System& system) {
-    FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)),
-                            static_cast<u32>(Param(system, 1)), Param(system, 2))
+    FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)),
+                            static_cast<LimitableResource>(Param(system, 1)), Param(system, 2))
                            .raw);
 }