kernel: More accurately reserve and release resources

This commit is contained in:
ameerj 2021-02-12 19:05:24 -05:00
parent 5fa6b15215
commit ec9b6641b1
6 changed files with 42 additions and 14 deletions

View File

@ -141,11 +141,17 @@ struct KernelCore::Impl {
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 700).IsSuccess()); ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 700).IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200) ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200)
.IsSuccess()); .IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 900).IsSuccess()); ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 933).IsSuccess());
if (!system_resource_limit->Reserve(LimitableResource::PhysicalMemory, 0x60000)) { // Derived from recent software updates. The kernel reserves 27MB
constexpr u64 kernel_size{0x1b00000};
if (!system_resource_limit->Reserve(LimitableResource::PhysicalMemory, kernel_size)) {
UNREACHABLE(); UNREACHABLE();
} }
// Reserve secure applet memory, introduced in firmware 5.0.0
constexpr u64 secure_applet_memory_size{0x400000};
ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory,
secure_applet_memory_size));
} }
void InitializePreemption(KernelCore& kernel) { void InitializePreemption(KernelCore& kernel) {
@ -302,8 +308,11 @@ struct KernelCore::Impl {
// Allocate slab heaps // Allocate slab heaps
user_slab_heap_pages = std::make_unique<Memory::SlabHeap<Memory::Page>>(); user_slab_heap_pages = std::make_unique<Memory::SlabHeap<Memory::Page>>();
constexpr u64 user_slab_heap_size{0x1ef000};
// Reserve slab heaps
ASSERT(
system_resource_limit->Reserve(LimitableResource::PhysicalMemory, user_slab_heap_size));
// Initialize slab heaps // Initialize slab heaps
constexpr u64 user_slab_heap_size{0x3de000};
user_slab_heap_pages->Initialize( user_slab_heap_pages->Initialize(
system.DeviceMemory().GetPointer(Core::DramMemoryMap::SlabHeapBase), system.DeviceMemory().GetPointer(Core::DramMemoryMap::SlabHeapBase),
user_slab_heap_size); user_slab_heap_size);

View File

@ -39,6 +39,7 @@ namespace {
*/ */
void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) { void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) {
const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart();
ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1));
auto thread_res = KThread::Create(system, ThreadType::User, "main", entry_point, priority, 0, auto thread_res = KThread::Create(system, ThreadType::User, "main", entry_point, priority, 0,
owner_process.GetIdealCoreId(), stack_top, &owner_process); owner_process.GetIdealCoreId(), stack_top, &owner_process);
@ -279,7 +280,7 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
if (!memory_reservation.Succeeded()) { if (!memory_reservation.Succeeded()) {
LOG_ERROR(Kernel, "Could not reserve process memory requirements of size {:X} bytes", LOG_ERROR(Kernel, "Could not reserve process memory requirements of size {:X} bytes",
code_size + system_resource_size); code_size + system_resource_size);
return ERR_RESOURCE_LIMIT_EXCEEDED; return ResultResourceLimitedExceeded;
} }
// Initialize proces address space // Initialize proces address space
if (const ResultCode result{ if (const ResultCode result{

View File

@ -4,15 +4,23 @@
#include "common/assert.h" #include "common/assert.h"
#include "core/hle/kernel/client_session.h" #include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/server_session.h" #include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/session.h" #include "core/hle/kernel/session.h"
namespace Kernel { namespace Kernel {
Session::Session(KernelCore& kernel) : KSynchronizationObject{kernel} {} Session::Session(KernelCore& kernel) : KSynchronizationObject{kernel} {}
Session::~Session() = default; Session::~Session() {
// Release reserved resource when the Session pair was created.
kernel.GetSystemResourceLimit()->Release(LimitableResource::Sessions, 1);
}
Session::SessionPair Session::Create(KernelCore& kernel, std::string name) { Session::SessionPair Session::Create(KernelCore& kernel, std::string name) {
// Reserve a new session from the resource limit.
KScopedResourceReservation session_reservation(kernel.GetSystemResourceLimit(),
LimitableResource::Sessions);
ASSERT(session_reservation.Succeeded());
auto session{std::make_shared<Session>(kernel)}; auto session{std::make_shared<Session>(kernel)};
auto client_session{Kernel::ClientSession::Create(kernel, session, name + "_Client").Unwrap()}; auto client_session{Kernel::ClientSession::Create(kernel, session, name + "_Client").Unwrap()};
auto server_session{Kernel::ServerSession::Create(kernel, session, name + "_Server").Unwrap()}; auto server_session{Kernel::ServerSession::Create(kernel, session, name + "_Server").Unwrap()};
@ -21,6 +29,7 @@ Session::SessionPair Session::Create(KernelCore& kernel, std::string name) {
session->client = client_session; session->client = client_session;
session->server = server_session; session->server = server_session;
session_reservation.Commit();
return std::make_pair(std::move(client_session), std::move(server_session)); return std::make_pair(std::move(client_session), std::move(server_session));
} }

View File

@ -14,7 +14,9 @@ namespace Kernel {
SharedMemory::SharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory) SharedMemory::SharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory)
: Object{kernel}, device_memory{device_memory} {} : Object{kernel}, device_memory{device_memory} {}
SharedMemory::~SharedMemory() = default; SharedMemory::~SharedMemory() {
kernel.GetSystemResourceLimit()->Release(LimitableResource::PhysicalMemory, size);
}
std::shared_ptr<SharedMemory> SharedMemory::Create( std::shared_ptr<SharedMemory> SharedMemory::Create(
KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process,

View File

@ -138,6 +138,7 @@ ResultCode MapUnmapMemorySanityChecks(const Memory::PageTable& manager, VAddr ds
enum class ResourceLimitValueType { enum class ResourceLimitValueType {
CurrentValue, CurrentValue,
LimitValue, LimitValue,
PeakValue,
}; };
ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit, ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit,
@ -160,11 +161,17 @@ ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_
return ResultInvalidHandle; return ResultInvalidHandle;
} }
if (value_type == ResourceLimitValueType::CurrentValue) { switch (value_type) {
case ResourceLimitValueType::CurrentValue:
return MakeResult(resource_limit_object->GetCurrentValue(type)); return MakeResult(resource_limit_object->GetCurrentValue(type));
} case ResourceLimitValueType::LimitValue:
return MakeResult(resource_limit_object->GetLimitValue(type)); return MakeResult(resource_limit_object->GetLimitValue(type));
case ResourceLimitValueType::PeakValue:
return MakeResult(resource_limit_object->GetPeakValue(type));
default:
LOG_ERROR(Kernel_SVC, "Invalid resource value_type: '{}'", value_type);
return ResultInvalidEnumValue;
}
} }
} // Anonymous namespace } // Anonymous namespace
@ -314,8 +321,6 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle,
return ResultNotFound; return ResultNotFound;
} }
ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(LimitableResource::Sessions, 1));
auto client_port = it->second; auto client_port = it->second;
std::shared_ptr<ClientSession> client_session; std::shared_ptr<ClientSession> client_session;
@ -1522,7 +1527,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e
system.CoreTiming().GetGlobalTimeNs().count() + 100000000); system.CoreTiming().GetGlobalTimeNs().count() + 100000000);
if (!thread_reservation.Succeeded()) { if (!thread_reservation.Succeeded()) {
LOG_ERROR(Kernel_SVC, "Could not reserve a new thread"); LOG_ERROR(Kernel_SVC, "Could not reserve a new thread");
return ERR_RESOURCE_LIMIT_EXCEEDED; return ResultResourceLimitedExceeded;
} }
std::shared_ptr<KThread> thread; std::shared_ptr<KThread> thread;
@ -1896,7 +1901,7 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd
LimitableResource::TransferMemory); LimitableResource::TransferMemory);
if (!trmem_reservation.Succeeded()) { if (!trmem_reservation.Succeeded()) {
LOG_ERROR(Kernel_SVC, "Could not reserve a new transfer memory"); LOG_ERROR(Kernel_SVC, "Could not reserve a new transfer memory");
return ERR_RESOURCE_LIMIT_EXCEEDED; return ResultResourceLimitedExceeded;
} }
auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, perms); auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, perms);
@ -2026,7 +2031,7 @@ static ResultCode SignalEvent(Core::System& system, Handle event_handle) {
LimitableResource::Events); LimitableResource::Events);
if (!event_reservation.Succeeded()) { if (!event_reservation.Succeeded()) {
LOG_ERROR(Kernel, "Could not reserve a new event"); LOG_ERROR(Kernel, "Could not reserve a new event");
return ERR_RESOURCE_LIMIT_EXCEEDED; return ResultResourceLimitedExceeded;
} }
// Get the writable event. // Get the writable event.

View File

@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/memory/page_table.h"
#include "core/hle/kernel/process.h" #include "core/hle/kernel/process.h"
@ -17,6 +18,7 @@ TransferMemory::TransferMemory(KernelCore& kernel, Core::Memory::Memory& memory)
TransferMemory::~TransferMemory() { TransferMemory::~TransferMemory() {
// Release memory region when transfer memory is destroyed // Release memory region when transfer memory is destroyed
Reset(); Reset();
owner_process->GetResourceLimit()->Release(LimitableResource::TransferMemory, 1);
} }
std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel,