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.
This commit is contained in:
ameerj 2021-04-12 16:14:19 -04:00
parent ddbd1387aa
commit 5e85bc3d23
2 changed files with 27 additions and 38 deletions
src/core/hle/kernel

View file

@ -67,8 +67,13 @@ struct KernelCore::Impl {
is_phantom_mode_for_singlecore = false; is_phantom_mode_for_singlecore = false;
InitializePhysicalCores(); 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(); InitializeSchedulers();
InitializeSuspendThreads(); InitializeSuspendThreads();
InitializePreemption(kernel); InitializePreemption(kernel);
@ -137,27 +142,32 @@ struct KernelCore::Impl {
} }
// Creates the default system resource limit // 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); 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. // 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()); .IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Threads, 800).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::Events, 900).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, 1133).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 // 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, ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory,
secure_applet_memory_size)); 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) { void InitializePreemption(KernelCore& kernel) {
@ -531,11 +541,7 @@ struct KernelCore::Impl {
linear_region_start); linear_region_start);
} }
void InitializeMemoryLayout() { void InitializeMemoryLayout(const KMemoryLayout& memory_layout) {
// Derive the initial memory layout from the emulated board
KMemoryLayout memory_layout;
DeriveInitialMemoryLayout(memory_layout);
const auto system_pool = memory_layout.GetKernelSystemPoolRegionPhysicalExtents(); const auto system_pool = memory_layout.GetKernelSystemPoolRegionPhysicalExtents();
const auto applet_pool = memory_layout.GetKernelAppletPoolRegionPhysicalExtents(); const auto applet_pool = memory_layout.GetKernelAppletPoolRegionPhysicalExtents();
const auto application_pool = memory_layout.GetKernelApplicationPoolRegionPhysicalExtents(); 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}, system.Kernel(), system.DeviceMemory(), nullptr, {time_phys_addr, time_size / PageSize},
KMemoryPermission::None, KMemoryPermission::Read, time_phys_addr, time_size, KMemoryPermission::None, KMemoryPermission::Read, time_phys_addr, time_size,
"Time:SharedMemory"); "Time:SharedMemory");
}
void InitializeSlabHeaps() {
// Allocate slab heaps // Allocate slab heaps
user_slab_heap_pages = std::make_unique<KSlabHeap<Page>>(); 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 // Reserve slab heaps
ASSERT( ASSERT(
system_resource_limit->Reserve(LimitableResource::PhysicalMemory, user_slab_heap_size)); system_resource_limit->Reserve(LimitableResource::PhysicalMemory, user_slab_heap_size));

View file

@ -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); std::shared_ptr<Process> process = std::make_shared<Process>(system);
process->name = std::move(name); process->name = std::move(name);
// TODO: This is inaccurate process->resource_limit = kernel.GetSystemResourceLimit();
// The process should hold a reference to the kernel-wide resource limit.
process->resource_limit = std::make_shared<KResourceLimit>(kernel, system);
process->status = ProcessStatus::Created; process->status = ProcessStatus::Created;
process->program_id = 0; process->program_id = 0;
process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID() process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
@ -160,17 +158,13 @@ void Process::DecrementThreadCount() {
} }
u64 Process::GetTotalPhysicalMemoryAvailable() const { 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) + 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 (capacity < memory_usage_capacity) { if (capacity < memory_usage_capacity) {
return capacity; return capacity;
} }
return memory_usage_capacity; return memory_usage_capacity;
} }
@ -272,10 +266,6 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
system_resource_size = metadata.GetSystemResourceSize(); system_resource_size = metadata.GetSystemResourceSize();
image_size = code_size; 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, KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory,
code_size + system_resource_size); code_size + system_resource_size);
if (!memory_reservation.Succeeded()) { if (!memory_reservation.Succeeded()) {
@ -324,16 +314,6 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
UNREACHABLE(); 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 // Create TLS region
tls_region_address = CreateTLSRegion(); tls_region_address = CreateTLSRegion();
memory_reservation.Commit(); memory_reservation.Commit();