hle: kernel: Migrate KResourceLimit to KAutoObject.
This commit is contained in:
parent
674122038a
commit
b57c5a9b54
13 changed files with 198 additions and 123 deletions
|
@ -12,11 +12,12 @@
|
||||||
#include "core/hle/kernel/k_event.h"
|
#include "core/hle/kernel/k_event.h"
|
||||||
#include "core/hle/kernel/k_memory_layout.h"
|
#include "core/hle/kernel/k_memory_layout.h"
|
||||||
#include "core/hle/kernel/k_memory_manager.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_session.h"
|
||||||
#include "core/hle/kernel/k_shared_memory.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_system_control.h"
|
||||||
#include "core/hle/kernel/k_thread.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/memory_types.h"
|
||||||
#include "core/hle/kernel/process.h"
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
@ -31,7 +32,8 @@ namespace Kernel::Init {
|
||||||
HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \
|
HANDLER(KEvent, (SLAB_COUNT(KEvent)), ##__VA_ARGS__) \
|
||||||
HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \
|
HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \
|
||||||
HANDLER(KSharedMemory, (SLAB_COUNT(KSharedMemory)), ##__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 {
|
namespace {
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,16 @@
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
constexpr s64 DefaultTimeout = 10000000000; // 10 seconds
|
constexpr s64 DefaultTimeout = 10000000000; // 10 seconds
|
||||||
|
|
||||||
KResourceLimit::KResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing_)
|
KResourceLimit::KResourceLimit(KernelCore& kernel)
|
||||||
: Object{kernel}, lock{kernel}, cond_var{kernel}, core_timing(core_timing_) {}
|
: KAutoObjectWithSlabHeapAndContainer{kernel}, lock{kernel}, cond_var{kernel} {}
|
||||||
KResourceLimit::~KResourceLimit() = default;
|
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 {
|
s64 KResourceLimit::GetLimitValue(LimitableResource which) const {
|
||||||
const auto index = static_cast<std::size_t>(which);
|
const auto index = static_cast<std::size_t>(which);
|
||||||
s64 value{};
|
s64 value{};
|
||||||
|
@ -78,7 +84,7 @@ ResultCode KResourceLimit::SetLimitValue(LimitableResource which, s64 value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KResourceLimit::Reserve(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) {
|
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] &&
|
if (current_hints[index] + value <= limit_values[index] &&
|
||||||
(timeout < 0 || core_timing.GetGlobalTimeNs().count() < timeout)) {
|
(timeout < 0 || core_timing->GetGlobalTimeNs().count() < timeout)) {
|
||||||
waiter_count++;
|
waiter_count++;
|
||||||
cond_var.Wait(&lock, timeout);
|
cond_var.Wait(&lock, timeout);
|
||||||
waiter_count--;
|
waiter_count--;
|
||||||
|
|
|
@ -32,10 +32,16 @@ constexpr bool IsValidResourceType(LimitableResource type) {
|
||||||
return type < LimitableResource::Count;
|
return type < LimitableResource::Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
class KResourceLimit final : public Object {
|
class KResourceLimit final
|
||||||
|
: public KAutoObjectWithSlabHeapAndContainer<KResourceLimit, KAutoObjectWithList> {
|
||||||
|
KERNEL_AUTOOBJECT_TRAITS(KResourceLimit, KAutoObject);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit KResourceLimit(KernelCore& kernel, const Core::Timing::CoreTiming& core_timing_);
|
explicit KResourceLimit(KernelCore& kernel);
|
||||||
~KResourceLimit();
|
virtual ~KResourceLimit();
|
||||||
|
|
||||||
|
void Initialize(const Core::Timing::CoreTiming* core_timing_);
|
||||||
|
virtual void Finalize() override;
|
||||||
|
|
||||||
s64 GetLimitValue(LimitableResource which) const;
|
s64 GetLimitValue(LimitableResource which) const;
|
||||||
s64 GetCurrentValue(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);
|
||||||
void Release(LimitableResource which, s64 value, s64 hint);
|
void Release(LimitableResource which, s64 value, s64 hint);
|
||||||
|
|
||||||
|
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
|
||||||
|
|
||||||
|
// DEPRECATED
|
||||||
|
|
||||||
std::string GetTypeName() const override {
|
std::string GetTypeName() const override {
|
||||||
return "KResourceLimit";
|
return "KResourceLimit";
|
||||||
}
|
}
|
||||||
|
@ -61,8 +71,6 @@ public:
|
||||||
return HANDLE_TYPE;
|
return HANDLE_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Finalize() override {}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using ResourceArray = std::array<s64, static_cast<std::size_t>(LimitableResource::Count)>;
|
using ResourceArray = std::array<s64, static_cast<std::size_t>(LimitableResource::Count)>;
|
||||||
ResourceArray limit_values{};
|
ResourceArray limit_values{};
|
||||||
|
@ -72,6 +80,6 @@ private:
|
||||||
mutable KLightLock lock;
|
mutable KLightLock lock;
|
||||||
s32 waiter_count{};
|
s32 waiter_count{};
|
||||||
KLightConditionVariable cond_var;
|
KLightConditionVariable cond_var;
|
||||||
const Core::Timing::CoreTiming& core_timing;
|
const Core::Timing::CoreTiming* core_timing{};
|
||||||
};
|
};
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -15,8 +15,7 @@ namespace Kernel {
|
||||||
|
|
||||||
class KScopedResourceReservation {
|
class KScopedResourceReservation {
|
||||||
public:
|
public:
|
||||||
explicit KScopedResourceReservation(std::shared_ptr<KResourceLimit> l, LimitableResource r,
|
explicit KScopedResourceReservation(KResourceLimit* l, LimitableResource r, s64 v, s64 timeout)
|
||||||
s64 v, s64 timeout)
|
|
||||||
: resource_limit(std::move(l)), value(v), resource(r) {
|
: resource_limit(std::move(l)), value(v), resource(r) {
|
||||||
if (resource_limit && value) {
|
if (resource_limit && value) {
|
||||||
success = resource_limit->Reserve(resource, value, timeout);
|
success = resource_limit->Reserve(resource, value, timeout);
|
||||||
|
@ -25,8 +24,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit KScopedResourceReservation(std::shared_ptr<KResourceLimit> l, LimitableResource r,
|
explicit KScopedResourceReservation(KResourceLimit* l, LimitableResource r, s64 v = 1)
|
||||||
s64 v = 1)
|
|
||||||
: resource_limit(std::move(l)), value(v), resource(r) {
|
: resource_limit(std::move(l)), value(v), resource(r) {
|
||||||
if (resource_limit && value) {
|
if (resource_limit && value) {
|
||||||
success = resource_limit->Reserve(resource, value);
|
success = resource_limit->Reserve(resource, value);
|
||||||
|
@ -58,7 +56,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<KResourceLimit> resource_limit;
|
KResourceLimit* resource_limit{};
|
||||||
s64 value;
|
s64 value;
|
||||||
LimitableResource resource;
|
LimitableResource resource;
|
||||||
bool success;
|
bool success;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "core/hle/kernel/k_scoped_resource_reservation.h"
|
#include "core/hle/kernel/k_scoped_resource_reservation.h"
|
||||||
#include "core/hle/kernel/k_shared_memory.h"
|
#include "core/hle/kernel/k_shared_memory.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
#include "core/hle/kernel/svc_results.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
@ -22,12 +23,7 @@ ResultCode KSharedMemory::Initialize(KernelCore& kernel_, Core::DeviceMemory& de
|
||||||
KMemoryPermission owner_permission_,
|
KMemoryPermission owner_permission_,
|
||||||
KMemoryPermission user_permission_, PAddr physical_address_,
|
KMemoryPermission user_permission_, PAddr physical_address_,
|
||||||
std::size_t size_, std::string name_) {
|
std::size_t size_, std::string name_) {
|
||||||
|
// Set members.
|
||||||
resource_limit = kernel_.GetSystemResourceLimit();
|
|
||||||
KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory,
|
|
||||||
size_);
|
|
||||||
ASSERT(memory_reservation.Succeeded());
|
|
||||||
|
|
||||||
owner_process = owner_process_;
|
owner_process = owner_process_;
|
||||||
device_memory = &device_memory_;
|
device_memory = &device_memory_;
|
||||||
page_list = std::move(page_list_);
|
page_list = std::move(page_list_);
|
||||||
|
@ -36,9 +32,27 @@ ResultCode KSharedMemory::Initialize(KernelCore& kernel_, Core::DeviceMemory& de
|
||||||
physical_address = physical_address_;
|
physical_address = physical_address_;
|
||||||
size = size_;
|
size = size_;
|
||||||
name = name_;
|
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;
|
is_initialized = true;
|
||||||
|
|
||||||
memory_reservation.Commit();
|
// Clear all pages in the memory.
|
||||||
|
std::memset(device_memory_.GetPointer(physical_address_), 0, size_);
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ private:
|
||||||
KMemoryPermission user_permission{};
|
KMemoryPermission user_permission{};
|
||||||
PAddr physical_address{};
|
PAddr physical_address{};
|
||||||
std::size_t size{};
|
std::size_t size{};
|
||||||
std::shared_ptr<KResourceLimit> resource_limit;
|
KResourceLimit* resource_limit{};
|
||||||
bool is_initialized{};
|
bool is_initialized{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -27,9 +27,7 @@ class KTransferMemory final
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit KTransferMemory(KernelCore& kernel);
|
explicit KTransferMemory(KernelCore& kernel);
|
||||||
~KTransferMemory() override;
|
virtual ~KTransferMemory() override;
|
||||||
|
|
||||||
static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory;
|
|
||||||
|
|
||||||
ResultCode Initialize(VAddr address_, std::size_t size_, Svc::MemoryPermission owner_perm_);
|
ResultCode Initialize(VAddr address_, std::size_t size_, Svc::MemoryPermission owner_perm_);
|
||||||
|
|
||||||
|
@ -67,6 +65,7 @@ public:
|
||||||
return GetTypeName();
|
return GetTypeName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory;
|
||||||
HandleType GetHandleType() const override {
|
HandleType GetHandleType() const override {
|
||||||
return HANDLE_TYPE;
|
return HANDLE_TYPE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,8 +74,8 @@ struct KernelCore::Impl {
|
||||||
Init::InitializeSlabHeaps(system, memory_layout);
|
Init::InitializeSlabHeaps(system, memory_layout);
|
||||||
|
|
||||||
// Initialize kernel memory and resources.
|
// Initialize kernel memory and resources.
|
||||||
InitializeMemoryLayout(memory_layout);
|
|
||||||
InitializeSystemResourceLimit(kernel, system.CoreTiming(), memory_layout);
|
InitializeSystemResourceLimit(kernel, system.CoreTiming(), memory_layout);
|
||||||
|
InitializeMemoryLayout(memory_layout);
|
||||||
InitializePageSlab();
|
InitializePageSlab();
|
||||||
InitializeSchedulers();
|
InitializeSchedulers();
|
||||||
InitializeSuspendThreads();
|
InitializeSuspendThreads();
|
||||||
|
@ -126,11 +126,19 @@ struct KernelCore::Impl {
|
||||||
|
|
||||||
exclusive_monitor.reset();
|
exclusive_monitor.reset();
|
||||||
|
|
||||||
|
hid_shared_mem->Close();
|
||||||
hid_shared_mem = nullptr;
|
hid_shared_mem = nullptr;
|
||||||
|
|
||||||
|
font_shared_mem->Close();
|
||||||
font_shared_mem = nullptr;
|
font_shared_mem = nullptr;
|
||||||
|
|
||||||
|
irs_shared_mem->Close();
|
||||||
irs_shared_mem = nullptr;
|
irs_shared_mem = nullptr;
|
||||||
|
|
||||||
|
time_shared_mem->Close();
|
||||||
time_shared_mem = nullptr;
|
time_shared_mem = nullptr;
|
||||||
|
|
||||||
|
system_resource_limit->Close();
|
||||||
system_resource_limit = nullptr;
|
system_resource_limit = nullptr;
|
||||||
|
|
||||||
// Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
|
// 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,
|
void InitializeSystemResourceLimit(KernelCore& kernel,
|
||||||
const Core::Timing::CoreTiming& core_timing,
|
const Core::Timing::CoreTiming& core_timing,
|
||||||
const KMemoryLayout& memory_layout) {
|
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();
|
const auto [total_size, kernel_size] = memory_layout.GetTotalAndKernelMemorySizes();
|
||||||
|
|
||||||
// If setting the default system values fails, then something seriously wrong has occurred.
|
// 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.
|
// Lists all processes that exist in the current session.
|
||||||
std::vector<Process*> process_list;
|
std::vector<Process*> process_list;
|
||||||
Process* current_process = nullptr;
|
Process* current_process{};
|
||||||
std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
|
std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
|
||||||
Kernel::TimeManager time_manager;
|
Kernel::TimeManager time_manager;
|
||||||
|
|
||||||
std::shared_ptr<KResourceLimit> system_resource_limit;
|
KResourceLimit* system_resource_limit{};
|
||||||
|
|
||||||
std::shared_ptr<Core::Timing::EventType> preemption_event;
|
std::shared_ptr<Core::Timing::EventType> preemption_event;
|
||||||
|
|
||||||
|
@ -704,7 +714,11 @@ void KernelCore::Shutdown() {
|
||||||
impl->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;
|
return impl->system_resource_limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,10 @@ public:
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
/// Retrieves a shared pointer to the system resource limit instance.
|
/// 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.
|
/// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
|
||||||
KScopedAutoObject<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
|
KScopedAutoObject<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
|
||||||
|
@ -263,24 +266,26 @@ public:
|
||||||
/// Gets the slab heap for the specified kernel object type.
|
/// Gets the slab heap for the specified kernel object type.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
KSlabHeap<T>& SlabHeap() {
|
KSlabHeap<T>& SlabHeap() {
|
||||||
if constexpr (std::is_same_v<T, Process>) {
|
if constexpr (std::is_same_v<T, KClientSession>) {
|
||||||
return slab_heap_container->process;
|
return slab_heap_container->client_session;
|
||||||
} else if constexpr (std::is_same_v<T, KThread>) {
|
|
||||||
return slab_heap_container->thread;
|
|
||||||
} else if constexpr (std::is_same_v<T, KEvent>) {
|
} else if constexpr (std::is_same_v<T, KEvent>) {
|
||||||
return slab_heap_container->event;
|
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>) {
|
} else if constexpr (std::is_same_v<T, KLinkedListNode>) {
|
||||||
return slab_heap_container->linked_list_node;
|
return slab_heap_container->linked_list_node;
|
||||||
} else if constexpr (std::is_same_v<T, KWritableEvent>) {
|
} else if constexpr (std::is_same_v<T, Process>) {
|
||||||
return slab_heap_container->writeable_event;
|
return slab_heap_container->process;
|
||||||
} else if constexpr (std::is_same_v<T, KClientSession>) {
|
} else if constexpr (std::is_same_v<T, KResourceLimit>) {
|
||||||
return slab_heap_container->client_session;
|
return slab_heap_container->resource_limit;
|
||||||
} else if constexpr (std::is_same_v<T, KSession>) {
|
} else if constexpr (std::is_same_v<T, KSession>) {
|
||||||
return slab_heap_container->session;
|
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>) {
|
} else if constexpr (std::is_same_v<T, KTransferMemory>) {
|
||||||
return slab_heap_container->transfer_memory;
|
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:
|
private:
|
||||||
/// Helper to encapsulate all slab heaps in a single heap allocated container
|
/// Helper to encapsulate all slab heaps in a single heap allocated container
|
||||||
struct SlabHeapContainer {
|
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<KClientSession> client_session;
|
||||||
|
KSlabHeap<KEvent> event;
|
||||||
|
KSlabHeap<KLinkedListNode> linked_list_node;
|
||||||
|
KSlabHeap<Process> process;
|
||||||
|
KSlabHeap<KResourceLimit> resource_limit;
|
||||||
KSlabHeap<KSession> session;
|
KSlabHeap<KSession> session;
|
||||||
|
KSlabHeap<KSharedMemory> shared_memory;
|
||||||
|
KSlabHeap<KThread> thread;
|
||||||
KSlabHeap<KTransferMemory> transfer_memory;
|
KSlabHeap<KTransferMemory> transfer_memory;
|
||||||
|
KSlabHeap<KWritableEvent> writeable_event;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<SlabHeapContainer> slab_heap_container;
|
std::unique_ptr<SlabHeapContainer> slab_heap_container;
|
||||||
|
|
|
@ -138,10 +138,13 @@ ResultCode Process::Initialize(Process* process, Core::System& system, std::stri
|
||||||
|
|
||||||
kernel.AppendNewProcess(process);
|
kernel.AppendNewProcess(process);
|
||||||
|
|
||||||
|
// Open a reference to the resource limit.
|
||||||
|
process->resource_limit->Open();
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<KResourceLimit> Process::GetResourceLimit() const {
|
KResourceLimit* Process::GetResourceLimit() const {
|
||||||
return resource_limit;
|
return resource_limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +169,10 @@ u64 Process::GetTotalPhysicalMemoryAvailable() const {
|
||||||
const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) +
|
const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) +
|
||||||
page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
|
page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
|
||||||
main_thread_stack_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) {
|
if (capacity < memory_usage_capacity) {
|
||||||
return capacity;
|
return capacity;
|
||||||
}
|
}
|
||||||
|
@ -371,6 +377,16 @@ void Process::PrepareForTermination() {
|
||||||
ChangeStatus(ProcessStatus::Exited);
|
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
|
* Attempts to find a TLS page that contains a free slot for
|
||||||
* use by a thread.
|
* use by a thread.
|
||||||
|
|
|
@ -171,7 +171,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the resource limit descriptor for this process
|
/// 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
|
/// Gets the ideal CPU core ID for this process
|
||||||
u8 GetIdealCoreId() const {
|
u8 GetIdealCoreId() const {
|
||||||
|
@ -348,9 +348,7 @@ public:
|
||||||
|
|
||||||
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
|
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
|
||||||
|
|
||||||
virtual void Finalize() override {
|
virtual void Finalize();
|
||||||
UNIMPLEMENTED();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual u64 GetId() const override final {
|
virtual u64 GetId() const override final {
|
||||||
return GetProcessID();
|
return GetProcessID();
|
||||||
|
@ -415,7 +413,7 @@ private:
|
||||||
u32 system_resource_size = 0;
|
u32 system_resource_size = 0;
|
||||||
|
|
||||||
/// Resource limit descriptor for this process
|
/// 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.
|
/// The ideal CPU core for this process, threads are scheduled on this core by default.
|
||||||
u8 ideal_core = 0;
|
u8 ideal_core = 0;
|
||||||
|
|
|
@ -153,9 +153,9 @@ ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_
|
||||||
const auto* const current_process = system.Kernel().CurrentProcess();
|
const auto* const current_process = system.Kernel().CurrentProcess();
|
||||||
ASSERT(current_process != nullptr);
|
ASSERT(current_process != nullptr);
|
||||||
|
|
||||||
const auto resource_limit_object =
|
auto resource_limit_object =
|
||||||
current_process->GetHandleTable().Get<KResourceLimit>(resource_limit);
|
current_process->GetHandleTable().GetObject<KResourceLimit>(resource_limit);
|
||||||
if (!resource_limit_object) {
|
if (resource_limit_object.IsNull()) {
|
||||||
LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
|
LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
|
||||||
resource_limit);
|
resource_limit);
|
||||||
return ResultInvalidHandle;
|
return ResultInvalidHandle;
|
||||||
|
@ -843,12 +843,10 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto table_result = handle_table.Create(resource_limit.get());
|
Handle handle{};
|
||||||
if (table_result.Failed()) {
|
R_TRY(handle_table.Add(&handle, resource_limit));
|
||||||
return table_result.Code();
|
|
||||||
}
|
|
||||||
|
|
||||||
*result = *table_result;
|
*result = handle;
|
||||||
return RESULT_SUCCESS;
|
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) {
|
static ResultCode CreateResourceLimit(Core::System& system, Handle* out_handle) {
|
||||||
std::lock_guard lock{HLE::g_hle_lock};
|
|
||||||
LOG_DEBUG(Kernel_SVC, "called");
|
LOG_DEBUG(Kernel_SVC, "called");
|
||||||
|
|
||||||
|
// Create a new resource limit.
|
||||||
auto& kernel = system.Kernel();
|
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();
|
// Ensure we don't leak a reference to the limit.
|
||||||
ASSERT(current_process != nullptr);
|
SCOPE_EXIT({ resource_limit->Close(); });
|
||||||
|
|
||||||
const auto handle = current_process->GetHandleTable().Create(resource_limit.get());
|
// Initialize the resource limit.
|
||||||
if (handle.Failed()) {
|
resource_limit->Initialize(&system.CoreTiming());
|
||||||
return handle.Code();
|
|
||||||
}
|
// 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;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode GetResourceLimitLimitValue(Core::System& system, u64* out_value,
|
static ResultCode GetResourceLimitLimitValue(Core::System& system, u64* out_limit_value,
|
||||||
Handle resource_limit, u32 resource_type) {
|
Handle resource_limit_handle,
|
||||||
LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type);
|
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,
|
// Validate the resource.
|
||||||
ResourceLimitValueType::LimitValue);
|
R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
|
||||||
if (limit_value.Failed()) {
|
|
||||||
return limit_value.Code();
|
// 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;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode GetResourceLimitCurrentValue(Core::System& system, u64* out_value,
|
static ResultCode GetResourceLimitCurrentValue(Core::System& system, u64* out_current_value,
|
||||||
Handle resource_limit, u32 resource_type) {
|
Handle resource_limit_handle,
|
||||||
LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type);
|
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,
|
// Validate the resource.
|
||||||
ResourceLimitValueType::CurrentValue);
|
R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
|
||||||
if (current_value.Failed()) {
|
|
||||||
return current_value.Code();
|
// 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;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resource_limit,
|
static ResultCode SetResourceLimitLimitValue(Core::System& system, Handle resource_limit_handle,
|
||||||
u32 resource_type, u64 value) {
|
LimitableResource which, u64 limit_value) {
|
||||||
LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit,
|
LOG_DEBUG(Kernel_SVC, "called, resource_limit_handle={:08X}, which={}, limit_value={}",
|
||||||
resource_type, value);
|
resource_limit_handle, which, limit_value);
|
||||||
|
|
||||||
const auto type = static_cast<LimitableResource>(resource_type);
|
// Validate the resource.
|
||||||
if (!IsValidResourceType(type)) {
|
R_UNLESS(IsValidResourceType(which), ResultInvalidEnumValue);
|
||||||
LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
|
|
||||||
return ResultInvalidEnumValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* const current_process = system.Kernel().CurrentProcess();
|
// Get the resource limit.
|
||||||
ASSERT(current_process != nullptr);
|
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 =
|
// Set the limit value.
|
||||||
current_process->GetHandleTable().Get<KResourceLimit>(resource_limit);
|
R_TRY(resource_limit->SetLimitValue(which, limit_value));
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,15 +154,28 @@ void SvcWrap64(Core::System& system) {
|
||||||
FuncReturn(system, retval);
|
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, ¶m_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)>
|
template <ResultCode func(Core::System&, u32, u64)>
|
||||||
void SvcWrap64(Core::System& system) {
|
void SvcWrap64(Core::System& system) {
|
||||||
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)), Param(system, 1)).raw);
|
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) {
|
void SvcWrap64(Core::System& system) {
|
||||||
FuncReturn(system, func(system, static_cast<u32>(Param(system, 0)),
|
FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)),
|
||||||
static_cast<u32>(Param(system, 1)), Param(system, 2))
|
static_cast<LimitableResource>(Param(system, 1)), Param(system, 2))
|
||||||
.raw);
|
.raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue