diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_scoped_resource_reservation.h | 67 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 15 | ||||
| -rw-r--r-- | src/core/hle/kernel/memory/page_table.cpp | 37 | ||||
| -rw-r--r-- | src/core/hle/kernel/process.cpp | 34 | ||||
| -rw-r--r-- | src/core/hle/kernel/session.cpp | 11 | ||||
| -rw-r--r-- | src/core/hle/kernel/shared_memory.cpp | 11 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 48 | ||||
| -rw-r--r-- | src/core/hle/kernel/transfer_memory.cpp | 2 |
9 files changed, 190 insertions, 36 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 52151e788..1662ec63d 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -174,6 +174,7 @@ add_library(core STATIC | |||
| 174 | hle/kernel/k_scheduler.h | 174 | hle/kernel/k_scheduler.h |
| 175 | hle/kernel/k_scheduler_lock.h | 175 | hle/kernel/k_scheduler_lock.h |
| 176 | hle/kernel/k_scoped_lock.h | 176 | hle/kernel/k_scoped_lock.h |
| 177 | hle/kernel/k_scoped_resource_reservation.h | ||
| 177 | hle/kernel/k_scoped_scheduler_lock_and_sleep.h | 178 | hle/kernel/k_scoped_scheduler_lock_and_sleep.h |
| 178 | hle/kernel/k_synchronization_object.cpp | 179 | hle/kernel/k_synchronization_object.cpp |
| 179 | hle/kernel/k_synchronization_object.h | 180 | hle/kernel/k_synchronization_object.h |
diff --git a/src/core/hle/kernel/k_scoped_resource_reservation.h b/src/core/hle/kernel/k_scoped_resource_reservation.h new file mode 100644 index 000000000..c5deca00b --- /dev/null +++ b/src/core/hle/kernel/k_scoped_resource_reservation.h | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | // Copyright 2021 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | // This file references various implementation details from Atmosphere, an open-source firmware for | ||
| 6 | // the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. | ||
| 7 | |||
| 8 | #pragma once | ||
| 9 | |||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "core/hle/kernel/k_resource_limit.h" | ||
| 12 | #include "core/hle/kernel/process.h" | ||
| 13 | |||
| 14 | namespace Kernel { | ||
| 15 | |||
| 16 | class KScopedResourceReservation { | ||
| 17 | public: | ||
| 18 | explicit KScopedResourceReservation(std::shared_ptr<KResourceLimit> l, LimitableResource r, | ||
| 19 | s64 v, s64 timeout) | ||
| 20 | : resource_limit(std::move(l)), value(v), resource(r) { | ||
| 21 | if (resource_limit && value) { | ||
| 22 | success = resource_limit->Reserve(resource, value, timeout); | ||
| 23 | } else { | ||
| 24 | success = true; | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | explicit KScopedResourceReservation(std::shared_ptr<KResourceLimit> l, LimitableResource r, | ||
| 29 | s64 v = 1) | ||
| 30 | : resource_limit(std::move(l)), value(v), resource(r) { | ||
| 31 | if (resource_limit && value) { | ||
| 32 | success = resource_limit->Reserve(resource, value); | ||
| 33 | } else { | ||
| 34 | success = true; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | explicit KScopedResourceReservation(const Process* p, LimitableResource r, s64 v, s64 t) | ||
| 39 | : KScopedResourceReservation(p->GetResourceLimit(), r, v, t) {} | ||
| 40 | |||
| 41 | explicit KScopedResourceReservation(const Process* p, LimitableResource r, s64 v = 1) | ||
| 42 | : KScopedResourceReservation(p->GetResourceLimit(), r, v) {} | ||
| 43 | |||
| 44 | ~KScopedResourceReservation() noexcept { | ||
| 45 | if (resource_limit && value && success) { | ||
| 46 | // resource was not committed, release the reservation. | ||
| 47 | resource_limit->Release(resource, value); | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | /// Commit the resource reservation, destruction of this object does not release the resource | ||
| 52 | void Commit() { | ||
| 53 | resource_limit = nullptr; | ||
| 54 | } | ||
| 55 | |||
| 56 | [[nodiscard]] bool Succeeded() const { | ||
| 57 | return success; | ||
| 58 | } | ||
| 59 | |||
| 60 | private: | ||
| 61 | std::shared_ptr<KResourceLimit> resource_limit; | ||
| 62 | s64 value; | ||
| 63 | LimitableResource resource; | ||
| 64 | bool success; | ||
| 65 | }; | ||
| 66 | |||
| 67 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 8da5a5c86..b6e6f115e 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -141,11 +141,17 @@ struct KernelCore::Impl { | |||
| 141 | ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 700).IsSuccess()); | 141 | ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 700).IsSuccess()); |
| 142 | ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200) | 142 | ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200) |
| 143 | .IsSuccess()); | 143 | .IsSuccess()); |
| 144 | ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 900).IsSuccess()); | 144 | ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 933).IsSuccess()); |
| 145 | 145 | ||
| 146 | if (!system_resource_limit->Reserve(LimitableResource::PhysicalMemory, 0x60000)) { | 146 | // Derived from recent software updates. The kernel reserves 27MB |
| 147 | constexpr u64 kernel_size{0x1b00000}; | ||
| 148 | if (!system_resource_limit->Reserve(LimitableResource::PhysicalMemory, kernel_size)) { | ||
| 147 | UNREACHABLE(); | 149 | UNREACHABLE(); |
| 148 | } | 150 | } |
| 151 | // Reserve secure applet memory, introduced in firmware 5.0.0 | ||
| 152 | constexpr u64 secure_applet_memory_size{0x400000}; | ||
| 153 | ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory, | ||
| 154 | secure_applet_memory_size)); | ||
| 149 | } | 155 | } |
| 150 | 156 | ||
| 151 | void InitializePreemption(KernelCore& kernel) { | 157 | void InitializePreemption(KernelCore& kernel) { |
| @@ -302,8 +308,11 @@ struct KernelCore::Impl { | |||
| 302 | // Allocate slab heaps | 308 | // Allocate slab heaps |
| 303 | user_slab_heap_pages = std::make_unique<Memory::SlabHeap<Memory::Page>>(); | 309 | user_slab_heap_pages = std::make_unique<Memory::SlabHeap<Memory::Page>>(); |
| 304 | 310 | ||
| 311 | constexpr u64 user_slab_heap_size{0x1ef000}; | ||
| 312 | // Reserve slab heaps | ||
| 313 | ASSERT( | ||
| 314 | system_resource_limit->Reserve(LimitableResource::PhysicalMemory, user_slab_heap_size)); | ||
| 305 | // Initialize slab heaps | 315 | // Initialize slab heaps |
| 306 | constexpr u64 user_slab_heap_size{0x3de000}; | ||
| 307 | user_slab_heap_pages->Initialize( | 316 | user_slab_heap_pages->Initialize( |
| 308 | system.DeviceMemory().GetPointer(Core::DramMemoryMap::SlabHeapBase), | 317 | system.DeviceMemory().GetPointer(Core::DramMemoryMap::SlabHeapBase), |
| 309 | user_slab_heap_size); | 318 | user_slab_heap_size); |
diff --git a/src/core/hle/kernel/memory/page_table.cpp b/src/core/hle/kernel/memory/page_table.cpp index 5947fc748..00ed9b881 100644 --- a/src/core/hle/kernel/memory/page_table.cpp +++ b/src/core/hle/kernel/memory/page_table.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "common/scope_exit.h" | 7 | #include "common/scope_exit.h" |
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/hle/kernel/k_resource_limit.h" | 9 | #include "core/hle/kernel/k_scoped_resource_reservation.h" |
| 10 | #include "core/hle/kernel/kernel.h" | 10 | #include "core/hle/kernel/kernel.h" |
| 11 | #include "core/hle/kernel/memory/address_space_info.h" | 11 | #include "core/hle/kernel/memory/address_space_info.h" |
| 12 | #include "core/hle/kernel/memory/memory_block.h" | 12 | #include "core/hle/kernel/memory/memory_block.h" |
| @@ -409,27 +409,25 @@ ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) { | |||
| 409 | return RESULT_SUCCESS; | 409 | return RESULT_SUCCESS; |
| 410 | } | 410 | } |
| 411 | 411 | ||
| 412 | auto process{system.Kernel().CurrentProcess()}; | ||
| 413 | const std::size_t remaining_size{size - mapped_size}; | 412 | const std::size_t remaining_size{size - mapped_size}; |
| 414 | const std::size_t remaining_pages{remaining_size / PageSize}; | 413 | const std::size_t remaining_pages{remaining_size / PageSize}; |
| 415 | 414 | ||
| 416 | if (process->GetResourceLimit() && | 415 | // Reserve the memory from the process resource limit. |
| 417 | !process->GetResourceLimit()->Reserve(LimitableResource::PhysicalMemory, remaining_size)) { | 416 | KScopedResourceReservation memory_reservation( |
| 417 | system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory, | ||
| 418 | remaining_size); | ||
| 419 | if (!memory_reservation.Succeeded()) { | ||
| 420 | LOG_ERROR(Kernel, "Could not reserve remaining {:X} bytes", remaining_size); | ||
| 418 | return ResultResourceLimitedExceeded; | 421 | return ResultResourceLimitedExceeded; |
| 419 | } | 422 | } |
| 420 | 423 | ||
| 421 | PageLinkedList page_linked_list; | 424 | PageLinkedList page_linked_list; |
| 422 | { | ||
| 423 | auto block_guard = detail::ScopeExit([&] { | ||
| 424 | system.Kernel().MemoryManager().Free(page_linked_list, remaining_pages, memory_pool); | ||
| 425 | process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, remaining_size); | ||
| 426 | }); | ||
| 427 | 425 | ||
| 428 | CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, | 426 | CASCADE_CODE( |
| 429 | memory_pool)); | 427 | system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, memory_pool)); |
| 430 | 428 | ||
| 431 | block_guard.Cancel(); | 429 | // We succeeded, so commit the memory reservation. |
| 432 | } | 430 | memory_reservation.Commit(); |
| 433 | 431 | ||
| 434 | MapPhysicalMemory(page_linked_list, addr, end_addr); | 432 | MapPhysicalMemory(page_linked_list, addr, end_addr); |
| 435 | 433 | ||
| @@ -781,9 +779,13 @@ ResultVal<VAddr> PageTable::SetHeapSize(std::size_t size) { | |||
| 781 | 779 | ||
| 782 | const u64 delta{size - previous_heap_size}; | 780 | const u64 delta{size - previous_heap_size}; |
| 783 | 781 | ||
| 784 | auto process{system.Kernel().CurrentProcess()}; | 782 | // Reserve memory for the heap extension. |
| 785 | if (process->GetResourceLimit() && delta != 0 && | 783 | KScopedResourceReservation memory_reservation( |
| 786 | !process->GetResourceLimit()->Reserve(LimitableResource::PhysicalMemory, delta)) { | 784 | system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory, |
| 785 | delta); | ||
| 786 | |||
| 787 | if (!memory_reservation.Succeeded()) { | ||
| 788 | LOG_ERROR(Kernel, "Could not reserve heap extension of size {:X} bytes", delta); | ||
| 787 | return ResultResourceLimitedExceeded; | 789 | return ResultResourceLimitedExceeded; |
| 788 | } | 790 | } |
| 789 | 791 | ||
| @@ -800,6 +802,9 @@ ResultVal<VAddr> PageTable::SetHeapSize(std::size_t size) { | |||
| 800 | CASCADE_CODE( | 802 | CASCADE_CODE( |
| 801 | Operate(current_heap_addr, num_pages, page_linked_list, OperationType::MapGroup)); | 803 | Operate(current_heap_addr, num_pages, page_linked_list, OperationType::MapGroup)); |
| 802 | 804 | ||
| 805 | // Succeeded in allocation, commit the resource reservation | ||
| 806 | memory_reservation.Commit(); | ||
| 807 | |||
| 803 | block_manager->Update(current_heap_addr, num_pages, MemoryState::Normal, | 808 | block_manager->Update(current_heap_addr, num_pages, MemoryState::Normal, |
| 804 | MemoryPermission::ReadAndWrite); | 809 | MemoryPermission::ReadAndWrite); |
| 805 | 810 | ||
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 39dc3898a..47b3ac57b 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include "core/hle/kernel/code_set.h" | 16 | #include "core/hle/kernel/code_set.h" |
| 17 | #include "core/hle/kernel/k_resource_limit.h" | 17 | #include "core/hle/kernel/k_resource_limit.h" |
| 18 | #include "core/hle/kernel/k_scheduler.h" | 18 | #include "core/hle/kernel/k_scheduler.h" |
| 19 | #include "core/hle/kernel/k_scoped_resource_reservation.h" | ||
| 19 | #include "core/hle/kernel/k_thread.h" | 20 | #include "core/hle/kernel/k_thread.h" |
| 20 | #include "core/hle/kernel/kernel.h" | 21 | #include "core/hle/kernel/kernel.h" |
| 21 | #include "core/hle/kernel/memory/memory_block_manager.h" | 22 | #include "core/hle/kernel/memory/memory_block_manager.h" |
| @@ -38,6 +39,7 @@ namespace { | |||
| 38 | */ | 39 | */ |
| 39 | void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) { | 40 | void SetupMainThread(Core::System& system, Process& owner_process, u32 priority, VAddr stack_top) { |
| 40 | const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); | 41 | const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart(); |
| 42 | ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1)); | ||
| 41 | auto thread_res = KThread::Create(system, ThreadType::User, "main", entry_point, priority, 0, | 43 | auto thread_res = KThread::Create(system, ThreadType::User, "main", entry_point, priority, 0, |
| 42 | owner_process.GetIdealCoreId(), stack_top, &owner_process); | 44 | owner_process.GetIdealCoreId(), stack_top, &owner_process); |
| 43 | 45 | ||
| @@ -116,6 +118,9 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name, | |||
| 116 | 118 | ||
| 117 | std::shared_ptr<Process> process = std::make_shared<Process>(system); | 119 | std::shared_ptr<Process> process = std::make_shared<Process>(system); |
| 118 | process->name = std::move(name); | 120 | process->name = std::move(name); |
| 121 | |||
| 122 | // TODO: This is inaccurate | ||
| 123 | // The process should hold a reference to the kernel-wide resource limit. | ||
| 119 | process->resource_limit = std::make_shared<KResourceLimit>(kernel, system); | 124 | process->resource_limit = std::make_shared<KResourceLimit>(kernel, system); |
| 120 | process->status = ProcessStatus::Created; | 125 | process->status = ProcessStatus::Created; |
| 121 | process->program_id = 0; | 126 | process->program_id = 0; |
| @@ -154,6 +159,9 @@ void Process::DecrementThreadCount() { | |||
| 154 | } | 159 | } |
| 155 | 160 | ||
| 156 | u64 Process::GetTotalPhysicalMemoryAvailable() const { | 161 | u64 Process::GetTotalPhysicalMemoryAvailable() const { |
| 162 | // TODO: This is expected to always return the application memory pool size after accurately | ||
| 163 | // reserving kernel resources. The current workaround uses a process-local resource limit of | ||
| 164 | // application memory pool size, which is inaccurate. | ||
| 157 | const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) + | 165 | const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) + |
| 158 | page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size + | 166 | page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size + |
| 159 | main_thread_stack_size}; | 167 | main_thread_stack_size}; |
| @@ -263,6 +271,17 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, | |||
| 263 | system_resource_size = metadata.GetSystemResourceSize(); | 271 | system_resource_size = metadata.GetSystemResourceSize(); |
| 264 | image_size = code_size; | 272 | image_size = code_size; |
| 265 | 273 | ||
| 274 | // Set initial resource limits | ||
| 275 | resource_limit->SetLimitValue( | ||
| 276 | LimitableResource::PhysicalMemory, | ||
| 277 | kernel.MemoryManager().GetSize(Memory::MemoryManager::Pool::Application)); | ||
| 278 | KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory, | ||
| 279 | code_size + system_resource_size); | ||
| 280 | if (!memory_reservation.Succeeded()) { | ||
| 281 | LOG_ERROR(Kernel, "Could not reserve process memory requirements of size {:X} bytes", | ||
| 282 | code_size + system_resource_size); | ||
| 283 | return ResultResourceLimitedExceeded; | ||
| 284 | } | ||
| 266 | // Initialize proces address space | 285 | // Initialize proces address space |
| 267 | if (const ResultCode result{ | 286 | if (const ResultCode result{ |
| 268 | page_table->InitializeForProcess(metadata.GetAddressSpaceType(), false, 0x8000000, | 287 | page_table->InitializeForProcess(metadata.GetAddressSpaceType(), false, 0x8000000, |
| @@ -304,24 +323,22 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, | |||
| 304 | UNREACHABLE(); | 323 | UNREACHABLE(); |
| 305 | } | 324 | } |
| 306 | 325 | ||
| 307 | // Set initial resource limits | ||
| 308 | resource_limit->SetLimitValue( | ||
| 309 | LimitableResource::PhysicalMemory, | ||
| 310 | kernel.MemoryManager().GetSize(Memory::MemoryManager::Pool::Application)); | ||
| 311 | resource_limit->SetLimitValue(LimitableResource::Threads, 608); | 326 | resource_limit->SetLimitValue(LimitableResource::Threads, 608); |
| 312 | resource_limit->SetLimitValue(LimitableResource::Events, 700); | 327 | resource_limit->SetLimitValue(LimitableResource::Events, 700); |
| 313 | resource_limit->SetLimitValue(LimitableResource::TransferMemory, 128); | 328 | resource_limit->SetLimitValue(LimitableResource::TransferMemory, 128); |
| 314 | resource_limit->SetLimitValue(LimitableResource::Sessions, 894); | 329 | resource_limit->SetLimitValue(LimitableResource::Sessions, 894); |
| 315 | ASSERT(resource_limit->Reserve(LimitableResource::PhysicalMemory, code_size)); | ||
| 316 | 330 | ||
| 317 | // Create TLS region | 331 | // Create TLS region |
| 318 | tls_region_address = CreateTLSRegion(); | 332 | tls_region_address = CreateTLSRegion(); |
| 333 | memory_reservation.Commit(); | ||
| 319 | 334 | ||
| 320 | return handle_table.SetSize(capabilities.GetHandleTableSize()); | 335 | return handle_table.SetSize(capabilities.GetHandleTableSize()); |
| 321 | } | 336 | } |
| 322 | 337 | ||
| 323 | void Process::Run(s32 main_thread_priority, u64 stack_size) { | 338 | void Process::Run(s32 main_thread_priority, u64 stack_size) { |
| 324 | AllocateMainThreadStack(stack_size); | 339 | AllocateMainThreadStack(stack_size); |
| 340 | resource_limit->Reserve(LimitableResource::Threads, 1); | ||
| 341 | resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size); | ||
| 325 | 342 | ||
| 326 | const std::size_t heap_capacity{memory_usage_capacity - main_thread_stack_size - image_size}; | 343 | const std::size_t heap_capacity{memory_usage_capacity - main_thread_stack_size - image_size}; |
| 327 | ASSERT(!page_table->SetHeapCapacity(heap_capacity).IsError()); | 344 | ASSERT(!page_table->SetHeapCapacity(heap_capacity).IsError()); |
| @@ -329,8 +346,6 @@ void Process::Run(s32 main_thread_priority, u64 stack_size) { | |||
| 329 | ChangeStatus(ProcessStatus::Running); | 346 | ChangeStatus(ProcessStatus::Running); |
| 330 | 347 | ||
| 331 | SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top); | 348 | SetupMainThread(system, *this, main_thread_priority, main_thread_stack_top); |
| 332 | resource_limit->Reserve(LimitableResource::Threads, 1); | ||
| 333 | resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size); | ||
| 334 | } | 349 | } |
| 335 | 350 | ||
| 336 | void Process::PrepareForTermination() { | 351 | void Process::PrepareForTermination() { |
| @@ -357,6 +372,11 @@ void Process::PrepareForTermination() { | |||
| 357 | FreeTLSRegion(tls_region_address); | 372 | FreeTLSRegion(tls_region_address); |
| 358 | tls_region_address = 0; | 373 | tls_region_address = 0; |
| 359 | 374 | ||
| 375 | if (resource_limit) { | ||
| 376 | resource_limit->Release(LimitableResource::PhysicalMemory, | ||
| 377 | main_thread_stack_size + image_size); | ||
| 378 | } | ||
| 379 | |||
| 360 | ChangeStatus(ProcessStatus::Exited); | 380 | ChangeStatus(ProcessStatus::Exited); |
| 361 | } | 381 | } |
| 362 | 382 | ||
diff --git a/src/core/hle/kernel/session.cpp b/src/core/hle/kernel/session.cpp index 75304b961..8830d4e91 100644 --- a/src/core/hle/kernel/session.cpp +++ b/src/core/hle/kernel/session.cpp | |||
| @@ -4,15 +4,23 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | #include "core/hle/kernel/client_session.h" | 6 | #include "core/hle/kernel/client_session.h" |
| 7 | #include "core/hle/kernel/k_scoped_resource_reservation.h" | ||
| 7 | #include "core/hle/kernel/server_session.h" | 8 | #include "core/hle/kernel/server_session.h" |
| 8 | #include "core/hle/kernel/session.h" | 9 | #include "core/hle/kernel/session.h" |
| 9 | 10 | ||
| 10 | namespace Kernel { | 11 | namespace Kernel { |
| 11 | 12 | ||
| 12 | Session::Session(KernelCore& kernel) : KSynchronizationObject{kernel} {} | 13 | Session::Session(KernelCore& kernel) : KSynchronizationObject{kernel} {} |
| 13 | Session::~Session() = default; | 14 | Session::~Session() { |
| 15 | // Release reserved resource when the Session pair was created. | ||
| 16 | kernel.GetSystemResourceLimit()->Release(LimitableResource::Sessions, 1); | ||
| 17 | } | ||
| 14 | 18 | ||
| 15 | Session::SessionPair Session::Create(KernelCore& kernel, std::string name) { | 19 | Session::SessionPair Session::Create(KernelCore& kernel, std::string name) { |
| 20 | // Reserve a new session from the resource limit. | ||
| 21 | KScopedResourceReservation session_reservation(kernel.GetSystemResourceLimit(), | ||
| 22 | LimitableResource::Sessions); | ||
| 23 | ASSERT(session_reservation.Succeeded()); | ||
| 16 | auto session{std::make_shared<Session>(kernel)}; | 24 | auto session{std::make_shared<Session>(kernel)}; |
| 17 | auto client_session{Kernel::ClientSession::Create(kernel, session, name + "_Client").Unwrap()}; | 25 | auto client_session{Kernel::ClientSession::Create(kernel, session, name + "_Client").Unwrap()}; |
| 18 | auto server_session{Kernel::ServerSession::Create(kernel, session, name + "_Server").Unwrap()}; | 26 | auto server_session{Kernel::ServerSession::Create(kernel, session, name + "_Server").Unwrap()}; |
| @@ -21,6 +29,7 @@ Session::SessionPair Session::Create(KernelCore& kernel, std::string name) { | |||
| 21 | session->client = client_session; | 29 | session->client = client_session; |
| 22 | session->server = server_session; | 30 | session->server = server_session; |
| 23 | 31 | ||
| 32 | session_reservation.Commit(); | ||
| 24 | return std::make_pair(std::move(client_session), std::move(server_session)); | 33 | return std::make_pair(std::move(client_session), std::move(server_session)); |
| 25 | } | 34 | } |
| 26 | 35 | ||
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 0cd467110..2eadd51d7 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | #include "core/core.h" | 6 | #include "core/core.h" |
| 7 | #include "core/hle/kernel/k_scoped_resource_reservation.h" | ||
| 7 | #include "core/hle/kernel/kernel.h" | 8 | #include "core/hle/kernel/kernel.h" |
| 8 | #include "core/hle/kernel/memory/page_table.h" | 9 | #include "core/hle/kernel/memory/page_table.h" |
| 9 | #include "core/hle/kernel/shared_memory.h" | 10 | #include "core/hle/kernel/shared_memory.h" |
| @@ -13,7 +14,9 @@ namespace Kernel { | |||
| 13 | SharedMemory::SharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory) | 14 | SharedMemory::SharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory) |
| 14 | : Object{kernel}, device_memory{device_memory} {} | 15 | : Object{kernel}, device_memory{device_memory} {} |
| 15 | 16 | ||
| 16 | SharedMemory::~SharedMemory() = default; | 17 | SharedMemory::~SharedMemory() { |
| 18 | kernel.GetSystemResourceLimit()->Release(LimitableResource::PhysicalMemory, size); | ||
| 19 | } | ||
| 17 | 20 | ||
| 18 | std::shared_ptr<SharedMemory> SharedMemory::Create( | 21 | std::shared_ptr<SharedMemory> SharedMemory::Create( |
| 19 | KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, | 22 | KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, |
| @@ -21,6 +24,11 @@ std::shared_ptr<SharedMemory> SharedMemory::Create( | |||
| 21 | Memory::MemoryPermission user_permission, PAddr physical_address, std::size_t size, | 24 | Memory::MemoryPermission user_permission, PAddr physical_address, std::size_t size, |
| 22 | std::string name) { | 25 | std::string name) { |
| 23 | 26 | ||
| 27 | const auto resource_limit = kernel.GetSystemResourceLimit(); | ||
| 28 | KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory, | ||
| 29 | size); | ||
| 30 | ASSERT(memory_reservation.Succeeded()); | ||
| 31 | |||
| 24 | std::shared_ptr<SharedMemory> shared_memory{ | 32 | std::shared_ptr<SharedMemory> shared_memory{ |
| 25 | std::make_shared<SharedMemory>(kernel, device_memory)}; | 33 | std::make_shared<SharedMemory>(kernel, device_memory)}; |
| 26 | 34 | ||
| @@ -32,6 +40,7 @@ std::shared_ptr<SharedMemory> SharedMemory::Create( | |||
| 32 | shared_memory->size = size; | 40 | shared_memory->size = size; |
| 33 | shared_memory->name = name; | 41 | shared_memory->name = name; |
| 34 | 42 | ||
| 43 | memory_reservation.Commit(); | ||
| 35 | return shared_memory; | 44 | return shared_memory; |
| 36 | } | 45 | } |
| 37 | 46 | ||
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 4ef3c7ac5..31d899e06 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include "core/hle/kernel/k_readable_event.h" | 30 | #include "core/hle/kernel/k_readable_event.h" |
| 31 | #include "core/hle/kernel/k_resource_limit.h" | 31 | #include "core/hle/kernel/k_resource_limit.h" |
| 32 | #include "core/hle/kernel/k_scheduler.h" | 32 | #include "core/hle/kernel/k_scheduler.h" |
| 33 | #include "core/hle/kernel/k_scoped_resource_reservation.h" | ||
| 33 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" | 34 | #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" |
| 34 | #include "core/hle/kernel/k_synchronization_object.h" | 35 | #include "core/hle/kernel/k_synchronization_object.h" |
| 35 | #include "core/hle/kernel/k_thread.h" | 36 | #include "core/hle/kernel/k_thread.h" |
| @@ -137,6 +138,7 @@ ResultCode MapUnmapMemorySanityChecks(const Memory::PageTable& manager, VAddr ds | |||
| 137 | enum class ResourceLimitValueType { | 138 | enum class ResourceLimitValueType { |
| 138 | CurrentValue, | 139 | CurrentValue, |
| 139 | LimitValue, | 140 | LimitValue, |
| 141 | PeakValue, | ||
| 140 | }; | 142 | }; |
| 141 | 143 | ||
| 142 | ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit, | 144 | ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_limit, |
| @@ -159,11 +161,17 @@ ResultVal<s64> RetrieveResourceLimitValue(Core::System& system, Handle resource_ | |||
| 159 | return ResultInvalidHandle; | 161 | return ResultInvalidHandle; |
| 160 | } | 162 | } |
| 161 | 163 | ||
| 162 | if (value_type == ResourceLimitValueType::CurrentValue) { | 164 | switch (value_type) { |
| 165 | case ResourceLimitValueType::CurrentValue: | ||
| 163 | return MakeResult(resource_limit_object->GetCurrentValue(type)); | 166 | return MakeResult(resource_limit_object->GetCurrentValue(type)); |
| 167 | case ResourceLimitValueType::LimitValue: | ||
| 168 | return MakeResult(resource_limit_object->GetLimitValue(type)); | ||
| 169 | case ResourceLimitValueType::PeakValue: | ||
| 170 | return MakeResult(resource_limit_object->GetPeakValue(type)); | ||
| 171 | default: | ||
| 172 | LOG_ERROR(Kernel_SVC, "Invalid resource value_type: '{}'", value_type); | ||
| 173 | return ResultInvalidEnumValue; | ||
| 164 | } | 174 | } |
| 165 | |||
| 166 | return MakeResult(resource_limit_object->GetLimitValue(type)); | ||
| 167 | } | 175 | } |
| 168 | } // Anonymous namespace | 176 | } // Anonymous namespace |
| 169 | 177 | ||
| @@ -313,8 +321,6 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out_handle, | |||
| 313 | return ResultNotFound; | 321 | return ResultNotFound; |
| 314 | } | 322 | } |
| 315 | 323 | ||
| 316 | ASSERT(kernel.CurrentProcess()->GetResourceLimit()->Reserve(LimitableResource::Sessions, 1)); | ||
| 317 | |||
| 318 | auto client_port = it->second; | 324 | auto client_port = it->second; |
| 319 | 325 | ||
| 320 | std::shared_ptr<ClientSession> client_session; | 326 | std::shared_ptr<ClientSession> client_session; |
| @@ -1516,8 +1522,13 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e | |||
| 1516 | return ResultInvalidPriority; | 1522 | return ResultInvalidPriority; |
| 1517 | } | 1523 | } |
| 1518 | 1524 | ||
| 1519 | ASSERT(process.GetResourceLimit()->Reserve( | 1525 | KScopedResourceReservation thread_reservation( |
| 1520 | LimitableResource::Threads, 1, system.CoreTiming().GetGlobalTimeNs().count() + 100000000)); | 1526 | kernel.CurrentProcess(), LimitableResource::Threads, 1, |
| 1527 | system.CoreTiming().GetGlobalTimeNs().count() + 100000000); | ||
| 1528 | if (!thread_reservation.Succeeded()) { | ||
| 1529 | LOG_ERROR(Kernel_SVC, "Could not reserve a new thread"); | ||
| 1530 | return ResultResourceLimitedExceeded; | ||
| 1531 | } | ||
| 1521 | 1532 | ||
| 1522 | std::shared_ptr<KThread> thread; | 1533 | std::shared_ptr<KThread> thread; |
| 1523 | { | 1534 | { |
| @@ -1537,6 +1548,7 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e | |||
| 1537 | // Set the thread name for debugging purposes. | 1548 | // Set the thread name for debugging purposes. |
| 1538 | thread->SetName( | 1549 | thread->SetName( |
| 1539 | fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle)); | 1550 | fmt::format("thread[entry_point={:X}, handle={:X}]", entry_point, *new_thread_handle)); |
| 1551 | thread_reservation.Commit(); | ||
| 1540 | 1552 | ||
| 1541 | return RESULT_SUCCESS; | 1553 | return RESULT_SUCCESS; |
| 1542 | } | 1554 | } |
| @@ -1884,6 +1896,13 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd | |||
| 1884 | } | 1896 | } |
| 1885 | 1897 | ||
| 1886 | auto& kernel = system.Kernel(); | 1898 | auto& kernel = system.Kernel(); |
| 1899 | // Reserve a new transfer memory from the process resource limit. | ||
| 1900 | KScopedResourceReservation trmem_reservation(kernel.CurrentProcess(), | ||
| 1901 | LimitableResource::TransferMemory); | ||
| 1902 | if (!trmem_reservation.Succeeded()) { | ||
| 1903 | LOG_ERROR(Kernel_SVC, "Could not reserve a new transfer memory"); | ||
| 1904 | return ResultResourceLimitedExceeded; | ||
| 1905 | } | ||
| 1887 | auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, perms); | 1906 | auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, perms); |
| 1888 | 1907 | ||
| 1889 | if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) { | 1908 | if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) { |
| @@ -1895,6 +1914,7 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd | |||
| 1895 | if (result.Failed()) { | 1914 | if (result.Failed()) { |
| 1896 | return result.Code(); | 1915 | return result.Code(); |
| 1897 | } | 1916 | } |
| 1917 | trmem_reservation.Commit(); | ||
| 1898 | 1918 | ||
| 1899 | *handle = *result; | 1919 | *handle = *result; |
| 1900 | return RESULT_SUCCESS; | 1920 | return RESULT_SUCCESS; |
| @@ -2002,8 +2022,17 @@ static ResultCode SetThreadCoreMask32(Core::System& system, Handle thread_handle | |||
| 2002 | static ResultCode SignalEvent(Core::System& system, Handle event_handle) { | 2022 | static ResultCode SignalEvent(Core::System& system, Handle event_handle) { |
| 2003 | LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle); | 2023 | LOG_DEBUG(Kernel_SVC, "called, event_handle=0x{:08X}", event_handle); |
| 2004 | 2024 | ||
| 2025 | auto& kernel = system.Kernel(); | ||
| 2005 | // Get the current handle table. | 2026 | // Get the current handle table. |
| 2006 | const HandleTable& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); | 2027 | const HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable(); |
| 2028 | |||
| 2029 | // Reserve a new event from the process resource limit. | ||
| 2030 | KScopedResourceReservation event_reservation(kernel.CurrentProcess(), | ||
| 2031 | LimitableResource::Events); | ||
| 2032 | if (!event_reservation.Succeeded()) { | ||
| 2033 | LOG_ERROR(Kernel, "Could not reserve a new event"); | ||
| 2034 | return ResultResourceLimitedExceeded; | ||
| 2035 | } | ||
| 2007 | 2036 | ||
| 2008 | // Get the writable event. | 2037 | // Get the writable event. |
| 2009 | auto writable_event = handle_table.Get<KWritableEvent>(event_handle); | 2038 | auto writable_event = handle_table.Get<KWritableEvent>(event_handle); |
| @@ -2012,6 +2041,9 @@ static ResultCode SignalEvent(Core::System& system, Handle event_handle) { | |||
| 2012 | return ResultInvalidHandle; | 2041 | return ResultInvalidHandle; |
| 2013 | } | 2042 | } |
| 2014 | 2043 | ||
| 2044 | // Commit the successfuly reservation. | ||
| 2045 | event_reservation.Commit(); | ||
| 2046 | |||
| 2015 | return writable_event->Signal(); | 2047 | return writable_event->Signal(); |
| 2016 | } | 2048 | } |
| 2017 | 2049 | ||
diff --git a/src/core/hle/kernel/transfer_memory.cpp b/src/core/hle/kernel/transfer_memory.cpp index 765f408c3..6b0fc1591 100644 --- a/src/core/hle/kernel/transfer_memory.cpp +++ b/src/core/hle/kernel/transfer_memory.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "core/hle/kernel/k_resource_limit.h" | ||
| 5 | #include "core/hle/kernel/kernel.h" | 6 | #include "core/hle/kernel/kernel.h" |
| 6 | #include "core/hle/kernel/memory/page_table.h" | 7 | #include "core/hle/kernel/memory/page_table.h" |
| 7 | #include "core/hle/kernel/process.h" | 8 | #include "core/hle/kernel/process.h" |
| @@ -17,6 +18,7 @@ TransferMemory::TransferMemory(KernelCore& kernel, Core::Memory::Memory& memory) | |||
| 17 | TransferMemory::~TransferMemory() { | 18 | TransferMemory::~TransferMemory() { |
| 18 | // Release memory region when transfer memory is destroyed | 19 | // Release memory region when transfer memory is destroyed |
| 19 | Reset(); | 20 | Reset(); |
| 21 | owner_process->GetResourceLimit()->Release(LimitableResource::TransferMemory, 1); | ||
| 20 | } | 22 | } |
| 21 | 23 | ||
| 22 | std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, | 24 | std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, |