From 0d62f30b00fbfe598573ea8fd433bd64d7be3e5f Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 5 Feb 2021 23:14:31 -0800 Subject: hle: kernel: Rename SharedMemory to KSharedMemory. --- src/core/CMakeLists.txt | 4 +- src/core/hle/kernel/k_shared_memory.cpp | 66 +++++++++++++++++++ src/core/hle/kernel/k_shared_memory.h | 87 +++++++++++++++++++++++++ src/core/hle/kernel/kernel.cpp | 34 +++++----- src/core/hle/kernel/kernel.h | 18 ++--- src/core/hle/kernel/shared_memory.cpp | 66 ------------------- src/core/hle/kernel/shared_memory.h | 87 ------------------------- src/core/hle/kernel/svc.cpp | 4 +- src/core/hle/service/hid/hid.cpp | 2 +- src/core/hle/service/hid/hid.h | 4 +- src/core/hle/service/hid/irs.cpp | 2 +- src/core/hle/service/hid/irs.h | 4 +- src/core/hle/service/ns/pl_u.cpp | 4 +- src/core/hle/service/time/time_sharedmemory.cpp | 2 +- src/core/hle/service/time/time_sharedmemory.h | 6 +- 15 files changed, 195 insertions(+), 195 deletions(-) create mode 100644 src/core/hle/kernel/k_shared_memory.cpp create mode 100644 src/core/hle/kernel/k_shared_memory.h delete mode 100644 src/core/hle/kernel/shared_memory.cpp delete mode 100644 src/core/hle/kernel/shared_memory.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c6bdf72ec..8d4823f93 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -175,6 +175,8 @@ add_library(core STATIC hle/kernel/k_scoped_lock.h hle/kernel/k_scoped_resource_reservation.h hle/kernel/k_scoped_scheduler_lock_and_sleep.h + hle/kernel/k_shared_memory.cpp + hle/kernel/k_shared_memory.h hle/kernel/k_synchronization_object.cpp hle/kernel/k_synchronization_object.h hle/kernel/k_thread.cpp @@ -218,8 +220,6 @@ add_library(core STATIC hle/kernel/service_thread.h hle/kernel/session.cpp hle/kernel/session.h - hle/kernel/shared_memory.cpp - hle/kernel/shared_memory.h hle/kernel/svc.cpp hle/kernel/svc.h hle/kernel/svc_common.h diff --git a/src/core/hle/kernel/k_shared_memory.cpp b/src/core/hle/kernel/k_shared_memory.cpp new file mode 100644 index 000000000..dd82e0217 --- /dev/null +++ b/src/core/hle/kernel/k_shared_memory.cpp @@ -0,0 +1,66 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" +#include "core/core.h" +#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/memory/page_table.h" + +namespace Kernel { + +KSharedMemory::KSharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory) + : Object{kernel}, device_memory{device_memory} {} + +KSharedMemory::~KSharedMemory() { + kernel.GetSystemResourceLimit()->Release(LimitableResource::PhysicalMemory, size); +} + +std::shared_ptr KSharedMemory::Create( + KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, + Memory::PageLinkedList&& page_list, Memory::MemoryPermission owner_permission, + Memory::MemoryPermission user_permission, PAddr physical_address, std::size_t size, + std::string name) { + + const auto resource_limit = kernel.GetSystemResourceLimit(); + KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory, + size); + ASSERT(memory_reservation.Succeeded()); + + std::shared_ptr shared_memory{ + std::make_shared(kernel, device_memory)}; + + shared_memory->owner_process = owner_process; + shared_memory->page_list = std::move(page_list); + shared_memory->owner_permission = owner_permission; + shared_memory->user_permission = user_permission; + shared_memory->physical_address = physical_address; + shared_memory->size = size; + shared_memory->name = name; + + memory_reservation.Commit(); + return shared_memory; +} + +ResultCode KSharedMemory::Map(Process& target_process, VAddr address, std::size_t size, + Memory::MemoryPermission permissions) { + const u64 page_count{(size + Memory::PageSize - 1) / Memory::PageSize}; + + if (page_list.GetNumPages() != page_count) { + UNIMPLEMENTED_MSG("Page count does not match"); + } + + const Memory::MemoryPermission expected = + &target_process == owner_process ? owner_permission : user_permission; + + if (permissions != expected) { + UNIMPLEMENTED_MSG("Permission does not match"); + } + + return target_process.PageTable().MapPages(address, page_list, Memory::MemoryState::Shared, + permissions); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_shared_memory.h b/src/core/hle/kernel/k_shared_memory.h new file mode 100644 index 000000000..4d1354415 --- /dev/null +++ b/src/core/hle/kernel/k_shared_memory.h @@ -0,0 +1,87 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "common/common_types.h" +#include "core/device_memory.h" +#include "core/hle/kernel/memory/memory_block.h" +#include "core/hle/kernel/memory/page_linked_list.h" +#include "core/hle/kernel/object.h" +#include "core/hle/kernel/process.h" +#include "core/hle/result.h" + +namespace Kernel { + +class KernelCore; + +class KSharedMemory final : public Object { +public: + explicit KSharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory); + ~KSharedMemory() override; + + static std::shared_ptr Create( + KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, + Memory::PageLinkedList&& page_list, Memory::MemoryPermission owner_permission, + Memory::MemoryPermission user_permission, PAddr physical_address, std::size_t size, + std::string name); + + std::string GetTypeName() const override { + return "SharedMemory"; + } + + std::string GetName() const override { + return name; + } + + static constexpr HandleType HANDLE_TYPE = HandleType::SharedMemory; + HandleType GetHandleType() const override { + return HANDLE_TYPE; + } + + /** + * Maps a shared memory block to an address in the target process' address space + * @param target_process Process on which to map the memory block + * @param address Address in system memory to map shared memory block to + * @param size Size of the shared memory block to map + * @param permissions Memory block map permissions (specified by SVC field) + */ + ResultCode Map(Process& target_process, VAddr address, std::size_t size, + Memory::MemoryPermission permissions); + + /** + * Gets a pointer to the shared memory block + * @param offset Offset from the start of the shared memory block to get pointer + * @return A pointer to the shared memory block from the specified offset + */ + u8* GetPointer(std::size_t offset = 0) { + return device_memory.GetPointer(physical_address + offset); + } + + /** + * Gets a pointer to the shared memory block + * @param offset Offset from the start of the shared memory block to get pointer + * @return A pointer to the shared memory block from the specified offset + */ + const u8* GetPointer(std::size_t offset = 0) const { + return device_memory.GetPointer(physical_address + offset); + } + + void Finalize() override {} + +private: + Core::DeviceMemory& device_memory; + Process* owner_process{}; + Memory::PageLinkedList page_list; + Memory::MemoryPermission owner_permission{}; + Memory::MemoryPermission user_permission{}; + PAddr physical_address{}; + std::size_t size{}; + std::string name; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b6e6f115e..5eb602843 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -29,6 +29,7 @@ #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scheduler.h" +#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/memory/memory_layout.h" @@ -37,7 +38,6 @@ #include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/service_thread.h" -#include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/time_manager.h" #include "core/hle/lock.h" @@ -288,19 +288,19 @@ struct KernelCore::Impl { layout.System().StartAddress(), layout.System().EndAddress()); - hid_shared_mem = Kernel::SharedMemory::Create( + hid_shared_mem = Kernel::KSharedMemory::Create( system.Kernel(), system.DeviceMemory(), nullptr, {hid_addr, hid_size / Memory::PageSize}, Memory::MemoryPermission::None, Memory::MemoryPermission::Read, hid_addr, hid_size, "HID:SharedMemory"); - font_shared_mem = Kernel::SharedMemory::Create( + font_shared_mem = Kernel::KSharedMemory::Create( system.Kernel(), system.DeviceMemory(), nullptr, {font_pa, font_size / Memory::PageSize}, Memory::MemoryPermission::None, Memory::MemoryPermission::Read, font_pa, font_size, "Font:SharedMemory"); - irs_shared_mem = Kernel::SharedMemory::Create( + irs_shared_mem = Kernel::KSharedMemory::Create( system.Kernel(), system.DeviceMemory(), nullptr, {irs_addr, irs_size / Memory::PageSize}, Memory::MemoryPermission::None, Memory::MemoryPermission::Read, irs_addr, irs_size, "IRS:SharedMemory"); - time_shared_mem = Kernel::SharedMemory::Create( + time_shared_mem = Kernel::KSharedMemory::Create( system.Kernel(), system.DeviceMemory(), nullptr, {time_addr, time_size / Memory::PageSize}, Memory::MemoryPermission::None, Memory::MemoryPermission::Read, time_addr, time_size, "Time:SharedMemory"); @@ -352,10 +352,10 @@ struct KernelCore::Impl { std::unique_ptr> user_slab_heap_pages; // Shared memory for services - std::shared_ptr hid_shared_mem; - std::shared_ptr font_shared_mem; - std::shared_ptr irs_shared_mem; - std::shared_ptr time_shared_mem; + std::shared_ptr hid_shared_mem; + std::shared_ptr font_shared_mem; + std::shared_ptr irs_shared_mem; + std::shared_ptr time_shared_mem; // Threads used for services std::unordered_set> service_threads; @@ -589,35 +589,35 @@ const Memory::SlabHeap& KernelCore::GetUserSlabHeapPages() const { return *impl->user_slab_heap_pages; } -Kernel::SharedMemory& KernelCore::GetHidSharedMem() { +Kernel::KSharedMemory& KernelCore::GetHidSharedMem() { return *impl->hid_shared_mem; } -const Kernel::SharedMemory& KernelCore::GetHidSharedMem() const { +const Kernel::KSharedMemory& KernelCore::GetHidSharedMem() const { return *impl->hid_shared_mem; } -Kernel::SharedMemory& KernelCore::GetFontSharedMem() { +Kernel::KSharedMemory& KernelCore::GetFontSharedMem() { return *impl->font_shared_mem; } -const Kernel::SharedMemory& KernelCore::GetFontSharedMem() const { +const Kernel::KSharedMemory& KernelCore::GetFontSharedMem() const { return *impl->font_shared_mem; } -Kernel::SharedMemory& KernelCore::GetIrsSharedMem() { +Kernel::KSharedMemory& KernelCore::GetIrsSharedMem() { return *impl->irs_shared_mem; } -const Kernel::SharedMemory& KernelCore::GetIrsSharedMem() const { +const Kernel::KSharedMemory& KernelCore::GetIrsSharedMem() const { return *impl->irs_shared_mem; } -Kernel::SharedMemory& KernelCore::GetTimeSharedMem() { +Kernel::KSharedMemory& KernelCore::GetTimeSharedMem() { return *impl->time_shared_mem; } -const Kernel::SharedMemory& KernelCore::GetTimeSharedMem() const { +const Kernel::KSharedMemory& KernelCore::GetTimeSharedMem() const { return *impl->time_shared_mem; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 806a0d986..c5b32b260 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -40,7 +40,7 @@ class PhysicalCore; class Process; class KResourceLimit; class KScheduler; -class SharedMemory; +class KSharedMemory; class ServiceThread; class Synchronization; class KThread; @@ -190,28 +190,28 @@ public: const Memory::SlabHeap& GetUserSlabHeapPages() const; /// Gets the shared memory object for HID services. - Kernel::SharedMemory& GetHidSharedMem(); + Kernel::KSharedMemory& GetHidSharedMem(); /// Gets the shared memory object for HID services. - const Kernel::SharedMemory& GetHidSharedMem() const; + const Kernel::KSharedMemory& GetHidSharedMem() const; /// Gets the shared memory object for font services. - Kernel::SharedMemory& GetFontSharedMem(); + Kernel::KSharedMemory& GetFontSharedMem(); /// Gets the shared memory object for font services. - const Kernel::SharedMemory& GetFontSharedMem() const; + const Kernel::KSharedMemory& GetFontSharedMem() const; /// Gets the shared memory object for IRS services. - Kernel::SharedMemory& GetIrsSharedMem(); + Kernel::KSharedMemory& GetIrsSharedMem(); /// Gets the shared memory object for IRS services. - const Kernel::SharedMemory& GetIrsSharedMem() const; + const Kernel::KSharedMemory& GetIrsSharedMem() const; /// Gets the shared memory object for Time services. - Kernel::SharedMemory& GetTimeSharedMem(); + Kernel::KSharedMemory& GetTimeSharedMem(); /// Gets the shared memory object for Time services. - const Kernel::SharedMemory& GetTimeSharedMem() const; + const Kernel::KSharedMemory& GetTimeSharedMem() const; /// Suspend/unsuspend the OS. void Suspend(bool in_suspention); diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp deleted file mode 100644 index 2eadd51d7..000000000 --- a/src/core/hle/kernel/shared_memory.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/assert.h" -#include "core/core.h" -#include "core/hle/kernel/k_scoped_resource_reservation.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/memory/page_table.h" -#include "core/hle/kernel/shared_memory.h" - -namespace Kernel { - -SharedMemory::SharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory) - : Object{kernel}, device_memory{device_memory} {} - -SharedMemory::~SharedMemory() { - kernel.GetSystemResourceLimit()->Release(LimitableResource::PhysicalMemory, size); -} - -std::shared_ptr SharedMemory::Create( - KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, - Memory::PageLinkedList&& page_list, Memory::MemoryPermission owner_permission, - Memory::MemoryPermission user_permission, PAddr physical_address, std::size_t size, - std::string name) { - - const auto resource_limit = kernel.GetSystemResourceLimit(); - KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory, - size); - ASSERT(memory_reservation.Succeeded()); - - std::shared_ptr shared_memory{ - std::make_shared(kernel, device_memory)}; - - shared_memory->owner_process = owner_process; - shared_memory->page_list = std::move(page_list); - shared_memory->owner_permission = owner_permission; - shared_memory->user_permission = user_permission; - shared_memory->physical_address = physical_address; - shared_memory->size = size; - shared_memory->name = name; - - memory_reservation.Commit(); - return shared_memory; -} - -ResultCode SharedMemory::Map(Process& target_process, VAddr address, std::size_t size, - Memory::MemoryPermission permissions) { - const u64 page_count{(size + Memory::PageSize - 1) / Memory::PageSize}; - - if (page_list.GetNumPages() != page_count) { - UNIMPLEMENTED_MSG("Page count does not match"); - } - - const Memory::MemoryPermission expected = - &target_process == owner_process ? owner_permission : user_permission; - - if (permissions != expected) { - UNIMPLEMENTED_MSG("Permission does not match"); - } - - return target_process.PageTable().MapPages(address, page_list, Memory::MemoryState::Shared, - permissions); -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h deleted file mode 100644 index 623bd8b11..000000000 --- a/src/core/hle/kernel/shared_memory.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include - -#include "common/common_types.h" -#include "core/device_memory.h" -#include "core/hle/kernel/memory/memory_block.h" -#include "core/hle/kernel/memory/page_linked_list.h" -#include "core/hle/kernel/object.h" -#include "core/hle/kernel/process.h" -#include "core/hle/result.h" - -namespace Kernel { - -class KernelCore; - -class SharedMemory final : public Object { -public: - explicit SharedMemory(KernelCore& kernel, Core::DeviceMemory& device_memory); - ~SharedMemory() override; - - static std::shared_ptr Create( - KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, - Memory::PageLinkedList&& page_list, Memory::MemoryPermission owner_permission, - Memory::MemoryPermission user_permission, PAddr physical_address, std::size_t size, - std::string name); - - std::string GetTypeName() const override { - return "SharedMemory"; - } - - std::string GetName() const override { - return name; - } - - static constexpr HandleType HANDLE_TYPE = HandleType::SharedMemory; - HandleType GetHandleType() const override { - return HANDLE_TYPE; - } - - /** - * Maps a shared memory block to an address in the target process' address space - * @param target_process Process on which to map the memory block - * @param address Address in system memory to map shared memory block to - * @param size Size of the shared memory block to map - * @param permissions Memory block map permissions (specified by SVC field) - */ - ResultCode Map(Process& target_process, VAddr address, std::size_t size, - Memory::MemoryPermission permissions); - - /** - * Gets a pointer to the shared memory block - * @param offset Offset from the start of the shared memory block to get pointer - * @return A pointer to the shared memory block from the specified offset - */ - u8* GetPointer(std::size_t offset = 0) { - return device_memory.GetPointer(physical_address + offset); - } - - /** - * Gets a pointer to the shared memory block - * @param offset Offset from the start of the shared memory block to get pointer - * @return A pointer to the shared memory block from the specified offset - */ - const u8* GetPointer(std::size_t offset = 0) const { - return device_memory.GetPointer(physical_address + offset); - } - - void Finalize() override {} - -private: - Core::DeviceMemory& device_memory; - Process* owner_process{}; - Memory::PageLinkedList page_list; - Memory::MemoryPermission owner_permission{}; - Memory::MemoryPermission user_permission{}; - PAddr physical_address{}; - std::size_t size{}; - std::string name; -}; - -} // namespace Kernel diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 31d899e06..85899f83c 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -32,6 +32,7 @@ #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" +#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_writable_event.h" @@ -41,7 +42,6 @@ #include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/process.h" -#include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/svc.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/kernel/svc_types.h" @@ -1267,7 +1267,7 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han return ResultInvalidMemoryRange; } - auto shared_memory{current_process->GetHandleTable().Get(shared_memory_handle)}; + auto shared_memory{current_process->GetHandleTable().Get(shared_memory_handle)}; if (!shared_memory) { LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}", shared_memory_handle); diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 1e2677320..ffc3dfdc3 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -15,9 +15,9 @@ #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/client_session.h" #include "core/hle/kernel/k_readable_event.h" +#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/shared_memory.h" #include "core/hle/service/hid/errors.h" #include "core/hle/service/hid/hid.h" #include "core/hle/service/hid/irs.h" diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 7cc0433e2..06ddcf3e4 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -14,7 +14,7 @@ struct EventType; } namespace Kernel { -class SharedMemory; +class KSharedMemory; } namespace Service::SM { @@ -69,7 +69,7 @@ private: void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); - std::shared_ptr shared_mem; + std::shared_ptr shared_mem; std::shared_ptr pad_update_event; std::shared_ptr motion_update_event; diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index c8413099f..2dfa936fb 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp @@ -6,8 +6,8 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/shared_memory.h" #include "core/hle/service/hid/irs.h" namespace Service::HID { diff --git a/src/core/hle/service/hid/irs.h b/src/core/hle/service/hid/irs.h index be0c486ba..b0c8c7168 100644 --- a/src/core/hle/service/hid/irs.h +++ b/src/core/hle/service/hid/irs.h @@ -12,7 +12,7 @@ class System; } namespace Kernel { -class SharedMemory; +class KSharedMemory; } namespace Service::HID { @@ -42,7 +42,7 @@ private: void StopImageProcessorAsync(Kernel::HLERequestContext& ctx); void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx); - std::shared_ptr shared_mem; + std::shared_ptr shared_mem; const u32 device_handle{0xABCD}; }; diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index b6ac0a81a..fcd15d81f 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp @@ -19,9 +19,9 @@ #include "core/file_sys/romfs.h" #include "core/file_sys/system_archive/system_archive.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_memory.h" -#include "core/hle/kernel/shared_memory.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/ns/pl_u.h" @@ -131,7 +131,7 @@ struct PL_U::Impl { } /// Handle to shared memory region designated for a shared font - std::shared_ptr shared_font_mem; + std::shared_ptr shared_font_mem; /// Backing memory for the shared font data std::shared_ptr shared_font; diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp index e0ae9f874..4d8de81be 100644 --- a/src/core/hle/service/time/time_sharedmemory.cpp +++ b/src/core/hle/service/time/time_sharedmemory.cpp @@ -22,7 +22,7 @@ SharedMemory::SharedMemory(Core::System& system) : system(system) { SharedMemory::~SharedMemory() = default; -std::shared_ptr SharedMemory::GetSharedMemoryHolder() const { +std::shared_ptr SharedMemory::GetSharedMemoryHolder() const { return shared_memory_holder; } diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h index e0c3e63da..299680517 100644 --- a/src/core/hle/service/time/time_sharedmemory.h +++ b/src/core/hle/service/time/time_sharedmemory.h @@ -6,8 +6,8 @@ #include "common/common_types.h" #include "common/uuid.h" +#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/shared_memory.h" #include "core/hle/service/time/clock_types.h" namespace Service::Time { @@ -18,7 +18,7 @@ public: ~SharedMemory(); // Return the shared memory handle - std::shared_ptr GetSharedMemoryHolder() const; + std::shared_ptr GetSharedMemoryHolder() const; // TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this? template @@ -63,7 +63,7 @@ public: void SetAutomaticCorrectionEnabled(bool is_enabled); private: - std::shared_ptr shared_memory_holder; + std::shared_ptr shared_memory_holder; Core::System& system; Format shared_memory_format{}; }; -- cgit v1.2.3 From b5b92fd1e5f44634ccccc8e0526cd725dfd81f34 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 8 Feb 2021 18:01:19 -0800 Subject: common: alignment: Add DivideUp utility method. --- src/common/alignment.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/common/alignment.h b/src/common/alignment.h index fb81f10d8..32d796ffa 100644 --- a/src/common/alignment.h +++ b/src/common/alignment.h @@ -42,6 +42,11 @@ requires std::is_integral_v[[nodiscard]] constexpr bool IsAligned(T value, si return (value & mask) == 0; } +template +requires std::is_integral_v[[nodiscard]] constexpr T DivideUp(T x, U y) { + return (x + (y - 1)) / y; +} + template class AlignmentAllocator { public: -- cgit v1.2.3 From 24e1e17a8ae3f2b2962b702d383abd19b57c7b05 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 8 Feb 2021 18:01:40 -0800 Subject: core: memory: Add templated GetPointer methods. --- src/core/memory.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/core/memory.h b/src/core/memory.h index 705ebb23d..6d34fcfe2 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -116,6 +116,11 @@ public: */ u8* GetPointer(VAddr vaddr); + template + T* GetPointer(VAddr vaddr) { + return reinterpret_cast(GetPointer(vaddr)); + } + /** * Gets a pointer to the given address. * @@ -126,6 +131,11 @@ public: */ const u8* GetPointer(VAddr vaddr) const; + template + const T* GetPointer(VAddr vaddr) const { + return reinterpret_cast(GetPointer(vaddr)); + } + /** * Reads an 8-bit unsigned value from the current process' address space * at the given virtual address. -- cgit v1.2.3 From 6da91da08e54d02a4087eaddcbe192bd53eeaa9f Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 8 Feb 2021 18:02:36 -0800 Subject: hle: kernel: Add KSpinLock implementation. --- src/core/CMakeLists.txt | 2 ++ src/core/hle/kernel/k_spin_lock.cpp | 54 +++++++++++++++++++++++++++++++++++++ src/core/hle/kernel/k_spin_lock.h | 33 +++++++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 src/core/hle/kernel/k_spin_lock.cpp create mode 100644 src/core/hle/kernel/k_spin_lock.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 8d4823f93..a6b5fef56 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -177,6 +177,8 @@ add_library(core STATIC hle/kernel/k_scoped_scheduler_lock_and_sleep.h hle/kernel/k_shared_memory.cpp hle/kernel/k_shared_memory.h + hle/kernel/k_spin_lock.cpp + hle/kernel/k_spin_lock.h hle/kernel/k_synchronization_object.cpp hle/kernel/k_synchronization_object.h hle/kernel/k_thread.cpp diff --git a/src/core/hle/kernel/k_spin_lock.cpp b/src/core/hle/kernel/k_spin_lock.cpp new file mode 100644 index 000000000..4412aa4bb --- /dev/null +++ b/src/core/hle/kernel/k_spin_lock.cpp @@ -0,0 +1,54 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/k_spin_lock.h" + +#if _MSC_VER +#include +#if _M_AMD64 +#define __x86_64__ 1 +#endif +#if _M_ARM64 +#define __aarch64__ 1 +#endif +#else +#if __x86_64__ +#include +#endif +#endif + +namespace { + +void ThreadPause() { +#if __x86_64__ + _mm_pause(); +#elif __aarch64__ && _MSC_VER + __yield(); +#elif __aarch64__ + asm("yield"); +#endif +} + +} // namespace + +namespace Kernel { + +void KSpinLock::Lock() { + while (lck.test_and_set(std::memory_order_acquire)) { + ThreadPause(); + } +} + +void KSpinLock::Unlock() { + lck.clear(std::memory_order_release); +} + +bool KSpinLock::TryLock() { + if (lck.test_and_set(std::memory_order_acquire)) { + return false; + } + return true; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_spin_lock.h b/src/core/hle/kernel/k_spin_lock.h new file mode 100644 index 000000000..12c4b2e88 --- /dev/null +++ b/src/core/hle/kernel/k_spin_lock.h @@ -0,0 +1,33 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "core/hle/kernel/k_scoped_lock.h" + +namespace Kernel { + +class KSpinLock { +public: + KSpinLock() = default; + + KSpinLock(const KSpinLock&) = delete; + KSpinLock& operator=(const KSpinLock&) = delete; + + KSpinLock(KSpinLock&&) = delete; + KSpinLock& operator=(KSpinLock&&) = delete; + + void Lock(); + void Unlock(); + [[nodiscard]] bool TryLock(); + +private: + std::atomic_flag lck = ATOMIC_FLAG_INIT; +}; + +using KScopedSpinLock = KScopedLock; + +} // namespace Kernel -- cgit v1.2.3 From c9235764c7c4b8fb73d2236d8818a52cbd9c0980 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 8 Feb 2021 18:05:13 -0800 Subject: common: Add implementation of TinyMT (Mersenne Twister RNG). --- src/common/CMakeLists.txt | 1 + src/common/tiny_mt.h | 250 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 251 insertions(+) create mode 100644 src/common/tiny_mt.h diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index b657506b1..788516ded 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -167,6 +167,7 @@ add_library(common STATIC threadsafe_queue.h time_zone.cpp time_zone.h + tiny_mt.h tree.h uint128.h uuid.cpp diff --git a/src/common/tiny_mt.h b/src/common/tiny_mt.h new file mode 100644 index 000000000..19ae5b7d6 --- /dev/null +++ b/src/common/tiny_mt.h @@ -0,0 +1,250 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/alignment.h" +#include "common/common_types.h" + +namespace Common { + +// Implementation of TinyMT (mersenne twister RNG). +// Like Nintendo, we will use the sample parameters. +class TinyMT { +public: + static constexpr std::size_t NumStateWords = 4; + + struct State { + std::array data{}; + }; + +private: + static constexpr u32 ParamMat1 = 0x8F7011EE; + static constexpr u32 ParamMat2 = 0xFC78FF1F; + static constexpr u32 ParamTmat = 0x3793FDFF; + + static constexpr u32 ParamMult = 0x6C078965; + static constexpr u32 ParamPlus = 0x0019660D; + static constexpr u32 ParamXor = 0x5D588B65; + + static constexpr u32 TopBitmask = 0x7FFFFFFF; + + static constexpr int MinimumInitIterations = 8; + static constexpr int NumDiscardedInitOutputs = 8; + + static constexpr u32 XorByShifted27(u32 value) { + return value ^ (value >> 27); + } + + static constexpr u32 XorByShifted30(u32 value) { + return value ^ (value >> 30); + } + +private: + State state{}; + +private: + // Internal API. + void FinalizeInitialization() { + const u32 state0 = this->state.data[0] & TopBitmask; + const u32 state1 = this->state.data[1]; + const u32 state2 = this->state.data[2]; + const u32 state3 = this->state.data[3]; + + if (state0 == 0 && state1 == 0 && state2 == 0 && state3 == 0) { + this->state.data[0] = 'T'; + this->state.data[1] = 'I'; + this->state.data[2] = 'N'; + this->state.data[3] = 'Y'; + } + + for (int i = 0; i < NumDiscardedInitOutputs; i++) { + this->GenerateRandomU32(); + } + } + + u32 GenerateRandomU24() { + return (this->GenerateRandomU32() >> 8); + } + + static void GenerateInitialValuePlus(TinyMT::State* state, int index, u32 value) { + u32& state0 = state->data[(index + 0) % NumStateWords]; + u32& state1 = state->data[(index + 1) % NumStateWords]; + u32& state2 = state->data[(index + 2) % NumStateWords]; + u32& state3 = state->data[(index + 3) % NumStateWords]; + + const u32 x = XorByShifted27(state0 ^ state1 ^ state3) * ParamPlus; + const u32 y = x + index + value; + + state0 = y; + state1 += x; + state2 += y; + } + + static void GenerateInitialValueXor(TinyMT::State* state, int index) { + u32& state0 = state->data[(index + 0) % NumStateWords]; + u32& state1 = state->data[(index + 1) % NumStateWords]; + u32& state2 = state->data[(index + 2) % NumStateWords]; + u32& state3 = state->data[(index + 3) % NumStateWords]; + + const u32 x = XorByShifted27(state0 + state1 + state3) * ParamXor; + const u32 y = x - index; + + state0 = y; + state1 ^= x; + state2 ^= y; + } + +public: + constexpr TinyMT() = default; + + // Public API. + + // Initialization. + void Initialize(u32 seed) { + this->state.data[0] = seed; + this->state.data[1] = ParamMat1; + this->state.data[2] = ParamMat2; + this->state.data[3] = ParamTmat; + + for (int i = 1; i < MinimumInitIterations; i++) { + const u32 mixed = XorByShifted30(this->state.data[(i - 1) % NumStateWords]); + this->state.data[i % NumStateWords] ^= mixed * ParamMult + i; + } + + this->FinalizeInitialization(); + } + + void Initialize(const u32* seed, int seed_count) { + this->state.data[0] = 0; + this->state.data[1] = ParamMat1; + this->state.data[2] = ParamMat2; + this->state.data[3] = ParamTmat; + + { + const int num_init_iterations = std::max(seed_count + 1, MinimumInitIterations) - 1; + + GenerateInitialValuePlus(&this->state, 0, seed_count); + + for (int i = 0; i < num_init_iterations; i++) { + GenerateInitialValuePlus(&this->state, (i + 1) % NumStateWords, + (i < seed_count) ? seed[i] : 0); + } + + for (int i = 0; i < static_cast(NumStateWords); i++) { + GenerateInitialValueXor(&this->state, + (i + 1 + num_init_iterations) % NumStateWords); + } + } + + this->FinalizeInitialization(); + } + + // State management. + void GetState(TinyMT::State& out) const { + out.data = this->state.data; + } + + void SetState(const TinyMT::State& state_) { + this->state.data = state_.data; + } + + // Random generation. + void GenerateRandomBytes(void* dst, std::size_t size) { + const uintptr_t start = reinterpret_cast(dst); + const uintptr_t end = start + size; + const uintptr_t aligned_start = Common::AlignUp(start, 4); + const uintptr_t aligned_end = Common::AlignDown(end, 4); + + // Make sure we're aligned. + if (start < aligned_start) { + const u32 rnd = this->GenerateRandomU32(); + std::memcpy(dst, &rnd, aligned_start - start); + } + + // Write as many aligned u32s as we can. + { + u32* cur_dst = reinterpret_cast(aligned_start); + u32* const end_dst = reinterpret_cast(aligned_end); + + while (cur_dst < end_dst) { + *(cur_dst++) = this->GenerateRandomU32(); + } + } + + // Handle any leftover unaligned data. + if (aligned_end < end) { + const u32 rnd = this->GenerateRandomU32(); + std::memcpy(reinterpret_cast(aligned_end), &rnd, end - aligned_end); + } + } + + u32 GenerateRandomU32() { + // Advance state. + const u32 x0 = + (this->state.data[0] & TopBitmask) ^ this->state.data[1] ^ this->state.data[2]; + const u32 y0 = this->state.data[3]; + const u32 x1 = x0 ^ (x0 << 1); + const u32 y1 = y0 ^ (y0 >> 1) ^ x1; + + const u32 state0 = this->state.data[1]; + u32 state1 = this->state.data[2]; + u32 state2 = x1 ^ (y1 << 10); + const u32 state3 = y1; + + if ((y1 & 1) != 0) { + state1 ^= ParamMat1; + state2 ^= ParamMat2; + } + + this->state.data[0] = state0; + this->state.data[1] = state1; + this->state.data[2] = state2; + this->state.data[3] = state3; + + // Temper. + const u32 t1 = state0 + (state2 >> 8); + u32 t0 = state3 ^ t1; + + if ((t1 & 1) != 0) { + t0 ^= ParamTmat; + } + + return t0; + } + + u64 GenerateRandomU64() { + const u32 lo = this->GenerateRandomU32(); + const u32 hi = this->GenerateRandomU32(); + return (u64{hi} << 32) | u64{lo}; + } + + float GenerateRandomF32() { + // Floats have 24 bits of mantissa. + constexpr u32 MantissaBits = 24; + return static_cast(GenerateRandomU24()) * (1.0f / (1U << MantissaBits)); + } + + double GenerateRandomF64() { + // Doubles have 53 bits of mantissa. + // The smart way to generate 53 bits of random would be to use 32 bits + // from the first rnd32() call, and then 21 from the second. + // Nintendo does not. They use (32 - 5) = 27 bits from the first rnd32() + // call, and (32 - 6) bits from the second. We'll do what they do, but + // There's not a clear reason why. + constexpr u32 MantissaBits = 53; + constexpr u32 Shift1st = (64 - MantissaBits) / 2; + constexpr u32 Shift2nd = (64 - MantissaBits) - Shift1st; + + const u32 first = (this->GenerateRandomU32() >> Shift1st); + const u32 second = (this->GenerateRandomU32() >> Shift2nd); + + return (1.0 * first * (u64{1} << (32 - Shift2nd)) + second) * + (1.0 / (u64{1} << MantissaBits)); + } +}; + +} // namespace Common -- cgit v1.2.3 From e7c33d1ad6b464a591279068f07a6b1de82109f6 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 8 Feb 2021 18:08:08 -0800 Subject: hle: kernel: system_control: Add function GenerateRandomU64. --- src/core/hle/kernel/memory/system_control.cpp | 7 ++++--- src/core/hle/kernel/memory/system_control.h | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/core/hle/kernel/memory/system_control.cpp b/src/core/hle/kernel/memory/system_control.cpp index 11d204bc2..e855696ad 100644 --- a/src/core/hle/kernel/memory/system_control.cpp +++ b/src/core/hle/kernel/memory/system_control.cpp @@ -25,16 +25,17 @@ u64 GenerateUniformRange(u64 min, u64 max, F f) { } } -u64 GenerateRandomU64ForInit() { +} // Anonymous namespace + +u64 GenerateRandomU64() { static std::random_device device; static std::mt19937 gen(device()); static std::uniform_int_distribution distribution(1, std::numeric_limits::max()); return distribution(gen); } -} // Anonymous namespace u64 GenerateRandomRange(u64 min, u64 max) { - return GenerateUniformRange(min, max, GenerateRandomU64ForInit); + return GenerateUniformRange(min, max, GenerateRandomU64); } } // namespace Kernel::Memory::SystemControl diff --git a/src/core/hle/kernel/memory/system_control.h b/src/core/hle/kernel/memory/system_control.h index 19cab8cbc..a01b6b014 100644 --- a/src/core/hle/kernel/memory/system_control.h +++ b/src/core/hle/kernel/memory/system_control.h @@ -9,5 +9,6 @@ namespace Kernel::Memory::SystemControl { u64 GenerateRandomRange(u64 min, u64 max); +u64 GenerateRandomU64(); } // namespace Kernel::Memory::SystemControl -- cgit v1.2.3 From a02566136c225e0824a3f217766efcb3b3f55ec2 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Feb 2021 18:39:06 -0800 Subject: hle: kernel: Add KPageBitmap class. --- src/core/CMakeLists.txt | 1 + src/core/hle/kernel/k_page_bitmap.h | 279 ++++++++++++++++++++++++++++++++++++ 2 files changed, 280 insertions(+) create mode 100644 src/core/hle/kernel/k_page_bitmap.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a6b5fef56..6604bc2c5 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -164,6 +164,7 @@ add_library(core STATIC hle/kernel/k_light_condition_variable.h hle/kernel/k_light_lock.cpp hle/kernel/k_light_lock.h + hle/kernel/k_page_bitmap.h hle/kernel/k_priority_queue.h hle/kernel/k_readable_event.cpp hle/kernel/k_readable_event.h diff --git a/src/core/hle/kernel/k_page_bitmap.h b/src/core/hle/kernel/k_page_bitmap.h new file mode 100644 index 000000000..da2d20032 --- /dev/null +++ b/src/core/hle/kernel/k_page_bitmap.h @@ -0,0 +1,279 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "common/alignment.h" +#include "common/assert.h" +#include "common/bit_util.h" +#include "common/common_types.h" +#include "common/tiny_mt.h" +#include "core/hle/kernel/memory/system_control.h" + +namespace Kernel { + +class KPageBitmap { +private: + class RandomBitGenerator { + private: + Common::TinyMT rng{}; + u32 entropy{}; + u32 bits_available{}; + + private: + void RefreshEntropy() { + entropy = rng.GenerateRandomU32(); + bits_available = static_cast(Common::BitSize()); + } + + bool GenerateRandomBit() { + if (bits_available == 0) { + this->RefreshEntropy(); + } + + const bool rnd_bit = (entropy & 1) != 0; + entropy >>= 1; + --bits_available; + return rnd_bit; + } + + public: + RandomBitGenerator() { + rng.Initialize(static_cast(Memory::SystemControl::GenerateRandomU64())); + } + + std::size_t SelectRandomBit(u64 bitmap) { + u64 selected = 0; + + u64 cur_num_bits = Common::BitSize() / 2; + u64 cur_mask = (1ULL << cur_num_bits) - 1; + + while (cur_num_bits) { + const u64 low = (bitmap >> 0) & cur_mask; + const u64 high = (bitmap >> cur_num_bits) & cur_mask; + + bool choose_low; + if (high == 0) { + // If only low val is set, choose low. + choose_low = true; + } else if (low == 0) { + // If only high val is set, choose high. + choose_low = false; + } else { + // If both are set, choose random. + choose_low = this->GenerateRandomBit(); + } + + // If we chose low, proceed with low. + if (choose_low) { + bitmap = low; + selected += 0; + } else { + bitmap = high; + selected += cur_num_bits; + } + + // Proceed. + cur_num_bits /= 2; + cur_mask >>= cur_num_bits; + } + + return selected; + } + }; + +public: + static constexpr std::size_t MaxDepth = 4; + +private: + std::array bit_storages{}; + RandomBitGenerator rng{}; + std::size_t num_bits{}; + std::size_t used_depths{}; + +public: + KPageBitmap() = default; + + constexpr std::size_t GetNumBits() const { + return num_bits; + } + constexpr s32 GetHighestDepthIndex() const { + return static_cast(used_depths) - 1; + } + + u64* Initialize(u64* storage, std::size_t size) { + // Initially, everything is un-set. + num_bits = 0; + + // Calculate the needed bitmap depth. + used_depths = static_cast(GetRequiredDepth(size)); + ASSERT(used_depths <= MaxDepth); + + // Set the bitmap pointers. + for (s32 depth = this->GetHighestDepthIndex(); depth >= 0; depth--) { + bit_storages[depth] = storage; + size = Common::AlignUp(size, Common::BitSize()) / Common::BitSize(); + storage += size; + } + + return storage; + } + + s64 FindFreeBlock(bool random) { + uintptr_t offset = 0; + s32 depth = 0; + + if (random) { + do { + const u64 v = bit_storages[depth][offset]; + if (v == 0) { + // If depth is bigger than zero, then a previous level indicated a block was + // free. + ASSERT(depth == 0); + return -1; + } + offset = offset * Common::BitSize() + rng.SelectRandomBit(v); + ++depth; + } while (depth < static_cast(used_depths)); + } else { + do { + const u64 v = bit_storages[depth][offset]; + if (v == 0) { + // If depth is bigger than zero, then a previous level indicated a block was + // free. + ASSERT(depth == 0); + return -1; + } + offset = offset * Common::BitSize() + std::countr_zero(v); + ++depth; + } while (depth < static_cast(used_depths)); + } + + return static_cast(offset); + } + + void SetBit(std::size_t offset) { + this->SetBit(this->GetHighestDepthIndex(), offset); + num_bits++; + } + + void ClearBit(std::size_t offset) { + this->ClearBit(this->GetHighestDepthIndex(), offset); + num_bits--; + } + + bool ClearRange(std::size_t offset, std::size_t count) { + s32 depth = this->GetHighestDepthIndex(); + u64* bits = bit_storages[depth]; + std::size_t bit_ind = offset / Common::BitSize(); + if (count < Common::BitSize()) { + const std::size_t shift = offset % Common::BitSize(); + ASSERT(shift + count <= Common::BitSize()); + // Check that all the bits are set. + const u64 mask = ((u64(1) << count) - 1) << shift; + u64 v = bits[bit_ind]; + if ((v & mask) != mask) { + return false; + } + + // Clear the bits. + v &= ~mask; + bits[bit_ind] = v; + if (v == 0) { + this->ClearBit(depth - 1, bit_ind); + } + } else { + ASSERT(offset % Common::BitSize() == 0); + ASSERT(count % Common::BitSize() == 0); + // Check that all the bits are set. + std::size_t remaining = count; + std::size_t i = 0; + do { + if (bits[bit_ind + i++] != ~u64(0)) { + return false; + } + remaining -= Common::BitSize(); + } while (remaining > 0); + + // Clear the bits. + remaining = count; + i = 0; + do { + bits[bit_ind + i] = 0; + this->ClearBit(depth - 1, bit_ind + i); + i++; + remaining -= Common::BitSize(); + } while (remaining > 0); + } + + num_bits -= count; + return true; + } + +private: + void SetBit(s32 depth, std::size_t offset) { + while (depth >= 0) { + std::size_t ind = offset / Common::BitSize(); + std::size_t which = offset % Common::BitSize(); + const u64 mask = u64(1) << which; + + u64* bit = std::addressof(bit_storages[depth][ind]); + u64 v = *bit; + ASSERT((v & mask) == 0); + *bit = v | mask; + if (v) { + break; + } + offset = ind; + depth--; + } + } + + void ClearBit(s32 depth, std::size_t offset) { + while (depth >= 0) { + std::size_t ind = offset / Common::BitSize(); + std::size_t which = offset % Common::BitSize(); + const u64 mask = u64(1) << which; + + u64* bit = std::addressof(bit_storages[depth][ind]); + u64 v = *bit; + ASSERT((v & mask) != 0); + v &= ~mask; + *bit = v; + if (v) { + break; + } + offset = ind; + depth--; + } + } + +private: + static constexpr s32 GetRequiredDepth(std::size_t region_size) { + s32 depth = 0; + while (true) { + region_size /= Common::BitSize(); + depth++; + if (region_size == 0) { + return depth; + } + } + } + +public: + static constexpr std::size_t CalculateManagementOverheadSize(std::size_t region_size) { + std::size_t overhead_bits = 0; + for (s32 depth = GetRequiredDepth(region_size) - 1; depth >= 0; depth--) { + region_size = + Common::AlignUp(region_size, Common::BitSize()) / Common::BitSize(); + overhead_bits += region_size; + } + return overhead_bits * sizeof(u64); + } +}; + +} // namespace Kernel -- cgit v1.2.3 From 6a19086001b5d7229728199d074b72c1d0dd34af Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Feb 2021 18:48:02 -0800 Subject: hle: kernel: memory: PageHeap: Migrate to KPageBitmap class. --- src/core/hle/kernel/memory/memory_manager.cpp | 6 +- src/core/hle/kernel/memory/memory_manager.h | 4 +- src/core/hle/kernel/memory/page_heap.cpp | 8 +- src/core/hle/kernel/memory/page_heap.h | 202 ++------------------------ 4 files changed, 23 insertions(+), 197 deletions(-) diff --git a/src/core/hle/kernel/memory/memory_manager.cpp b/src/core/hle/kernel/memory/memory_manager.cpp index 77f135cdc..c373d9947 100644 --- a/src/core/hle/kernel/memory/memory_manager.cpp +++ b/src/core/hle/kernel/memory/memory_manager.cpp @@ -21,7 +21,7 @@ std::size_t MemoryManager::Impl::Initialize(Pool new_pool, u64 start_address, u6 const auto ref_count_size{(size / PageSize) * sizeof(u16)}; const auto optimize_map_size{(Common::AlignUp((size / PageSize), 64) / 64) * sizeof(u64)}; const auto manager_size{Common::AlignUp(optimize_map_size + ref_count_size, PageSize)}; - const auto page_heap_size{PageHeap::CalculateMetadataOverheadSize(size)}; + const auto page_heap_size{PageHeap::CalculateManagementOverheadSize(size)}; const auto total_metadata_size{manager_size + page_heap_size}; ASSERT(manager_size <= total_metadata_size); ASSERT(Common::IsAligned(total_metadata_size, PageSize)); @@ -63,7 +63,7 @@ VAddr MemoryManager::AllocateContinuous(std::size_t num_pages, std::size_t align // Loop, trying to iterate from each block // TODO (bunnei): Support multiple managers Impl& chosen_manager{managers[pool_index]}; - VAddr allocated_block{chosen_manager.AllocateBlock(heap_index)}; + VAddr allocated_block{chosen_manager.AllocateBlock(heap_index, false)}; // If we failed to allocate, quit now if (!allocated_block) { @@ -116,7 +116,7 @@ ResultCode MemoryManager::Allocate(PageLinkedList& page_list, std::size_t num_pa while (num_pages >= pages_per_alloc) { // Allocate a block - VAddr allocated_block{chosen_manager.AllocateBlock(index)}; + VAddr allocated_block{chosen_manager.AllocateBlock(index, false)}; if (!allocated_block) { break; } diff --git a/src/core/hle/kernel/memory/memory_manager.h b/src/core/hle/kernel/memory/memory_manager.h index 3cf444857..00c04eebd 100644 --- a/src/core/hle/kernel/memory/memory_manager.h +++ b/src/core/hle/kernel/memory/memory_manager.h @@ -67,8 +67,8 @@ private: std::size_t Initialize(Pool new_pool, u64 start_address, u64 end_address); - VAddr AllocateBlock(s32 index) { - return heap.AllocateBlock(index); + VAddr AllocateBlock(s32 index, bool random) { + return heap.AllocateBlock(index, random); } void Free(VAddr addr, std::size_t num_pages) { diff --git a/src/core/hle/kernel/memory/page_heap.cpp b/src/core/hle/kernel/memory/page_heap.cpp index 0ab1f7205..8fb53a0e8 100644 --- a/src/core/hle/kernel/memory/page_heap.cpp +++ b/src/core/hle/kernel/memory/page_heap.cpp @@ -32,11 +32,11 @@ void PageHeap::Initialize(VAddr address, std::size_t size, std::size_t metadata_ } } -VAddr PageHeap::AllocateBlock(s32 index) { +VAddr PageHeap::AllocateBlock(s32 index, bool random) { const std::size_t needed_size{blocks[index].GetSize()}; for (s32 i{index}; i < static_cast(MemoryBlockPageShifts.size()); i++) { - if (const VAddr addr{blocks[i].PopBlock()}; addr) { + if (const VAddr addr{blocks[i].PopBlock(random)}; addr) { if (const std::size_t allocated_size{blocks[i].GetSize()}; allocated_size > needed_size) { Free(addr + needed_size, (allocated_size - needed_size) / PageSize); @@ -104,13 +104,13 @@ void PageHeap::Free(VAddr addr, std::size_t num_pages) { } } -std::size_t PageHeap::CalculateMetadataOverheadSize(std::size_t region_size) { +std::size_t PageHeap::CalculateManagementOverheadSize(std::size_t region_size) { std::size_t overhead_size = 0; for (std::size_t i = 0; i < MemoryBlockPageShifts.size(); i++) { const std::size_t cur_block_shift{MemoryBlockPageShifts[i]}; const std::size_t next_block_shift{ (i != MemoryBlockPageShifts.size() - 1) ? MemoryBlockPageShifts[i + 1] : 0}; - overhead_size += PageHeap::Block::CalculateMetadataOverheadSize( + overhead_size += PageHeap::Block::CalculateManagementOverheadSize( region_size, cur_block_shift, next_block_shift); } return Common::AlignUp(overhead_size, PageSize); diff --git a/src/core/hle/kernel/memory/page_heap.h b/src/core/hle/kernel/memory/page_heap.h index 131093284..ee339f329 100644 --- a/src/core/hle/kernel/memory/page_heap.h +++ b/src/core/hle/kernel/memory/page_heap.h @@ -15,6 +15,7 @@ #include "common/assert.h" #include "common/common_funcs.h" #include "common/common_types.h" +#include "core/hle/kernel/k_page_bitmap.h" #include "core/hle/kernel/memory/memory_types.h" namespace Kernel::Memory { @@ -57,189 +58,14 @@ private: class Block final : NonCopyable { private: - class Bitmap final : NonCopyable { - public: - static constexpr std::size_t MaxDepth{4}; - - private: - std::array bit_storages{}; - std::size_t num_bits{}; - std::size_t used_depths{}; - - public: - constexpr Bitmap() = default; - - constexpr std::size_t GetNumBits() const { - return num_bits; - } - constexpr s32 GetHighestDepthIndex() const { - return static_cast(used_depths) - 1; - } - - constexpr u64* Initialize(u64* storage, std::size_t size) { - //* Initially, everything is un-set - num_bits = 0; - - // Calculate the needed bitmap depth - used_depths = static_cast(GetRequiredDepth(size)); - ASSERT(used_depths <= MaxDepth); - - // Set the bitmap pointers - for (s32 depth{GetHighestDepthIndex()}; depth >= 0; depth--) { - bit_storages[depth] = storage; - size = Common::AlignUp(size, 64) / 64; - storage += size; - } - - return storage; - } - - s64 FindFreeBlock() const { - uintptr_t offset{}; - s32 depth{}; - - do { - const u64 v{bit_storages[depth][offset]}; - if (v == 0) { - // Non-zero depth indicates that a previous level had a free block - ASSERT(depth == 0); - return -1; - } - offset = offset * 64 + static_cast(std::countr_zero(v)); - ++depth; - } while (depth < static_cast(used_depths)); - - return static_cast(offset); - } - - constexpr void SetBit(std::size_t offset) { - SetBit(GetHighestDepthIndex(), offset); - num_bits++; - } - - constexpr void ClearBit(std::size_t offset) { - ClearBit(GetHighestDepthIndex(), offset); - num_bits--; - } - - constexpr bool ClearRange(std::size_t offset, std::size_t count) { - const s32 depth{GetHighestDepthIndex()}; - const auto bit_ind{offset / 64}; - u64* bits{bit_storages[depth]}; - if (count < 64) { - const auto shift{offset % 64}; - ASSERT(shift + count <= 64); - // Check that all the bits are set - const u64 mask{((1ULL << count) - 1) << shift}; - u64 v{bits[bit_ind]}; - if ((v & mask) != mask) { - return false; - } - - // Clear the bits - v &= ~mask; - bits[bit_ind] = v; - if (v == 0) { - ClearBit(depth - 1, bit_ind); - } - } else { - ASSERT(offset % 64 == 0); - ASSERT(count % 64 == 0); - // Check that all the bits are set - std::size_t remaining{count}; - std::size_t i = 0; - do { - if (bits[bit_ind + i++] != ~u64(0)) { - return false; - } - remaining -= 64; - } while (remaining > 0); - - // Clear the bits - remaining = count; - i = 0; - do { - bits[bit_ind + i] = 0; - ClearBit(depth - 1, bit_ind + i); - i++; - remaining -= 64; - } while (remaining > 0); - } - - num_bits -= count; - return true; - } - - private: - constexpr void SetBit(s32 depth, std::size_t offset) { - while (depth >= 0) { - const auto ind{offset / 64}; - const auto which{offset % 64}; - const u64 mask{1ULL << which}; - - u64* bit{std::addressof(bit_storages[depth][ind])}; - const u64 v{*bit}; - ASSERT((v & mask) == 0); - *bit = v | mask; - if (v) { - break; - } - offset = ind; - depth--; - } - } - - constexpr void ClearBit(s32 depth, std::size_t offset) { - while (depth >= 0) { - const auto ind{offset / 64}; - const auto which{offset % 64}; - const u64 mask{1ULL << which}; - - u64* bit{std::addressof(bit_storages[depth][ind])}; - u64 v{*bit}; - ASSERT((v & mask) != 0); - v &= ~mask; - *bit = v; - if (v) { - break; - } - offset = ind; - depth--; - } - } - - private: - static constexpr s32 GetRequiredDepth(std::size_t region_size) { - s32 depth = 0; - while (true) { - region_size /= 64; - depth++; - if (region_size == 0) { - return depth; - } - } - } - - public: - static constexpr std::size_t CalculateMetadataOverheadSize(std::size_t region_size) { - std::size_t overhead_bits = 0; - for (s32 depth{GetRequiredDepth(region_size) - 1}; depth >= 0; depth--) { - region_size = Common::AlignUp(region_size, 64) / 64; - overhead_bits += region_size; - } - return overhead_bits * sizeof(u64); - } - }; - - private: - Bitmap bitmap; + KPageBitmap bitmap; VAddr heap_address{}; uintptr_t end_offset{}; std::size_t block_shift{}; std::size_t next_block_shift{}; public: - constexpr Block() = default; + Block() = default; constexpr std::size_t GetShift() const { return block_shift; @@ -260,8 +86,8 @@ private: return GetNumFreeBlocks() * GetNumPages(); } - constexpr u64* Initialize(VAddr addr, std::size_t size, std::size_t bs, std::size_t nbs, - u64* bit_storage) { + u64* Initialize(VAddr addr, std::size_t size, std::size_t bs, std::size_t nbs, + u64* bit_storage) { // Set shifts block_shift = bs; next_block_shift = nbs; @@ -278,7 +104,7 @@ private: return bitmap.Initialize(bit_storage, end_offset); } - constexpr VAddr PushBlock(VAddr address) { + VAddr PushBlock(VAddr address) { // Set the bit for the free block std::size_t offset{(address - heap_address) >> GetShift()}; bitmap.SetBit(offset); @@ -296,9 +122,9 @@ private: return 0; } - VAddr PopBlock() { + VAddr PopBlock(bool random) { // Find a free block - const s64 soffset{bitmap.FindFreeBlock()}; + const s64 soffset{bitmap.FindFreeBlock(random)}; if (soffset < 0) { return 0; } @@ -310,13 +136,13 @@ private: } public: - static constexpr std::size_t CalculateMetadataOverheadSize(std::size_t region_size, - std::size_t cur_block_shift, - std::size_t next_block_shift) { + static constexpr std::size_t CalculateManagementOverheadSize(std::size_t region_size, + std::size_t cur_block_shift, + std::size_t next_block_shift) { const auto cur_block_size{(1ULL << cur_block_shift)}; const auto next_block_size{(1ULL << next_block_shift)}; const auto align{(next_block_shift != 0) ? next_block_size : cur_block_size}; - return Bitmap::CalculateMetadataOverheadSize( + return KPageBitmap::CalculateManagementOverheadSize( (align * 2 + Common::AlignUp(region_size, align)) / cur_block_size); } }; @@ -338,14 +164,14 @@ public: } void Initialize(VAddr heap_address, std::size_t heap_size, std::size_t metadata_size); - VAddr AllocateBlock(s32 index); + VAddr AllocateBlock(s32 index, bool random); void Free(VAddr addr, std::size_t num_pages); void UpdateUsedSize() { used_size = heap_size - (GetNumFreePages() * PageSize); } - static std::size_t CalculateMetadataOverheadSize(std::size_t region_size); + static std::size_t CalculateManagementOverheadSize(std::size_t region_size); private: constexpr std::size_t GetNumFreePages() const { -- cgit v1.2.3 From f7a008d77f8aa47baf4c874c508b38af4965a145 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 11 Feb 2021 18:55:22 -0800 Subject: hle: kernel: KSystemControl does not belong in Memory namespace. --- src/core/CMakeLists.txt | 4 +-- src/core/hle/kernel/k_page_bitmap.h | 4 +-- src/core/hle/kernel/k_system_control.cpp | 42 +++++++++++++++++++++++++++ src/core/hle/kernel/k_system_control.h | 19 ++++++++++++ src/core/hle/kernel/memory/page_table.cpp | 11 +++---- src/core/hle/kernel/memory/system_control.cpp | 41 -------------------------- src/core/hle/kernel/memory/system_control.h | 14 --------- src/core/hle/service/ldr/ldr.cpp | 4 +-- 8 files changed, 73 insertions(+), 66 deletions(-) create mode 100644 src/core/hle/kernel/k_system_control.cpp create mode 100644 src/core/hle/kernel/k_system_control.h delete mode 100644 src/core/hle/kernel/memory/system_control.cpp delete mode 100644 src/core/hle/kernel/memory/system_control.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 6604bc2c5..8aad9cb41 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -182,6 +182,8 @@ add_library(core STATIC hle/kernel/k_spin_lock.h hle/kernel/k_synchronization_object.cpp hle/kernel/k_synchronization_object.h + hle/kernel/k_system_control.cpp + hle/kernel/k_system_control.h hle/kernel/k_thread.cpp hle/kernel/k_thread.h hle/kernel/k_thread_queue.h @@ -204,8 +206,6 @@ add_library(core STATIC hle/kernel/memory/page_table.cpp hle/kernel/memory/page_table.h hle/kernel/memory/slab_heap.h - hle/kernel/memory/system_control.cpp - hle/kernel/memory/system_control.h hle/kernel/object.cpp hle/kernel/object.h hle/kernel/physical_core.cpp diff --git a/src/core/hle/kernel/k_page_bitmap.h b/src/core/hle/kernel/k_page_bitmap.h index da2d20032..c75d667c9 100644 --- a/src/core/hle/kernel/k_page_bitmap.h +++ b/src/core/hle/kernel/k_page_bitmap.h @@ -12,7 +12,7 @@ #include "common/bit_util.h" #include "common/common_types.h" #include "common/tiny_mt.h" -#include "core/hle/kernel/memory/system_control.h" +#include "core/hle/kernel/k_system_control.h" namespace Kernel { @@ -43,7 +43,7 @@ private: public: RandomBitGenerator() { - rng.Initialize(static_cast(Memory::SystemControl::GenerateRandomU64())); + rng.Initialize(static_cast(KSystemControl::GenerateRandomU64())); } std::size_t SelectRandomBit(u64 bitmap) { diff --git a/src/core/hle/kernel/k_system_control.cpp b/src/core/hle/kernel/k_system_control.cpp new file mode 100644 index 000000000..aa1682f69 --- /dev/null +++ b/src/core/hle/kernel/k_system_control.cpp @@ -0,0 +1,42 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include + +#include "core/hle/kernel/k_system_control.h" + +namespace Kernel { + +namespace { +template +u64 GenerateUniformRange(u64 min, u64 max, F f) { + // Handle the case where the difference is too large to represent. + if (max == std::numeric_limits::max() && min == std::numeric_limits::min()) { + return f(); + } + + // Iterate until we get a value in range. + const u64 range_size = ((max + 1) - min); + const u64 effective_max = (std::numeric_limits::max() / range_size) * range_size; + while (true) { + if (const u64 rnd = f(); rnd < effective_max) { + return min + (rnd % range_size); + } + } +} + +} // Anonymous namespace + +u64 KSystemControl::GenerateRandomU64() { + static std::random_device device; + static std::mt19937 gen(device()); + static std::uniform_int_distribution distribution(1, std::numeric_limits::max()); + return distribution(gen); +} + +u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) { + return GenerateUniformRange(min, max, GenerateRandomU64); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_system_control.h b/src/core/hle/kernel/k_system_control.h new file mode 100644 index 000000000..1d5b64ffa --- /dev/null +++ b/src/core/hle/kernel/k_system_control.h @@ -0,0 +1,19 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +namespace Kernel { + +class KSystemControl { +public: + KSystemControl() = default; + + static u64 GenerateRandomRange(u64 min, u64 max); + static u64 GenerateRandomU64(); +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/memory/page_table.cpp b/src/core/hle/kernel/memory/page_table.cpp index 00ed9b881..034d43ecd 100644 --- a/src/core/hle/kernel/memory/page_table.cpp +++ b/src/core/hle/kernel/memory/page_table.cpp @@ -6,14 +6,15 @@ #include "common/assert.h" #include "common/scope_exit.h" #include "core/core.h" +#include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_system_control.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/memory/address_space_info.h" #include "core/hle/kernel/memory/memory_block.h" #include "core/hle/kernel/memory/memory_block_manager.h" #include "core/hle/kernel/memory/page_linked_list.h" #include "core/hle/kernel/memory/page_table.h" -#include "core/hle/kernel/memory/system_control.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_results.h" #include "core/memory.h" @@ -149,13 +150,13 @@ ResultCode PageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_t // Determine random placements for each region std::size_t alias_rnd{}, heap_rnd{}, stack_rnd{}, kmap_rnd{}; if (enable_aslr) { - alias_rnd = SystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * + alias_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * RegionAlignment; - heap_rnd = SystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * + heap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * RegionAlignment; - stack_rnd = SystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * + stack_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * RegionAlignment; - kmap_rnd = SystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * + kmap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * RegionAlignment; } diff --git a/src/core/hle/kernel/memory/system_control.cpp b/src/core/hle/kernel/memory/system_control.cpp deleted file mode 100644 index e855696ad..000000000 --- a/src/core/hle/kernel/memory/system_control.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include - -#include "core/hle/kernel/memory/system_control.h" - -namespace Kernel::Memory::SystemControl { -namespace { -template -u64 GenerateUniformRange(u64 min, u64 max, F f) { - // Handle the case where the difference is too large to represent. - if (max == std::numeric_limits::max() && min == std::numeric_limits::min()) { - return f(); - } - - // Iterate until we get a value in range. - const u64 range_size = ((max + 1) - min); - const u64 effective_max = (std::numeric_limits::max() / range_size) * range_size; - while (true) { - if (const u64 rnd = f(); rnd < effective_max) { - return min + (rnd % range_size); - } - } -} - -} // Anonymous namespace - -u64 GenerateRandomU64() { - static std::random_device device; - static std::mt19937 gen(device()); - static std::uniform_int_distribution distribution(1, std::numeric_limits::max()); - return distribution(gen); -} - -u64 GenerateRandomRange(u64 min, u64 max) { - return GenerateUniformRange(min, max, GenerateRandomU64); -} - -} // namespace Kernel::Memory::SystemControl diff --git a/src/core/hle/kernel/memory/system_control.h b/src/core/hle/kernel/memory/system_control.h deleted file mode 100644 index a01b6b014..000000000 --- a/src/core/hle/kernel/memory/system_control.h +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "common/common_types.h" - -namespace Kernel::Memory::SystemControl { - -u64 GenerateRandomRange(u64 min, u64 max); -u64 GenerateRandomU64(); - -} // namespace Kernel::Memory::SystemControl diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index c724d2554..d3cd25ff8 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -11,8 +11,8 @@ #include "common/scope_exit.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/k_system_control.h" #include "core/hle/kernel/memory/page_table.h" -#include "core/hle/kernel/memory/system_control.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/service/ldr/ldr.h" @@ -315,7 +315,7 @@ public: Kernel::Memory::PageBits}; do { addr = page_table.GetAliasCodeRegionStart() + - (Kernel::Memory::SystemControl::GenerateRandomRange(0, end_pages) + (Kernel::KSystemControl::GenerateRandomRange(0, end_pages) << Kernel::Memory::PageBits); } while (!page_table.IsInsideAddressSpace(addr, size) || page_table.IsInsideHeapRegion(addr, size) || -- cgit v1.2.3 From 701ef616b265d8914f77a399d9a1f41e68683a72 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 12 Feb 2021 15:29:25 -0800 Subject: hle: kernel: memory_manager: Rename AllocateContinuous to AllocateContinuous. --- src/core/hle/kernel/memory/memory_manager.cpp | 5 +++-- src/core/hle/kernel/memory/memory_manager.h | 27 +++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/core/hle/kernel/memory/memory_manager.cpp b/src/core/hle/kernel/memory/memory_manager.cpp index c373d9947..ffda77374 100644 --- a/src/core/hle/kernel/memory/memory_manager.cpp +++ b/src/core/hle/kernel/memory/memory_manager.cpp @@ -46,14 +46,15 @@ void MemoryManager::InitializeManager(Pool pool, u64 start_address, u64 end_addr managers[static_cast(pool)].Initialize(pool, start_address, end_address); } -VAddr MemoryManager::AllocateContinuous(std::size_t num_pages, std::size_t align_pages, Pool pool, - Direction dir) { +VAddr MemoryManager::AllocateAndOpenContinuous(std::size_t num_pages, std::size_t align_pages, + u32 option) { // Early return if we're allocating no pages if (num_pages == 0) { return {}; } // Lock the pool that we're allocating from + const auto [pool, dir] = DecodeOption(option); const auto pool_index{static_cast(pool)}; std::lock_guard lock{pool_locks[pool_index]}; diff --git a/src/core/hle/kernel/memory/memory_manager.h b/src/core/hle/kernel/memory/memory_manager.h index 00c04eebd..80dfbc8c2 100644 --- a/src/core/hle/kernel/memory/memory_manager.h +++ b/src/core/hle/kernel/memory/memory_manager.h @@ -6,7 +6,9 @@ #include #include +#include +#include "common/common_funcs.h" #include "common/common_types.h" #include "core/hle/kernel/memory/page_heap.h" #include "core/hle/result.h" @@ -44,8 +46,8 @@ public: } void InitializeManager(Pool pool, u64 start_address, u64 end_address); - VAddr AllocateContinuous(std::size_t num_pages, std::size_t align_pages, Pool pool, - Direction dir = Direction::FromFront); + + VAddr AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option); ResultCode Allocate(PageLinkedList& page_list, std::size_t num_pages, Pool pool, Direction dir = Direction::FromFront); ResultCode Free(PageLinkedList& page_list, std::size_t num_pages, Pool pool, @@ -53,6 +55,27 @@ public: static constexpr std::size_t MaxManagerCount = 10; +public: + static constexpr u32 EncodeOption(Pool pool, Direction dir) { + return (static_cast(pool) << static_cast(Pool::Shift)) | + (static_cast(dir) << static_cast(Direction::Shift)); + } + + static constexpr Pool GetPool(u32 option) { + return static_cast((static_cast(option) & static_cast(Pool::Mask)) >> + static_cast(Pool::Shift)); + } + + static constexpr Direction GetDirection(u32 option) { + return static_cast( + (static_cast(option) & static_cast(Direction::Mask)) >> + static_cast(Direction::Shift)); + } + + static constexpr std::tuple DecodeOption(u32 option) { + return std::make_tuple(GetPool(option), GetDirection(option)); + } + private: class Impl final : NonCopyable { private: -- cgit v1.2.3 From 7ed5dd0d62347054d5a03a24354cd43bec1184ba Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 12 Feb 2021 15:47:05 -0800 Subject: hle: kernel: Migrate AddressSpaceInfo to KAddressSpaceInfo. --- src/core/CMakeLists.txt | 4 +- src/core/hle/kernel/k_address_space_info.cpp | 117 +++++++++++++++++++++ src/core/hle/kernel/k_address_space_info.h | 31 ++++++ src/core/hle/kernel/memory/address_space_info.cpp | 119 ---------------------- src/core/hle/kernel/memory/address_space_info.h | 34 ------- src/core/hle/kernel/memory/page_table.cpp | 34 +++---- 6 files changed, 167 insertions(+), 172 deletions(-) create mode 100644 src/core/hle/kernel/k_address_space_info.cpp create mode 100644 src/core/hle/kernel/k_address_space_info.h delete mode 100644 src/core/hle/kernel/memory/address_space_info.cpp delete mode 100644 src/core/hle/kernel/memory/address_space_info.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 8aad9cb41..442618e90 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -156,6 +156,8 @@ add_library(core STATIC hle/kernel/hle_ipc.h hle/kernel/k_address_arbiter.cpp hle/kernel/k_address_arbiter.h + hle/kernel/k_address_space_info.cpp + hle/kernel/k_address_space_info.h hle/kernel/k_affinity_mask.h hle/kernel/k_condition_variable.cpp hle/kernel/k_condition_variable.h @@ -191,8 +193,6 @@ add_library(core STATIC hle/kernel/k_writable_event.h hle/kernel/kernel.cpp hle/kernel/kernel.h - hle/kernel/memory/address_space_info.cpp - hle/kernel/memory/address_space_info.h hle/kernel/memory/memory_block.h hle/kernel/memory/memory_block_manager.cpp hle/kernel/memory/memory_block_manager.h diff --git a/src/core/hle/kernel/k_address_space_info.cpp b/src/core/hle/kernel/k_address_space_info.cpp new file mode 100644 index 000000000..24944d15b --- /dev/null +++ b/src/core/hle/kernel/k_address_space_info.cpp @@ -0,0 +1,117 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include + +#include "common/assert.h" +#include "core/hle/kernel/k_address_space_info.h" + +namespace Kernel { + +namespace { + +enum : u64 { + Size_1_MB = 0x100000, + Size_2_MB = 2 * Size_1_MB, + Size_128_MB = 128 * Size_1_MB, + Size_1_GB = 0x40000000, + Size_2_GB = 2 * Size_1_GB, + Size_4_GB = 4 * Size_1_GB, + Size_6_GB = 6 * Size_1_GB, + Size_64_GB = 64 * Size_1_GB, + Size_512_GB = 512 * Size_1_GB, + Invalid = std::numeric_limits::max(), +}; + +// clang-format off +constexpr std::array AddressSpaceInfos{{ + { .bit_width = 32, .address = Size_2_MB , .size = Size_1_GB - Size_2_MB , .type = KAddressSpaceInfo::Type::MapSmall, }, + { .bit_width = 32, .address = Size_1_GB , .size = Size_4_GB - Size_1_GB , .type = KAddressSpaceInfo::Type::MapLarge, }, + { .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = KAddressSpaceInfo::Type::Heap, }, + { .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = KAddressSpaceInfo::Type::Alias, }, + { .bit_width = 36, .address = Size_128_MB, .size = Size_2_GB - Size_128_MB, .type = KAddressSpaceInfo::Type::MapSmall, }, + { .bit_width = 36, .address = Size_2_GB , .size = Size_64_GB - Size_2_GB , .type = KAddressSpaceInfo::Type::MapLarge, }, + { .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, }, + { .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Alias, }, + { .bit_width = 39, .address = Size_128_MB, .size = Size_512_GB - Size_128_MB, .type = KAddressSpaceInfo::Type::Map39Bit, }, + { .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = KAddressSpaceInfo::Type::MapSmall }, + { .bit_width = 39, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, }, + { .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = KAddressSpaceInfo::Type::Alias, }, + { .bit_width = 39, .address = Invalid , .size = Size_2_GB , .type = KAddressSpaceInfo::Type::Stack, }, +}}; +// clang-format on + +constexpr bool IsAllowedIndexForAddress(std::size_t index) { + return index < AddressSpaceInfos.size() && AddressSpaceInfos[index].address != Invalid; +} + +using IndexArray = + std::array(KAddressSpaceInfo::Type::Count)>; + +constexpr IndexArray AddressSpaceIndices32Bit{ + 0, 1, 0, 2, 0, 3, +}; + +constexpr IndexArray AddressSpaceIndices36Bit{ + 4, 5, 4, 6, 4, 7, +}; + +constexpr IndexArray AddressSpaceIndices39Bit{ + 9, 8, 8, 10, 12, 11, +}; + +constexpr bool IsAllowed32BitType(KAddressSpaceInfo::Type type) { + return type < KAddressSpaceInfo::Type::Count && type != KAddressSpaceInfo::Type::Map39Bit && + type != KAddressSpaceInfo::Type::Stack; +} + +constexpr bool IsAllowed36BitType(KAddressSpaceInfo::Type type) { + return type < KAddressSpaceInfo::Type::Count && type != KAddressSpaceInfo::Type::Map39Bit && + type != KAddressSpaceInfo::Type::Stack; +} + +constexpr bool IsAllowed39BitType(KAddressSpaceInfo::Type type) { + return type < KAddressSpaceInfo::Type::Count && type != KAddressSpaceInfo::Type::MapLarge; +} + +} // namespace + +u64 KAddressSpaceInfo::GetAddressSpaceStart(std::size_t width, Type type) { + const std::size_t index{static_cast(type)}; + switch (width) { + case 32: + ASSERT(IsAllowed32BitType(type)); + ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices32Bit[index])); + return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].address; + case 36: + ASSERT(IsAllowed36BitType(type)); + ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices36Bit[index])); + return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].address; + case 39: + ASSERT(IsAllowed39BitType(type)); + ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices39Bit[index])); + return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].address; + } + UNREACHABLE(); + return 0; +} + +std::size_t KAddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type) { + const std::size_t index{static_cast(type)}; + switch (width) { + case 32: + ASSERT(IsAllowed32BitType(type)); + return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].size; + case 36: + ASSERT(IsAllowed36BitType(type)); + return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].size; + case 39: + ASSERT(IsAllowed39BitType(type)); + return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].size; + } + UNREACHABLE(); + return 0; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_address_space_info.h b/src/core/hle/kernel/k_address_space_info.h new file mode 100644 index 000000000..06f31c6d5 --- /dev/null +++ b/src/core/hle/kernel/k_address_space_info.h @@ -0,0 +1,31 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +namespace Kernel { + +struct KAddressSpaceInfo final { + enum class Type : u32 { + MapSmall = 0, + MapLarge = 1, + Map39Bit = 2, + Heap = 3, + Stack = 4, + Alias = 5, + Count, + }; + + static u64 GetAddressSpaceStart(std::size_t width, Type type); + static std::size_t GetAddressSpaceSize(std::size_t width, Type type); + + const std::size_t bit_width{}; + const std::size_t address{}; + const std::size_t size{}; + const Type type{}; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/memory/address_space_info.cpp b/src/core/hle/kernel/memory/address_space_info.cpp deleted file mode 100644 index 6cf43ba24..000000000 --- a/src/core/hle/kernel/memory/address_space_info.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -// This file references various implementation details from Atmosphere, an open-source firmware for -// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. - -#include - -#include "common/assert.h" -#include "core/hle/kernel/memory/address_space_info.h" - -namespace Kernel::Memory { - -namespace { - -enum : u64 { - Size_1_MB = 0x100000, - Size_2_MB = 2 * Size_1_MB, - Size_128_MB = 128 * Size_1_MB, - Size_1_GB = 0x40000000, - Size_2_GB = 2 * Size_1_GB, - Size_4_GB = 4 * Size_1_GB, - Size_6_GB = 6 * Size_1_GB, - Size_64_GB = 64 * Size_1_GB, - Size_512_GB = 512 * Size_1_GB, - Invalid = std::numeric_limits::max(), -}; - -// clang-format off -constexpr std::array AddressSpaceInfos{{ - { .bit_width = 32, .address = Size_2_MB , .size = Size_1_GB - Size_2_MB , .type = AddressSpaceInfo::Type::Is32Bit, }, - { .bit_width = 32, .address = Size_1_GB , .size = Size_4_GB - Size_1_GB , .type = AddressSpaceInfo::Type::Small64Bit, }, - { .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = AddressSpaceInfo::Type::Heap, }, - { .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = AddressSpaceInfo::Type::Alias, }, - { .bit_width = 36, .address = Size_128_MB, .size = Size_2_GB - Size_128_MB, .type = AddressSpaceInfo::Type::Is32Bit, }, - { .bit_width = 36, .address = Size_2_GB , .size = Size_64_GB - Size_2_GB , .type = AddressSpaceInfo::Type::Small64Bit, }, - { .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = AddressSpaceInfo::Type::Heap, }, - { .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = AddressSpaceInfo::Type::Alias, }, - { .bit_width = 39, .address = Size_128_MB, .size = Size_512_GB - Size_128_MB, .type = AddressSpaceInfo::Type::Large64Bit, }, - { .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = AddressSpaceInfo::Type::Is32Bit }, - { .bit_width = 39, .address = Invalid , .size = Size_6_GB , .type = AddressSpaceInfo::Type::Heap, }, - { .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = AddressSpaceInfo::Type::Alias, }, - { .bit_width = 39, .address = Invalid , .size = Size_2_GB , .type = AddressSpaceInfo::Type::Stack, }, -}}; -// clang-format on - -constexpr bool IsAllowedIndexForAddress(std::size_t index) { - return index < AddressSpaceInfos.size() && AddressSpaceInfos[index].address != Invalid; -} - -using IndexArray = std::array(AddressSpaceInfo::Type::Count)>; - -constexpr IndexArray AddressSpaceIndices32Bit{ - 0, 1, 0, 2, 0, 3, -}; - -constexpr IndexArray AddressSpaceIndices36Bit{ - 4, 5, 4, 6, 4, 7, -}; - -constexpr IndexArray AddressSpaceIndices39Bit{ - 9, 8, 8, 10, 12, 11, -}; - -constexpr bool IsAllowed32BitType(AddressSpaceInfo::Type type) { - return type < AddressSpaceInfo::Type::Count && type != AddressSpaceInfo::Type::Large64Bit && - type != AddressSpaceInfo::Type::Stack; -} - -constexpr bool IsAllowed36BitType(AddressSpaceInfo::Type type) { - return type < AddressSpaceInfo::Type::Count && type != AddressSpaceInfo::Type::Large64Bit && - type != AddressSpaceInfo::Type::Stack; -} - -constexpr bool IsAllowed39BitType(AddressSpaceInfo::Type type) { - return type < AddressSpaceInfo::Type::Count && type != AddressSpaceInfo::Type::Small64Bit; -} - -} // namespace - -u64 AddressSpaceInfo::GetAddressSpaceStart(std::size_t width, Type type) { - const std::size_t index{static_cast(type)}; - switch (width) { - case 32: - ASSERT(IsAllowed32BitType(type)); - ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices32Bit[index])); - return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].address; - case 36: - ASSERT(IsAllowed36BitType(type)); - ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices36Bit[index])); - return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].address; - case 39: - ASSERT(IsAllowed39BitType(type)); - ASSERT(IsAllowedIndexForAddress(AddressSpaceIndices39Bit[index])); - return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].address; - } - UNREACHABLE(); - return 0; -} - -std::size_t AddressSpaceInfo::GetAddressSpaceSize(std::size_t width, Type type) { - const std::size_t index{static_cast(type)}; - switch (width) { - case 32: - ASSERT(IsAllowed32BitType(type)); - return AddressSpaceInfos[AddressSpaceIndices32Bit[index]].size; - case 36: - ASSERT(IsAllowed36BitType(type)); - return AddressSpaceInfos[AddressSpaceIndices36Bit[index]].size; - case 39: - ASSERT(IsAllowed39BitType(type)); - return AddressSpaceInfos[AddressSpaceIndices39Bit[index]].size; - } - UNREACHABLE(); - return 0; -} - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/address_space_info.h b/src/core/hle/kernel/memory/address_space_info.h deleted file mode 100644 index a4e6e91e5..000000000 --- a/src/core/hle/kernel/memory/address_space_info.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -// This file references various implementation details from Atmosphere, an open-source firmware for -// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. - -#pragma once - -#include "common/common_types.h" - -namespace Kernel::Memory { - -struct AddressSpaceInfo final { - enum class Type : u32 { - Is32Bit = 0, - Small64Bit = 1, - Large64Bit = 2, - Heap = 3, - Stack = 4, - Alias = 5, - Count, - }; - - static u64 GetAddressSpaceStart(std::size_t width, Type type); - static std::size_t GetAddressSpaceSize(std::size_t width, Type type); - - const std::size_t bit_width{}; - const std::size_t address{}; - const std::size_t size{}; - const Type type{}; -}; - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/page_table.cpp b/src/core/hle/kernel/memory/page_table.cpp index 034d43ecd..02a17a695 100644 --- a/src/core/hle/kernel/memory/page_table.cpp +++ b/src/core/hle/kernel/memory/page_table.cpp @@ -6,11 +6,11 @@ #include "common/assert.h" #include "common/scope_exit.h" #include "core/core.h" +#include "core/hle/kernel/k_address_space_info.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_system_control.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/memory/address_space_info.h" #include "core/hle/kernel/memory/memory_block.h" #include "core/hle/kernel/memory/memory_block_manager.h" #include "core/hle/kernel/memory/page_linked_list.h" @@ -64,19 +64,19 @@ ResultCode PageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_t bool enable_aslr, VAddr code_addr, std::size_t code_size, Memory::MemoryManager::Pool pool) { - const auto GetSpaceStart = [this](AddressSpaceInfo::Type type) { - return AddressSpaceInfo::GetAddressSpaceStart(address_space_width, type); + const auto GetSpaceStart = [this](KAddressSpaceInfo::Type type) { + return KAddressSpaceInfo::GetAddressSpaceStart(address_space_width, type); }; - const auto GetSpaceSize = [this](AddressSpaceInfo::Type type) { - return AddressSpaceInfo::GetAddressSpaceSize(address_space_width, type); + const auto GetSpaceSize = [this](KAddressSpaceInfo::Type type) { + return KAddressSpaceInfo::GetAddressSpaceSize(address_space_width, type); }; // Set our width and heap/alias sizes address_space_width = GetAddressSpaceWidthFromType(as_type); const VAddr start = 0; const VAddr end{1ULL << address_space_width}; - std::size_t alias_region_size{GetSpaceSize(AddressSpaceInfo::Type::Alias)}; - std::size_t heap_region_size{GetSpaceSize(AddressSpaceInfo::Type::Heap)}; + std::size_t alias_region_size{GetSpaceSize(KAddressSpaceInfo::Type::Alias)}; + std::size_t heap_region_size{GetSpaceSize(KAddressSpaceInfo::Type::Heap)}; ASSERT(start <= code_addr); ASSERT(code_addr < code_addr + code_size); @@ -96,12 +96,12 @@ ResultCode PageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_t std::size_t kernel_map_region_size{}; if (address_space_width == 39) { - alias_region_size = GetSpaceSize(AddressSpaceInfo::Type::Alias); - heap_region_size = GetSpaceSize(AddressSpaceInfo::Type::Heap); - stack_region_size = GetSpaceSize(AddressSpaceInfo::Type::Stack); - kernel_map_region_size = GetSpaceSize(AddressSpaceInfo::Type::Is32Bit); - code_region_start = GetSpaceStart(AddressSpaceInfo::Type::Large64Bit); - code_region_end = code_region_start + GetSpaceSize(AddressSpaceInfo::Type::Large64Bit); + alias_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Alias); + heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Heap); + stack_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Stack); + kernel_map_region_size = GetSpaceSize(KAddressSpaceInfo::Type::MapSmall); + code_region_start = GetSpaceStart(KAddressSpaceInfo::Type::Map39Bit); + code_region_end = code_region_start + GetSpaceSize(KAddressSpaceInfo::Type::Map39Bit); alias_code_region_start = code_region_start; alias_code_region_end = code_region_end; process_code_start = Common::AlignDown(code_addr, RegionAlignment); @@ -109,12 +109,12 @@ ResultCode PageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_t } else { stack_region_size = 0; kernel_map_region_size = 0; - code_region_start = GetSpaceStart(AddressSpaceInfo::Type::Is32Bit); - code_region_end = code_region_start + GetSpaceSize(AddressSpaceInfo::Type::Is32Bit); + code_region_start = GetSpaceStart(KAddressSpaceInfo::Type::MapSmall); + code_region_end = code_region_start + GetSpaceSize(KAddressSpaceInfo::Type::MapSmall); stack_region_start = code_region_start; alias_code_region_start = code_region_start; - alias_code_region_end = GetSpaceStart(AddressSpaceInfo::Type::Small64Bit) + - GetSpaceSize(AddressSpaceInfo::Type::Small64Bit); + alias_code_region_end = GetSpaceStart(KAddressSpaceInfo::Type::MapLarge) + + GetSpaceSize(KAddressSpaceInfo::Type::MapLarge); stack_region_end = code_region_end; kernel_map_region_start = code_region_start; kernel_map_region_end = code_region_end; -- cgit v1.2.3 From 1d162f28d139ffbffa6fb84945e3e8b668dc841e Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 12 Feb 2021 16:02:35 -0800 Subject: hle: kernel: Migrate MemoryLayout to KMemoryLayout. --- src/core/CMakeLists.txt | 2 +- src/core/hle/kernel/k_memory_layout.h | 90 ++++++++++++++++++++++++++++++ src/core/hle/kernel/k_thread.cpp | 8 +-- src/core/hle/kernel/kernel.cpp | 4 +- src/core/hle/kernel/memory/memory_layout.h | 90 ------------------------------ src/core/hle/kernel/svc.cpp | 13 ++--- 6 files changed, 103 insertions(+), 104 deletions(-) create mode 100644 src/core/hle/kernel/k_memory_layout.h delete mode 100644 src/core/hle/kernel/memory/memory_layout.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 442618e90..d12260d9c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -166,6 +166,7 @@ add_library(core STATIC hle/kernel/k_light_condition_variable.h hle/kernel/k_light_lock.cpp hle/kernel/k_light_lock.h + hle/kernel/k_memory_layout.h hle/kernel/k_page_bitmap.h hle/kernel/k_priority_queue.h hle/kernel/k_readable_event.cpp @@ -196,7 +197,6 @@ add_library(core STATIC hle/kernel/memory/memory_block.h hle/kernel/memory/memory_block_manager.cpp hle/kernel/memory/memory_block_manager.h - hle/kernel/memory/memory_layout.h hle/kernel/memory/memory_manager.cpp hle/kernel/memory/memory_manager.h hle/kernel/memory/memory_types.h diff --git a/src/core/hle/kernel/k_memory_layout.h b/src/core/hle/kernel/k_memory_layout.h new file mode 100644 index 000000000..0821d2d8c --- /dev/null +++ b/src/core/hle/kernel/k_memory_layout.h @@ -0,0 +1,90 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" +#include "core/device_memory.h" + +namespace Kernel { + +constexpr std::size_t KernelAslrAlignment = 2 * 1024 * 1024; +constexpr std::size_t KernelVirtualAddressSpaceWidth = 1ULL << 39; +constexpr std::size_t KernelPhysicalAddressSpaceWidth = 1ULL << 48; +constexpr std::size_t KernelVirtualAddressSpaceBase = 0ULL - KernelVirtualAddressSpaceWidth; +constexpr std::size_t KernelVirtualAddressSpaceEnd = + KernelVirtualAddressSpaceBase + (KernelVirtualAddressSpaceWidth - KernelAslrAlignment); +constexpr std::size_t KernelVirtualAddressSpaceLast = KernelVirtualAddressSpaceEnd - 1; +constexpr std::size_t KernelVirtualAddressSpaceSize = + KernelVirtualAddressSpaceEnd - KernelVirtualAddressSpaceBase; + +constexpr bool IsKernelAddressKey(VAddr key) { + return KernelVirtualAddressSpaceBase <= key && key <= KernelVirtualAddressSpaceLast; +} + +constexpr bool IsKernelAddress(VAddr address) { + return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd; +} + +class KMemoryRegion final { + friend class KMemoryLayout; + +public: + constexpr PAddr StartAddress() const { + return start_address; + } + + constexpr PAddr EndAddress() const { + return end_address; + } + +private: + constexpr KMemoryRegion() = default; + constexpr KMemoryRegion(PAddr start_address, PAddr end_address) + : start_address{start_address}, end_address{end_address} {} + + const PAddr start_address{}; + const PAddr end_address{}; +}; + +class KMemoryLayout final { +public: + constexpr const KMemoryRegion& Application() const { + return application; + } + + constexpr const KMemoryRegion& Applet() const { + return applet; + } + + constexpr const KMemoryRegion& System() const { + return system; + } + + static constexpr KMemoryLayout GetDefaultLayout() { + constexpr std::size_t application_size{0xcd500000}; + constexpr std::size_t applet_size{0x1fb00000}; + constexpr PAddr application_start_address{Core::DramMemoryMap::End - application_size}; + constexpr PAddr application_end_address{Core::DramMemoryMap::End}; + constexpr PAddr applet_start_address{application_start_address - applet_size}; + constexpr PAddr applet_end_address{applet_start_address + applet_size}; + constexpr PAddr system_start_address{Core::DramMemoryMap::SlabHeapEnd}; + constexpr PAddr system_end_address{applet_start_address}; + return {application_start_address, application_end_address, applet_start_address, + applet_end_address, system_start_address, system_end_address}; + } + +private: + constexpr KMemoryLayout(PAddr application_start_address, std::size_t application_size, + PAddr applet_start_address, std::size_t applet_size, + PAddr system_start_address, std::size_t system_size) + : application{application_start_address, application_size}, + applet{applet_start_address, applet_size}, system{system_start_address, system_size} {} + + const KMemoryRegion application; + const KMemoryRegion applet; + const KMemoryRegion system; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index e5620da5a..1661afbd9 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -20,13 +20,13 @@ #include "core/hardware_properties.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/k_condition_variable.h" +#include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_thread_queue.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/memory/memory_layout.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_results.h" @@ -782,7 +782,7 @@ void KThread::AddWaiterImpl(KThread* thread) { } // Keep track of how many kernel waiters we have. - if (Memory::IsKernelAddressKey(thread->GetAddressKey())) { + if (IsKernelAddressKey(thread->GetAddressKey())) { ASSERT((num_kernel_waiters++) >= 0); } @@ -795,7 +795,7 @@ void KThread::RemoveWaiterImpl(KThread* thread) { ASSERT(kernel.GlobalSchedulerContext().IsLocked()); // Keep track of how many kernel waiters we have. - if (Memory::IsKernelAddressKey(thread->GetAddressKey())) { + if (IsKernelAddressKey(thread->GetAddressKey())) { ASSERT((num_kernel_waiters--) > 0); } @@ -870,7 +870,7 @@ KThread* KThread::RemoveWaiterByKey(s32* out_num_waiters, VAddr key) { KThread* thread = std::addressof(*it); // Keep track of how many kernel waiters we have. - if (Memory::IsKernelAddressKey(thread->GetAddressKey())) { + if (IsKernelAddressKey(thread->GetAddressKey())) { ASSERT((num_kernel_waiters--) > 0); } it = waiter_list.erase(it); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 5eb602843..98b3ec712 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -27,12 +27,12 @@ #include "core/hardware_properties.h" #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/handle_table.h" +#include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/memory/memory_layout.h" #include "core/hle/kernel/memory/memory_manager.h" #include "core/hle/kernel/memory/slab_heap.h" #include "core/hle/kernel/physical_core.h" @@ -266,7 +266,7 @@ struct KernelCore::Impl { void InitializeMemoryLayout() { // Initialize memory layout - constexpr Memory::MemoryLayout layout{Memory::MemoryLayout::GetDefaultLayout()}; + constexpr KMemoryLayout layout{KMemoryLayout::GetDefaultLayout()}; constexpr std::size_t hid_size{0x40000}; constexpr std::size_t font_size{0x1100000}; constexpr std::size_t irs_size{0x8000}; diff --git a/src/core/hle/kernel/memory/memory_layout.h b/src/core/hle/kernel/memory/memory_layout.h deleted file mode 100644 index c7c0b2f49..000000000 --- a/src/core/hle/kernel/memory/memory_layout.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "common/common_types.h" -#include "core/device_memory.h" - -namespace Kernel::Memory { - -constexpr std::size_t KernelAslrAlignment = 2 * 1024 * 1024; -constexpr std::size_t KernelVirtualAddressSpaceWidth = 1ULL << 39; -constexpr std::size_t KernelPhysicalAddressSpaceWidth = 1ULL << 48; -constexpr std::size_t KernelVirtualAddressSpaceBase = 0ULL - KernelVirtualAddressSpaceWidth; -constexpr std::size_t KernelVirtualAddressSpaceEnd = - KernelVirtualAddressSpaceBase + (KernelVirtualAddressSpaceWidth - KernelAslrAlignment); -constexpr std::size_t KernelVirtualAddressSpaceLast = KernelVirtualAddressSpaceEnd - 1; -constexpr std::size_t KernelVirtualAddressSpaceSize = - KernelVirtualAddressSpaceEnd - KernelVirtualAddressSpaceBase; - -constexpr bool IsKernelAddressKey(VAddr key) { - return KernelVirtualAddressSpaceBase <= key && key <= KernelVirtualAddressSpaceLast; -} - -constexpr bool IsKernelAddress(VAddr address) { - return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd; -} - -class MemoryRegion final { - friend class MemoryLayout; - -public: - constexpr PAddr StartAddress() const { - return start_address; - } - - constexpr PAddr EndAddress() const { - return end_address; - } - -private: - constexpr MemoryRegion() = default; - constexpr MemoryRegion(PAddr start_address, PAddr end_address) - : start_address{start_address}, end_address{end_address} {} - - const PAddr start_address{}; - const PAddr end_address{}; -}; - -class MemoryLayout final { -public: - constexpr const MemoryRegion& Application() const { - return application; - } - - constexpr const MemoryRegion& Applet() const { - return applet; - } - - constexpr const MemoryRegion& System() const { - return system; - } - - static constexpr MemoryLayout GetDefaultLayout() { - constexpr std::size_t application_size{0xcd500000}; - constexpr std::size_t applet_size{0x1fb00000}; - constexpr PAddr application_start_address{Core::DramMemoryMap::End - application_size}; - constexpr PAddr application_end_address{Core::DramMemoryMap::End}; - constexpr PAddr applet_start_address{application_start_address - applet_size}; - constexpr PAddr applet_end_address{applet_start_address + applet_size}; - constexpr PAddr system_start_address{Core::DramMemoryMap::SlabHeapEnd}; - constexpr PAddr system_end_address{applet_start_address}; - return {application_start_address, application_end_address, applet_start_address, - applet_end_address, system_start_address, system_end_address}; - } - -private: - constexpr MemoryLayout(PAddr application_start_address, std::size_t application_size, - PAddr applet_start_address, std::size_t applet_size, - PAddr system_start_address, std::size_t system_size) - : application{application_start_address, application_size}, - applet{applet_start_address, applet_size}, system{system_start_address, system_size} {} - - const MemoryRegion application; - const MemoryRegion applet; - const MemoryRegion system; -}; - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 85899f83c..12cfdcf2c 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -27,6 +27,7 @@ #include "core/hle/kernel/k_address_arbiter.h" #include "core/hle/kernel/k_condition_variable.h" #include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scheduler.h" @@ -38,7 +39,6 @@ #include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/memory/memory_block.h" -#include "core/hle/kernel/memory/memory_layout.h" #include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/process.h" @@ -508,7 +508,7 @@ static ResultCode ArbitrateLock(Core::System& system, Handle thread_handle, VAdd thread_handle, address, tag); // Validate the input address. - if (Memory::IsKernelAddress(address)) { + if (IsKernelAddress(address)) { LOG_ERROR(Kernel_SVC, "Attempting to arbitrate a lock on a kernel address (address={:08X})", address); return ResultInvalidCurrentMemory; @@ -531,8 +531,7 @@ static ResultCode ArbitrateUnlock(Core::System& system, VAddr address) { LOG_TRACE(Kernel_SVC, "called address=0x{:X}", address); // Validate the input address. - - if (Memory::IsKernelAddress(address)) { + if (IsKernelAddress(address)) { LOG_ERROR(Kernel_SVC, "Attempting to arbitrate an unlock on a kernel address (address={:08X})", address); @@ -1638,7 +1637,7 @@ static ResultCode WaitProcessWideKeyAtomic(Core::System& system, VAddr address, cv_key, tag, timeout_ns); // Validate input. - if (Memory::IsKernelAddress(address)) { + if (IsKernelAddress(address)) { LOG_ERROR(Kernel_SVC, "Attempted to wait on kernel address (address={:08X})", address); return ResultInvalidCurrentMemory; } @@ -1720,7 +1719,7 @@ static ResultCode WaitForAddress(Core::System& system, VAddr address, Svc::Arbit address, arb_type, value, timeout_ns); // Validate input. - if (Memory::IsKernelAddress(address)) { + if (IsKernelAddress(address)) { LOG_ERROR(Kernel_SVC, "Attempting to wait on kernel address (address={:08X})", address); return ResultInvalidCurrentMemory; } @@ -1765,7 +1764,7 @@ static ResultCode SignalToAddress(Core::System& system, VAddr address, Svc::Sign address, signal_type, value, count); // Validate input. - if (Memory::IsKernelAddress(address)) { + if (IsKernelAddress(address)) { LOG_ERROR(Kernel_SVC, "Attempting to signal to a kernel address (address={:08X})", address); return ResultInvalidCurrentMemory; } -- cgit v1.2.3 From 9e520e8f1233cb4e586b076cd5cc8b7c22ec85ce Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 12 Feb 2021 16:21:12 -0800 Subject: hle: kernel: Migrate SlabHeap to KSlabHeap. --- src/core/CMakeLists.txt | 2 +- src/core/hle/kernel/k_slab_heap.h | 160 ++++++++++++++++++++++++++++++++ src/core/hle/kernel/kernel.cpp | 10 +- src/core/hle/kernel/kernel.h | 10 +- src/core/hle/kernel/memory/slab_heap.h | 163 --------------------------------- 5 files changed, 172 insertions(+), 173 deletions(-) create mode 100644 src/core/hle/kernel/k_slab_heap.h delete mode 100644 src/core/hle/kernel/memory/slab_heap.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index d12260d9c..a2dce69a7 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -181,6 +181,7 @@ add_library(core STATIC hle/kernel/k_scoped_scheduler_lock_and_sleep.h hle/kernel/k_shared_memory.cpp hle/kernel/k_shared_memory.h + hle/kernel/k_slab_heap.h hle/kernel/k_spin_lock.cpp hle/kernel/k_spin_lock.h hle/kernel/k_synchronization_object.cpp @@ -205,7 +206,6 @@ add_library(core STATIC hle/kernel/memory/page_heap.h hle/kernel/memory/page_table.cpp hle/kernel/memory/page_table.h - hle/kernel/memory/slab_heap.h hle/kernel/object.cpp hle/kernel/object.h hle/kernel/physical_core.cpp diff --git a/src/core/hle/kernel/k_slab_heap.h b/src/core/hle/kernel/k_slab_heap.h new file mode 100644 index 000000000..aa4471d2f --- /dev/null +++ b/src/core/hle/kernel/k_slab_heap.h @@ -0,0 +1,160 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/assert.h" +#include "common/common_types.h" + +namespace Kernel { + +namespace impl { + +class KSlabHeapImpl final : NonCopyable { +public: + struct Node { + Node* next{}; + }; + + constexpr KSlabHeapImpl() = default; + + void Initialize(std::size_t size) { + ASSERT(head == nullptr); + obj_size = size; + } + + constexpr std::size_t GetObjectSize() const { + return obj_size; + } + + Node* GetHead() const { + return head; + } + + void* Allocate() { + Node* ret = head.load(); + + do { + if (ret == nullptr) { + break; + } + } while (!head.compare_exchange_weak(ret, ret->next)); + + return ret; + } + + void Free(void* obj) { + Node* node = static_cast(obj); + + Node* cur_head = head.load(); + do { + node->next = cur_head; + } while (!head.compare_exchange_weak(cur_head, node)); + } + +private: + std::atomic head{}; + std::size_t obj_size{}; +}; + +} // namespace impl + +class KSlabHeapBase : NonCopyable { +public: + constexpr KSlabHeapBase() = default; + + constexpr bool Contains(uintptr_t addr) const { + return start <= addr && addr < end; + } + + constexpr std::size_t GetSlabHeapSize() const { + return (end - start) / GetObjectSize(); + } + + constexpr std::size_t GetObjectSize() const { + return impl.GetObjectSize(); + } + + constexpr uintptr_t GetSlabHeapAddress() const { + return start; + } + + std::size_t GetObjectIndexImpl(const void* obj) const { + return (reinterpret_cast(obj) - start) / GetObjectSize(); + } + + std::size_t GetPeakIndex() const { + return GetObjectIndexImpl(reinterpret_cast(peak)); + } + + void* AllocateImpl() { + return impl.Allocate(); + } + + void FreeImpl(void* obj) { + // Don't allow freeing an object that wasn't allocated from this heap + ASSERT(Contains(reinterpret_cast(obj))); + impl.Free(obj); + } + + void InitializeImpl(std::size_t obj_size, void* memory, std::size_t memory_size) { + // Ensure we don't initialize a slab using null memory + ASSERT(memory != nullptr); + + // Initialize the base allocator + impl.Initialize(obj_size); + + // Set our tracking variables + const std::size_t num_obj = (memory_size / obj_size); + start = reinterpret_cast(memory); + end = start + num_obj * obj_size; + peak = start; + + // Free the objects + u8* cur = reinterpret_cast(end); + + for (std::size_t i{}; i < num_obj; i++) { + cur -= obj_size; + impl.Free(cur); + } + } + +private: + using Impl = impl::KSlabHeapImpl; + + Impl impl; + uintptr_t peak{}; + uintptr_t start{}; + uintptr_t end{}; +}; + +template +class KSlabHeap final : public KSlabHeapBase { +public: + constexpr KSlabHeap() : KSlabHeapBase() {} + + void Initialize(void* memory, std::size_t memory_size) { + InitializeImpl(sizeof(T), memory, memory_size); + } + + T* Allocate() { + T* obj = static_cast(AllocateImpl()); + if (obj != nullptr) { + new (obj) T(); + } + return obj; + } + + void Free(T* obj) { + FreeImpl(obj); + } + + constexpr std::size_t GetObjectIndex(const T* obj) const { + return GetObjectIndexImpl(obj); + } +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 98b3ec712..e4de3f3bf 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -31,10 +31,10 @@ #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_shared_memory.h" +#include "core/hle/kernel/k_slab_heap.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/memory/memory_manager.h" -#include "core/hle/kernel/memory/slab_heap.h" #include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/service_thread.h" @@ -306,7 +306,7 @@ struct KernelCore::Impl { Memory::MemoryPermission::Read, time_addr, time_size, "Time:SharedMemory"); // Allocate slab heaps - user_slab_heap_pages = std::make_unique>(); + user_slab_heap_pages = std::make_unique>(); constexpr u64 user_slab_heap_size{0x1ef000}; // Reserve slab heaps @@ -349,7 +349,7 @@ struct KernelCore::Impl { // Kernel memory management std::unique_ptr memory_manager; - std::unique_ptr> user_slab_heap_pages; + std::unique_ptr> user_slab_heap_pages; // Shared memory for services std::shared_ptr hid_shared_mem; @@ -581,11 +581,11 @@ const Memory::MemoryManager& KernelCore::MemoryManager() const { return *impl->memory_manager; } -Memory::SlabHeap& KernelCore::GetUserSlabHeapPages() { +KSlabHeap& KernelCore::GetUserSlabHeapPages() { return *impl->user_slab_heap_pages; } -const Memory::SlabHeap& KernelCore::GetUserSlabHeapPages() const { +const KSlabHeap& KernelCore::GetUserSlabHeapPages() const { return *impl->user_slab_heap_pages; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index c5b32b260..5488c962a 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -29,8 +29,7 @@ namespace Kernel { namespace Memory { class MemoryManager; -template -class SlabHeap; + } // namespace Memory class ClientPort; @@ -46,6 +45,9 @@ class Synchronization; class KThread; class TimeManager; +template +class KSlabHeap; + using EmuThreadHandle = uintptr_t; constexpr EmuThreadHandle EmuThreadHandleInvalid{}; constexpr EmuThreadHandle EmuThreadHandleReserved{1ULL << 63}; @@ -184,10 +186,10 @@ public: const Memory::MemoryManager& MemoryManager() const; /// Gets the slab heap allocated for user space pages. - Memory::SlabHeap& GetUserSlabHeapPages(); + KSlabHeap& GetUserSlabHeapPages(); /// Gets the slab heap allocated for user space pages. - const Memory::SlabHeap& GetUserSlabHeapPages() const; + const KSlabHeap& GetUserSlabHeapPages() const; /// Gets the shared memory object for HID services. Kernel::KSharedMemory& GetHidSharedMem(); diff --git a/src/core/hle/kernel/memory/slab_heap.h b/src/core/hle/kernel/memory/slab_heap.h deleted file mode 100644 index 465eaddb3..000000000 --- a/src/core/hle/kernel/memory/slab_heap.h +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -// This file references various implementation details from Atmosphere, an open-source firmware for -// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. - -#pragma once - -#include - -#include "common/assert.h" -#include "common/common_types.h" - -namespace Kernel::Memory { - -namespace impl { - -class SlabHeapImpl final : NonCopyable { -public: - struct Node { - Node* next{}; - }; - - constexpr SlabHeapImpl() = default; - - void Initialize(std::size_t size) { - ASSERT(head == nullptr); - obj_size = size; - } - - constexpr std::size_t GetObjectSize() const { - return obj_size; - } - - Node* GetHead() const { - return head; - } - - void* Allocate() { - Node* ret = head.load(); - - do { - if (ret == nullptr) { - break; - } - } while (!head.compare_exchange_weak(ret, ret->next)); - - return ret; - } - - void Free(void* obj) { - Node* node = static_cast(obj); - - Node* cur_head = head.load(); - do { - node->next = cur_head; - } while (!head.compare_exchange_weak(cur_head, node)); - } - -private: - std::atomic head{}; - std::size_t obj_size{}; -}; - -} // namespace impl - -class SlabHeapBase : NonCopyable { -public: - constexpr SlabHeapBase() = default; - - constexpr bool Contains(uintptr_t addr) const { - return start <= addr && addr < end; - } - - constexpr std::size_t GetSlabHeapSize() const { - return (end - start) / GetObjectSize(); - } - - constexpr std::size_t GetObjectSize() const { - return impl.GetObjectSize(); - } - - constexpr uintptr_t GetSlabHeapAddress() const { - return start; - } - - std::size_t GetObjectIndexImpl(const void* obj) const { - return (reinterpret_cast(obj) - start) / GetObjectSize(); - } - - std::size_t GetPeakIndex() const { - return GetObjectIndexImpl(reinterpret_cast(peak)); - } - - void* AllocateImpl() { - return impl.Allocate(); - } - - void FreeImpl(void* obj) { - // Don't allow freeing an object that wasn't allocated from this heap - ASSERT(Contains(reinterpret_cast(obj))); - impl.Free(obj); - } - - void InitializeImpl(std::size_t obj_size, void* memory, std::size_t memory_size) { - // Ensure we don't initialize a slab using null memory - ASSERT(memory != nullptr); - - // Initialize the base allocator - impl.Initialize(obj_size); - - // Set our tracking variables - const std::size_t num_obj = (memory_size / obj_size); - start = reinterpret_cast(memory); - end = start + num_obj * obj_size; - peak = start; - - // Free the objects - u8* cur = reinterpret_cast(end); - - for (std::size_t i{}; i < num_obj; i++) { - cur -= obj_size; - impl.Free(cur); - } - } - -private: - using Impl = impl::SlabHeapImpl; - - Impl impl; - uintptr_t peak{}; - uintptr_t start{}; - uintptr_t end{}; -}; - -template -class SlabHeap final : public SlabHeapBase { -public: - constexpr SlabHeap() : SlabHeapBase() {} - - void Initialize(void* memory, std::size_t memory_size) { - InitializeImpl(sizeof(T), memory, memory_size); - } - - T* Allocate() { - T* obj = static_cast(AllocateImpl()); - if (obj != nullptr) { - new (obj) T(); - } - return obj; - } - - void Free(T* obj) { - FreeImpl(obj); - } - - constexpr std::size_t GetObjectIndex(const T* obj) const { - return GetObjectIndexImpl(obj); - } -}; - -} // namespace Kernel::Memory -- cgit v1.2.3 From 65e0178cc09299550aee949d7b89e211017bddee Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 12 Feb 2021 17:02:51 -0800 Subject: hle: kernel: Migrate to KMemoryBlock, KMemoryBlockManager, and others. --- src/core/CMakeLists.txt | 8 +- src/core/hle/kernel/k_memory_block.h | 332 +++++++++++++++ src/core/hle/kernel/k_memory_block_manager.cpp | 223 ++++++++++ src/core/hle/kernel/k_memory_block_manager.h | 67 +++ src/core/hle/kernel/k_shared_memory.cpp | 12 +- src/core/hle/kernel/k_shared_memory.h | 12 +- src/core/hle/kernel/kernel.cpp | 32 +- src/core/hle/kernel/kernel.h | 6 +- src/core/hle/kernel/memory/memory_block.h | 335 --------------- .../hle/kernel/memory/memory_block_manager.cpp | 223 ---------- src/core/hle/kernel/memory/memory_block_manager.h | 66 --- src/core/hle/kernel/memory/memory_types.h | 18 - src/core/hle/kernel/memory/page_heap.h | 2 +- src/core/hle/kernel/memory/page_linked_list.h | 2 +- src/core/hle/kernel/memory/page_table.cpp | 456 +++++++++++---------- src/core/hle/kernel/memory/page_table.h | 81 ++-- src/core/hle/kernel/memory_types.h | 18 + src/core/hle/kernel/process.cpp | 41 +- src/core/hle/kernel/svc.cpp | 28 +- src/core/hle/kernel/transfer_memory.cpp | 2 +- src/core/hle/kernel/transfer_memory.h | 6 +- src/core/hle/service/ldr/ldr.cpp | 21 +- 22 files changed, 997 insertions(+), 994 deletions(-) create mode 100644 src/core/hle/kernel/k_memory_block.h create mode 100644 src/core/hle/kernel/k_memory_block_manager.cpp create mode 100644 src/core/hle/kernel/k_memory_block_manager.h delete mode 100644 src/core/hle/kernel/memory/memory_block.h delete mode 100644 src/core/hle/kernel/memory/memory_block_manager.cpp delete mode 100644 src/core/hle/kernel/memory/memory_block_manager.h delete mode 100644 src/core/hle/kernel/memory/memory_types.h create mode 100644 src/core/hle/kernel/memory_types.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a2dce69a7..a304dd935 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -166,6 +166,9 @@ add_library(core STATIC hle/kernel/k_light_condition_variable.h hle/kernel/k_light_lock.cpp hle/kernel/k_light_lock.h + hle/kernel/k_memory_block.h + hle/kernel/k_memory_block_manager.cpp + hle/kernel/k_memory_block_manager.h hle/kernel/k_memory_layout.h hle/kernel/k_page_bitmap.h hle/kernel/k_priority_queue.h @@ -195,12 +198,9 @@ add_library(core STATIC hle/kernel/k_writable_event.h hle/kernel/kernel.cpp hle/kernel/kernel.h - hle/kernel/memory/memory_block.h - hle/kernel/memory/memory_block_manager.cpp - hle/kernel/memory/memory_block_manager.h + hle/kernel/memory_types.h hle/kernel/memory/memory_manager.cpp hle/kernel/memory/memory_manager.h - hle/kernel/memory/memory_types.h hle/kernel/memory/page_linked_list.h hle/kernel/memory/page_heap.cpp hle/kernel/memory/page_heap.h diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h new file mode 100644 index 000000000..c5b9c5e85 --- /dev/null +++ b/src/core/hle/kernel/k_memory_block.h @@ -0,0 +1,332 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/alignment.h" +#include "common/assert.h" +#include "common/common_types.h" +#include "core/hle/kernel/memory_types.h" +#include "core/hle/kernel/svc_types.h" + +namespace Kernel { + +enum class KMemoryState : u32 { + None = 0, + Mask = 0xFF, + All = ~None, + + FlagCanReprotect = (1 << 8), + FlagCanDebug = (1 << 9), + FlagCanUseIpc = (1 << 10), + FlagCanUseNonDeviceIpc = (1 << 11), + FlagCanUseNonSecureIpc = (1 << 12), + FlagMapped = (1 << 13), + FlagCode = (1 << 14), + FlagCanAlias = (1 << 15), + FlagCanCodeAlias = (1 << 16), + FlagCanTransfer = (1 << 17), + FlagCanQueryPhysical = (1 << 18), + FlagCanDeviceMap = (1 << 19), + FlagCanAlignedDeviceMap = (1 << 20), + FlagCanIpcUserBuffer = (1 << 21), + FlagReferenceCounted = (1 << 22), + FlagCanMapProcess = (1 << 23), + FlagCanChangeAttribute = (1 << 24), + FlagCanCodeMemory = (1 << 25), + + FlagsData = FlagCanReprotect | FlagCanUseIpc | FlagCanUseNonDeviceIpc | FlagCanUseNonSecureIpc | + FlagMapped | FlagCanAlias | FlagCanTransfer | FlagCanQueryPhysical | + FlagCanDeviceMap | FlagCanAlignedDeviceMap | FlagCanIpcUserBuffer | + FlagReferenceCounted | FlagCanChangeAttribute, + + FlagsCode = FlagCanDebug | FlagCanUseIpc | FlagCanUseNonDeviceIpc | FlagCanUseNonSecureIpc | + FlagMapped | FlagCode | FlagCanQueryPhysical | FlagCanDeviceMap | + FlagCanAlignedDeviceMap | FlagReferenceCounted, + + FlagsMisc = FlagMapped | FlagReferenceCounted | FlagCanQueryPhysical | FlagCanDeviceMap, + + Free = static_cast(Svc::MemoryState::Free), + Io = static_cast(Svc::MemoryState::Io) | FlagMapped, + Static = static_cast(Svc::MemoryState::Static) | FlagMapped | FlagCanQueryPhysical, + Code = static_cast(Svc::MemoryState::Code) | FlagsCode | FlagCanMapProcess, + CodeData = static_cast(Svc::MemoryState::CodeData) | FlagsData | FlagCanMapProcess | + FlagCanCodeMemory, + Shared = static_cast(Svc::MemoryState::Shared) | FlagMapped | FlagReferenceCounted, + Normal = static_cast(Svc::MemoryState::Normal) | FlagsData | FlagCanCodeMemory, + + AliasCode = static_cast(Svc::MemoryState::AliasCode) | FlagsCode | FlagCanMapProcess | + FlagCanCodeAlias, + AliasCodeData = static_cast(Svc::MemoryState::AliasCodeData) | FlagsData | + FlagCanMapProcess | FlagCanCodeAlias | FlagCanCodeMemory, + + Ipc = static_cast(Svc::MemoryState::Ipc) | FlagsMisc | FlagCanAlignedDeviceMap | + FlagCanUseIpc | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, + + Stack = static_cast(Svc::MemoryState::Stack) | FlagsMisc | FlagCanAlignedDeviceMap | + FlagCanUseIpc | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, + + ThreadLocal = + static_cast(Svc::MemoryState::ThreadLocal) | FlagMapped | FlagReferenceCounted, + + Transferred = static_cast(Svc::MemoryState::Transferred) | FlagsMisc | + FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc | + FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, + + SharedTransferred = static_cast(Svc::MemoryState::SharedTransferred) | FlagsMisc | + FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, + + SharedCode = static_cast(Svc::MemoryState::SharedCode) | FlagMapped | + FlagReferenceCounted | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, + + Inaccessible = static_cast(Svc::MemoryState::Inaccessible), + + NonSecureIpc = static_cast(Svc::MemoryState::NonSecureIpc) | FlagsMisc | + FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, + + NonDeviceIpc = + static_cast(Svc::MemoryState::NonDeviceIpc) | FlagsMisc | FlagCanUseNonDeviceIpc, + + Kernel = static_cast(Svc::MemoryState::Kernel) | FlagMapped, + + GeneratedCode = static_cast(Svc::MemoryState::GeneratedCode) | FlagMapped | + FlagReferenceCounted | FlagCanDebug, + CodeOut = static_cast(Svc::MemoryState::CodeOut) | FlagMapped | FlagReferenceCounted, +}; +DECLARE_ENUM_FLAG_OPERATORS(KMemoryState); + +static_assert(static_cast(KMemoryState::Free) == 0x00000000); +static_assert(static_cast(KMemoryState::Io) == 0x00002001); +static_assert(static_cast(KMemoryState::Static) == 0x00042002); +static_assert(static_cast(KMemoryState::Code) == 0x00DC7E03); +static_assert(static_cast(KMemoryState::CodeData) == 0x03FEBD04); +static_assert(static_cast(KMemoryState::Normal) == 0x037EBD05); +static_assert(static_cast(KMemoryState::Shared) == 0x00402006); +static_assert(static_cast(KMemoryState::AliasCode) == 0x00DD7E08); +static_assert(static_cast(KMemoryState::AliasCodeData) == 0x03FFBD09); +static_assert(static_cast(KMemoryState::Ipc) == 0x005C3C0A); +static_assert(static_cast(KMemoryState::Stack) == 0x005C3C0B); +static_assert(static_cast(KMemoryState::ThreadLocal) == 0x0040200C); +static_assert(static_cast(KMemoryState::Transferred) == 0x015C3C0D); +static_assert(static_cast(KMemoryState::SharedTransferred) == 0x005C380E); +static_assert(static_cast(KMemoryState::SharedCode) == 0x0040380F); +static_assert(static_cast(KMemoryState::Inaccessible) == 0x00000010); +static_assert(static_cast(KMemoryState::NonSecureIpc) == 0x005C3811); +static_assert(static_cast(KMemoryState::NonDeviceIpc) == 0x004C2812); +static_assert(static_cast(KMemoryState::Kernel) == 0x00002013); +static_assert(static_cast(KMemoryState::GeneratedCode) == 0x00402214); +static_assert(static_cast(KMemoryState::CodeOut) == 0x00402015); + +enum class KMemoryPermission : u8 { + None = 0, + Mask = static_cast(~None), + + Read = 1 << 0, + Write = 1 << 1, + Execute = 1 << 2, + + ReadAndWrite = Read | Write, + ReadAndExecute = Read | Execute, + + UserMask = static_cast(Svc::MemoryPermission::Read | Svc::MemoryPermission::Write | + Svc::MemoryPermission::Execute), +}; +DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission); + +enum class KMemoryAttribute : u8 { + None = 0x00, + Mask = 0x7F, + All = Mask, + DontCareMask = 0x80, + + Locked = static_cast(Svc::MemoryAttribute::Locked), + IpcLocked = static_cast(Svc::MemoryAttribute::IpcLocked), + DeviceShared = static_cast(Svc::MemoryAttribute::DeviceShared), + Uncached = static_cast(Svc::MemoryAttribute::Uncached), + + IpcAndDeviceMapped = IpcLocked | DeviceShared, + LockedAndIpcLocked = Locked | IpcLocked, + DeviceSharedAndUncached = DeviceShared | Uncached +}; +DECLARE_ENUM_FLAG_OPERATORS(KMemoryAttribute); + +static_assert((static_cast(KMemoryAttribute::Mask) & + static_cast(KMemoryAttribute::DontCareMask)) == 0); + +struct KMemoryInfo { + VAddr addr{}; + std::size_t size{}; + KMemoryState state{}; + KMemoryPermission perm{}; + KMemoryAttribute attribute{}; + KMemoryPermission original_perm{}; + u16 ipc_lock_count{}; + u16 device_use_count{}; + + constexpr Svc::MemoryInfo GetSvcMemoryInfo() const { + return { + addr, + size, + static_cast(state & KMemoryState::Mask), + static_cast(attribute & KMemoryAttribute::Mask), + static_cast(perm & KMemoryPermission::UserMask), + ipc_lock_count, + device_use_count, + }; + } + + constexpr VAddr GetAddress() const { + return addr; + } + constexpr std::size_t GetSize() const { + return size; + } + constexpr std::size_t GetNumPages() const { + return GetSize() / PageSize; + } + constexpr VAddr GetEndAddress() const { + return GetAddress() + GetSize(); + } + constexpr VAddr GetLastAddress() const { + return GetEndAddress() - 1; + } +}; + +class KMemoryBlock final { + friend class KMemoryBlockManager; + +private: + VAddr addr{}; + std::size_t num_pages{}; + KMemoryState state{KMemoryState::None}; + u16 ipc_lock_count{}; + u16 device_use_count{}; + KMemoryPermission perm{KMemoryPermission::None}; + KMemoryPermission original_perm{KMemoryPermission::None}; + KMemoryAttribute attribute{KMemoryAttribute::None}; + +public: + static constexpr int Compare(const KMemoryBlock& lhs, const KMemoryBlock& rhs) { + if (lhs.GetAddress() < rhs.GetAddress()) { + return -1; + } else if (lhs.GetAddress() <= rhs.GetLastAddress()) { + return 0; + } else { + return 1; + } + } + +public: + constexpr KMemoryBlock() = default; + constexpr KMemoryBlock(VAddr addr_, std::size_t num_pages_, KMemoryState state_, + KMemoryPermission perm_, KMemoryAttribute attribute_) + : addr{addr_}, num_pages(num_pages_), state{state_}, perm{perm_}, attribute{attribute_} {} + + constexpr VAddr GetAddress() const { + return addr; + } + + constexpr std::size_t GetNumPages() const { + return num_pages; + } + + constexpr std::size_t GetSize() const { + return GetNumPages() * PageSize; + } + + constexpr VAddr GetEndAddress() const { + return GetAddress() + GetSize(); + } + + constexpr VAddr GetLastAddress() const { + return GetEndAddress() - 1; + } + + constexpr KMemoryInfo GetMemoryInfo() const { + return { + GetAddress(), GetSize(), state, perm, + attribute, original_perm, ipc_lock_count, device_use_count, + }; + } + + void ShareToDevice(KMemoryPermission /*new_perm*/) { + ASSERT((attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared || + device_use_count == 0); + attribute |= KMemoryAttribute::DeviceShared; + const u16 new_use_count{++device_use_count}; + ASSERT(new_use_count > 0); + } + + void UnshareToDevice(KMemoryPermission /*new_perm*/) { + ASSERT((attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared); + const u16 prev_use_count{device_use_count--}; + ASSERT(prev_use_count > 0); + if (prev_use_count == 1) { + attribute &= ~KMemoryAttribute::DeviceShared; + } + } + +private: + constexpr bool HasProperties(KMemoryState s, KMemoryPermission p, KMemoryAttribute a) const { + constexpr KMemoryAttribute AttributeIgnoreMask{KMemoryAttribute::DontCareMask | + KMemoryAttribute::IpcLocked | + KMemoryAttribute::DeviceShared}; + return state == s && perm == p && + (attribute | AttributeIgnoreMask) == (a | AttributeIgnoreMask); + } + + constexpr bool HasSameProperties(const KMemoryBlock& rhs) const { + return state == rhs.state && perm == rhs.perm && original_perm == rhs.original_perm && + attribute == rhs.attribute && ipc_lock_count == rhs.ipc_lock_count && + device_use_count == rhs.device_use_count; + } + + constexpr bool Contains(VAddr start) const { + return GetAddress() <= start && start <= GetEndAddress(); + } + + constexpr void Add(std::size_t count) { + ASSERT(count > 0); + ASSERT(GetAddress() + count * PageSize - 1 < GetEndAddress() + count * PageSize - 1); + + num_pages += count; + } + + constexpr void Update(KMemoryState new_state, KMemoryPermission new_perm, + KMemoryAttribute new_attribute) { + ASSERT(original_perm == KMemoryPermission::None); + ASSERT((attribute & KMemoryAttribute::IpcLocked) == KMemoryAttribute::None); + + state = new_state; + perm = new_perm; + + attribute = static_cast( + new_attribute | + (attribute & (KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared))); + } + + constexpr KMemoryBlock Split(VAddr split_addr) { + ASSERT(GetAddress() < split_addr); + ASSERT(Contains(split_addr)); + ASSERT(Common::IsAligned(split_addr, PageSize)); + + KMemoryBlock block; + block.addr = addr; + block.num_pages = (split_addr - GetAddress()) / PageSize; + block.state = state; + block.ipc_lock_count = ipc_lock_count; + block.device_use_count = device_use_count; + block.perm = perm; + block.original_perm = original_perm; + block.attribute = attribute; + + addr = split_addr; + num_pages -= block.num_pages; + + return block; + } +}; +static_assert(std::is_trivially_destructible::value); + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_memory_block_manager.cpp b/src/core/hle/kernel/k_memory_block_manager.cpp new file mode 100644 index 000000000..4a2d88008 --- /dev/null +++ b/src/core/hle/kernel/k_memory_block_manager.cpp @@ -0,0 +1,223 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/kernel/k_memory_block_manager.h" +#include "core/hle/kernel/memory_types.h" + +namespace Kernel { + +KMemoryBlockManager::KMemoryBlockManager(VAddr start_addr, VAddr end_addr) + : start_addr{start_addr}, end_addr{end_addr} { + const u64 num_pages{(end_addr - start_addr) / PageSize}; + memory_block_tree.emplace_back(start_addr, num_pages, KMemoryState::Free, + KMemoryPermission::None, KMemoryAttribute::None); +} + +KMemoryBlockManager::iterator KMemoryBlockManager::FindIterator(VAddr addr) { + auto node{memory_block_tree.begin()}; + while (node != end()) { + const VAddr end_addr{node->GetNumPages() * PageSize + node->GetAddress()}; + if (node->GetAddress() <= addr && end_addr - 1 >= addr) { + return node; + } + node = std::next(node); + } + return end(); +} + +VAddr KMemoryBlockManager::FindFreeArea(VAddr region_start, std::size_t region_num_pages, + std::size_t num_pages, std::size_t align, + std::size_t offset, std::size_t guard_pages) { + if (num_pages == 0) { + return {}; + } + + const VAddr region_end{region_start + region_num_pages * PageSize}; + const VAddr region_last{region_end - 1}; + for (auto it{FindIterator(region_start)}; it != memory_block_tree.cend(); it++) { + const auto info{it->GetMemoryInfo()}; + if (region_last < info.GetAddress()) { + break; + } + + if (info.state != KMemoryState::Free) { + continue; + } + + VAddr area{(info.GetAddress() <= region_start) ? region_start : info.GetAddress()}; + area += guard_pages * PageSize; + + const VAddr offset_area{Common::AlignDown(area, align) + offset}; + area = (area <= offset_area) ? offset_area : offset_area + align; + + const VAddr area_end{area + num_pages * PageSize + guard_pages * PageSize}; + const VAddr area_last{area_end - 1}; + + if (info.GetAddress() <= area && area < area_last && area_last <= region_last && + area_last <= info.GetLastAddress()) { + return area; + } + } + + return {}; +} + +void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState prev_state, + KMemoryPermission prev_perm, KMemoryAttribute prev_attribute, + KMemoryState state, KMemoryPermission perm, + KMemoryAttribute attribute) { + const VAddr end_addr{addr + num_pages * PageSize}; + iterator node{memory_block_tree.begin()}; + + prev_attribute |= KMemoryAttribute::IpcAndDeviceMapped; + + while (node != memory_block_tree.end()) { + KMemoryBlock* block{&(*node)}; + iterator next_node{std::next(node)}; + const VAddr cur_addr{block->GetAddress()}; + const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr}; + + if (addr < cur_end_addr && cur_addr < end_addr) { + if (!block->HasProperties(prev_state, prev_perm, prev_attribute)) { + node = next_node; + continue; + } + + iterator new_node{node}; + if (addr > cur_addr) { + memory_block_tree.insert(node, block->Split(addr)); + } + + if (end_addr < cur_end_addr) { + new_node = memory_block_tree.insert(node, block->Split(end_addr)); + } + + new_node->Update(state, perm, attribute); + + MergeAdjacent(new_node, next_node); + } + + if (cur_end_addr - 1 >= end_addr - 1) { + break; + } + + node = next_node; + } +} + +void KMemoryBlockManager::Update(VAddr addr, std::size_t num_pages, KMemoryState state, + KMemoryPermission perm, KMemoryAttribute attribute) { + const VAddr end_addr{addr + num_pages * PageSize}; + iterator node{memory_block_tree.begin()}; + + while (node != memory_block_tree.end()) { + KMemoryBlock* block{&(*node)}; + iterator next_node{std::next(node)}; + const VAddr cur_addr{block->GetAddress()}; + const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr}; + + if (addr < cur_end_addr && cur_addr < end_addr) { + iterator new_node{node}; + + if (addr > cur_addr) { + memory_block_tree.insert(node, block->Split(addr)); + } + + if (end_addr < cur_end_addr) { + new_node = memory_block_tree.insert(node, block->Split(end_addr)); + } + + new_node->Update(state, perm, attribute); + + MergeAdjacent(new_node, next_node); + } + + if (cur_end_addr - 1 >= end_addr - 1) { + break; + } + + node = next_node; + } +} + +void KMemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func, + KMemoryPermission perm) { + const VAddr end_addr{addr + num_pages * PageSize}; + iterator node{memory_block_tree.begin()}; + + while (node != memory_block_tree.end()) { + KMemoryBlock* block{&(*node)}; + iterator next_node{std::next(node)}; + const VAddr cur_addr{block->GetAddress()}; + const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr}; + + if (addr < cur_end_addr && cur_addr < end_addr) { + iterator new_node{node}; + + if (addr > cur_addr) { + memory_block_tree.insert(node, block->Split(addr)); + } + + if (end_addr < cur_end_addr) { + new_node = memory_block_tree.insert(node, block->Split(end_addr)); + } + + lock_func(new_node, perm); + + MergeAdjacent(new_node, next_node); + } + + if (cur_end_addr - 1 >= end_addr - 1) { + break; + } + + node = next_node; + } +} + +void KMemoryBlockManager::IterateForRange(VAddr start, VAddr end, IterateFunc&& func) { + const_iterator it{FindIterator(start)}; + KMemoryInfo info{}; + do { + info = it->GetMemoryInfo(); + func(info); + it = std::next(it); + } while (info.addr + info.size - 1 < end - 1 && it != cend()); +} + +void KMemoryBlockManager::MergeAdjacent(iterator it, iterator& next_it) { + KMemoryBlock* block{&(*it)}; + + auto EraseIt = [&](const iterator it_to_erase) { + if (next_it == it_to_erase) { + next_it = std::next(next_it); + } + memory_block_tree.erase(it_to_erase); + }; + + if (it != memory_block_tree.begin()) { + KMemoryBlock* prev{&(*std::prev(it))}; + + if (block->HasSameProperties(*prev)) { + const iterator prev_it{std::prev(it)}; + + prev->Add(block->GetNumPages()); + EraseIt(it); + + it = prev_it; + block = prev; + } + } + + if (it != cend()) { + const KMemoryBlock* const next{&(*std::next(it))}; + + if (block->HasSameProperties(*next)) { + block->Add(next->GetNumPages()); + EraseIt(std::next(it)); + } + } +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_memory_block_manager.h b/src/core/hle/kernel/k_memory_block_manager.h new file mode 100644 index 000000000..e11cc70c8 --- /dev/null +++ b/src/core/hle/kernel/k_memory_block_manager.h @@ -0,0 +1,67 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "common/common_types.h" +#include "core/hle/kernel/k_memory_block.h" + +namespace Kernel { + +class KMemoryBlockManager final { +public: + using MemoryBlockTree = std::list; + using iterator = MemoryBlockTree::iterator; + using const_iterator = MemoryBlockTree::const_iterator; + +public: + KMemoryBlockManager(VAddr start_addr, VAddr end_addr); + + iterator end() { + return memory_block_tree.end(); + } + const_iterator end() const { + return memory_block_tree.end(); + } + const_iterator cend() const { + return memory_block_tree.cend(); + } + + iterator FindIterator(VAddr addr); + + VAddr FindFreeArea(VAddr region_start, std::size_t region_num_pages, std::size_t num_pages, + std::size_t align, std::size_t offset, std::size_t guard_pages); + + void Update(VAddr addr, std::size_t num_pages, KMemoryState prev_state, + KMemoryPermission prev_perm, KMemoryAttribute prev_attribute, KMemoryState state, + KMemoryPermission perm, KMemoryAttribute attribute); + + void Update(VAddr addr, std::size_t num_pages, KMemoryState state, + KMemoryPermission perm = KMemoryPermission::None, + KMemoryAttribute attribute = KMemoryAttribute::None); + + using LockFunc = std::function; + void UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func, + KMemoryPermission perm); + + using IterateFunc = std::function; + void IterateForRange(VAddr start, VAddr end, IterateFunc&& func); + + KMemoryBlock& FindBlock(VAddr addr) { + return *FindIterator(addr); + } + +private: + void MergeAdjacent(iterator it, iterator& next_it); + + [[maybe_unused]] const VAddr start_addr; + [[maybe_unused]] const VAddr end_addr; + + MemoryBlockTree memory_block_tree; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_shared_memory.cpp b/src/core/hle/kernel/k_shared_memory.cpp index dd82e0217..eb48afe9d 100644 --- a/src/core/hle/kernel/k_shared_memory.cpp +++ b/src/core/hle/kernel/k_shared_memory.cpp @@ -20,8 +20,8 @@ KSharedMemory::~KSharedMemory() { std::shared_ptr KSharedMemory::Create( KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, - Memory::PageLinkedList&& page_list, Memory::MemoryPermission owner_permission, - Memory::MemoryPermission user_permission, PAddr physical_address, std::size_t size, + Memory::PageLinkedList&& page_list, KMemoryPermission owner_permission, + KMemoryPermission user_permission, PAddr physical_address, std::size_t size, std::string name) { const auto resource_limit = kernel.GetSystemResourceLimit(); @@ -45,21 +45,21 @@ std::shared_ptr KSharedMemory::Create( } ResultCode KSharedMemory::Map(Process& target_process, VAddr address, std::size_t size, - Memory::MemoryPermission permissions) { - const u64 page_count{(size + Memory::PageSize - 1) / Memory::PageSize}; + KMemoryPermission permissions) { + const u64 page_count{(size + PageSize - 1) / PageSize}; if (page_list.GetNumPages() != page_count) { UNIMPLEMENTED_MSG("Page count does not match"); } - const Memory::MemoryPermission expected = + const KMemoryPermission expected = &target_process == owner_process ? owner_permission : user_permission; if (permissions != expected) { UNIMPLEMENTED_MSG("Permission does not match"); } - return target_process.PageTable().MapPages(address, page_list, Memory::MemoryState::Shared, + return target_process.PageTable().MapPages(address, page_list, KMemoryState::Shared, permissions); } diff --git a/src/core/hle/kernel/k_shared_memory.h b/src/core/hle/kernel/k_shared_memory.h index 4d1354415..1ecb4f7dd 100644 --- a/src/core/hle/kernel/k_shared_memory.h +++ b/src/core/hle/kernel/k_shared_memory.h @@ -9,7 +9,7 @@ #include "common/common_types.h" #include "core/device_memory.h" -#include "core/hle/kernel/memory/memory_block.h" +#include "core/hle/kernel/k_memory_block.h" #include "core/hle/kernel/memory/page_linked_list.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/process.h" @@ -26,8 +26,8 @@ public: static std::shared_ptr Create( KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, - Memory::PageLinkedList&& page_list, Memory::MemoryPermission owner_permission, - Memory::MemoryPermission user_permission, PAddr physical_address, std::size_t size, + Memory::PageLinkedList&& page_list, KMemoryPermission owner_permission, + KMemoryPermission user_permission, PAddr physical_address, std::size_t size, std::string name); std::string GetTypeName() const override { @@ -51,7 +51,7 @@ public: * @param permissions Memory block map permissions (specified by SVC field) */ ResultCode Map(Process& target_process, VAddr address, std::size_t size, - Memory::MemoryPermission permissions); + KMemoryPermission permissions); /** * Gets a pointer to the shared memory block @@ -77,8 +77,8 @@ private: Core::DeviceMemory& device_memory; Process* owner_process{}; Memory::PageLinkedList page_list; - Memory::MemoryPermission owner_permission{}; - Memory::MemoryPermission user_permission{}; + KMemoryPermission owner_permission{}; + KMemoryPermission user_permission{}; PAddr physical_address{}; std::size_t size{}; std::string name; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index e4de3f3bf..eab73c46c 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -289,24 +289,24 @@ struct KernelCore::Impl { layout.System().EndAddress()); hid_shared_mem = Kernel::KSharedMemory::Create( - system.Kernel(), system.DeviceMemory(), nullptr, - {hid_addr, hid_size / Memory::PageSize}, Memory::MemoryPermission::None, - Memory::MemoryPermission::Read, hid_addr, hid_size, "HID:SharedMemory"); + system.Kernel(), system.DeviceMemory(), nullptr, {hid_addr, hid_size / PageSize}, + KMemoryPermission::None, KMemoryPermission::Read, hid_addr, hid_size, + "HID:SharedMemory"); font_shared_mem = Kernel::KSharedMemory::Create( - system.Kernel(), system.DeviceMemory(), nullptr, - {font_pa, font_size / Memory::PageSize}, Memory::MemoryPermission::None, - Memory::MemoryPermission::Read, font_pa, font_size, "Font:SharedMemory"); + system.Kernel(), system.DeviceMemory(), nullptr, {font_pa, font_size / PageSize}, + KMemoryPermission::None, KMemoryPermission::Read, font_pa, font_size, + "Font:SharedMemory"); irs_shared_mem = Kernel::KSharedMemory::Create( - system.Kernel(), system.DeviceMemory(), nullptr, - {irs_addr, irs_size / Memory::PageSize}, Memory::MemoryPermission::None, - Memory::MemoryPermission::Read, irs_addr, irs_size, "IRS:SharedMemory"); + system.Kernel(), system.DeviceMemory(), nullptr, {irs_addr, irs_size / PageSize}, + KMemoryPermission::None, KMemoryPermission::Read, irs_addr, irs_size, + "IRS:SharedMemory"); time_shared_mem = Kernel::KSharedMemory::Create( - system.Kernel(), system.DeviceMemory(), nullptr, - {time_addr, time_size / Memory::PageSize}, Memory::MemoryPermission::None, - Memory::MemoryPermission::Read, time_addr, time_size, "Time:SharedMemory"); + system.Kernel(), system.DeviceMemory(), nullptr, {time_addr, time_size / PageSize}, + KMemoryPermission::None, KMemoryPermission::Read, time_addr, time_size, + "Time:SharedMemory"); // Allocate slab heaps - user_slab_heap_pages = std::make_unique>(); + user_slab_heap_pages = std::make_unique>(); constexpr u64 user_slab_heap_size{0x1ef000}; // Reserve slab heaps @@ -349,7 +349,7 @@ struct KernelCore::Impl { // Kernel memory management std::unique_ptr memory_manager; - std::unique_ptr> user_slab_heap_pages; + std::unique_ptr> user_slab_heap_pages; // Shared memory for services std::shared_ptr hid_shared_mem; @@ -581,11 +581,11 @@ const Memory::MemoryManager& KernelCore::MemoryManager() const { return *impl->memory_manager; } -KSlabHeap& KernelCore::GetUserSlabHeapPages() { +KSlabHeap& KernelCore::GetUserSlabHeapPages() { return *impl->user_slab_heap_pages; } -const KSlabHeap& KernelCore::GetUserSlabHeapPages() const { +const KSlabHeap& KernelCore::GetUserSlabHeapPages() const { return *impl->user_slab_heap_pages; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 5488c962a..498f94417 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -11,7 +11,7 @@ #include #include "core/arm/cpu_interrupt_handler.h" #include "core/hardware_properties.h" -#include "core/hle/kernel/memory/memory_types.h" +#include "core/hle/kernel/memory_types.h" #include "core/hle/kernel/object.h" namespace Core { @@ -186,10 +186,10 @@ public: const Memory::MemoryManager& MemoryManager() const; /// Gets the slab heap allocated for user space pages. - KSlabHeap& GetUserSlabHeapPages(); + KSlabHeap& GetUserSlabHeapPages(); /// Gets the slab heap allocated for user space pages. - const KSlabHeap& GetUserSlabHeapPages() const; + const KSlabHeap& GetUserSlabHeapPages() const; /// Gets the shared memory object for HID services. Kernel::KSharedMemory& GetHidSharedMem(); diff --git a/src/core/hle/kernel/memory/memory_block.h b/src/core/hle/kernel/memory/memory_block.h deleted file mode 100644 index 83acece1e..000000000 --- a/src/core/hle/kernel/memory/memory_block.h +++ /dev/null @@ -1,335 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -// This file references various implementation details from Atmosphere, an open-source firmware for -// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. - -#pragma once - -#include "common/alignment.h" -#include "common/assert.h" -#include "common/common_types.h" -#include "core/hle/kernel/memory/memory_types.h" -#include "core/hle/kernel/svc_types.h" - -namespace Kernel::Memory { - -enum class MemoryState : u32 { - None = 0, - Mask = 0xFF, - All = ~None, - - FlagCanReprotect = (1 << 8), - FlagCanDebug = (1 << 9), - FlagCanUseIpc = (1 << 10), - FlagCanUseNonDeviceIpc = (1 << 11), - FlagCanUseNonSecureIpc = (1 << 12), - FlagMapped = (1 << 13), - FlagCode = (1 << 14), - FlagCanAlias = (1 << 15), - FlagCanCodeAlias = (1 << 16), - FlagCanTransfer = (1 << 17), - FlagCanQueryPhysical = (1 << 18), - FlagCanDeviceMap = (1 << 19), - FlagCanAlignedDeviceMap = (1 << 20), - FlagCanIpcUserBuffer = (1 << 21), - FlagReferenceCounted = (1 << 22), - FlagCanMapProcess = (1 << 23), - FlagCanChangeAttribute = (1 << 24), - FlagCanCodeMemory = (1 << 25), - - FlagsData = FlagCanReprotect | FlagCanUseIpc | FlagCanUseNonDeviceIpc | FlagCanUseNonSecureIpc | - FlagMapped | FlagCanAlias | FlagCanTransfer | FlagCanQueryPhysical | - FlagCanDeviceMap | FlagCanAlignedDeviceMap | FlagCanIpcUserBuffer | - FlagReferenceCounted | FlagCanChangeAttribute, - - FlagsCode = FlagCanDebug | FlagCanUseIpc | FlagCanUseNonDeviceIpc | FlagCanUseNonSecureIpc | - FlagMapped | FlagCode | FlagCanQueryPhysical | FlagCanDeviceMap | - FlagCanAlignedDeviceMap | FlagReferenceCounted, - - FlagsMisc = FlagMapped | FlagReferenceCounted | FlagCanQueryPhysical | FlagCanDeviceMap, - - Free = static_cast(Svc::MemoryState::Free), - Io = static_cast(Svc::MemoryState::Io) | FlagMapped, - Static = static_cast(Svc::MemoryState::Static) | FlagMapped | FlagCanQueryPhysical, - Code = static_cast(Svc::MemoryState::Code) | FlagsCode | FlagCanMapProcess, - CodeData = static_cast(Svc::MemoryState::CodeData) | FlagsData | FlagCanMapProcess | - FlagCanCodeMemory, - Shared = static_cast(Svc::MemoryState::Shared) | FlagMapped | FlagReferenceCounted, - Normal = static_cast(Svc::MemoryState::Normal) | FlagsData | FlagCanCodeMemory, - - AliasCode = static_cast(Svc::MemoryState::AliasCode) | FlagsCode | FlagCanMapProcess | - FlagCanCodeAlias, - AliasCodeData = static_cast(Svc::MemoryState::AliasCodeData) | FlagsData | - FlagCanMapProcess | FlagCanCodeAlias | FlagCanCodeMemory, - - Ipc = static_cast(Svc::MemoryState::Ipc) | FlagsMisc | FlagCanAlignedDeviceMap | - FlagCanUseIpc | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, - - Stack = static_cast(Svc::MemoryState::Stack) | FlagsMisc | FlagCanAlignedDeviceMap | - FlagCanUseIpc | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, - - ThreadLocal = - static_cast(Svc::MemoryState::ThreadLocal) | FlagMapped | FlagReferenceCounted, - - Transferred = static_cast(Svc::MemoryState::Transferred) | FlagsMisc | - FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc | - FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, - - SharedTransferred = static_cast(Svc::MemoryState::SharedTransferred) | FlagsMisc | - FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, - - SharedCode = static_cast(Svc::MemoryState::SharedCode) | FlagMapped | - FlagReferenceCounted | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, - - Inaccessible = static_cast(Svc::MemoryState::Inaccessible), - - NonSecureIpc = static_cast(Svc::MemoryState::NonSecureIpc) | FlagsMisc | - FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc, - - NonDeviceIpc = - static_cast(Svc::MemoryState::NonDeviceIpc) | FlagsMisc | FlagCanUseNonDeviceIpc, - - Kernel = static_cast(Svc::MemoryState::Kernel) | FlagMapped, - - GeneratedCode = static_cast(Svc::MemoryState::GeneratedCode) | FlagMapped | - FlagReferenceCounted | FlagCanDebug, - CodeOut = static_cast(Svc::MemoryState::CodeOut) | FlagMapped | FlagReferenceCounted, -}; -DECLARE_ENUM_FLAG_OPERATORS(MemoryState); - -static_assert(static_cast(MemoryState::Free) == 0x00000000); -static_assert(static_cast(MemoryState::Io) == 0x00002001); -static_assert(static_cast(MemoryState::Static) == 0x00042002); -static_assert(static_cast(MemoryState::Code) == 0x00DC7E03); -static_assert(static_cast(MemoryState::CodeData) == 0x03FEBD04); -static_assert(static_cast(MemoryState::Normal) == 0x037EBD05); -static_assert(static_cast(MemoryState::Shared) == 0x00402006); -static_assert(static_cast(MemoryState::AliasCode) == 0x00DD7E08); -static_assert(static_cast(MemoryState::AliasCodeData) == 0x03FFBD09); -static_assert(static_cast(MemoryState::Ipc) == 0x005C3C0A); -static_assert(static_cast(MemoryState::Stack) == 0x005C3C0B); -static_assert(static_cast(MemoryState::ThreadLocal) == 0x0040200C); -static_assert(static_cast(MemoryState::Transferred) == 0x015C3C0D); -static_assert(static_cast(MemoryState::SharedTransferred) == 0x005C380E); -static_assert(static_cast(MemoryState::SharedCode) == 0x0040380F); -static_assert(static_cast(MemoryState::Inaccessible) == 0x00000010); -static_assert(static_cast(MemoryState::NonSecureIpc) == 0x005C3811); -static_assert(static_cast(MemoryState::NonDeviceIpc) == 0x004C2812); -static_assert(static_cast(MemoryState::Kernel) == 0x00002013); -static_assert(static_cast(MemoryState::GeneratedCode) == 0x00402214); -static_assert(static_cast(MemoryState::CodeOut) == 0x00402015); - -enum class MemoryPermission : u8 { - None = 0, - Mask = static_cast(~None), - - Read = 1 << 0, - Write = 1 << 1, - Execute = 1 << 2, - - ReadAndWrite = Read | Write, - ReadAndExecute = Read | Execute, - - UserMask = static_cast(Svc::MemoryPermission::Read | Svc::MemoryPermission::Write | - Svc::MemoryPermission::Execute), -}; -DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission); - -enum class MemoryAttribute : u8 { - None = 0x00, - Mask = 0x7F, - All = Mask, - DontCareMask = 0x80, - - Locked = static_cast(Svc::MemoryAttribute::Locked), - IpcLocked = static_cast(Svc::MemoryAttribute::IpcLocked), - DeviceShared = static_cast(Svc::MemoryAttribute::DeviceShared), - Uncached = static_cast(Svc::MemoryAttribute::Uncached), - - IpcAndDeviceMapped = IpcLocked | DeviceShared, - LockedAndIpcLocked = Locked | IpcLocked, - DeviceSharedAndUncached = DeviceShared | Uncached -}; -DECLARE_ENUM_FLAG_OPERATORS(MemoryAttribute); - -static_assert((static_cast(MemoryAttribute::Mask) & - static_cast(MemoryAttribute::DontCareMask)) == 0); - -struct MemoryInfo { - VAddr addr{}; - std::size_t size{}; - MemoryState state{}; - MemoryPermission perm{}; - MemoryAttribute attribute{}; - MemoryPermission original_perm{}; - u16 ipc_lock_count{}; - u16 device_use_count{}; - - constexpr Svc::MemoryInfo GetSvcMemoryInfo() const { - return { - addr, - size, - static_cast(state & MemoryState::Mask), - static_cast(attribute & MemoryAttribute::Mask), - static_cast(perm & MemoryPermission::UserMask), - ipc_lock_count, - device_use_count, - }; - } - - constexpr VAddr GetAddress() const { - return addr; - } - constexpr std::size_t GetSize() const { - return size; - } - constexpr std::size_t GetNumPages() const { - return GetSize() / PageSize; - } - constexpr VAddr GetEndAddress() const { - return GetAddress() + GetSize(); - } - constexpr VAddr GetLastAddress() const { - return GetEndAddress() - 1; - } -}; - -class MemoryBlock final { - friend class MemoryBlockManager; - -private: - VAddr addr{}; - std::size_t num_pages{}; - MemoryState state{MemoryState::None}; - u16 ipc_lock_count{}; - u16 device_use_count{}; - MemoryPermission perm{MemoryPermission::None}; - MemoryPermission original_perm{MemoryPermission::None}; - MemoryAttribute attribute{MemoryAttribute::None}; - -public: - static constexpr int Compare(const MemoryBlock& lhs, const MemoryBlock& rhs) { - if (lhs.GetAddress() < rhs.GetAddress()) { - return -1; - } else if (lhs.GetAddress() <= rhs.GetLastAddress()) { - return 0; - } else { - return 1; - } - } - -public: - constexpr MemoryBlock() = default; - constexpr MemoryBlock(VAddr addr_, std::size_t num_pages_, MemoryState state_, - MemoryPermission perm_, MemoryAttribute attribute_) - : addr{addr_}, num_pages(num_pages_), state{state_}, perm{perm_}, attribute{attribute_} {} - - constexpr VAddr GetAddress() const { - return addr; - } - - constexpr std::size_t GetNumPages() const { - return num_pages; - } - - constexpr std::size_t GetSize() const { - return GetNumPages() * PageSize; - } - - constexpr VAddr GetEndAddress() const { - return GetAddress() + GetSize(); - } - - constexpr VAddr GetLastAddress() const { - return GetEndAddress() - 1; - } - - constexpr MemoryInfo GetMemoryInfo() const { - return { - GetAddress(), GetSize(), state, perm, - attribute, original_perm, ipc_lock_count, device_use_count, - }; - } - - void ShareToDevice(MemoryPermission /*new_perm*/) { - ASSERT((attribute & MemoryAttribute::DeviceShared) == MemoryAttribute::DeviceShared || - device_use_count == 0); - attribute |= MemoryAttribute::DeviceShared; - const u16 new_use_count{++device_use_count}; - ASSERT(new_use_count > 0); - } - - void UnshareToDevice(MemoryPermission /*new_perm*/) { - ASSERT((attribute & MemoryAttribute::DeviceShared) == MemoryAttribute::DeviceShared); - const u16 prev_use_count{device_use_count--}; - ASSERT(prev_use_count > 0); - if (prev_use_count == 1) { - attribute &= ~MemoryAttribute::DeviceShared; - } - } - -private: - constexpr bool HasProperties(MemoryState s, MemoryPermission p, MemoryAttribute a) const { - constexpr MemoryAttribute AttributeIgnoreMask{MemoryAttribute::DontCareMask | - MemoryAttribute::IpcLocked | - MemoryAttribute::DeviceShared}; - return state == s && perm == p && - (attribute | AttributeIgnoreMask) == (a | AttributeIgnoreMask); - } - - constexpr bool HasSameProperties(const MemoryBlock& rhs) const { - return state == rhs.state && perm == rhs.perm && original_perm == rhs.original_perm && - attribute == rhs.attribute && ipc_lock_count == rhs.ipc_lock_count && - device_use_count == rhs.device_use_count; - } - - constexpr bool Contains(VAddr start) const { - return GetAddress() <= start && start <= GetEndAddress(); - } - - constexpr void Add(std::size_t count) { - ASSERT(count > 0); - ASSERT(GetAddress() + count * PageSize - 1 < GetEndAddress() + count * PageSize - 1); - - num_pages += count; - } - - constexpr void Update(MemoryState new_state, MemoryPermission new_perm, - MemoryAttribute new_attribute) { - ASSERT(original_perm == MemoryPermission::None); - ASSERT((attribute & MemoryAttribute::IpcLocked) == MemoryAttribute::None); - - state = new_state; - perm = new_perm; - - attribute = static_cast( - new_attribute | - (attribute & (MemoryAttribute::IpcLocked | MemoryAttribute::DeviceShared))); - } - - constexpr MemoryBlock Split(VAddr split_addr) { - ASSERT(GetAddress() < split_addr); - ASSERT(Contains(split_addr)); - ASSERT(Common::IsAligned(split_addr, PageSize)); - - MemoryBlock block; - block.addr = addr; - block.num_pages = (split_addr - GetAddress()) / PageSize; - block.state = state; - block.ipc_lock_count = ipc_lock_count; - block.device_use_count = device_use_count; - block.perm = perm; - block.original_perm = original_perm; - block.attribute = attribute; - - addr = split_addr; - num_pages -= block.num_pages; - - return block; - } -}; -static_assert(std::is_trivially_destructible::value); - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/memory_block_manager.cpp b/src/core/hle/kernel/memory/memory_block_manager.cpp deleted file mode 100644 index 0732fa5a1..000000000 --- a/src/core/hle/kernel/memory/memory_block_manager.cpp +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/kernel/memory/memory_block_manager.h" -#include "core/hle/kernel/memory/memory_types.h" - -namespace Kernel::Memory { - -MemoryBlockManager::MemoryBlockManager(VAddr start_addr, VAddr end_addr) - : start_addr{start_addr}, end_addr{end_addr} { - const u64 num_pages{(end_addr - start_addr) / PageSize}; - memory_block_tree.emplace_back(start_addr, num_pages, MemoryState::Free, MemoryPermission::None, - MemoryAttribute::None); -} - -MemoryBlockManager::iterator MemoryBlockManager::FindIterator(VAddr addr) { - auto node{memory_block_tree.begin()}; - while (node != end()) { - const VAddr end_addr{node->GetNumPages() * PageSize + node->GetAddress()}; - if (node->GetAddress() <= addr && end_addr - 1 >= addr) { - return node; - } - node = std::next(node); - } - return end(); -} - -VAddr MemoryBlockManager::FindFreeArea(VAddr region_start, std::size_t region_num_pages, - std::size_t num_pages, std::size_t align, std::size_t offset, - std::size_t guard_pages) { - if (num_pages == 0) { - return {}; - } - - const VAddr region_end{region_start + region_num_pages * PageSize}; - const VAddr region_last{region_end - 1}; - for (auto it{FindIterator(region_start)}; it != memory_block_tree.cend(); it++) { - const auto info{it->GetMemoryInfo()}; - if (region_last < info.GetAddress()) { - break; - } - - if (info.state != MemoryState::Free) { - continue; - } - - VAddr area{(info.GetAddress() <= region_start) ? region_start : info.GetAddress()}; - area += guard_pages * PageSize; - - const VAddr offset_area{Common::AlignDown(area, align) + offset}; - area = (area <= offset_area) ? offset_area : offset_area + align; - - const VAddr area_end{area + num_pages * PageSize + guard_pages * PageSize}; - const VAddr area_last{area_end - 1}; - - if (info.GetAddress() <= area && area < area_last && area_last <= region_last && - area_last <= info.GetLastAddress()) { - return area; - } - } - - return {}; -} - -void MemoryBlockManager::Update(VAddr addr, std::size_t num_pages, MemoryState prev_state, - MemoryPermission prev_perm, MemoryAttribute prev_attribute, - MemoryState state, MemoryPermission perm, - MemoryAttribute attribute) { - const VAddr end_addr{addr + num_pages * PageSize}; - iterator node{memory_block_tree.begin()}; - - prev_attribute |= MemoryAttribute::IpcAndDeviceMapped; - - while (node != memory_block_tree.end()) { - MemoryBlock* block{&(*node)}; - iterator next_node{std::next(node)}; - const VAddr cur_addr{block->GetAddress()}; - const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr}; - - if (addr < cur_end_addr && cur_addr < end_addr) { - if (!block->HasProperties(prev_state, prev_perm, prev_attribute)) { - node = next_node; - continue; - } - - iterator new_node{node}; - if (addr > cur_addr) { - memory_block_tree.insert(node, block->Split(addr)); - } - - if (end_addr < cur_end_addr) { - new_node = memory_block_tree.insert(node, block->Split(end_addr)); - } - - new_node->Update(state, perm, attribute); - - MergeAdjacent(new_node, next_node); - } - - if (cur_end_addr - 1 >= end_addr - 1) { - break; - } - - node = next_node; - } -} - -void MemoryBlockManager::Update(VAddr addr, std::size_t num_pages, MemoryState state, - MemoryPermission perm, MemoryAttribute attribute) { - const VAddr end_addr{addr + num_pages * PageSize}; - iterator node{memory_block_tree.begin()}; - - while (node != memory_block_tree.end()) { - MemoryBlock* block{&(*node)}; - iterator next_node{std::next(node)}; - const VAddr cur_addr{block->GetAddress()}; - const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr}; - - if (addr < cur_end_addr && cur_addr < end_addr) { - iterator new_node{node}; - - if (addr > cur_addr) { - memory_block_tree.insert(node, block->Split(addr)); - } - - if (end_addr < cur_end_addr) { - new_node = memory_block_tree.insert(node, block->Split(end_addr)); - } - - new_node->Update(state, perm, attribute); - - MergeAdjacent(new_node, next_node); - } - - if (cur_end_addr - 1 >= end_addr - 1) { - break; - } - - node = next_node; - } -} - -void MemoryBlockManager::UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func, - MemoryPermission perm) { - const VAddr end_addr{addr + num_pages * PageSize}; - iterator node{memory_block_tree.begin()}; - - while (node != memory_block_tree.end()) { - MemoryBlock* block{&(*node)}; - iterator next_node{std::next(node)}; - const VAddr cur_addr{block->GetAddress()}; - const VAddr cur_end_addr{block->GetNumPages() * PageSize + cur_addr}; - - if (addr < cur_end_addr && cur_addr < end_addr) { - iterator new_node{node}; - - if (addr > cur_addr) { - memory_block_tree.insert(node, block->Split(addr)); - } - - if (end_addr < cur_end_addr) { - new_node = memory_block_tree.insert(node, block->Split(end_addr)); - } - - lock_func(new_node, perm); - - MergeAdjacent(new_node, next_node); - } - - if (cur_end_addr - 1 >= end_addr - 1) { - break; - } - - node = next_node; - } -} - -void MemoryBlockManager::IterateForRange(VAddr start, VAddr end, IterateFunc&& func) { - const_iterator it{FindIterator(start)}; - MemoryInfo info{}; - do { - info = it->GetMemoryInfo(); - func(info); - it = std::next(it); - } while (info.addr + info.size - 1 < end - 1 && it != cend()); -} - -void MemoryBlockManager::MergeAdjacent(iterator it, iterator& next_it) { - MemoryBlock* block{&(*it)}; - - auto EraseIt = [&](const iterator it_to_erase) { - if (next_it == it_to_erase) { - next_it = std::next(next_it); - } - memory_block_tree.erase(it_to_erase); - }; - - if (it != memory_block_tree.begin()) { - MemoryBlock* prev{&(*std::prev(it))}; - - if (block->HasSameProperties(*prev)) { - const iterator prev_it{std::prev(it)}; - - prev->Add(block->GetNumPages()); - EraseIt(it); - - it = prev_it; - block = prev; - } - } - - if (it != cend()) { - const MemoryBlock* const next{&(*std::next(it))}; - - if (block->HasSameProperties(*next)) { - block->Add(next->GetNumPages()); - EraseIt(std::next(it)); - } - } -} - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/memory_block_manager.h b/src/core/hle/kernel/memory/memory_block_manager.h deleted file mode 100644 index f57d1bbcc..000000000 --- a/src/core/hle/kernel/memory/memory_block_manager.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include - -#include "common/common_types.h" -#include "core/hle/kernel/memory/memory_block.h" - -namespace Kernel::Memory { - -class MemoryBlockManager final { -public: - using MemoryBlockTree = std::list; - using iterator = MemoryBlockTree::iterator; - using const_iterator = MemoryBlockTree::const_iterator; - -public: - MemoryBlockManager(VAddr start_addr, VAddr end_addr); - - iterator end() { - return memory_block_tree.end(); - } - const_iterator end() const { - return memory_block_tree.end(); - } - const_iterator cend() const { - return memory_block_tree.cend(); - } - - iterator FindIterator(VAddr addr); - - VAddr FindFreeArea(VAddr region_start, std::size_t region_num_pages, std::size_t num_pages, - std::size_t align, std::size_t offset, std::size_t guard_pages); - - void Update(VAddr addr, std::size_t num_pages, MemoryState prev_state, - MemoryPermission prev_perm, MemoryAttribute prev_attribute, MemoryState state, - MemoryPermission perm, MemoryAttribute attribute); - - void Update(VAddr addr, std::size_t num_pages, MemoryState state, - MemoryPermission perm = MemoryPermission::None, - MemoryAttribute attribute = MemoryAttribute::None); - - using LockFunc = std::function; - void UpdateLock(VAddr addr, std::size_t num_pages, LockFunc&& lock_func, MemoryPermission perm); - - using IterateFunc = std::function; - void IterateForRange(VAddr start, VAddr end, IterateFunc&& func); - - MemoryBlock& FindBlock(VAddr addr) { - return *FindIterator(addr); - } - -private: - void MergeAdjacent(iterator it, iterator& next_it); - - [[maybe_unused]] const VAddr start_addr; - [[maybe_unused]] const VAddr end_addr; - - MemoryBlockTree memory_block_tree; -}; - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/memory_types.h b/src/core/hle/kernel/memory/memory_types.h deleted file mode 100644 index a75bf77c0..000000000 --- a/src/core/hle/kernel/memory/memory_types.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include - -#include "common/common_types.h" - -namespace Kernel::Memory { - -constexpr std::size_t PageBits{12}; -constexpr std::size_t PageSize{1 << PageBits}; - -using Page = std::array; - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/page_heap.h b/src/core/hle/kernel/memory/page_heap.h index ee339f329..e21d60a54 100644 --- a/src/core/hle/kernel/memory/page_heap.h +++ b/src/core/hle/kernel/memory/page_heap.h @@ -16,7 +16,7 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "core/hle/kernel/k_page_bitmap.h" -#include "core/hle/kernel/memory/memory_types.h" +#include "core/hle/kernel/memory_types.h" namespace Kernel::Memory { diff --git a/src/core/hle/kernel/memory/page_linked_list.h b/src/core/hle/kernel/memory/page_linked_list.h index 45dc13eaf..9b871f15b 100644 --- a/src/core/hle/kernel/memory/page_linked_list.h +++ b/src/core/hle/kernel/memory/page_linked_list.h @@ -8,7 +8,7 @@ #include "common/assert.h" #include "common/common_types.h" -#include "core/hle/kernel/memory/memory_types.h" +#include "core/hle/kernel/memory_types.h" #include "core/hle/result.h" namespace Kernel::Memory { diff --git a/src/core/hle/kernel/memory/page_table.cpp b/src/core/hle/kernel/memory/page_table.cpp index 02a17a695..183482648 100644 --- a/src/core/hle/kernel/memory/page_table.cpp +++ b/src/core/hle/kernel/memory/page_table.cpp @@ -7,12 +7,12 @@ #include "common/scope_exit.h" #include "core/core.h" #include "core/hle/kernel/k_address_space_info.h" +#include "core/hle/kernel/k_memory_block.h" +#include "core/hle/kernel/k_memory_block_manager.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_system_control.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/memory/memory_block.h" -#include "core/hle/kernel/memory/memory_block_manager.h" #include "core/hle/kernel/memory/page_linked_list.h" #include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/process.h" @@ -38,14 +38,14 @@ constexpr std::size_t GetAddressSpaceWidthFromType(FileSys::ProgramAddressSpaceT } } -constexpr u64 GetAddressInRange(const MemoryInfo& info, VAddr addr) { +constexpr u64 GetAddressInRange(const KMemoryInfo& info, VAddr addr) { if (info.GetAddress() < addr) { return addr; } return info.GetAddress(); } -constexpr std::size_t GetSizeInRange(const MemoryInfo& info, VAddr start, VAddr end) { +constexpr std::size_t GetSizeInRange(const KMemoryInfo& info, VAddr start, VAddr end) { std::size_t size{info.GetSize()}; if (info.GetAddress() < start) { size -= start - info.GetAddress(); @@ -271,8 +271,8 @@ ResultCode PageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_t return InitializeMemoryLayout(start, end); } -ResultCode PageTable::MapProcessCode(VAddr addr, std::size_t num_pages, MemoryState state, - MemoryPermission perm) { +ResultCode PageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemoryState state, + KMemoryPermission perm) { std::lock_guard lock{page_table_lock}; const u64 size{num_pages * PageSize}; @@ -300,12 +300,12 @@ ResultCode PageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std:: const std::size_t num_pages{size / PageSize}; - MemoryState state{}; - MemoryPermission perm{}; - CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, src_addr, size, MemoryState::All, - MemoryState::Normal, MemoryPermission::Mask, - MemoryPermission::ReadAndWrite, MemoryAttribute::Mask, - MemoryAttribute::None, MemoryAttribute::IpcAndDeviceMapped)); + KMemoryState state{}; + KMemoryPermission perm{}; + CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, src_addr, size, KMemoryState::All, + KMemoryState::Normal, KMemoryPermission::Mask, + KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, + KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); if (IsRegionMapped(dst_addr, size)) { return ResultInvalidCurrentMemory; @@ -318,16 +318,16 @@ ResultCode PageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std:: auto block_guard = detail::ScopeExit( [&] { Operate(src_addr, num_pages, perm, OperationType::ChangePermissions); }); - CASCADE_CODE( - Operate(src_addr, num_pages, MemoryPermission::None, OperationType::ChangePermissions)); - CASCADE_CODE(MapPages(dst_addr, page_linked_list, MemoryPermission::None)); + CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::None, + OperationType::ChangePermissions)); + CASCADE_CODE(MapPages(dst_addr, page_linked_list, KMemoryPermission::None)); block_guard.Cancel(); } - block_manager->Update(src_addr, num_pages, state, MemoryPermission::None, - MemoryAttribute::Locked); - block_manager->Update(dst_addr, num_pages, MemoryState::AliasCode); + block_manager->Update(src_addr, num_pages, state, KMemoryPermission::None, + KMemoryAttribute::Locked); + block_manager->Update(dst_addr, num_pages, KMemoryState::AliasCode); return RESULT_SUCCESS; } @@ -341,23 +341,24 @@ ResultCode PageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std const std::size_t num_pages{size / PageSize}; - CASCADE_CODE(CheckMemoryState(nullptr, nullptr, nullptr, src_addr, size, MemoryState::All, - MemoryState::Normal, MemoryPermission::None, - MemoryPermission::None, MemoryAttribute::Mask, - MemoryAttribute::Locked, MemoryAttribute::IpcAndDeviceMapped)); + CASCADE_CODE(CheckMemoryState(nullptr, nullptr, nullptr, src_addr, size, KMemoryState::All, + KMemoryState::Normal, KMemoryPermission::None, + KMemoryPermission::None, KMemoryAttribute::Mask, + KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); - MemoryState state{}; + KMemoryState state{}; CASCADE_CODE(CheckMemoryState( - &state, nullptr, nullptr, dst_addr, PageSize, MemoryState::FlagCanCodeAlias, - MemoryState::FlagCanCodeAlias, MemoryPermission::None, MemoryPermission::None, - MemoryAttribute::Mask, MemoryAttribute::None, MemoryAttribute::IpcAndDeviceMapped)); - CASCADE_CODE(CheckMemoryState(dst_addr, size, MemoryState::All, state, MemoryPermission::None, - MemoryPermission::None, MemoryAttribute::Mask, - MemoryAttribute::None)); - CASCADE_CODE(Operate(dst_addr, num_pages, MemoryPermission::None, OperationType::Unmap)); - - block_manager->Update(dst_addr, num_pages, MemoryState::Free); - block_manager->Update(src_addr, num_pages, MemoryState::Normal, MemoryPermission::ReadAndWrite); + &state, nullptr, nullptr, dst_addr, PageSize, KMemoryState::FlagCanCodeAlias, + KMemoryState::FlagCanCodeAlias, KMemoryPermission::None, KMemoryPermission::None, + KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); + CASCADE_CODE(CheckMemoryState(dst_addr, size, KMemoryState::All, state, KMemoryPermission::None, + KMemoryPermission::None, KMemoryAttribute::Mask, + KMemoryAttribute::None)); + CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap)); + + block_manager->Update(dst_addr, num_pages, KMemoryState::Free); + block_manager->Update(src_addr, num_pages, KMemoryState::Normal, + KMemoryPermission::ReadAndWrite); return RESULT_SUCCESS; } @@ -367,8 +368,8 @@ void PageTable::MapPhysicalMemory(PageLinkedList& page_linked_list, VAddr start, PAddr map_addr{node->GetAddress()}; std::size_t src_num_pages{node->GetNumPages()}; - block_manager->IterateForRange(start, end, [&](const MemoryInfo& info) { - if (info.state != MemoryState::Free) { + block_manager->IterateForRange(start, end, [&](const KMemoryInfo& info) { + if (info.state != KMemoryState::Free) { return; } @@ -383,7 +384,7 @@ void PageTable::MapPhysicalMemory(PageLinkedList& page_linked_list, VAddr start, } const std::size_t num_pages{std::min(src_num_pages, dst_num_pages)}; - Operate(dst_addr, num_pages, MemoryPermission::ReadAndWrite, OperationType::Map, + Operate(dst_addr, num_pages, KMemoryPermission::ReadAndWrite, OperationType::Map, map_addr); dst_addr += num_pages * PageSize; @@ -400,8 +401,8 @@ ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) { std::size_t mapped_size{}; const VAddr end_addr{addr + size}; - block_manager->IterateForRange(addr, end_addr, [&](const MemoryInfo& info) { - if (info.state != MemoryState::Free) { + block_manager->IterateForRange(addr, end_addr, [&](const KMemoryInfo& info) { + if (info.state != KMemoryState::Free) { mapped_size += GetSizeInRange(info, addr, end_addr); } }); @@ -435,9 +436,9 @@ ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) { physical_memory_usage += remaining_size; const std::size_t num_pages{size / PageSize}; - block_manager->Update(addr, num_pages, MemoryState::Free, MemoryPermission::None, - MemoryAttribute::None, MemoryState::Normal, - MemoryPermission::ReadAndWrite, MemoryAttribute::None); + block_manager->Update(addr, num_pages, KMemoryState::Free, KMemoryPermission::None, + KMemoryAttribute::None, KMemoryState::Normal, + KMemoryPermission::ReadAndWrite, KMemoryAttribute::None); return RESULT_SUCCESS; } @@ -450,14 +451,14 @@ ResultCode PageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) { std::size_t mapped_size{}; // Verify that the region can be unmapped - block_manager->IterateForRange(addr, end_addr, [&](const MemoryInfo& info) { - if (info.state == MemoryState::Normal) { - if (info.attribute != MemoryAttribute::None) { + block_manager->IterateForRange(addr, end_addr, [&](const KMemoryInfo& info) { + if (info.state == KMemoryState::Normal) { + if (info.attribute != KMemoryAttribute::None) { result = ResultInvalidCurrentMemory; return; } mapped_size += GetSizeInRange(info, addr, end_addr); - } else if (info.state != MemoryState::Free) { + } else if (info.state != KMemoryState::Free) { result = ResultInvalidCurrentMemory; } }); @@ -487,15 +488,15 @@ ResultCode PageTable::UnmapMemory(VAddr addr, std::size_t size) { PageLinkedList page_linked_list; // Unmap each region within the range - block_manager->IterateForRange(addr, end_addr, [&](const MemoryInfo& info) { - if (info.state == MemoryState::Normal) { + block_manager->IterateForRange(addr, end_addr, [&](const KMemoryInfo& info) { + if (info.state == KMemoryState::Normal) { const std::size_t block_size{GetSizeInRange(info, addr, end_addr)}; const std::size_t block_num_pages{block_size / PageSize}; const VAddr block_addr{GetAddressInRange(info, addr)}; AddRegionToPages(block_addr, block_size / PageSize, page_linked_list); - if (result = Operate(block_addr, block_num_pages, MemoryPermission::None, + if (result = Operate(block_addr, block_num_pages, KMemoryPermission::None, OperationType::Unmap); result.IsError()) { return; @@ -510,7 +511,7 @@ ResultCode PageTable::UnmapMemory(VAddr addr, std::size_t size) { const std::size_t num_pages{size / PageSize}; system.Kernel().MemoryManager().Free(page_linked_list, num_pages, memory_pool); - block_manager->Update(addr, num_pages, MemoryState::Free); + block_manager->Update(addr, num_pages, KMemoryState::Free); return RESULT_SUCCESS; } @@ -518,11 +519,11 @@ ResultCode PageTable::UnmapMemory(VAddr addr, std::size_t size) { ResultCode PageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) { std::lock_guard lock{page_table_lock}; - MemoryState src_state{}; + KMemoryState src_state{}; CASCADE_CODE(CheckMemoryState( - &src_state, nullptr, nullptr, src_addr, size, MemoryState::FlagCanAlias, - MemoryState::FlagCanAlias, MemoryPermission::Mask, MemoryPermission::ReadAndWrite, - MemoryAttribute::Mask, MemoryAttribute::None, MemoryAttribute::IpcAndDeviceMapped)); + &src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, + KMemoryState::FlagCanAlias, KMemoryPermission::Mask, KMemoryPermission::ReadAndWrite, + KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); if (IsRegionMapped(dst_addr, size)) { return ResultInvalidCurrentMemory; @@ -535,20 +536,21 @@ ResultCode PageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) { { auto block_guard = detail::ScopeExit([&] { - Operate(src_addr, num_pages, MemoryPermission::ReadAndWrite, + Operate(src_addr, num_pages, KMemoryPermission::ReadAndWrite, OperationType::ChangePermissions); }); - CASCADE_CODE( - Operate(src_addr, num_pages, MemoryPermission::None, OperationType::ChangePermissions)); - CASCADE_CODE(MapPages(dst_addr, page_linked_list, MemoryPermission::ReadAndWrite)); + CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::None, + OperationType::ChangePermissions)); + CASCADE_CODE(MapPages(dst_addr, page_linked_list, KMemoryPermission::ReadAndWrite)); block_guard.Cancel(); } - block_manager->Update(src_addr, num_pages, src_state, MemoryPermission::None, - MemoryAttribute::Locked); - block_manager->Update(dst_addr, num_pages, MemoryState::Stack, MemoryPermission::ReadAndWrite); + block_manager->Update(src_addr, num_pages, src_state, KMemoryPermission::None, + KMemoryAttribute::Locked); + block_manager->Update(dst_addr, num_pages, KMemoryState::Stack, + KMemoryPermission::ReadAndWrite); return RESULT_SUCCESS; } @@ -556,17 +558,17 @@ ResultCode PageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) { ResultCode PageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) { std::lock_guard lock{page_table_lock}; - MemoryState src_state{}; + KMemoryState src_state{}; CASCADE_CODE(CheckMemoryState( - &src_state, nullptr, nullptr, src_addr, size, MemoryState::FlagCanAlias, - MemoryState::FlagCanAlias, MemoryPermission::Mask, MemoryPermission::None, - MemoryAttribute::Mask, MemoryAttribute::Locked, MemoryAttribute::IpcAndDeviceMapped)); + &src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, + KMemoryState::FlagCanAlias, KMemoryPermission::Mask, KMemoryPermission::None, + KMemoryAttribute::Mask, KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); - MemoryPermission dst_perm{}; - CASCADE_CODE(CheckMemoryState(nullptr, &dst_perm, nullptr, dst_addr, size, MemoryState::All, - MemoryState::Stack, MemoryPermission::None, - MemoryPermission::None, MemoryAttribute::Mask, - MemoryAttribute::None, MemoryAttribute::IpcAndDeviceMapped)); + KMemoryPermission dst_perm{}; + CASCADE_CODE(CheckMemoryState(nullptr, &dst_perm, nullptr, dst_addr, size, KMemoryState::All, + KMemoryState::Stack, KMemoryPermission::None, + KMemoryPermission::None, KMemoryAttribute::Mask, + KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); PageLinkedList src_pages; PageLinkedList dst_pages; @@ -582,21 +584,21 @@ ResultCode PageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) { { auto block_guard = detail::ScopeExit([&] { MapPages(dst_addr, dst_pages, dst_perm); }); - CASCADE_CODE(Operate(dst_addr, num_pages, MemoryPermission::None, OperationType::Unmap)); - CASCADE_CODE(Operate(src_addr, num_pages, MemoryPermission::ReadAndWrite, + CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap)); + CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::ReadAndWrite, OperationType::ChangePermissions)); block_guard.Cancel(); } - block_manager->Update(src_addr, num_pages, src_state, MemoryPermission::ReadAndWrite); - block_manager->Update(dst_addr, num_pages, MemoryState::Free); + block_manager->Update(src_addr, num_pages, src_state, KMemoryPermission::ReadAndWrite); + block_manager->Update(dst_addr, num_pages, KMemoryState::Free); return RESULT_SUCCESS; } ResultCode PageTable::MapPages(VAddr addr, const PageLinkedList& page_linked_list, - MemoryPermission perm) { + KMemoryPermission perm) { VAddr cur_addr{addr}; for (const auto& node : page_linked_list.Nodes()) { @@ -605,8 +607,8 @@ ResultCode PageTable::MapPages(VAddr addr, const PageLinkedList& page_linked_lis result.IsError()) { const std::size_t num_pages{(addr - cur_addr) / PageSize}; - ASSERT( - Operate(addr, num_pages, MemoryPermission::None, OperationType::Unmap).IsSuccess()); + ASSERT(Operate(addr, num_pages, KMemoryPermission::None, OperationType::Unmap) + .IsSuccess()); return result; } @@ -617,8 +619,8 @@ ResultCode PageTable::MapPages(VAddr addr, const PageLinkedList& page_linked_lis return RESULT_SUCCESS; } -ResultCode PageTable::MapPages(VAddr addr, PageLinkedList& page_linked_list, MemoryState state, - MemoryPermission perm) { +ResultCode PageTable::MapPages(VAddr addr, PageLinkedList& page_linked_list, KMemoryState state, + KMemoryPermission perm) { std::lock_guard lock{page_table_lock}; const std::size_t num_pages{page_linked_list.GetNumPages()}; @@ -639,26 +641,27 @@ ResultCode PageTable::MapPages(VAddr addr, PageLinkedList& page_linked_list, Mem return RESULT_SUCCESS; } -ResultCode PageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, MemoryPermission perm) { +ResultCode PageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, + KMemoryPermission perm) { std::lock_guard lock{page_table_lock}; - MemoryState prev_state{}; - MemoryPermission prev_perm{}; + KMemoryState prev_state{}; + KMemoryPermission prev_perm{}; CASCADE_CODE(CheckMemoryState( - &prev_state, &prev_perm, nullptr, addr, size, MemoryState::FlagCode, MemoryState::FlagCode, - MemoryPermission::None, MemoryPermission::None, MemoryAttribute::Mask, - MemoryAttribute::None, MemoryAttribute::IpcAndDeviceMapped)); + &prev_state, &prev_perm, nullptr, addr, size, KMemoryState::FlagCode, + KMemoryState::FlagCode, KMemoryPermission::None, KMemoryPermission::None, + KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); - MemoryState state{prev_state}; + KMemoryState state{prev_state}; // Ensure state is mutable if permission allows write - if ((perm & MemoryPermission::Write) != MemoryPermission::None) { - if (prev_state == MemoryState::Code) { - state = MemoryState::CodeData; - } else if (prev_state == MemoryState::AliasCode) { - state = MemoryState::AliasCodeData; + if ((perm & KMemoryPermission::Write) != KMemoryPermission::None) { + if (prev_state == KMemoryState::Code) { + state = KMemoryState::CodeData; + } else if (prev_state == KMemoryState::AliasCode) { + state = KMemoryState::AliasCodeData; } else { UNREACHABLE(); } @@ -669,13 +672,13 @@ ResultCode PageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, Memo return RESULT_SUCCESS; } - if ((prev_perm & MemoryPermission::Execute) != (perm & MemoryPermission::Execute)) { + if ((prev_perm & KMemoryPermission::Execute) != (perm & KMemoryPermission::Execute)) { // Memory execution state is changing, invalidate CPU cache range system.InvalidateCpuInstructionCacheRange(addr, size); } const std::size_t num_pages{size / PageSize}; - const OperationType operation{(perm & MemoryPermission::Execute) != MemoryPermission::None + const OperationType operation{(perm & KMemoryPermission::Execute) != KMemoryPermission::None ? OperationType::ChangePermissionsAndRefresh : OperationType::ChangePermissions}; @@ -686,35 +689,35 @@ ResultCode PageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, Memo return RESULT_SUCCESS; } -MemoryInfo PageTable::QueryInfoImpl(VAddr addr) { +KMemoryInfo PageTable::QueryInfoImpl(VAddr addr) { std::lock_guard lock{page_table_lock}; return block_manager->FindBlock(addr).GetMemoryInfo(); } -MemoryInfo PageTable::QueryInfo(VAddr addr) { +KMemoryInfo PageTable::QueryInfo(VAddr addr) { if (!Contains(addr, 1)) { - return {address_space_end, 0 - address_space_end, MemoryState::Inaccessible, - MemoryPermission::None, MemoryAttribute::None, MemoryPermission::None}; + return {address_space_end, 0 - address_space_end, KMemoryState::Inaccessible, + KMemoryPermission::None, KMemoryAttribute::None, KMemoryPermission::None}; } return QueryInfoImpl(addr); } -ResultCode PageTable::ReserveTransferMemory(VAddr addr, std::size_t size, MemoryPermission perm) { +ResultCode PageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm) { std::lock_guard lock{page_table_lock}; - MemoryState state{}; - MemoryAttribute attribute{}; + KMemoryState state{}; + KMemoryAttribute attribute{}; - CASCADE_CODE(CheckMemoryState(&state, nullptr, &attribute, addr, size, - MemoryState::FlagCanTransfer | MemoryState::FlagReferenceCounted, - MemoryState::FlagCanTransfer | MemoryState::FlagReferenceCounted, - MemoryPermission::Mask, MemoryPermission::ReadAndWrite, - MemoryAttribute::Mask, MemoryAttribute::None, - MemoryAttribute::IpcAndDeviceMapped)); + CASCADE_CODE(CheckMemoryState( + &state, nullptr, &attribute, addr, size, + KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, + KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::Mask, + KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, KMemoryAttribute::None, + KMemoryAttribute::IpcAndDeviceMapped)); - block_manager->Update(addr, size / PageSize, state, perm, attribute | MemoryAttribute::Locked); + block_manager->Update(addr, size / PageSize, state, perm, attribute | KMemoryAttribute::Locked); return RESULT_SUCCESS; } @@ -722,33 +725,33 @@ ResultCode PageTable::ReserveTransferMemory(VAddr addr, std::size_t size, Memory ResultCode PageTable::ResetTransferMemory(VAddr addr, std::size_t size) { std::lock_guard lock{page_table_lock}; - MemoryState state{}; + KMemoryState state{}; - CASCADE_CODE(CheckMemoryState(&state, nullptr, nullptr, addr, size, - MemoryState::FlagCanTransfer | MemoryState::FlagReferenceCounted, - MemoryState::FlagCanTransfer | MemoryState::FlagReferenceCounted, - MemoryPermission::None, MemoryPermission::None, - MemoryAttribute::Mask, MemoryAttribute::Locked, - MemoryAttribute::IpcAndDeviceMapped)); + CASCADE_CODE( + CheckMemoryState(&state, nullptr, nullptr, addr, size, + KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, + KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, + KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::Mask, + KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); - block_manager->Update(addr, size / PageSize, state, MemoryPermission::ReadAndWrite); + block_manager->Update(addr, size / PageSize, state, KMemoryPermission::ReadAndWrite); return RESULT_SUCCESS; } -ResultCode PageTable::SetMemoryAttribute(VAddr addr, std::size_t size, MemoryAttribute mask, - MemoryAttribute value) { +ResultCode PageTable::SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask, + KMemoryAttribute value) { std::lock_guard lock{page_table_lock}; - MemoryState state{}; - MemoryPermission perm{}; - MemoryAttribute attribute{}; + KMemoryState state{}; + KMemoryPermission perm{}; + KMemoryAttribute attribute{}; - CASCADE_CODE(CheckMemoryState(&state, &perm, &attribute, addr, size, - MemoryState::FlagCanChangeAttribute, - MemoryState::FlagCanChangeAttribute, MemoryPermission::None, - MemoryPermission::None, MemoryAttribute::LockedAndIpcLocked, - MemoryAttribute::None, MemoryAttribute::DeviceSharedAndUncached)); + CASCADE_CODE(CheckMemoryState( + &state, &perm, &attribute, addr, size, KMemoryState::FlagCanChangeAttribute, + KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None, + KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None, + KMemoryAttribute::DeviceSharedAndUncached)); attribute = attribute & ~mask; attribute = attribute | (mask & value); @@ -806,8 +809,8 @@ ResultVal PageTable::SetHeapSize(std::size_t size) { // Succeeded in allocation, commit the resource reservation memory_reservation.Commit(); - block_manager->Update(current_heap_addr, num_pages, MemoryState::Normal, - MemoryPermission::ReadAndWrite); + block_manager->Update(current_heap_addr, num_pages, KMemoryState::Normal, + KMemoryPermission::ReadAndWrite); current_heap_addr = heap_region_start + size; } @@ -817,8 +820,8 @@ ResultVal PageTable::SetHeapSize(std::size_t size) { ResultVal PageTable::AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, bool is_map_only, VAddr region_start, - std::size_t region_num_pages, MemoryState state, - MemoryPermission perm, PAddr map_addr) { + std::size_t region_num_pages, KMemoryState state, + KMemoryPermission perm, PAddr map_addr) { std::lock_guard lock{page_table_lock}; if (!CanContain(region_start, region_num_pages * PageSize, state)) { @@ -852,19 +855,19 @@ ResultVal PageTable::AllocateAndMapMemory(std::size_t needed_num_pages, s ResultCode PageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) { std::lock_guard lock{page_table_lock}; - MemoryPermission perm{}; + KMemoryPermission perm{}; if (const ResultCode result{CheckMemoryState( - nullptr, &perm, nullptr, addr, size, MemoryState::FlagCanChangeAttribute, - MemoryState::FlagCanChangeAttribute, MemoryPermission::None, MemoryPermission::None, - MemoryAttribute::LockedAndIpcLocked, MemoryAttribute::None, - MemoryAttribute::DeviceSharedAndUncached)}; + nullptr, &perm, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute, + KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None, + KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None, + KMemoryAttribute::DeviceSharedAndUncached)}; result.IsError()) { return result; } block_manager->UpdateLock( addr, size / PageSize, - [](MemoryBlockManager::iterator block, MemoryPermission perm) { + [](KMemoryBlockManager::iterator block, KMemoryPermission perm) { block->ShareToDevice(perm); }, perm); @@ -875,19 +878,19 @@ ResultCode PageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) { ResultCode PageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) { std::lock_guard lock{page_table_lock}; - MemoryPermission perm{}; + KMemoryPermission perm{}; if (const ResultCode result{CheckMemoryState( - nullptr, &perm, nullptr, addr, size, MemoryState::FlagCanChangeAttribute, - MemoryState::FlagCanChangeAttribute, MemoryPermission::None, MemoryPermission::None, - MemoryAttribute::LockedAndIpcLocked, MemoryAttribute::None, - MemoryAttribute::DeviceSharedAndUncached)}; + nullptr, &perm, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute, + KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None, + KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None, + KMemoryAttribute::DeviceSharedAndUncached)}; result.IsError()) { return result; } block_manager->UpdateLock( addr, size / PageSize, - [](MemoryBlockManager::iterator block, MemoryPermission perm) { + [](KMemoryBlockManager::iterator block, KMemoryPermission perm) { block->UnshareToDevice(perm); }, perm); @@ -896,15 +899,16 @@ ResultCode PageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) } ResultCode PageTable::InitializeMemoryLayout(VAddr start, VAddr end) { - block_manager = std::make_unique(start, end); + block_manager = std::make_unique(start, end); return RESULT_SUCCESS; } bool PageTable::IsRegionMapped(VAddr address, u64 size) { - return CheckMemoryState(address, size, MemoryState::All, MemoryState::Free, - MemoryPermission::Mask, MemoryPermission::None, MemoryAttribute::Mask, - MemoryAttribute::None, MemoryAttribute::IpcAndDeviceMapped) + return CheckMemoryState(address, size, KMemoryState::All, KMemoryState::Free, + KMemoryPermission::Mask, KMemoryPermission::None, + KMemoryAttribute::Mask, KMemoryAttribute::None, + KMemoryAttribute::IpcAndDeviceMapped) .IsError(); } @@ -966,7 +970,7 @@ ResultCode PageTable::Operate(VAddr addr, std::size_t num_pages, const PageLinke return RESULT_SUCCESS; } -ResultCode PageTable::Operate(VAddr addr, std::size_t num_pages, MemoryPermission perm, +ResultCode PageTable::Operate(VAddr addr, std::size_t num_pages, KMemoryPermission perm, OperationType operation, PAddr map_addr) { std::lock_guard lock{page_table_lock}; @@ -993,34 +997,34 @@ ResultCode PageTable::Operate(VAddr addr, std::size_t num_pages, MemoryPermissio return RESULT_SUCCESS; } -constexpr VAddr PageTable::GetRegionAddress(MemoryState state) const { +constexpr VAddr PageTable::GetRegionAddress(KMemoryState state) const { switch (state) { - case MemoryState::Free: - case MemoryState::Kernel: + case KMemoryState::Free: + case KMemoryState::Kernel: return address_space_start; - case MemoryState::Normal: + case KMemoryState::Normal: return heap_region_start; - case MemoryState::Ipc: - case MemoryState::NonSecureIpc: - case MemoryState::NonDeviceIpc: + case KMemoryState::Ipc: + case KMemoryState::NonSecureIpc: + case KMemoryState::NonDeviceIpc: return alias_region_start; - case MemoryState::Stack: + case KMemoryState::Stack: return stack_region_start; - case MemoryState::Io: - case MemoryState::Static: - case MemoryState::ThreadLocal: + case KMemoryState::Io: + case KMemoryState::Static: + case KMemoryState::ThreadLocal: return kernel_map_region_start; - case MemoryState::Shared: - case MemoryState::AliasCode: - case MemoryState::AliasCodeData: - case MemoryState::Transferred: - case MemoryState::SharedTransferred: - case MemoryState::SharedCode: - case MemoryState::GeneratedCode: - case MemoryState::CodeOut: + case KMemoryState::Shared: + case KMemoryState::AliasCode: + case KMemoryState::AliasCodeData: + case KMemoryState::Transferred: + case KMemoryState::SharedTransferred: + case KMemoryState::SharedCode: + case KMemoryState::GeneratedCode: + case KMemoryState::CodeOut: return alias_code_region_start; - case MemoryState::Code: - case MemoryState::CodeData: + case KMemoryState::Code: + case KMemoryState::CodeData: return code_region_start; default: UNREACHABLE(); @@ -1028,34 +1032,34 @@ constexpr VAddr PageTable::GetRegionAddress(MemoryState state) const { } } -constexpr std::size_t PageTable::GetRegionSize(MemoryState state) const { +constexpr std::size_t PageTable::GetRegionSize(KMemoryState state) const { switch (state) { - case MemoryState::Free: - case MemoryState::Kernel: + case KMemoryState::Free: + case KMemoryState::Kernel: return address_space_end - address_space_start; - case MemoryState::Normal: + case KMemoryState::Normal: return heap_region_end - heap_region_start; - case MemoryState::Ipc: - case MemoryState::NonSecureIpc: - case MemoryState::NonDeviceIpc: + case KMemoryState::Ipc: + case KMemoryState::NonSecureIpc: + case KMemoryState::NonDeviceIpc: return alias_region_end - alias_region_start; - case MemoryState::Stack: + case KMemoryState::Stack: return stack_region_end - stack_region_start; - case MemoryState::Io: - case MemoryState::Static: - case MemoryState::ThreadLocal: + case KMemoryState::Io: + case KMemoryState::Static: + case KMemoryState::ThreadLocal: return kernel_map_region_end - kernel_map_region_start; - case MemoryState::Shared: - case MemoryState::AliasCode: - case MemoryState::AliasCodeData: - case MemoryState::Transferred: - case MemoryState::SharedTransferred: - case MemoryState::SharedCode: - case MemoryState::GeneratedCode: - case MemoryState::CodeOut: + case KMemoryState::Shared: + case KMemoryState::AliasCode: + case KMemoryState::AliasCodeData: + case KMemoryState::Transferred: + case KMemoryState::SharedTransferred: + case KMemoryState::SharedCode: + case KMemoryState::GeneratedCode: + case KMemoryState::CodeOut: return alias_code_region_end - alias_code_region_start; - case MemoryState::Code: - case MemoryState::CodeData: + case KMemoryState::Code: + case KMemoryState::CodeData: return code_region_end - code_region_start; default: UNREACHABLE(); @@ -1063,7 +1067,7 @@ constexpr std::size_t PageTable::GetRegionSize(MemoryState state) const { } } -constexpr bool PageTable::CanContain(VAddr addr, std::size_t size, MemoryState state) const { +constexpr bool PageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) const { const VAddr end{addr + size}; const VAddr last{end - 1}; const VAddr region_start{GetRegionAddress(state)}; @@ -1074,30 +1078,30 @@ constexpr bool PageTable::CanContain(VAddr addr, std::size_t size, MemoryState s const bool is_in_alias{!(end <= alias_region_start || alias_region_end <= addr)}; switch (state) { - case MemoryState::Free: - case MemoryState::Kernel: + case KMemoryState::Free: + case KMemoryState::Kernel: return is_in_region; - case MemoryState::Io: - case MemoryState::Static: - case MemoryState::Code: - case MemoryState::CodeData: - case MemoryState::Shared: - case MemoryState::AliasCode: - case MemoryState::AliasCodeData: - case MemoryState::Stack: - case MemoryState::ThreadLocal: - case MemoryState::Transferred: - case MemoryState::SharedTransferred: - case MemoryState::SharedCode: - case MemoryState::GeneratedCode: - case MemoryState::CodeOut: + case KMemoryState::Io: + case KMemoryState::Static: + case KMemoryState::Code: + case KMemoryState::CodeData: + case KMemoryState::Shared: + case KMemoryState::AliasCode: + case KMemoryState::AliasCodeData: + case KMemoryState::Stack: + case KMemoryState::ThreadLocal: + case KMemoryState::Transferred: + case KMemoryState::SharedTransferred: + case KMemoryState::SharedCode: + case KMemoryState::GeneratedCode: + case KMemoryState::CodeOut: return is_in_region && !is_in_heap && !is_in_alias; - case MemoryState::Normal: + case KMemoryState::Normal: ASSERT(is_in_heap); return is_in_region && !is_in_alias; - case MemoryState::Ipc: - case MemoryState::NonSecureIpc: - case MemoryState::NonDeviceIpc: + case KMemoryState::Ipc: + case KMemoryState::NonSecureIpc: + case KMemoryState::NonDeviceIpc: ASSERT(is_in_alias); return is_in_region && !is_in_heap; default: @@ -1105,10 +1109,10 @@ constexpr bool PageTable::CanContain(VAddr addr, std::size_t size, MemoryState s } } -constexpr ResultCode PageTable::CheckMemoryState(const MemoryInfo& info, MemoryState state_mask, - MemoryState state, MemoryPermission perm_mask, - MemoryPermission perm, MemoryAttribute attr_mask, - MemoryAttribute attr) const { +constexpr ResultCode PageTable::CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, + KMemoryState state, KMemoryPermission perm_mask, + KMemoryPermission perm, KMemoryAttribute attr_mask, + KMemoryAttribute attr) const { // Validate the states match expectation if ((info.state & state_mask) != state) { return ResultInvalidCurrentMemory; @@ -1123,23 +1127,23 @@ constexpr ResultCode PageTable::CheckMemoryState(const MemoryInfo& info, MemoryS return RESULT_SUCCESS; } -ResultCode PageTable::CheckMemoryState(MemoryState* out_state, MemoryPermission* out_perm, - MemoryAttribute* out_attr, VAddr addr, std::size_t size, - MemoryState state_mask, MemoryState state, - MemoryPermission perm_mask, MemoryPermission perm, - MemoryAttribute attr_mask, MemoryAttribute attr, - MemoryAttribute ignore_attr) { +ResultCode PageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm, + KMemoryAttribute* out_attr, VAddr addr, std::size_t size, + KMemoryState state_mask, KMemoryState state, + KMemoryPermission perm_mask, KMemoryPermission perm, + KMemoryAttribute attr_mask, KMemoryAttribute attr, + KMemoryAttribute ignore_attr) { std::lock_guard lock{page_table_lock}; // Get information about the first block const VAddr last_addr{addr + size - 1}; - MemoryBlockManager::const_iterator it{block_manager->FindIterator(addr)}; - MemoryInfo info{it->GetMemoryInfo()}; + KMemoryBlockManager::const_iterator it{block_manager->FindIterator(addr)}; + KMemoryInfo info{it->GetMemoryInfo()}; // Validate all blocks in the range have correct state - const MemoryState first_state{info.state}; - const MemoryPermission first_perm{info.perm}; - const MemoryAttribute first_attr{info.attribute}; + const KMemoryState first_state{info.state}; + const KMemoryPermission first_perm{info.perm}; + const KMemoryAttribute first_attr{info.attribute}; while (true) { // Validate the current block @@ -1149,8 +1153,8 @@ ResultCode PageTable::CheckMemoryState(MemoryState* out_state, MemoryPermission* if (!(info.perm == first_perm)) { return ResultInvalidCurrentMemory; } - if (!((info.attribute | static_cast(ignore_attr)) == - (first_attr | static_cast(ignore_attr)))) { + if (!((info.attribute | static_cast(ignore_attr)) == + (first_attr | static_cast(ignore_attr)))) { return ResultInvalidCurrentMemory; } @@ -1176,7 +1180,7 @@ ResultCode PageTable::CheckMemoryState(MemoryState* out_state, MemoryPermission* *out_perm = first_perm; } if (out_attr) { - *out_attr = first_attr & static_cast(~ignore_attr); + *out_attr = first_attr & static_cast(~ignore_attr); } return RESULT_SUCCESS; diff --git a/src/core/hle/kernel/memory/page_table.h b/src/core/hle/kernel/memory/page_table.h index ce0d38849..a4914d050 100644 --- a/src/core/hle/kernel/memory/page_table.h +++ b/src/core/hle/kernel/memory/page_table.h @@ -10,7 +10,7 @@ #include "common/common_types.h" #include "common/page_table.h" #include "core/file_sys/program_metadata.h" -#include "core/hle/kernel/memory/memory_block.h" +#include "core/hle/kernel/k_memory_block.h" #include "core/hle/kernel/memory/memory_manager.h" #include "core/hle/result.h" @@ -18,9 +18,11 @@ namespace Core { class System; } -namespace Kernel::Memory { +namespace Kernel { +class KMemoryBlockManager; +} -class MemoryBlockManager; +namespace Kernel::Memory { class PageTable final : NonCopyable { public: @@ -29,8 +31,8 @@ public: ResultCode InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr, VAddr code_addr, std::size_t code_size, Memory::MemoryManager::Pool pool); - ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, MemoryState state, - MemoryPermission perm); + ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, KMemoryState state, + KMemoryPermission perm); ResultCode MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); ResultCode UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); ResultCode MapPhysicalMemory(VAddr addr, std::size_t size); @@ -38,20 +40,20 @@ public: ResultCode UnmapMemory(VAddr addr, std::size_t size); ResultCode Map(VAddr dst_addr, VAddr src_addr, std::size_t size); ResultCode Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size); - ResultCode MapPages(VAddr addr, PageLinkedList& page_linked_list, MemoryState state, - MemoryPermission perm); - ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, MemoryPermission perm); - MemoryInfo QueryInfo(VAddr addr); - ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, MemoryPermission perm); + ResultCode MapPages(VAddr addr, PageLinkedList& page_linked_list, KMemoryState state, + KMemoryPermission perm); + ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm); + KMemoryInfo QueryInfo(VAddr addr); + ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); ResultCode ResetTransferMemory(VAddr addr, std::size_t size); - ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, MemoryAttribute mask, - MemoryAttribute value); + ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask, + KMemoryAttribute value); ResultCode SetHeapCapacity(std::size_t new_heap_capacity); ResultVal SetHeapSize(std::size_t size); ResultVal AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, bool is_map_only, VAddr region_start, - std::size_t region_num_pages, MemoryState state, - MemoryPermission perm, PAddr map_addr = 0); + std::size_t region_num_pages, KMemoryState state, + KMemoryPermission perm, PAddr map_addr = 0); ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size); ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size); @@ -72,47 +74,48 @@ private: ChangePermissionsAndRefresh, }; - static constexpr MemoryAttribute DefaultMemoryIgnoreAttr = - MemoryAttribute::DontCareMask | MemoryAttribute::IpcLocked | MemoryAttribute::DeviceShared; + static constexpr KMemoryAttribute DefaultMemoryIgnoreAttr = KMemoryAttribute::DontCareMask | + KMemoryAttribute::IpcLocked | + KMemoryAttribute::DeviceShared; ResultCode InitializeMemoryLayout(VAddr start, VAddr end); - ResultCode MapPages(VAddr addr, const PageLinkedList& page_linked_list, MemoryPermission perm); + ResultCode MapPages(VAddr addr, const PageLinkedList& page_linked_list, KMemoryPermission perm); void MapPhysicalMemory(PageLinkedList& page_linked_list, VAddr start, VAddr end); bool IsRegionMapped(VAddr address, u64 size); bool IsRegionContiguous(VAddr addr, u64 size) const; void AddRegionToPages(VAddr start, std::size_t num_pages, PageLinkedList& page_linked_list); - MemoryInfo QueryInfoImpl(VAddr addr); + KMemoryInfo QueryInfoImpl(VAddr addr); VAddr AllocateVirtualMemory(VAddr start, std::size_t region_num_pages, u64 needed_num_pages, std::size_t align); ResultCode Operate(VAddr addr, std::size_t num_pages, const PageLinkedList& page_group, OperationType operation); - ResultCode Operate(VAddr addr, std::size_t num_pages, MemoryPermission perm, + ResultCode Operate(VAddr addr, std::size_t num_pages, KMemoryPermission perm, OperationType operation, PAddr map_addr = 0); - constexpr VAddr GetRegionAddress(MemoryState state) const; - constexpr std::size_t GetRegionSize(MemoryState state) const; - constexpr bool CanContain(VAddr addr, std::size_t size, MemoryState state) const; + constexpr VAddr GetRegionAddress(KMemoryState state) const; + constexpr std::size_t GetRegionSize(KMemoryState state) const; + constexpr bool CanContain(VAddr addr, std::size_t size, KMemoryState state) const; - constexpr ResultCode CheckMemoryState(const MemoryInfo& info, MemoryState state_mask, - MemoryState state, MemoryPermission perm_mask, - MemoryPermission perm, MemoryAttribute attr_mask, - MemoryAttribute attr) const; - ResultCode CheckMemoryState(MemoryState* out_state, MemoryPermission* out_perm, - MemoryAttribute* out_attr, VAddr addr, std::size_t size, - MemoryState state_mask, MemoryState state, - MemoryPermission perm_mask, MemoryPermission perm, - MemoryAttribute attr_mask, MemoryAttribute attr, - MemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr); - ResultCode CheckMemoryState(VAddr addr, std::size_t size, MemoryState state_mask, - MemoryState state, MemoryPermission perm_mask, - MemoryPermission perm, MemoryAttribute attr_mask, - MemoryAttribute attr, - MemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) { + constexpr ResultCode CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, + KMemoryState state, KMemoryPermission perm_mask, + KMemoryPermission perm, KMemoryAttribute attr_mask, + KMemoryAttribute attr) const; + ResultCode CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm, + KMemoryAttribute* out_attr, VAddr addr, std::size_t size, + KMemoryState state_mask, KMemoryState state, + KMemoryPermission perm_mask, KMemoryPermission perm, + KMemoryAttribute attr_mask, KMemoryAttribute attr, + KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr); + ResultCode CheckMemoryState(VAddr addr, std::size_t size, KMemoryState state_mask, + KMemoryState state, KMemoryPermission perm_mask, + KMemoryPermission perm, KMemoryAttribute attr_mask, + KMemoryAttribute attr, + KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) { return CheckMemoryState(nullptr, nullptr, nullptr, addr, size, state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr); } std::recursive_mutex page_table_lock; - std::unique_ptr block_manager; + std::unique_ptr block_manager; public: constexpr VAddr GetAddressSpaceStart() const { @@ -212,7 +215,7 @@ public: return !IsOutsideASLRRegion(address, size); } constexpr PAddr GetPhysicalAddr(VAddr addr) { - return page_table_impl.backing_addr[addr >> Memory::PageBits] + addr; + return page_table_impl.backing_addr[addr >> PageBits] + addr; } private: diff --git a/src/core/hle/kernel/memory_types.h b/src/core/hle/kernel/memory_types.h new file mode 100644 index 000000000..d458f0eca --- /dev/null +++ b/src/core/hle/kernel/memory_types.h @@ -0,0 +1,18 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/common_types.h" + +namespace Kernel { + +constexpr std::size_t PageBits{12}; +constexpr std::size_t PageSize{1 << PageBits}; + +using Page = std::array; + +} // namespace Kernel diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 47b3ac57b..f83977a8e 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -14,14 +14,14 @@ #include "core/device_memory.h" #include "core/file_sys/program_metadata.h" #include "core/hle/kernel/code_set.h" +#include "core/hle/kernel/k_memory_block_manager.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_slab_heap.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/memory/memory_block_manager.h" #include "core/hle/kernel/memory/page_table.h" -#include "core/hle/kernel/memory/slab_heap.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/lock.h" @@ -291,9 +291,9 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, } // Map process code region - if (const ResultCode result{page_table->MapProcessCode( - page_table->GetCodeRegionStart(), code_size / Memory::PageSize, - Memory::MemoryState::Code, Memory::MemoryPermission::None)}; + if (const ResultCode result{page_table->MapProcessCode(page_table->GetCodeRegionStart(), + code_size / PageSize, KMemoryState::Code, + KMemoryPermission::None)}; result.IsError()) { return result; } @@ -400,22 +400,22 @@ VAddr Process::CreateTLSRegion() { return *tls_page_iter->ReserveSlot(); } - Memory::Page* const tls_page_ptr{kernel.GetUserSlabHeapPages().Allocate()}; + Page* const tls_page_ptr{kernel.GetUserSlabHeapPages().Allocate()}; ASSERT(tls_page_ptr); const VAddr start{page_table->GetKernelMapRegionStart()}; const VAddr size{page_table->GetKernelMapRegionEnd() - start}; const PAddr tls_map_addr{system.DeviceMemory().GetPhysicalAddr(tls_page_ptr)}; - const VAddr tls_page_addr{ - page_table - ->AllocateAndMapMemory(1, Memory::PageSize, true, start, size / Memory::PageSize, - Memory::MemoryState::ThreadLocal, - Memory::MemoryPermission::ReadAndWrite, tls_map_addr) - .ValueOr(0)}; + const VAddr tls_page_addr{page_table + ->AllocateAndMapMemory(1, PageSize, true, start, size / PageSize, + KMemoryState::ThreadLocal, + KMemoryPermission::ReadAndWrite, + tls_map_addr) + .ValueOr(0)}; ASSERT(tls_page_addr); - std::memset(tls_page_ptr, 0, Memory::PageSize); + std::memset(tls_page_ptr, 0, PageSize); tls_pages.emplace_back(tls_page_addr); const auto reserve_result{tls_pages.back().ReserveSlot()}; @@ -442,15 +442,15 @@ void Process::FreeTLSRegion(VAddr tls_address) { void Process::LoadModule(CodeSet code_set, VAddr base_addr) { std::lock_guard lock{HLE::g_hle_lock}; const auto ReprotectSegment = [&](const CodeSet::Segment& segment, - Memory::MemoryPermission permission) { + KMemoryPermission permission) { page_table->SetCodeMemoryPermission(segment.addr + base_addr, segment.size, permission); }; system.Memory().WriteBlock(*this, base_addr, code_set.memory.data(), code_set.memory.size()); - ReprotectSegment(code_set.CodeSegment(), Memory::MemoryPermission::ReadAndExecute); - ReprotectSegment(code_set.RODataSegment(), Memory::MemoryPermission::Read); - ReprotectSegment(code_set.DataSegment(), Memory::MemoryPermission::ReadAndWrite); + ReprotectSegment(code_set.CodeSegment(), KMemoryPermission::ReadAndExecute); + ReprotectSegment(code_set.RODataSegment(), KMemoryPermission::Read); + ReprotectSegment(code_set.DataSegment(), KMemoryPermission::ReadAndWrite); } bool Process::IsSignaled() const { @@ -479,16 +479,15 @@ ResultCode Process::AllocateMainThreadStack(std::size_t stack_size) { ASSERT(stack_size); // The kernel always ensures that the given stack size is page aligned. - main_thread_stack_size = Common::AlignUp(stack_size, Memory::PageSize); + main_thread_stack_size = Common::AlignUp(stack_size, PageSize); const VAddr start{page_table->GetStackRegionStart()}; const std::size_t size{page_table->GetStackRegionEnd() - start}; CASCADE_RESULT(main_thread_stack_top, page_table->AllocateAndMapMemory( - main_thread_stack_size / Memory::PageSize, Memory::PageSize, false, start, - size / Memory::PageSize, Memory::MemoryState::Stack, - Memory::MemoryPermission::ReadAndWrite)); + main_thread_stack_size / PageSize, PageSize, false, start, size / PageSize, + KMemoryState::Stack, KMemoryPermission::ReadAndWrite)); main_thread_stack_top += main_thread_stack_size; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 12cfdcf2c..4ffd65d33 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -27,6 +27,7 @@ #include "core/hle/kernel/k_address_arbiter.h" #include "core/hle/kernel/k_condition_variable.h" #include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_memory_block.h" #include "core/hle/kernel/k_memory_layout.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_resource_limit.h" @@ -38,7 +39,6 @@ #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/memory/memory_block.h" #include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/process.h" @@ -230,9 +230,9 @@ static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 si return ResultInvalidCurrentMemory; } - const auto attributes{static_cast(mask | attribute)}; - if (attributes != static_cast(mask) || - (attributes | Memory::MemoryAttribute::Uncached) != Memory::MemoryAttribute::Uncached) { + const auto attributes{static_cast(mask | attribute)}; + if (attributes != static_cast(mask) || + (attributes | MemoryAttribute::Uncached) != MemoryAttribute::Uncached) { LOG_ERROR(Kernel_SVC, "Memory attribute doesn't match the given mask (Attribute: 0x{:X}, Mask: {:X}", attribute, mask); @@ -241,8 +241,8 @@ static ResultCode SetMemoryAttribute(Core::System& system, VAddr address, u64 si auto& page_table{system.Kernel().CurrentProcess()->PageTable()}; - return page_table.SetMemoryAttribute(address, size, static_cast(mask), - static_cast(attribute)); + return page_table.SetMemoryAttribute(address, size, static_cast(mask), + static_cast(attribute)); } static ResultCode SetMemoryAttribute32(Core::System& system, u32 address, u32 size, u32 mask, @@ -1231,9 +1231,8 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han return ResultInvalidCurrentMemory; } - const auto permission_type = static_cast(permissions); - if ((permission_type | Memory::MemoryPermission::Write) != - Memory::MemoryPermission::ReadAndWrite) { + const auto permission_type = static_cast(permissions); + if ((permission_type | MemoryPermission::Write) != MemoryPermission::ReadWrite) { LOG_ERROR(Kernel_SVC, "Expected Read or ReadWrite permission but got permissions=0x{:08X}", permissions); return ResultInvalidMemoryPermissions; @@ -1273,7 +1272,8 @@ static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_han return ResultInvalidHandle; } - return shared_memory->Map(*current_process, addr, size, permission_type); + return shared_memory->Map(*current_process, addr, size, + static_cast(permission_type)); } static ResultCode MapSharedMemory32(Core::System& system, Handle shared_memory_handle, u32 addr, @@ -1886,9 +1886,8 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd return ResultInvalidCurrentMemory; } - const auto perms{static_cast(permissions)}; - if (perms > Memory::MemoryPermission::ReadAndWrite || - perms == Memory::MemoryPermission::Write) { + const auto perms{static_cast(permissions)}; + if (perms > MemoryPermission::ReadWrite || perms == MemoryPermission::Write) { LOG_ERROR(Kernel_SVC, "Invalid memory permissions for transfer memory! (perms={:08X})", permissions); return ResultInvalidMemoryPermissions; @@ -1902,7 +1901,8 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd LOG_ERROR(Kernel_SVC, "Could not reserve a new transfer memory"); 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, + static_cast(perms)); if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) { return reserve_result; diff --git a/src/core/hle/kernel/transfer_memory.cpp b/src/core/hle/kernel/transfer_memory.cpp index 6b0fc1591..b92559616 100644 --- a/src/core/hle/kernel/transfer_memory.cpp +++ b/src/core/hle/kernel/transfer_memory.cpp @@ -24,7 +24,7 @@ TransferMemory::~TransferMemory() { std::shared_ptr TransferMemory::Create(KernelCore& kernel, Core::Memory::Memory& memory, VAddr base_address, std::size_t size, - Memory::MemoryPermission permissions) { + KMemoryPermission permissions) { std::shared_ptr transfer_memory{ std::make_shared(kernel, memory)}; diff --git a/src/core/hle/kernel/transfer_memory.h b/src/core/hle/kernel/transfer_memory.h index 777799d12..521951424 100644 --- a/src/core/hle/kernel/transfer_memory.h +++ b/src/core/hle/kernel/transfer_memory.h @@ -6,7 +6,7 @@ #include -#include "core/hle/kernel/memory/memory_block.h" +#include "core/hle/kernel/k_memory_block.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/physical_memory.h" @@ -36,7 +36,7 @@ public: static std::shared_ptr Create(KernelCore& kernel, Core::Memory::Memory& memory, VAddr base_address, std::size_t size, - Memory::MemoryPermission permissions); + KMemoryPermission permissions); TransferMemory(const TransferMemory&) = delete; TransferMemory& operator=(const TransferMemory&) = delete; @@ -82,7 +82,7 @@ private: std::size_t size{}; /// The memory permissions that are applied to this instance. - Memory::MemoryPermission owner_permissions{}; + KMemoryPermission owner_permissions{}; /// The process that this transfer memory instance was created under. Process* owner_process{}; diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index d3cd25ff8..b42184a3b 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -289,10 +289,10 @@ public: bool ValidateRegionForMap(Kernel::Memory::PageTable& page_table, VAddr start, std::size_t size) const { - constexpr std::size_t padding_size{4 * Kernel::Memory::PageSize}; + constexpr std::size_t padding_size{4 * Kernel::PageSize}; const auto start_info{page_table.QueryInfo(start - 1)}; - if (start_info.state != Kernel::Memory::MemoryState::Free) { + if (start_info.state != Kernel::KMemoryState::Free) { return {}; } @@ -302,7 +302,7 @@ public: const auto end_info{page_table.QueryInfo(start + size)}; - if (end_info.state != Kernel::Memory::MemoryState::Free) { + if (end_info.state != Kernel::KMemoryState::Free) { return {}; } @@ -312,11 +312,10 @@ public: VAddr GetRandomMapRegion(const Kernel::Memory::PageTable& page_table, std::size_t size) const { VAddr addr{}; const std::size_t end_pages{(page_table.GetAliasCodeRegionSize() - size) >> - Kernel::Memory::PageBits}; + Kernel::PageBits}; do { addr = page_table.GetAliasCodeRegionStart() + - (Kernel::KSystemControl::GenerateRandomRange(0, end_pages) - << Kernel::Memory::PageBits); + (Kernel::KSystemControl::GenerateRandomRange(0, end_pages) << Kernel::PageBits); } while (!page_table.IsInsideAddressSpace(addr, size) || page_table.IsInsideHeapRegion(addr, size) || page_table.IsInsideAliasRegion(addr, size)); @@ -387,7 +386,7 @@ public: const VAddr data_start{start + nro_header.segment_headers[DATA_INDEX].memory_offset}; const VAddr bss_start{data_start + nro_header.segment_headers[DATA_INDEX].memory_size}; const VAddr bss_end_addr{ - Common::AlignUp(bss_start + nro_header.bss_size, Kernel::Memory::PageSize)}; + Common::AlignUp(bss_start + nro_header.bss_size, Kernel::PageSize)}; auto CopyCode{[&](VAddr src_addr, VAddr dst_addr, u64 size) { std::vector source_data(size); @@ -402,12 +401,12 @@ public: nro_header.segment_headers[DATA_INDEX].memory_size); CASCADE_CODE(process->PageTable().SetCodeMemoryPermission( - text_start, ro_start - text_start, Kernel::Memory::MemoryPermission::ReadAndExecute)); - CASCADE_CODE(process->PageTable().SetCodeMemoryPermission( - ro_start, data_start - ro_start, Kernel::Memory::MemoryPermission::Read)); + text_start, ro_start - text_start, Kernel::KMemoryPermission::ReadAndExecute)); + CASCADE_CODE(process->PageTable().SetCodeMemoryPermission(ro_start, data_start - ro_start, + Kernel::KMemoryPermission::Read)); return process->PageTable().SetCodeMemoryPermission( - data_start, bss_end_addr - data_start, Kernel::Memory::MemoryPermission::ReadAndWrite); + data_start, bss_end_addr - data_start, Kernel::KMemoryPermission::ReadAndWrite); } void LoadNro(Kernel::HLERequestContext& ctx) { -- cgit v1.2.3 From 93109c870e957d495d24d61d94f7761c72f5624f Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 12 Feb 2021 17:26:01 -0800 Subject: hle: kernel: Migrate PageLinkedList to KPageLinkedList. --- src/core/CMakeLists.txt | 2 +- src/core/hle/kernel/k_page_linked_list.h | 92 +++++++++++++++++++++++++++ src/core/hle/kernel/k_shared_memory.cpp | 2 +- src/core/hle/kernel/k_shared_memory.h | 6 +- src/core/hle/kernel/memory/memory_manager.cpp | 6 +- src/core/hle/kernel/memory/memory_manager.h | 10 +-- src/core/hle/kernel/memory/page_linked_list.h | 92 --------------------------- src/core/hle/kernel/memory/page_table.cpp | 30 ++++----- src/core/hle/kernel/memory/page_table.h | 11 ++-- 9 files changed, 127 insertions(+), 124 deletions(-) create mode 100644 src/core/hle/kernel/k_page_linked_list.h delete mode 100644 src/core/hle/kernel/memory/page_linked_list.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a304dd935..70dab3f74 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -171,6 +171,7 @@ add_library(core STATIC hle/kernel/k_memory_block_manager.h hle/kernel/k_memory_layout.h hle/kernel/k_page_bitmap.h + hle/kernel/k_page_linked_list.h hle/kernel/k_priority_queue.h hle/kernel/k_readable_event.cpp hle/kernel/k_readable_event.h @@ -201,7 +202,6 @@ add_library(core STATIC hle/kernel/memory_types.h hle/kernel/memory/memory_manager.cpp hle/kernel/memory/memory_manager.h - hle/kernel/memory/page_linked_list.h hle/kernel/memory/page_heap.cpp hle/kernel/memory/page_heap.h hle/kernel/memory/page_table.cpp diff --git a/src/core/hle/kernel/k_page_linked_list.h b/src/core/hle/kernel/k_page_linked_list.h new file mode 100644 index 000000000..64024d01f --- /dev/null +++ b/src/core/hle/kernel/k_page_linked_list.h @@ -0,0 +1,92 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/assert.h" +#include "common/common_types.h" +#include "core/hle/kernel/memory_types.h" +#include "core/hle/result.h" + +namespace Kernel { + +class KPageLinkedList final { +public: + class Node final { + public: + constexpr Node(u64 addr, std::size_t num_pages) : addr{addr}, num_pages{num_pages} {} + + constexpr u64 GetAddress() const { + return addr; + } + + constexpr std::size_t GetNumPages() const { + return num_pages; + } + + private: + u64 addr{}; + std::size_t num_pages{}; + }; + +public: + KPageLinkedList() = default; + KPageLinkedList(u64 address, u64 num_pages) { + ASSERT(AddBlock(address, num_pages).IsSuccess()); + } + + constexpr std::list& Nodes() { + return nodes; + } + + constexpr const std::list& Nodes() const { + return nodes; + } + + std::size_t GetNumPages() const { + std::size_t num_pages = 0; + for (const Node& node : nodes) { + num_pages += node.GetNumPages(); + } + return num_pages; + } + + bool IsEqual(KPageLinkedList& other) const { + auto this_node = nodes.begin(); + auto other_node = other.nodes.begin(); + while (this_node != nodes.end() && other_node != other.nodes.end()) { + if (this_node->GetAddress() != other_node->GetAddress() || + this_node->GetNumPages() != other_node->GetNumPages()) { + return false; + } + this_node = std::next(this_node); + other_node = std::next(other_node); + } + + return this_node == nodes.end() && other_node == other.nodes.end(); + } + + ResultCode AddBlock(u64 address, u64 num_pages) { + if (!num_pages) { + return RESULT_SUCCESS; + } + if (!nodes.empty()) { + const auto node = nodes.back(); + if (node.GetAddress() + node.GetNumPages() * PageSize == address) { + address = node.GetAddress(); + num_pages += node.GetNumPages(); + nodes.pop_back(); + } + } + nodes.push_back({address, num_pages}); + return RESULT_SUCCESS; + } + +private: + std::list nodes; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_shared_memory.cpp b/src/core/hle/kernel/k_shared_memory.cpp index eb48afe9d..aade52764 100644 --- a/src/core/hle/kernel/k_shared_memory.cpp +++ b/src/core/hle/kernel/k_shared_memory.cpp @@ -20,7 +20,7 @@ KSharedMemory::~KSharedMemory() { std::shared_ptr KSharedMemory::Create( KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, - Memory::PageLinkedList&& page_list, KMemoryPermission owner_permission, + KPageLinkedList&& page_list, KMemoryPermission owner_permission, KMemoryPermission user_permission, PAddr physical_address, std::size_t size, std::string name) { diff --git a/src/core/hle/kernel/k_shared_memory.h b/src/core/hle/kernel/k_shared_memory.h index 1ecb4f7dd..016e34be5 100644 --- a/src/core/hle/kernel/k_shared_memory.h +++ b/src/core/hle/kernel/k_shared_memory.h @@ -10,7 +10,7 @@ #include "common/common_types.h" #include "core/device_memory.h" #include "core/hle/kernel/k_memory_block.h" -#include "core/hle/kernel/memory/page_linked_list.h" +#include "core/hle/kernel/k_page_linked_list.h" #include "core/hle/kernel/object.h" #include "core/hle/kernel/process.h" #include "core/hle/result.h" @@ -26,7 +26,7 @@ public: static std::shared_ptr Create( KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, - Memory::PageLinkedList&& page_list, KMemoryPermission owner_permission, + KPageLinkedList&& page_list, KMemoryPermission owner_permission, KMemoryPermission user_permission, PAddr physical_address, std::size_t size, std::string name); @@ -76,7 +76,7 @@ public: private: Core::DeviceMemory& device_memory; Process* owner_process{}; - Memory::PageLinkedList page_list; + KPageLinkedList page_list; KMemoryPermission owner_permission{}; KMemoryPermission user_permission{}; PAddr physical_address{}; diff --git a/src/core/hle/kernel/memory/memory_manager.cpp b/src/core/hle/kernel/memory/memory_manager.cpp index ffda77374..00d5b15f3 100644 --- a/src/core/hle/kernel/memory/memory_manager.cpp +++ b/src/core/hle/kernel/memory/memory_manager.cpp @@ -8,8 +8,8 @@ #include "common/assert.h" #include "common/common_types.h" #include "common/scope_exit.h" +#include "core/hle/kernel/k_page_linked_list.h" #include "core/hle/kernel/memory/memory_manager.h" -#include "core/hle/kernel/memory/page_linked_list.h" #include "core/hle/kernel/svc_results.h" namespace Kernel::Memory { @@ -80,7 +80,7 @@ VAddr MemoryManager::AllocateAndOpenContinuous(std::size_t num_pages, std::size_ return allocated_block; } -ResultCode MemoryManager::Allocate(PageLinkedList& page_list, std::size_t num_pages, Pool pool, +ResultCode MemoryManager::Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, Direction dir) { ASSERT(page_list.GetNumPages() == 0); @@ -149,7 +149,7 @@ ResultCode MemoryManager::Allocate(PageLinkedList& page_list, std::size_t num_pa return RESULT_SUCCESS; } -ResultCode MemoryManager::Free(PageLinkedList& page_list, std::size_t num_pages, Pool pool, +ResultCode MemoryManager::Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, Direction dir) { // Early return if we're freeing no pages if (!num_pages) { diff --git a/src/core/hle/kernel/memory/memory_manager.h b/src/core/hle/kernel/memory/memory_manager.h index 80dfbc8c2..d090979bd 100644 --- a/src/core/hle/kernel/memory/memory_manager.h +++ b/src/core/hle/kernel/memory/memory_manager.h @@ -13,9 +13,11 @@ #include "core/hle/kernel/memory/page_heap.h" #include "core/hle/result.h" -namespace Kernel::Memory { +namespace Kernel { +class KPageLinkedList; +} -class PageLinkedList; +namespace Kernel::Memory { class MemoryManager final : NonCopyable { public: @@ -48,9 +50,9 @@ public: void InitializeManager(Pool pool, u64 start_address, u64 end_address); VAddr AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option); - ResultCode Allocate(PageLinkedList& page_list, std::size_t num_pages, Pool pool, + ResultCode Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, Direction dir = Direction::FromFront); - ResultCode Free(PageLinkedList& page_list, std::size_t num_pages, Pool pool, + ResultCode Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, Direction dir = Direction::FromFront); static constexpr std::size_t MaxManagerCount = 10; diff --git a/src/core/hle/kernel/memory/page_linked_list.h b/src/core/hle/kernel/memory/page_linked_list.h deleted file mode 100644 index 9b871f15b..000000000 --- a/src/core/hle/kernel/memory/page_linked_list.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include - -#include "common/assert.h" -#include "common/common_types.h" -#include "core/hle/kernel/memory_types.h" -#include "core/hle/result.h" - -namespace Kernel::Memory { - -class PageLinkedList final { -public: - class Node final { - public: - constexpr Node(u64 addr, std::size_t num_pages) : addr{addr}, num_pages{num_pages} {} - - constexpr u64 GetAddress() const { - return addr; - } - - constexpr std::size_t GetNumPages() const { - return num_pages; - } - - private: - u64 addr{}; - std::size_t num_pages{}; - }; - -public: - PageLinkedList() = default; - PageLinkedList(u64 address, u64 num_pages) { - ASSERT(AddBlock(address, num_pages).IsSuccess()); - } - - constexpr std::list& Nodes() { - return nodes; - } - - constexpr const std::list& Nodes() const { - return nodes; - } - - std::size_t GetNumPages() const { - std::size_t num_pages = 0; - for (const Node& node : nodes) { - num_pages += node.GetNumPages(); - } - return num_pages; - } - - bool IsEqual(PageLinkedList& other) const { - auto this_node = nodes.begin(); - auto other_node = other.nodes.begin(); - while (this_node != nodes.end() && other_node != other.nodes.end()) { - if (this_node->GetAddress() != other_node->GetAddress() || - this_node->GetNumPages() != other_node->GetNumPages()) { - return false; - } - this_node = std::next(this_node); - other_node = std::next(other_node); - } - - return this_node == nodes.end() && other_node == other.nodes.end(); - } - - ResultCode AddBlock(u64 address, u64 num_pages) { - if (!num_pages) { - return RESULT_SUCCESS; - } - if (!nodes.empty()) { - const auto node = nodes.back(); - if (node.GetAddress() + node.GetNumPages() * PageSize == address) { - address = node.GetAddress(); - num_pages += node.GetNumPages(); - nodes.pop_back(); - } - } - nodes.push_back({address, num_pages}); - return RESULT_SUCCESS; - } - -private: - std::list nodes; -}; - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/page_table.cpp b/src/core/hle/kernel/memory/page_table.cpp index 183482648..c1efc23de 100644 --- a/src/core/hle/kernel/memory/page_table.cpp +++ b/src/core/hle/kernel/memory/page_table.cpp @@ -9,11 +9,11 @@ #include "core/hle/kernel/k_address_space_info.h" #include "core/hle/kernel/k_memory_block.h" #include "core/hle/kernel/k_memory_block_manager.h" +#include "core/hle/kernel/k_page_linked_list.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_system_control.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/memory/page_linked_list.h" #include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_results.h" @@ -285,7 +285,7 @@ ResultCode PageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemoryS return ResultInvalidCurrentMemory; } - PageLinkedList page_linked_list; + KPageLinkedList page_linked_list; CASCADE_CODE( system.Kernel().MemoryManager().Allocate(page_linked_list, num_pages, memory_pool)); CASCADE_CODE(Operate(addr, num_pages, page_linked_list, OperationType::MapGroup)); @@ -311,7 +311,7 @@ ResultCode PageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std:: return ResultInvalidCurrentMemory; } - PageLinkedList page_linked_list; + KPageLinkedList page_linked_list; AddRegionToPages(src_addr, num_pages, page_linked_list); { @@ -363,7 +363,7 @@ ResultCode PageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std return RESULT_SUCCESS; } -void PageTable::MapPhysicalMemory(PageLinkedList& page_linked_list, VAddr start, VAddr end) { +void PageTable::MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end) { auto node{page_linked_list.Nodes().begin()}; PAddr map_addr{node->GetAddress()}; std::size_t src_num_pages{node->GetNumPages()}; @@ -423,7 +423,7 @@ ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) { return ResultResourceLimitedExceeded; } - PageLinkedList page_linked_list; + KPageLinkedList page_linked_list; CASCADE_CODE( system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, memory_pool)); @@ -485,7 +485,7 @@ ResultCode PageTable::UnmapMemory(VAddr addr, std::size_t size) { const VAddr end_addr{addr + size}; ResultCode result{RESULT_SUCCESS}; - PageLinkedList page_linked_list; + KPageLinkedList page_linked_list; // Unmap each region within the range block_manager->IterateForRange(addr, end_addr, [&](const KMemoryInfo& info) { @@ -529,7 +529,7 @@ ResultCode PageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) { return ResultInvalidCurrentMemory; } - PageLinkedList page_linked_list; + KPageLinkedList page_linked_list; const std::size_t num_pages{size / PageSize}; AddRegionToPages(src_addr, num_pages, page_linked_list); @@ -570,8 +570,8 @@ ResultCode PageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) { KMemoryPermission::None, KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); - PageLinkedList src_pages; - PageLinkedList dst_pages; + KPageLinkedList src_pages; + KPageLinkedList dst_pages; const std::size_t num_pages{size / PageSize}; AddRegionToPages(src_addr, num_pages, src_pages); @@ -597,7 +597,7 @@ ResultCode PageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) { return RESULT_SUCCESS; } -ResultCode PageTable::MapPages(VAddr addr, const PageLinkedList& page_linked_list, +ResultCode PageTable::MapPages(VAddr addr, const KPageLinkedList& page_linked_list, KMemoryPermission perm) { VAddr cur_addr{addr}; @@ -619,7 +619,7 @@ ResultCode PageTable::MapPages(VAddr addr, const PageLinkedList& page_linked_lis return RESULT_SUCCESS; } -ResultCode PageTable::MapPages(VAddr addr, PageLinkedList& page_linked_list, KMemoryState state, +ResultCode PageTable::MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state, KMemoryPermission perm) { std::lock_guard lock{page_table_lock}; @@ -793,7 +793,7 @@ ResultVal PageTable::SetHeapSize(std::size_t size) { return ResultResourceLimitedExceeded; } - PageLinkedList page_linked_list; + KPageLinkedList page_linked_list; const std::size_t num_pages{delta / PageSize}; CASCADE_CODE( @@ -841,7 +841,7 @@ ResultVal PageTable::AllocateAndMapMemory(std::size_t needed_num_pages, s if (is_map_only) { CASCADE_CODE(Operate(addr, needed_num_pages, perm, OperationType::Map, map_addr)); } else { - PageLinkedList page_group; + KPageLinkedList page_group; CASCADE_CODE( system.Kernel().MemoryManager().Allocate(page_group, needed_num_pages, memory_pool)); CASCADE_CODE(Operate(addr, needed_num_pages, page_group, OperationType::MapGroup)); @@ -924,7 +924,7 @@ bool PageTable::IsRegionContiguous(VAddr addr, u64 size) const { } void PageTable::AddRegionToPages(VAddr start, std::size_t num_pages, - PageLinkedList& page_linked_list) { + KPageLinkedList& page_linked_list) { VAddr addr{start}; while (addr < start + (num_pages * PageSize)) { const PAddr paddr{GetPhysicalAddr(addr)}; @@ -945,7 +945,7 @@ VAddr PageTable::AllocateVirtualMemory(VAddr start, std::size_t region_num_pages IsKernel() ? 1 : 4); } -ResultCode PageTable::Operate(VAddr addr, std::size_t num_pages, const PageLinkedList& page_group, +ResultCode PageTable::Operate(VAddr addr, std::size_t num_pages, const KPageLinkedList& page_group, OperationType operation) { std::lock_guard lock{page_table_lock}; diff --git a/src/core/hle/kernel/memory/page_table.h b/src/core/hle/kernel/memory/page_table.h index a4914d050..736583b81 100644 --- a/src/core/hle/kernel/memory/page_table.h +++ b/src/core/hle/kernel/memory/page_table.h @@ -40,7 +40,7 @@ public: ResultCode UnmapMemory(VAddr addr, std::size_t size); ResultCode Map(VAddr dst_addr, VAddr src_addr, std::size_t size); ResultCode Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size); - ResultCode MapPages(VAddr addr, PageLinkedList& page_linked_list, KMemoryState state, + ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state, KMemoryPermission perm); ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm); KMemoryInfo QueryInfo(VAddr addr); @@ -79,15 +79,16 @@ private: KMemoryAttribute::DeviceShared; ResultCode InitializeMemoryLayout(VAddr start, VAddr end); - ResultCode MapPages(VAddr addr, const PageLinkedList& page_linked_list, KMemoryPermission perm); - void MapPhysicalMemory(PageLinkedList& page_linked_list, VAddr start, VAddr end); + ResultCode MapPages(VAddr addr, const KPageLinkedList& page_linked_list, + KMemoryPermission perm); + void MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end); bool IsRegionMapped(VAddr address, u64 size); bool IsRegionContiguous(VAddr addr, u64 size) const; - void AddRegionToPages(VAddr start, std::size_t num_pages, PageLinkedList& page_linked_list); + void AddRegionToPages(VAddr start, std::size_t num_pages, KPageLinkedList& page_linked_list); KMemoryInfo QueryInfoImpl(VAddr addr); VAddr AllocateVirtualMemory(VAddr start, std::size_t region_num_pages, u64 needed_num_pages, std::size_t align); - ResultCode Operate(VAddr addr, std::size_t num_pages, const PageLinkedList& page_group, + ResultCode Operate(VAddr addr, std::size_t num_pages, const KPageLinkedList& page_group, OperationType operation); ResultCode Operate(VAddr addr, std::size_t num_pages, KMemoryPermission perm, OperationType operation, PAddr map_addr = 0); -- cgit v1.2.3 From b1e27890e8728c19ceef404aa6352cd6f2913ded Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 12 Feb 2021 17:38:40 -0800 Subject: hle: kernel: Migrate MemoryManager to KMemoryManager. --- src/core/CMakeLists.txt | 4 +- src/core/hle/kernel/k_memory_manager.cpp | 176 ++++++++++++++++++++++++++ src/core/hle/kernel/k_memory_manager.h | 121 ++++++++++++++++++ src/core/hle/kernel/kernel.cpp | 16 +-- src/core/hle/kernel/kernel.h | 16 +-- src/core/hle/kernel/memory/memory_manager.cpp | 176 -------------------------- src/core/hle/kernel/memory/memory_manager.h | 121 ------------------ src/core/hle/kernel/memory/page_table.cpp | 2 +- src/core/hle/kernel/memory/page_table.h | 6 +- src/core/hle/kernel/process.cpp | 9 +- 10 files changed, 324 insertions(+), 323 deletions(-) create mode 100644 src/core/hle/kernel/k_memory_manager.cpp create mode 100644 src/core/hle/kernel/k_memory_manager.h delete mode 100644 src/core/hle/kernel/memory/memory_manager.cpp delete mode 100644 src/core/hle/kernel/memory/memory_manager.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 70dab3f74..2976187c0 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -170,6 +170,8 @@ add_library(core STATIC hle/kernel/k_memory_block_manager.cpp hle/kernel/k_memory_block_manager.h hle/kernel/k_memory_layout.h + hle/kernel/k_memory_manager.cpp + hle/kernel/k_memory_manager.h hle/kernel/k_page_bitmap.h hle/kernel/k_page_linked_list.h hle/kernel/k_priority_queue.h @@ -200,8 +202,6 @@ add_library(core STATIC hle/kernel/kernel.cpp hle/kernel/kernel.h hle/kernel/memory_types.h - hle/kernel/memory/memory_manager.cpp - hle/kernel/memory/memory_manager.h hle/kernel/memory/page_heap.cpp hle/kernel/memory/page_heap.h hle/kernel/memory/page_table.cpp diff --git a/src/core/hle/kernel/k_memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp new file mode 100644 index 000000000..5ea11a918 --- /dev/null +++ b/src/core/hle/kernel/k_memory_manager.cpp @@ -0,0 +1,176 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include + +#include "common/alignment.h" +#include "common/assert.h" +#include "common/common_types.h" +#include "common/scope_exit.h" +#include "core/hle/kernel/k_memory_manager.h" +#include "core/hle/kernel/k_page_linked_list.h" +#include "core/hle/kernel/svc_results.h" + +namespace Kernel { + +std::size_t KMemoryManager::Impl::Initialize(Pool new_pool, u64 start_address, u64 end_address) { + const auto size{end_address - start_address}; + + // Calculate metadata sizes + const auto ref_count_size{(size / PageSize) * sizeof(u16)}; + const auto optimize_map_size{(Common::AlignUp((size / PageSize), 64) / 64) * sizeof(u64)}; + const auto manager_size{Common::AlignUp(optimize_map_size + ref_count_size, PageSize)}; + const auto page_heap_size{Memory::PageHeap::CalculateManagementOverheadSize(size)}; + const auto total_metadata_size{manager_size + page_heap_size}; + ASSERT(manager_size <= total_metadata_size); + ASSERT(Common::IsAligned(total_metadata_size, PageSize)); + + // Setup region + pool = new_pool; + + // Initialize the manager's KPageHeap + heap.Initialize(start_address, size, page_heap_size); + + // Free the memory to the heap + heap.Free(start_address, size / PageSize); + + // Update the heap's used size + heap.UpdateUsedSize(); + + return total_metadata_size; +} + +void KMemoryManager::InitializeManager(Pool pool, u64 start_address, u64 end_address) { + ASSERT(pool < Pool::Count); + managers[static_cast(pool)].Initialize(pool, start_address, end_address); +} + +VAddr KMemoryManager::AllocateAndOpenContinuous(std::size_t num_pages, std::size_t align_pages, + u32 option) { + // Early return if we're allocating no pages + if (num_pages == 0) { + return {}; + } + + // Lock the pool that we're allocating from + const auto [pool, dir] = DecodeOption(option); + const auto pool_index{static_cast(pool)}; + std::lock_guard lock{pool_locks[pool_index]}; + + // Choose a heap based on our page size request + const s32 heap_index{Memory::PageHeap::GetAlignedBlockIndex(num_pages, align_pages)}; + + // Loop, trying to iterate from each block + // TODO (bunnei): Support multiple managers + Impl& chosen_manager{managers[pool_index]}; + VAddr allocated_block{chosen_manager.AllocateBlock(heap_index, false)}; + + // If we failed to allocate, quit now + if (!allocated_block) { + return {}; + } + + // If we allocated more than we need, free some + const auto allocated_pages{Memory::PageHeap::GetBlockNumPages(heap_index)}; + if (allocated_pages > num_pages) { + chosen_manager.Free(allocated_block + num_pages * PageSize, allocated_pages - num_pages); + } + + return allocated_block; +} + +ResultCode KMemoryManager::Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, + Direction dir) { + ASSERT(page_list.GetNumPages() == 0); + + // Early return if we're allocating no pages + if (num_pages == 0) { + return RESULT_SUCCESS; + } + + // Lock the pool that we're allocating from + const auto pool_index{static_cast(pool)}; + std::lock_guard lock{pool_locks[pool_index]}; + + // Choose a heap based on our page size request + const s32 heap_index{Memory::PageHeap::GetBlockIndex(num_pages)}; + if (heap_index < 0) { + return ResultOutOfMemory; + } + + // TODO (bunnei): Support multiple managers + Impl& chosen_manager{managers[pool_index]}; + + // Ensure that we don't leave anything un-freed + auto group_guard = detail::ScopeExit([&] { + for (const auto& it : page_list.Nodes()) { + const auto min_num_pages{std::min( + it.GetNumPages(), (chosen_manager.GetEndAddress() - it.GetAddress()) / PageSize)}; + chosen_manager.Free(it.GetAddress(), min_num_pages); + } + }); + + // Keep allocating until we've allocated all our pages + for (s32 index{heap_index}; index >= 0 && num_pages > 0; index--) { + const auto pages_per_alloc{Memory::PageHeap::GetBlockNumPages(index)}; + + while (num_pages >= pages_per_alloc) { + // Allocate a block + VAddr allocated_block{chosen_manager.AllocateBlock(index, false)}; + if (!allocated_block) { + break; + } + + // Safely add it to our group + { + auto block_guard = detail::ScopeExit( + [&] { chosen_manager.Free(allocated_block, pages_per_alloc); }); + + if (const ResultCode result{page_list.AddBlock(allocated_block, pages_per_alloc)}; + result.IsError()) { + return result; + } + + block_guard.Cancel(); + } + + num_pages -= pages_per_alloc; + } + } + + // Only succeed if we allocated as many pages as we wanted + if (num_pages) { + return ResultOutOfMemory; + } + + // We succeeded! + group_guard.Cancel(); + return RESULT_SUCCESS; +} + +ResultCode KMemoryManager::Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, + Direction dir) { + // Early return if we're freeing no pages + if (!num_pages) { + return RESULT_SUCCESS; + } + + // Lock the pool that we're freeing from + const auto pool_index{static_cast(pool)}; + std::lock_guard lock{pool_locks[pool_index]}; + + // TODO (bunnei): Support multiple managers + Impl& chosen_manager{managers[pool_index]}; + + // Free all of the pages + for (const auto& it : page_list.Nodes()) { + const auto min_num_pages{std::min( + it.GetNumPages(), (chosen_manager.GetEndAddress() - it.GetAddress()) / PageSize)}; + chosen_manager.Free(it.GetAddress(), min_num_pages); + } + + return RESULT_SUCCESS; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_memory_manager.h b/src/core/hle/kernel/k_memory_manager.h new file mode 100644 index 000000000..377f642d8 --- /dev/null +++ b/src/core/hle/kernel/k_memory_manager.h @@ -0,0 +1,121 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "core/hle/kernel/memory/page_heap.h" +#include "core/hle/result.h" + +namespace Kernel { +class KPageLinkedList; +} + +namespace Kernel { + +class KMemoryManager final : NonCopyable { +public: + enum class Pool : u32 { + Application = 0, + Applet = 1, + System = 2, + SystemNonSecure = 3, + + Count, + + Shift = 4, + Mask = (0xF << Shift), + }; + + enum class Direction : u32 { + FromFront = 0, + FromBack = 1, + + Shift = 0, + Mask = (0xF << Shift), + }; + + KMemoryManager() = default; + + constexpr std::size_t GetSize(Pool pool) const { + return managers[static_cast(pool)].GetSize(); + } + + void InitializeManager(Pool pool, u64 start_address, u64 end_address); + + VAddr AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option); + ResultCode Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, + Direction dir = Direction::FromFront); + ResultCode Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, + Direction dir = Direction::FromFront); + + static constexpr std::size_t MaxManagerCount = 10; + +public: + static constexpr u32 EncodeOption(Pool pool, Direction dir) { + return (static_cast(pool) << static_cast(Pool::Shift)) | + (static_cast(dir) << static_cast(Direction::Shift)); + } + + static constexpr Pool GetPool(u32 option) { + return static_cast((static_cast(option) & static_cast(Pool::Mask)) >> + static_cast(Pool::Shift)); + } + + static constexpr Direction GetDirection(u32 option) { + return static_cast( + (static_cast(option) & static_cast(Direction::Mask)) >> + static_cast(Direction::Shift)); + } + + static constexpr std::tuple DecodeOption(u32 option) { + return std::make_tuple(GetPool(option), GetDirection(option)); + } + +private: + class Impl final : NonCopyable { + private: + using RefCount = u16; + + private: + Memory::PageHeap heap; + Pool pool{}; + + public: + Impl() = default; + + std::size_t Initialize(Pool new_pool, u64 start_address, u64 end_address); + + VAddr AllocateBlock(s32 index, bool random) { + return heap.AllocateBlock(index, random); + } + + void Free(VAddr addr, std::size_t num_pages) { + heap.Free(addr, num_pages); + } + + constexpr std::size_t GetSize() const { + return heap.GetSize(); + } + + constexpr VAddr GetAddress() const { + return heap.GetAddress(); + } + + constexpr VAddr GetEndAddress() const { + return heap.GetEndAddress(); + } + }; + +private: + std::array(Pool::Count)> pool_locks; + std::array managers; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index eab73c46c..453695545 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -28,13 +28,13 @@ #include "core/hle/kernel/client_port.h" #include "core/hle/kernel/handle_table.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_scheduler.h" #include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_slab_heap.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/memory/memory_manager.h" #include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/service_thread.h" @@ -277,14 +277,14 @@ struct KernelCore::Impl { constexpr PAddr time_addr{layout.System().StartAddress() + hid_size + font_size + irs_size}; // Initialize memory manager - memory_manager = std::make_unique(); - memory_manager->InitializeManager(Memory::MemoryManager::Pool::Application, + memory_manager = std::make_unique(); + memory_manager->InitializeManager(KMemoryManager::Pool::Application, layout.Application().StartAddress(), layout.Application().EndAddress()); - memory_manager->InitializeManager(Memory::MemoryManager::Pool::Applet, + memory_manager->InitializeManager(KMemoryManager::Pool::Applet, layout.Applet().StartAddress(), layout.Applet().EndAddress()); - memory_manager->InitializeManager(Memory::MemoryManager::Pool::System, + memory_manager->InitializeManager(KMemoryManager::Pool::System, layout.System().StartAddress(), layout.System().EndAddress()); @@ -348,7 +348,7 @@ struct KernelCore::Impl { std::atomic next_host_thread_id{Core::Hardware::NUM_CPU_CORES}; // Kernel memory management - std::unique_ptr memory_manager; + std::unique_ptr memory_manager; std::unique_ptr> user_slab_heap_pages; // Shared memory for services @@ -573,11 +573,11 @@ KThread* KernelCore::GetCurrentEmuThread() const { return impl->GetCurrentEmuThread(); } -Memory::MemoryManager& KernelCore::MemoryManager() { +KMemoryManager& KernelCore::MemoryManager() { return *impl->memory_manager; } -const Memory::MemoryManager& KernelCore::MemoryManager() const { +const KMemoryManager& KernelCore::MemoryManager() const { return *impl->memory_manager; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 498f94417..56906f2da 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -27,22 +27,18 @@ struct EventType; namespace Kernel { -namespace Memory { -class MemoryManager; - -} // namespace Memory - class ClientPort; class GlobalSchedulerContext; class HandleTable; -class PhysicalCore; -class Process; +class KMemoryManager; class KResourceLimit; class KScheduler; class KSharedMemory; +class KThread; +class PhysicalCore; +class Process; class ServiceThread; class Synchronization; -class KThread; class TimeManager; template @@ -180,10 +176,10 @@ public: void RegisterHostThread(); /// Gets the virtual memory manager for the kernel. - Memory::MemoryManager& MemoryManager(); + KMemoryManager& MemoryManager(); /// Gets the virtual memory manager for the kernel. - const Memory::MemoryManager& MemoryManager() const; + const KMemoryManager& MemoryManager() const; /// Gets the slab heap allocated for user space pages. KSlabHeap& GetUserSlabHeapPages(); diff --git a/src/core/hle/kernel/memory/memory_manager.cpp b/src/core/hle/kernel/memory/memory_manager.cpp deleted file mode 100644 index 00d5b15f3..000000000 --- a/src/core/hle/kernel/memory/memory_manager.cpp +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include - -#include "common/alignment.h" -#include "common/assert.h" -#include "common/common_types.h" -#include "common/scope_exit.h" -#include "core/hle/kernel/k_page_linked_list.h" -#include "core/hle/kernel/memory/memory_manager.h" -#include "core/hle/kernel/svc_results.h" - -namespace Kernel::Memory { - -std::size_t MemoryManager::Impl::Initialize(Pool new_pool, u64 start_address, u64 end_address) { - const auto size{end_address - start_address}; - - // Calculate metadata sizes - const auto ref_count_size{(size / PageSize) * sizeof(u16)}; - const auto optimize_map_size{(Common::AlignUp((size / PageSize), 64) / 64) * sizeof(u64)}; - const auto manager_size{Common::AlignUp(optimize_map_size + ref_count_size, PageSize)}; - const auto page_heap_size{PageHeap::CalculateManagementOverheadSize(size)}; - const auto total_metadata_size{manager_size + page_heap_size}; - ASSERT(manager_size <= total_metadata_size); - ASSERT(Common::IsAligned(total_metadata_size, PageSize)); - - // Setup region - pool = new_pool; - - // Initialize the manager's KPageHeap - heap.Initialize(start_address, size, page_heap_size); - - // Free the memory to the heap - heap.Free(start_address, size / PageSize); - - // Update the heap's used size - heap.UpdateUsedSize(); - - return total_metadata_size; -} - -void MemoryManager::InitializeManager(Pool pool, u64 start_address, u64 end_address) { - ASSERT(pool < Pool::Count); - managers[static_cast(pool)].Initialize(pool, start_address, end_address); -} - -VAddr MemoryManager::AllocateAndOpenContinuous(std::size_t num_pages, std::size_t align_pages, - u32 option) { - // Early return if we're allocating no pages - if (num_pages == 0) { - return {}; - } - - // Lock the pool that we're allocating from - const auto [pool, dir] = DecodeOption(option); - const auto pool_index{static_cast(pool)}; - std::lock_guard lock{pool_locks[pool_index]}; - - // Choose a heap based on our page size request - const s32 heap_index{PageHeap::GetAlignedBlockIndex(num_pages, align_pages)}; - - // Loop, trying to iterate from each block - // TODO (bunnei): Support multiple managers - Impl& chosen_manager{managers[pool_index]}; - VAddr allocated_block{chosen_manager.AllocateBlock(heap_index, false)}; - - // If we failed to allocate, quit now - if (!allocated_block) { - return {}; - } - - // If we allocated more than we need, free some - const auto allocated_pages{PageHeap::GetBlockNumPages(heap_index)}; - if (allocated_pages > num_pages) { - chosen_manager.Free(allocated_block + num_pages * PageSize, allocated_pages - num_pages); - } - - return allocated_block; -} - -ResultCode MemoryManager::Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, - Direction dir) { - ASSERT(page_list.GetNumPages() == 0); - - // Early return if we're allocating no pages - if (num_pages == 0) { - return RESULT_SUCCESS; - } - - // Lock the pool that we're allocating from - const auto pool_index{static_cast(pool)}; - std::lock_guard lock{pool_locks[pool_index]}; - - // Choose a heap based on our page size request - const s32 heap_index{PageHeap::GetBlockIndex(num_pages)}; - if (heap_index < 0) { - return ResultOutOfMemory; - } - - // TODO (bunnei): Support multiple managers - Impl& chosen_manager{managers[pool_index]}; - - // Ensure that we don't leave anything un-freed - auto group_guard = detail::ScopeExit([&] { - for (const auto& it : page_list.Nodes()) { - const auto min_num_pages{std::min( - it.GetNumPages(), (chosen_manager.GetEndAddress() - it.GetAddress()) / PageSize)}; - chosen_manager.Free(it.GetAddress(), min_num_pages); - } - }); - - // Keep allocating until we've allocated all our pages - for (s32 index{heap_index}; index >= 0 && num_pages > 0; index--) { - const auto pages_per_alloc{PageHeap::GetBlockNumPages(index)}; - - while (num_pages >= pages_per_alloc) { - // Allocate a block - VAddr allocated_block{chosen_manager.AllocateBlock(index, false)}; - if (!allocated_block) { - break; - } - - // Safely add it to our group - { - auto block_guard = detail::ScopeExit( - [&] { chosen_manager.Free(allocated_block, pages_per_alloc); }); - - if (const ResultCode result{page_list.AddBlock(allocated_block, pages_per_alloc)}; - result.IsError()) { - return result; - } - - block_guard.Cancel(); - } - - num_pages -= pages_per_alloc; - } - } - - // Only succeed if we allocated as many pages as we wanted - if (num_pages) { - return ResultOutOfMemory; - } - - // We succeeded! - group_guard.Cancel(); - return RESULT_SUCCESS; -} - -ResultCode MemoryManager::Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, - Direction dir) { - // Early return if we're freeing no pages - if (!num_pages) { - return RESULT_SUCCESS; - } - - // Lock the pool that we're freeing from - const auto pool_index{static_cast(pool)}; - std::lock_guard lock{pool_locks[pool_index]}; - - // TODO (bunnei): Support multiple managers - Impl& chosen_manager{managers[pool_index]}; - - // Free all of the pages - for (const auto& it : page_list.Nodes()) { - const auto min_num_pages{std::min( - it.GetNumPages(), (chosen_manager.GetEndAddress() - it.GetAddress()) / PageSize)}; - chosen_manager.Free(it.GetAddress(), min_num_pages); - } - - return RESULT_SUCCESS; -} - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/memory_manager.h b/src/core/hle/kernel/memory/memory_manager.h deleted file mode 100644 index d090979bd..000000000 --- a/src/core/hle/kernel/memory/memory_manager.h +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include - -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "core/hle/kernel/memory/page_heap.h" -#include "core/hle/result.h" - -namespace Kernel { -class KPageLinkedList; -} - -namespace Kernel::Memory { - -class MemoryManager final : NonCopyable { -public: - enum class Pool : u32 { - Application = 0, - Applet = 1, - System = 2, - SystemNonSecure = 3, - - Count, - - Shift = 4, - Mask = (0xF << Shift), - }; - - enum class Direction : u32 { - FromFront = 0, - FromBack = 1, - - Shift = 0, - Mask = (0xF << Shift), - }; - - MemoryManager() = default; - - constexpr std::size_t GetSize(Pool pool) const { - return managers[static_cast(pool)].GetSize(); - } - - void InitializeManager(Pool pool, u64 start_address, u64 end_address); - - VAddr AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option); - ResultCode Allocate(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, - Direction dir = Direction::FromFront); - ResultCode Free(KPageLinkedList& page_list, std::size_t num_pages, Pool pool, - Direction dir = Direction::FromFront); - - static constexpr std::size_t MaxManagerCount = 10; - -public: - static constexpr u32 EncodeOption(Pool pool, Direction dir) { - return (static_cast(pool) << static_cast(Pool::Shift)) | - (static_cast(dir) << static_cast(Direction::Shift)); - } - - static constexpr Pool GetPool(u32 option) { - return static_cast((static_cast(option) & static_cast(Pool::Mask)) >> - static_cast(Pool::Shift)); - } - - static constexpr Direction GetDirection(u32 option) { - return static_cast( - (static_cast(option) & static_cast(Direction::Mask)) >> - static_cast(Direction::Shift)); - } - - static constexpr std::tuple DecodeOption(u32 option) { - return std::make_tuple(GetPool(option), GetDirection(option)); - } - -private: - class Impl final : NonCopyable { - private: - using RefCount = u16; - - private: - PageHeap heap; - Pool pool{}; - - public: - Impl() = default; - - std::size_t Initialize(Pool new_pool, u64 start_address, u64 end_address); - - VAddr AllocateBlock(s32 index, bool random) { - return heap.AllocateBlock(index, random); - } - - void Free(VAddr addr, std::size_t num_pages) { - heap.Free(addr, num_pages); - } - - constexpr std::size_t GetSize() const { - return heap.GetSize(); - } - - constexpr VAddr GetAddress() const { - return heap.GetAddress(); - } - - constexpr VAddr GetEndAddress() const { - return heap.GetEndAddress(); - } - }; - -private: - std::array(Pool::Count)> pool_locks; - std::array managers; -}; - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/page_table.cpp b/src/core/hle/kernel/memory/page_table.cpp index c1efc23de..ef9d97413 100644 --- a/src/core/hle/kernel/memory/page_table.cpp +++ b/src/core/hle/kernel/memory/page_table.cpp @@ -62,7 +62,7 @@ PageTable::PageTable(Core::System& system) : system{system} {} ResultCode PageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr, VAddr code_addr, std::size_t code_size, - Memory::MemoryManager::Pool pool) { + KMemoryManager::Pool pool) { const auto GetSpaceStart = [this](KAddressSpaceInfo::Type type) { return KAddressSpaceInfo::GetAddressSpaceStart(address_space_width, type); diff --git a/src/core/hle/kernel/memory/page_table.h b/src/core/hle/kernel/memory/page_table.h index 736583b81..a9e850e01 100644 --- a/src/core/hle/kernel/memory/page_table.h +++ b/src/core/hle/kernel/memory/page_table.h @@ -11,7 +11,7 @@ #include "common/page_table.h" #include "core/file_sys/program_metadata.h" #include "core/hle/kernel/k_memory_block.h" -#include "core/hle/kernel/memory/memory_manager.h" +#include "core/hle/kernel/k_memory_manager.h" #include "core/hle/result.h" namespace Core { @@ -30,7 +30,7 @@ public: ResultCode InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr, VAddr code_addr, std::size_t code_size, - Memory::MemoryManager::Pool pool); + KMemoryManager::Pool pool); ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, KMemoryState state, KMemoryPermission perm); ResultCode MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); @@ -271,7 +271,7 @@ private: bool is_kernel{}; bool is_aslr_enabled{}; - MemoryManager::Pool memory_pool{MemoryManager::Pool::Application}; + KMemoryManager::Pool memory_pool{KMemoryManager::Pool::Application}; Common::PageTable page_table_impl; diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index f83977a8e..e0359eb3c 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -274,7 +274,7 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, // Set initial resource limits resource_limit->SetLimitValue( LimitableResource::PhysicalMemory, - kernel.MemoryManager().GetSize(Memory::MemoryManager::Pool::Application)); + kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application)); KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory, code_size + system_resource_size); if (!memory_reservation.Succeeded()) { @@ -285,7 +285,7 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, // Initialize proces address space if (const ResultCode result{ page_table->InitializeForProcess(metadata.GetAddressSpaceType(), false, 0x8000000, - code_size, Memory::MemoryManager::Pool::Application)}; + code_size, KMemoryManager::Pool::Application)}; result.IsError()) { return result; } @@ -323,6 +323,11 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, 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); -- cgit v1.2.3 From 93e20867b0ab2e737e231a9b5bb29d40947fb311 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 12 Feb 2021 17:58:31 -0800 Subject: hle: kernel: Migrate PageHeap/PageTable to KPageHeap/KPageTable. --- src/core/CMakeLists.txt | 8 +- src/core/hle/kernel/k_memory_manager.cpp | 10 +- src/core/hle/kernel/k_memory_manager.h | 8 +- src/core/hle/kernel/k_page_heap.cpp | 116 +++ src/core/hle/kernel/k_page_heap.h | 193 ++++ src/core/hle/kernel/k_page_table.cpp | 1190 +++++++++++++++++++++++ src/core/hle/kernel/k_page_table.h | 279 ++++++ src/core/hle/kernel/k_shared_memory.cpp | 5 +- src/core/hle/kernel/memory/page_heap.cpp | 119 --- src/core/hle/kernel/memory/page_heap.h | 196 ---- src/core/hle/kernel/memory/page_table.cpp | 1189 ---------------------- src/core/hle/kernel/memory/page_table.h | 281 ------ src/core/hle/kernel/process.cpp | 8 +- src/core/hle/kernel/process.h | 11 +- src/core/hle/kernel/process_capability.cpp | 14 +- src/core/hle/kernel/process_capability.h | 16 +- src/core/hle/kernel/svc.cpp | 6 +- src/core/hle/kernel/transfer_memory.cpp | 2 +- src/core/hle/service/ldr/ldr.cpp | 7 +- src/core/loader/deconstructed_rom_directory.cpp | 2 +- src/core/loader/elf.cpp | 2 +- src/core/loader/kip.cpp | 2 +- src/core/loader/nro.cpp | 2 +- src/core/loader/nso.cpp | 2 +- src/core/memory.cpp | 2 +- src/core/memory/cheat_engine.cpp | 2 +- src/core/reporter.cpp | 2 +- src/video_core/memory_manager.cpp | 2 +- 28 files changed, 1830 insertions(+), 1846 deletions(-) create mode 100644 src/core/hle/kernel/k_page_heap.cpp create mode 100644 src/core/hle/kernel/k_page_heap.h create mode 100644 src/core/hle/kernel/k_page_table.cpp create mode 100644 src/core/hle/kernel/k_page_table.h delete mode 100644 src/core/hle/kernel/memory/page_heap.cpp delete mode 100644 src/core/hle/kernel/memory/page_heap.h delete mode 100644 src/core/hle/kernel/memory/page_table.cpp delete mode 100644 src/core/hle/kernel/memory/page_table.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 2976187c0..17f251c37 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -173,7 +173,11 @@ add_library(core STATIC hle/kernel/k_memory_manager.cpp hle/kernel/k_memory_manager.h hle/kernel/k_page_bitmap.h + hle/kernel/k_page_heap.cpp + hle/kernel/k_page_heap.h hle/kernel/k_page_linked_list.h + hle/kernel/k_page_table.cpp + hle/kernel/k_page_table.h hle/kernel/k_priority_queue.h hle/kernel/k_readable_event.cpp hle/kernel/k_readable_event.h @@ -202,10 +206,6 @@ add_library(core STATIC hle/kernel/kernel.cpp hle/kernel/kernel.h hle/kernel/memory_types.h - hle/kernel/memory/page_heap.cpp - hle/kernel/memory/page_heap.h - hle/kernel/memory/page_table.cpp - hle/kernel/memory/page_table.h hle/kernel/object.cpp hle/kernel/object.h hle/kernel/physical_core.cpp diff --git a/src/core/hle/kernel/k_memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp index 5ea11a918..9027602bf 100644 --- a/src/core/hle/kernel/k_memory_manager.cpp +++ b/src/core/hle/kernel/k_memory_manager.cpp @@ -21,7 +21,7 @@ std::size_t KMemoryManager::Impl::Initialize(Pool new_pool, u64 start_address, u const auto ref_count_size{(size / PageSize) * sizeof(u16)}; const auto optimize_map_size{(Common::AlignUp((size / PageSize), 64) / 64) * sizeof(u64)}; const auto manager_size{Common::AlignUp(optimize_map_size + ref_count_size, PageSize)}; - const auto page_heap_size{Memory::PageHeap::CalculateManagementOverheadSize(size)}; + const auto page_heap_size{KPageHeap::CalculateManagementOverheadSize(size)}; const auto total_metadata_size{manager_size + page_heap_size}; ASSERT(manager_size <= total_metadata_size); ASSERT(Common::IsAligned(total_metadata_size, PageSize)); @@ -59,7 +59,7 @@ VAddr KMemoryManager::AllocateAndOpenContinuous(std::size_t num_pages, std::size std::lock_guard lock{pool_locks[pool_index]}; // Choose a heap based on our page size request - const s32 heap_index{Memory::PageHeap::GetAlignedBlockIndex(num_pages, align_pages)}; + const s32 heap_index{KPageHeap::GetAlignedBlockIndex(num_pages, align_pages)}; // Loop, trying to iterate from each block // TODO (bunnei): Support multiple managers @@ -72,7 +72,7 @@ VAddr KMemoryManager::AllocateAndOpenContinuous(std::size_t num_pages, std::size } // If we allocated more than we need, free some - const auto allocated_pages{Memory::PageHeap::GetBlockNumPages(heap_index)}; + const auto allocated_pages{KPageHeap::GetBlockNumPages(heap_index)}; if (allocated_pages > num_pages) { chosen_manager.Free(allocated_block + num_pages * PageSize, allocated_pages - num_pages); } @@ -94,7 +94,7 @@ ResultCode KMemoryManager::Allocate(KPageLinkedList& page_list, std::size_t num_ std::lock_guard lock{pool_locks[pool_index]}; // Choose a heap based on our page size request - const s32 heap_index{Memory::PageHeap::GetBlockIndex(num_pages)}; + const s32 heap_index{KPageHeap::GetBlockIndex(num_pages)}; if (heap_index < 0) { return ResultOutOfMemory; } @@ -113,7 +113,7 @@ ResultCode KMemoryManager::Allocate(KPageLinkedList& page_list, std::size_t num_ // Keep allocating until we've allocated all our pages for (s32 index{heap_index}; index >= 0 && num_pages > 0; index--) { - const auto pages_per_alloc{Memory::PageHeap::GetBlockNumPages(index)}; + const auto pages_per_alloc{KPageHeap::GetBlockNumPages(index)}; while (num_pages >= pages_per_alloc) { // Allocate a block diff --git a/src/core/hle/kernel/k_memory_manager.h b/src/core/hle/kernel/k_memory_manager.h index 377f642d8..ae9f683b8 100644 --- a/src/core/hle/kernel/k_memory_manager.h +++ b/src/core/hle/kernel/k_memory_manager.h @@ -10,14 +10,12 @@ #include "common/common_funcs.h" #include "common/common_types.h" -#include "core/hle/kernel/memory/page_heap.h" +#include "core/hle/kernel/k_page_heap.h" #include "core/hle/result.h" namespace Kernel { -class KPageLinkedList; -} -namespace Kernel { +class KPageLinkedList; class KMemoryManager final : NonCopyable { public: @@ -84,7 +82,7 @@ private: using RefCount = u16; private: - Memory::PageHeap heap; + KPageHeap heap; Pool pool{}; public: diff --git a/src/core/hle/kernel/k_page_heap.cpp b/src/core/hle/kernel/k_page_heap.cpp new file mode 100644 index 000000000..07e062922 --- /dev/null +++ b/src/core/hle/kernel/k_page_heap.cpp @@ -0,0 +1,116 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/core.h" +#include "core/hle/kernel/k_page_heap.h" +#include "core/memory.h" + +namespace Kernel { + +void KPageHeap::Initialize(VAddr address, std::size_t size, std::size_t metadata_size) { + // Check our assumptions + ASSERT(Common::IsAligned((address), PageSize)); + ASSERT(Common::IsAligned(size, PageSize)); + + // Set our members + heap_address = address; + heap_size = size; + + // Setup bitmaps + metadata.resize(metadata_size / sizeof(u64)); + u64* cur_bitmap_storage{metadata.data()}; + for (std::size_t i = 0; i < MemoryBlockPageShifts.size(); i++) { + const std::size_t cur_block_shift{MemoryBlockPageShifts[i]}; + const std::size_t next_block_shift{ + (i != MemoryBlockPageShifts.size() - 1) ? MemoryBlockPageShifts[i + 1] : 0}; + cur_bitmap_storage = blocks[i].Initialize(heap_address, heap_size, cur_block_shift, + next_block_shift, cur_bitmap_storage); + } +} + +VAddr KPageHeap::AllocateBlock(s32 index, bool random) { + const std::size_t needed_size{blocks[index].GetSize()}; + + for (s32 i{index}; i < static_cast(MemoryBlockPageShifts.size()); i++) { + if (const VAddr addr{blocks[i].PopBlock(random)}; addr) { + if (const std::size_t allocated_size{blocks[i].GetSize()}; + allocated_size > needed_size) { + Free(addr + needed_size, (allocated_size - needed_size) / PageSize); + } + return addr; + } + } + + return 0; +} + +void KPageHeap::FreeBlock(VAddr block, s32 index) { + do { + block = blocks[index++].PushBlock(block); + } while (block != 0); +} + +void KPageHeap::Free(VAddr addr, std::size_t num_pages) { + // Freeing no pages is a no-op + if (num_pages == 0) { + return; + } + + // Find the largest block size that we can free, and free as many as possible + s32 big_index{static_cast(MemoryBlockPageShifts.size()) - 1}; + const VAddr start{addr}; + const VAddr end{(num_pages * PageSize) + addr}; + VAddr before_start{start}; + VAddr before_end{start}; + VAddr after_start{end}; + VAddr after_end{end}; + while (big_index >= 0) { + const std::size_t block_size{blocks[big_index].GetSize()}; + const VAddr big_start{Common::AlignUp((start), block_size)}; + const VAddr big_end{Common::AlignDown((end), block_size)}; + if (big_start < big_end) { + // Free as many big blocks as we can + for (auto block{big_start}; block < big_end; block += block_size) { + FreeBlock(block, big_index); + } + before_end = big_start; + after_start = big_end; + break; + } + big_index--; + } + ASSERT(big_index >= 0); + + // Free space before the big blocks + for (s32 i{big_index - 1}; i >= 0; i--) { + const std::size_t block_size{blocks[i].GetSize()}; + while (before_start + block_size <= before_end) { + before_end -= block_size; + FreeBlock(before_end, i); + } + } + + // Free space after the big blocks + for (s32 i{big_index - 1}; i >= 0; i--) { + const std::size_t block_size{blocks[i].GetSize()}; + while (after_start + block_size <= after_end) { + FreeBlock(after_start, i); + after_start += block_size; + } + } +} + +std::size_t KPageHeap::CalculateManagementOverheadSize(std::size_t region_size) { + std::size_t overhead_size = 0; + for (std::size_t i = 0; i < MemoryBlockPageShifts.size(); i++) { + const std::size_t cur_block_shift{MemoryBlockPageShifts[i]}; + const std::size_t next_block_shift{ + (i != MemoryBlockPageShifts.size() - 1) ? MemoryBlockPageShifts[i + 1] : 0}; + overhead_size += KPageHeap::Block::CalculateManagementOverheadSize( + region_size, cur_block_shift, next_block_shift); + } + return Common::AlignUp(overhead_size, PageSize); +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_page_heap.h b/src/core/hle/kernel/k_page_heap.h new file mode 100644 index 000000000..de5d6a189 --- /dev/null +++ b/src/core/hle/kernel/k_page_heap.h @@ -0,0 +1,193 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +#include "common/alignment.h" +#include "common/assert.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "core/hle/kernel/k_page_bitmap.h" +#include "core/hle/kernel/memory_types.h" + +namespace Kernel { + +class KPageHeap final : NonCopyable { +public: + static constexpr s32 GetAlignedBlockIndex(std::size_t num_pages, std::size_t align_pages) { + const auto target_pages{std::max(num_pages, align_pages)}; + for (std::size_t i = 0; i < NumMemoryBlockPageShifts; i++) { + if (target_pages <= + (static_cast(1) << MemoryBlockPageShifts[i]) / PageSize) { + return static_cast(i); + } + } + return -1; + } + + static constexpr s32 GetBlockIndex(std::size_t num_pages) { + for (s32 i{static_cast(NumMemoryBlockPageShifts) - 1}; i >= 0; i--) { + if (num_pages >= (static_cast(1) << MemoryBlockPageShifts[i]) / PageSize) { + return i; + } + } + return -1; + } + + static constexpr std::size_t GetBlockSize(std::size_t index) { + return static_cast(1) << MemoryBlockPageShifts[index]; + } + + static constexpr std::size_t GetBlockNumPages(std::size_t index) { + return GetBlockSize(index) / PageSize; + } + +private: + static constexpr std::size_t NumMemoryBlockPageShifts{7}; + static constexpr std::array MemoryBlockPageShifts{ + 0xC, 0x10, 0x15, 0x16, 0x19, 0x1D, 0x1E, + }; + + class Block final : NonCopyable { + private: + KPageBitmap bitmap; + VAddr heap_address{}; + uintptr_t end_offset{}; + std::size_t block_shift{}; + std::size_t next_block_shift{}; + + public: + Block() = default; + + constexpr std::size_t GetShift() const { + return block_shift; + } + constexpr std::size_t GetNextShift() const { + return next_block_shift; + } + constexpr std::size_t GetSize() const { + return static_cast(1) << GetShift(); + } + constexpr std::size_t GetNumPages() const { + return GetSize() / PageSize; + } + constexpr std::size_t GetNumFreeBlocks() const { + return bitmap.GetNumBits(); + } + constexpr std::size_t GetNumFreePages() const { + return GetNumFreeBlocks() * GetNumPages(); + } + + u64* Initialize(VAddr addr, std::size_t size, std::size_t bs, std::size_t nbs, + u64* bit_storage) { + // Set shifts + block_shift = bs; + next_block_shift = nbs; + + // Align up the address + VAddr end{addr + size}; + const auto align{(next_block_shift != 0) ? (1ULL << next_block_shift) + : (1ULL << block_shift)}; + addr = Common::AlignDown((addr), align); + end = Common::AlignUp((end), align); + + heap_address = addr; + end_offset = (end - addr) / (1ULL << block_shift); + return bitmap.Initialize(bit_storage, end_offset); + } + + VAddr PushBlock(VAddr address) { + // Set the bit for the free block + std::size_t offset{(address - heap_address) >> GetShift()}; + bitmap.SetBit(offset); + + // If we have a next shift, try to clear the blocks below and return the address + if (GetNextShift()) { + const auto diff{1ULL << (GetNextShift() - GetShift())}; + offset = Common::AlignDown(offset, diff); + if (bitmap.ClearRange(offset, diff)) { + return heap_address + (offset << GetShift()); + } + } + + // We couldn't coalesce, or we're already as big as possible + return 0; + } + + VAddr PopBlock(bool random) { + // Find a free block + const s64 soffset{bitmap.FindFreeBlock(random)}; + if (soffset < 0) { + return 0; + } + const auto offset{static_cast(soffset)}; + + // Update our tracking and return it + bitmap.ClearBit(offset); + return heap_address + (offset << GetShift()); + } + + public: + static constexpr std::size_t CalculateManagementOverheadSize(std::size_t region_size, + std::size_t cur_block_shift, + std::size_t next_block_shift) { + const auto cur_block_size{(1ULL << cur_block_shift)}; + const auto next_block_size{(1ULL << next_block_shift)}; + const auto align{(next_block_shift != 0) ? next_block_size : cur_block_size}; + return KPageBitmap::CalculateManagementOverheadSize( + (align * 2 + Common::AlignUp(region_size, align)) / cur_block_size); + } + }; + +public: + KPageHeap() = default; + + constexpr VAddr GetAddress() const { + return heap_address; + } + constexpr std::size_t GetSize() const { + return heap_size; + } + constexpr VAddr GetEndAddress() const { + return GetAddress() + GetSize(); + } + constexpr std::size_t GetPageOffset(VAddr block) const { + return (block - GetAddress()) / PageSize; + } + + void Initialize(VAddr heap_address, std::size_t heap_size, std::size_t metadata_size); + VAddr AllocateBlock(s32 index, bool random); + void Free(VAddr addr, std::size_t num_pages); + + void UpdateUsedSize() { + used_size = heap_size - (GetNumFreePages() * PageSize); + } + + static std::size_t CalculateManagementOverheadSize(std::size_t region_size); + +private: + constexpr std::size_t GetNumFreePages() const { + std::size_t num_free{}; + + for (const auto& block : blocks) { + num_free += block.GetNumFreePages(); + } + + return num_free; + } + + void FreeBlock(VAddr block, s32 index); + + VAddr heap_address{}; + std::size_t heap_size{}; + std::size_t used_size{}; + std::array blocks{}; + std::vector metadata; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp new file mode 100644 index 000000000..d09d5ce48 --- /dev/null +++ b/src/core/hle/kernel/k_page_table.cpp @@ -0,0 +1,1190 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/alignment.h" +#include "common/assert.h" +#include "common/scope_exit.h" +#include "core/core.h" +#include "core/hle/kernel/k_address_space_info.h" +#include "core/hle/kernel/k_memory_block.h" +#include "core/hle/kernel/k_memory_block_manager.h" +#include "core/hle/kernel/k_page_linked_list.h" +#include "core/hle/kernel/k_page_table.h" +#include "core/hle/kernel/k_resource_limit.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_system_control.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/process.h" +#include "core/hle/kernel/svc_results.h" +#include "core/memory.h" + +namespace Kernel { + +namespace { + +constexpr std::size_t GetAddressSpaceWidthFromType(FileSys::ProgramAddressSpaceType as_type) { + switch (as_type) { + case FileSys::ProgramAddressSpaceType::Is32Bit: + case FileSys::ProgramAddressSpaceType::Is32BitNoMap: + return 32; + case FileSys::ProgramAddressSpaceType::Is36Bit: + return 36; + case FileSys::ProgramAddressSpaceType::Is39Bit: + return 39; + default: + UNREACHABLE(); + return {}; + } +} + +constexpr u64 GetAddressInRange(const KMemoryInfo& info, VAddr addr) { + if (info.GetAddress() < addr) { + return addr; + } + return info.GetAddress(); +} + +constexpr std::size_t GetSizeInRange(const KMemoryInfo& info, VAddr start, VAddr end) { + std::size_t size{info.GetSize()}; + if (info.GetAddress() < start) { + size -= start - info.GetAddress(); + } + if (info.GetEndAddress() > end) { + size -= info.GetEndAddress() - end; + } + return size; +} + +} // namespace + +KPageTable::KPageTable(Core::System& system) : system{system} {} + +ResultCode KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, + bool enable_aslr, VAddr code_addr, + std::size_t code_size, KMemoryManager::Pool pool) { + + const auto GetSpaceStart = [this](KAddressSpaceInfo::Type type) { + return KAddressSpaceInfo::GetAddressSpaceStart(address_space_width, type); + }; + const auto GetSpaceSize = [this](KAddressSpaceInfo::Type type) { + return KAddressSpaceInfo::GetAddressSpaceSize(address_space_width, type); + }; + + // Set our width and heap/alias sizes + address_space_width = GetAddressSpaceWidthFromType(as_type); + const VAddr start = 0; + const VAddr end{1ULL << address_space_width}; + std::size_t alias_region_size{GetSpaceSize(KAddressSpaceInfo::Type::Alias)}; + std::size_t heap_region_size{GetSpaceSize(KAddressSpaceInfo::Type::Heap)}; + + ASSERT(start <= code_addr); + ASSERT(code_addr < code_addr + code_size); + ASSERT(code_addr + code_size - 1 <= end - 1); + + // Adjust heap/alias size if we don't have an alias region + if (as_type == FileSys::ProgramAddressSpaceType::Is32BitNoMap) { + heap_region_size += alias_region_size; + alias_region_size = 0; + } + + // Set code regions and determine remaining + constexpr std::size_t RegionAlignment{2 * 1024 * 1024}; + VAddr process_code_start{}; + VAddr process_code_end{}; + std::size_t stack_region_size{}; + std::size_t kernel_map_region_size{}; + + if (address_space_width == 39) { + alias_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Alias); + heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Heap); + stack_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Stack); + kernel_map_region_size = GetSpaceSize(KAddressSpaceInfo::Type::MapSmall); + code_region_start = GetSpaceStart(KAddressSpaceInfo::Type::Map39Bit); + code_region_end = code_region_start + GetSpaceSize(KAddressSpaceInfo::Type::Map39Bit); + alias_code_region_start = code_region_start; + alias_code_region_end = code_region_end; + process_code_start = Common::AlignDown(code_addr, RegionAlignment); + process_code_end = Common::AlignUp(code_addr + code_size, RegionAlignment); + } else { + stack_region_size = 0; + kernel_map_region_size = 0; + code_region_start = GetSpaceStart(KAddressSpaceInfo::Type::MapSmall); + code_region_end = code_region_start + GetSpaceSize(KAddressSpaceInfo::Type::MapSmall); + stack_region_start = code_region_start; + alias_code_region_start = code_region_start; + alias_code_region_end = GetSpaceStart(KAddressSpaceInfo::Type::MapLarge) + + GetSpaceSize(KAddressSpaceInfo::Type::MapLarge); + stack_region_end = code_region_end; + kernel_map_region_start = code_region_start; + kernel_map_region_end = code_region_end; + process_code_start = code_region_start; + process_code_end = code_region_end; + } + + // Set other basic fields + is_aslr_enabled = enable_aslr; + address_space_start = start; + address_space_end = end; + is_kernel = false; + + // Determine the region we can place our undetermineds in + VAddr alloc_start{}; + std::size_t alloc_size{}; + if ((process_code_start - code_region_start) >= (end - process_code_end)) { + alloc_start = code_region_start; + alloc_size = process_code_start - code_region_start; + } else { + alloc_start = process_code_end; + alloc_size = end - process_code_end; + } + const std::size_t needed_size{ + (alias_region_size + heap_region_size + stack_region_size + kernel_map_region_size)}; + if (alloc_size < needed_size) { + UNREACHABLE(); + return ResultOutOfMemory; + } + + const std::size_t remaining_size{alloc_size - needed_size}; + + // Determine random placements for each region + std::size_t alias_rnd{}, heap_rnd{}, stack_rnd{}, kmap_rnd{}; + if (enable_aslr) { + alias_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * + RegionAlignment; + heap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * + RegionAlignment; + stack_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * + RegionAlignment; + kmap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * + RegionAlignment; + } + + // Setup heap and alias regions + alias_region_start = alloc_start + alias_rnd; + alias_region_end = alias_region_start + alias_region_size; + heap_region_start = alloc_start + heap_rnd; + heap_region_end = heap_region_start + heap_region_size; + + if (alias_rnd <= heap_rnd) { + heap_region_start += alias_region_size; + heap_region_end += alias_region_size; + } else { + alias_region_start += heap_region_size; + alias_region_end += heap_region_size; + } + + // Setup stack region + if (stack_region_size) { + stack_region_start = alloc_start + stack_rnd; + stack_region_end = stack_region_start + stack_region_size; + + if (alias_rnd < stack_rnd) { + stack_region_start += alias_region_size; + stack_region_end += alias_region_size; + } else { + alias_region_start += stack_region_size; + alias_region_end += stack_region_size; + } + + if (heap_rnd < stack_rnd) { + stack_region_start += heap_region_size; + stack_region_end += heap_region_size; + } else { + heap_region_start += stack_region_size; + heap_region_end += stack_region_size; + } + } + + // Setup kernel map region + if (kernel_map_region_size) { + kernel_map_region_start = alloc_start + kmap_rnd; + kernel_map_region_end = kernel_map_region_start + kernel_map_region_size; + + if (alias_rnd < kmap_rnd) { + kernel_map_region_start += alias_region_size; + kernel_map_region_end += alias_region_size; + } else { + alias_region_start += kernel_map_region_size; + alias_region_end += kernel_map_region_size; + } + + if (heap_rnd < kmap_rnd) { + kernel_map_region_start += heap_region_size; + kernel_map_region_end += heap_region_size; + } else { + heap_region_start += kernel_map_region_size; + heap_region_end += kernel_map_region_size; + } + + if (stack_region_size) { + if (stack_rnd < kmap_rnd) { + kernel_map_region_start += stack_region_size; + kernel_map_region_end += stack_region_size; + } else { + stack_region_start += kernel_map_region_size; + stack_region_end += kernel_map_region_size; + } + } + } + + // Set heap members + current_heap_end = heap_region_start; + max_heap_size = 0; + max_physical_memory_size = 0; + + // Ensure that we regions inside our address space + auto IsInAddressSpace = [&](VAddr addr) { + return address_space_start <= addr && addr <= address_space_end; + }; + ASSERT(IsInAddressSpace(alias_region_start)); + ASSERT(IsInAddressSpace(alias_region_end)); + ASSERT(IsInAddressSpace(heap_region_start)); + ASSERT(IsInAddressSpace(heap_region_end)); + ASSERT(IsInAddressSpace(stack_region_start)); + ASSERT(IsInAddressSpace(stack_region_end)); + ASSERT(IsInAddressSpace(kernel_map_region_start)); + ASSERT(IsInAddressSpace(kernel_map_region_end)); + + // Ensure that we selected regions that don't overlap + const VAddr alias_start{alias_region_start}; + const VAddr alias_last{alias_region_end - 1}; + const VAddr heap_start{heap_region_start}; + const VAddr heap_last{heap_region_end - 1}; + const VAddr stack_start{stack_region_start}; + const VAddr stack_last{stack_region_end - 1}; + const VAddr kmap_start{kernel_map_region_start}; + const VAddr kmap_last{kernel_map_region_end - 1}; + ASSERT(alias_last < heap_start || heap_last < alias_start); + ASSERT(alias_last < stack_start || stack_last < alias_start); + ASSERT(alias_last < kmap_start || kmap_last < alias_start); + ASSERT(heap_last < stack_start || stack_last < heap_start); + ASSERT(heap_last < kmap_start || kmap_last < heap_start); + + current_heap_addr = heap_region_start; + heap_capacity = 0; + physical_memory_usage = 0; + memory_pool = pool; + + page_table_impl.Resize(address_space_width, PageBits); + + return InitializeMemoryLayout(start, end); +} + +ResultCode KPageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemoryState state, + KMemoryPermission perm) { + std::lock_guard lock{page_table_lock}; + + const u64 size{num_pages * PageSize}; + + if (!CanContain(addr, size, state)) { + return ResultInvalidCurrentMemory; + } + + if (IsRegionMapped(addr, size)) { + return ResultInvalidCurrentMemory; + } + + KPageLinkedList page_linked_list; + CASCADE_CODE( + system.Kernel().MemoryManager().Allocate(page_linked_list, num_pages, memory_pool)); + CASCADE_CODE(Operate(addr, num_pages, page_linked_list, OperationType::MapGroup)); + + block_manager->Update(addr, num_pages, state, perm); + + return RESULT_SUCCESS; +} + +ResultCode KPageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) { + std::lock_guard lock{page_table_lock}; + + const std::size_t num_pages{size / PageSize}; + + KMemoryState state{}; + KMemoryPermission perm{}; + CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, src_addr, size, KMemoryState::All, + KMemoryState::Normal, KMemoryPermission::Mask, + KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, + KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); + + if (IsRegionMapped(dst_addr, size)) { + return ResultInvalidCurrentMemory; + } + + KPageLinkedList page_linked_list; + AddRegionToPages(src_addr, num_pages, page_linked_list); + + { + auto block_guard = detail::ScopeExit( + [&] { Operate(src_addr, num_pages, perm, OperationType::ChangePermissions); }); + + CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::None, + OperationType::ChangePermissions)); + CASCADE_CODE(MapPages(dst_addr, page_linked_list, KMemoryPermission::None)); + + block_guard.Cancel(); + } + + block_manager->Update(src_addr, num_pages, state, KMemoryPermission::None, + KMemoryAttribute::Locked); + block_manager->Update(dst_addr, num_pages, KMemoryState::AliasCode); + + return RESULT_SUCCESS; +} + +ResultCode KPageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) { + std::lock_guard lock{page_table_lock}; + + if (!size) { + return RESULT_SUCCESS; + } + + const std::size_t num_pages{size / PageSize}; + + CASCADE_CODE(CheckMemoryState(nullptr, nullptr, nullptr, src_addr, size, KMemoryState::All, + KMemoryState::Normal, KMemoryPermission::None, + KMemoryPermission::None, KMemoryAttribute::Mask, + KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); + + KMemoryState state{}; + CASCADE_CODE(CheckMemoryState( + &state, nullptr, nullptr, dst_addr, PageSize, KMemoryState::FlagCanCodeAlias, + KMemoryState::FlagCanCodeAlias, KMemoryPermission::None, KMemoryPermission::None, + KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); + CASCADE_CODE(CheckMemoryState(dst_addr, size, KMemoryState::All, state, KMemoryPermission::None, + KMemoryPermission::None, KMemoryAttribute::Mask, + KMemoryAttribute::None)); + CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap)); + + block_manager->Update(dst_addr, num_pages, KMemoryState::Free); + block_manager->Update(src_addr, num_pages, KMemoryState::Normal, + KMemoryPermission::ReadAndWrite); + + return RESULT_SUCCESS; +} + +void KPageTable::MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end) { + auto node{page_linked_list.Nodes().begin()}; + PAddr map_addr{node->GetAddress()}; + std::size_t src_num_pages{node->GetNumPages()}; + + block_manager->IterateForRange(start, end, [&](const KMemoryInfo& info) { + if (info.state != KMemoryState::Free) { + return; + } + + std::size_t dst_num_pages{GetSizeInRange(info, start, end) / PageSize}; + VAddr dst_addr{GetAddressInRange(info, start)}; + + while (dst_num_pages) { + if (!src_num_pages) { + node = std::next(node); + map_addr = node->GetAddress(); + src_num_pages = node->GetNumPages(); + } + + const std::size_t num_pages{std::min(src_num_pages, dst_num_pages)}; + Operate(dst_addr, num_pages, KMemoryPermission::ReadAndWrite, OperationType::Map, + map_addr); + + dst_addr += num_pages * PageSize; + map_addr += num_pages * PageSize; + src_num_pages -= num_pages; + dst_num_pages -= num_pages; + } + }); +} + +ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) { + std::lock_guard lock{page_table_lock}; + + std::size_t mapped_size{}; + const VAddr end_addr{addr + size}; + + block_manager->IterateForRange(addr, end_addr, [&](const KMemoryInfo& info) { + if (info.state != KMemoryState::Free) { + mapped_size += GetSizeInRange(info, addr, end_addr); + } + }); + + if (mapped_size == size) { + return RESULT_SUCCESS; + } + + const std::size_t remaining_size{size - mapped_size}; + const std::size_t remaining_pages{remaining_size / PageSize}; + + // Reserve the memory from the process resource limit. + KScopedResourceReservation memory_reservation( + system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory, + remaining_size); + if (!memory_reservation.Succeeded()) { + LOG_ERROR(Kernel, "Could not reserve remaining {:X} bytes", remaining_size); + return ResultResourceLimitedExceeded; + } + + KPageLinkedList page_linked_list; + + CASCADE_CODE( + system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, memory_pool)); + + // We succeeded, so commit the memory reservation. + memory_reservation.Commit(); + + MapPhysicalMemory(page_linked_list, addr, end_addr); + + physical_memory_usage += remaining_size; + + const std::size_t num_pages{size / PageSize}; + block_manager->Update(addr, num_pages, KMemoryState::Free, KMemoryPermission::None, + KMemoryAttribute::None, KMemoryState::Normal, + KMemoryPermission::ReadAndWrite, KMemoryAttribute::None); + + return RESULT_SUCCESS; +} + +ResultCode KPageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) { + std::lock_guard lock{page_table_lock}; + + const VAddr end_addr{addr + size}; + ResultCode result{RESULT_SUCCESS}; + std::size_t mapped_size{}; + + // Verify that the region can be unmapped + block_manager->IterateForRange(addr, end_addr, [&](const KMemoryInfo& info) { + if (info.state == KMemoryState::Normal) { + if (info.attribute != KMemoryAttribute::None) { + result = ResultInvalidCurrentMemory; + return; + } + mapped_size += GetSizeInRange(info, addr, end_addr); + } else if (info.state != KMemoryState::Free) { + result = ResultInvalidCurrentMemory; + } + }); + + if (result.IsError()) { + return result; + } + + if (!mapped_size) { + return RESULT_SUCCESS; + } + + CASCADE_CODE(UnmapMemory(addr, size)); + + auto process{system.Kernel().CurrentProcess()}; + process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, mapped_size); + physical_memory_usage -= mapped_size; + + return RESULT_SUCCESS; +} + +ResultCode KPageTable::UnmapMemory(VAddr addr, std::size_t size) { + std::lock_guard lock{page_table_lock}; + + const VAddr end_addr{addr + size}; + ResultCode result{RESULT_SUCCESS}; + KPageLinkedList page_linked_list; + + // Unmap each region within the range + block_manager->IterateForRange(addr, end_addr, [&](const KMemoryInfo& info) { + if (info.state == KMemoryState::Normal) { + const std::size_t block_size{GetSizeInRange(info, addr, end_addr)}; + const std::size_t block_num_pages{block_size / PageSize}; + const VAddr block_addr{GetAddressInRange(info, addr)}; + + AddRegionToPages(block_addr, block_size / PageSize, page_linked_list); + + if (result = Operate(block_addr, block_num_pages, KMemoryPermission::None, + OperationType::Unmap); + result.IsError()) { + return; + } + } + }); + + if (result.IsError()) { + return result; + } + + const std::size_t num_pages{size / PageSize}; + system.Kernel().MemoryManager().Free(page_linked_list, num_pages, memory_pool); + + block_manager->Update(addr, num_pages, KMemoryState::Free); + + return RESULT_SUCCESS; +} + +ResultCode KPageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) { + std::lock_guard lock{page_table_lock}; + + KMemoryState src_state{}; + CASCADE_CODE(CheckMemoryState( + &src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, + KMemoryState::FlagCanAlias, KMemoryPermission::Mask, KMemoryPermission::ReadAndWrite, + KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); + + if (IsRegionMapped(dst_addr, size)) { + return ResultInvalidCurrentMemory; + } + + KPageLinkedList page_linked_list; + const std::size_t num_pages{size / PageSize}; + + AddRegionToPages(src_addr, num_pages, page_linked_list); + + { + auto block_guard = detail::ScopeExit([&] { + Operate(src_addr, num_pages, KMemoryPermission::ReadAndWrite, + OperationType::ChangePermissions); + }); + + CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::None, + OperationType::ChangePermissions)); + CASCADE_CODE(MapPages(dst_addr, page_linked_list, KMemoryPermission::ReadAndWrite)); + + block_guard.Cancel(); + } + + block_manager->Update(src_addr, num_pages, src_state, KMemoryPermission::None, + KMemoryAttribute::Locked); + block_manager->Update(dst_addr, num_pages, KMemoryState::Stack, + KMemoryPermission::ReadAndWrite); + + return RESULT_SUCCESS; +} + +ResultCode KPageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) { + std::lock_guard lock{page_table_lock}; + + KMemoryState src_state{}; + CASCADE_CODE(CheckMemoryState( + &src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, + KMemoryState::FlagCanAlias, KMemoryPermission::Mask, KMemoryPermission::None, + KMemoryAttribute::Mask, KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); + + KMemoryPermission dst_perm{}; + CASCADE_CODE(CheckMemoryState(nullptr, &dst_perm, nullptr, dst_addr, size, KMemoryState::All, + KMemoryState::Stack, KMemoryPermission::None, + KMemoryPermission::None, KMemoryAttribute::Mask, + KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); + + KPageLinkedList src_pages; + KPageLinkedList dst_pages; + const std::size_t num_pages{size / PageSize}; + + AddRegionToPages(src_addr, num_pages, src_pages); + AddRegionToPages(dst_addr, num_pages, dst_pages); + + if (!dst_pages.IsEqual(src_pages)) { + return ResultInvalidMemoryRange; + } + + { + auto block_guard = detail::ScopeExit([&] { MapPages(dst_addr, dst_pages, dst_perm); }); + + CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap)); + CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::ReadAndWrite, + OperationType::ChangePermissions)); + + block_guard.Cancel(); + } + + block_manager->Update(src_addr, num_pages, src_state, KMemoryPermission::ReadAndWrite); + block_manager->Update(dst_addr, num_pages, KMemoryState::Free); + + return RESULT_SUCCESS; +} + +ResultCode KPageTable::MapPages(VAddr addr, const KPageLinkedList& page_linked_list, + KMemoryPermission perm) { + VAddr cur_addr{addr}; + + for (const auto& node : page_linked_list.Nodes()) { + if (const auto result{ + Operate(cur_addr, node.GetNumPages(), perm, OperationType::Map, node.GetAddress())}; + result.IsError()) { + const std::size_t num_pages{(addr - cur_addr) / PageSize}; + + ASSERT(Operate(addr, num_pages, KMemoryPermission::None, OperationType::Unmap) + .IsSuccess()); + + return result; + } + + cur_addr += node.GetNumPages() * PageSize; + } + + return RESULT_SUCCESS; +} + +ResultCode KPageTable::MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state, + KMemoryPermission perm) { + std::lock_guard lock{page_table_lock}; + + const std::size_t num_pages{page_linked_list.GetNumPages()}; + const std::size_t size{num_pages * PageSize}; + + if (!CanContain(addr, size, state)) { + return ResultInvalidCurrentMemory; + } + + if (IsRegionMapped(addr, num_pages * PageSize)) { + return ResultInvalidCurrentMemory; + } + + CASCADE_CODE(MapPages(addr, page_linked_list, perm)); + + block_manager->Update(addr, num_pages, state, perm); + + return RESULT_SUCCESS; +} + +ResultCode KPageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, + KMemoryPermission perm) { + + std::lock_guard lock{page_table_lock}; + + KMemoryState prev_state{}; + KMemoryPermission prev_perm{}; + + CASCADE_CODE(CheckMemoryState( + &prev_state, &prev_perm, nullptr, addr, size, KMemoryState::FlagCode, + KMemoryState::FlagCode, KMemoryPermission::None, KMemoryPermission::None, + KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); + + KMemoryState state{prev_state}; + + // Ensure state is mutable if permission allows write + if ((perm & KMemoryPermission::Write) != KMemoryPermission::None) { + if (prev_state == KMemoryState::Code) { + state = KMemoryState::CodeData; + } else if (prev_state == KMemoryState::AliasCode) { + state = KMemoryState::AliasCodeData; + } else { + UNREACHABLE(); + } + } + + // Return early if there is nothing to change + if (state == prev_state && perm == prev_perm) { + return RESULT_SUCCESS; + } + + if ((prev_perm & KMemoryPermission::Execute) != (perm & KMemoryPermission::Execute)) { + // Memory execution state is changing, invalidate CPU cache range + system.InvalidateCpuInstructionCacheRange(addr, size); + } + + const std::size_t num_pages{size / PageSize}; + const OperationType operation{(perm & KMemoryPermission::Execute) != KMemoryPermission::None + ? OperationType::ChangePermissionsAndRefresh + : OperationType::ChangePermissions}; + + CASCADE_CODE(Operate(addr, num_pages, perm, operation)); + + block_manager->Update(addr, num_pages, state, perm); + + return RESULT_SUCCESS; +} + +KMemoryInfo KPageTable::QueryInfoImpl(VAddr addr) { + std::lock_guard lock{page_table_lock}; + + return block_manager->FindBlock(addr).GetMemoryInfo(); +} + +KMemoryInfo KPageTable::QueryInfo(VAddr addr) { + if (!Contains(addr, 1)) { + return {address_space_end, 0 - address_space_end, KMemoryState::Inaccessible, + KMemoryPermission::None, KMemoryAttribute::None, KMemoryPermission::None}; + } + + return QueryInfoImpl(addr); +} + +ResultCode KPageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm) { + std::lock_guard lock{page_table_lock}; + + KMemoryState state{}; + KMemoryAttribute attribute{}; + + CASCADE_CODE(CheckMemoryState( + &state, nullptr, &attribute, addr, size, + KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, + KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::Mask, + KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, KMemoryAttribute::None, + KMemoryAttribute::IpcAndDeviceMapped)); + + block_manager->Update(addr, size / PageSize, state, perm, attribute | KMemoryAttribute::Locked); + + return RESULT_SUCCESS; +} + +ResultCode KPageTable::ResetTransferMemory(VAddr addr, std::size_t size) { + std::lock_guard lock{page_table_lock}; + + KMemoryState state{}; + + CASCADE_CODE( + CheckMemoryState(&state, nullptr, nullptr, addr, size, + KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, + KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, + KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::Mask, + KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); + + block_manager->Update(addr, size / PageSize, state, KMemoryPermission::ReadAndWrite); + + return RESULT_SUCCESS; +} + +ResultCode KPageTable::SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask, + KMemoryAttribute value) { + std::lock_guard lock{page_table_lock}; + + KMemoryState state{}; + KMemoryPermission perm{}; + KMemoryAttribute attribute{}; + + CASCADE_CODE(CheckMemoryState( + &state, &perm, &attribute, addr, size, KMemoryState::FlagCanChangeAttribute, + KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None, + KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None, + KMemoryAttribute::DeviceSharedAndUncached)); + + attribute = attribute & ~mask; + attribute = attribute | (mask & value); + + block_manager->Update(addr, size / PageSize, state, perm, attribute); + + return RESULT_SUCCESS; +} + +ResultCode KPageTable::SetHeapCapacity(std::size_t new_heap_capacity) { + std::lock_guard lock{page_table_lock}; + heap_capacity = new_heap_capacity; + return RESULT_SUCCESS; +} + +ResultVal KPageTable::SetHeapSize(std::size_t size) { + + if (size > heap_region_end - heap_region_start) { + return ResultOutOfMemory; + } + + const u64 previous_heap_size{GetHeapSize()}; + + UNIMPLEMENTED_IF_MSG(previous_heap_size > size, "Heap shrink is unimplemented"); + + // Increase the heap size + { + std::lock_guard lock{page_table_lock}; + + const u64 delta{size - previous_heap_size}; + + // Reserve memory for the heap extension. + KScopedResourceReservation memory_reservation( + system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory, + delta); + + if (!memory_reservation.Succeeded()) { + LOG_ERROR(Kernel, "Could not reserve heap extension of size {:X} bytes", delta); + return ResultResourceLimitedExceeded; + } + + KPageLinkedList page_linked_list; + const std::size_t num_pages{delta / PageSize}; + + CASCADE_CODE( + system.Kernel().MemoryManager().Allocate(page_linked_list, num_pages, memory_pool)); + + if (IsRegionMapped(current_heap_addr, delta)) { + return ResultInvalidCurrentMemory; + } + + CASCADE_CODE( + Operate(current_heap_addr, num_pages, page_linked_list, OperationType::MapGroup)); + + // Succeeded in allocation, commit the resource reservation + memory_reservation.Commit(); + + block_manager->Update(current_heap_addr, num_pages, KMemoryState::Normal, + KMemoryPermission::ReadAndWrite); + + current_heap_addr = heap_region_start + size; + } + + return MakeResult(heap_region_start); +} + +ResultVal KPageTable::AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, + bool is_map_only, VAddr region_start, + std::size_t region_num_pages, KMemoryState state, + KMemoryPermission perm, PAddr map_addr) { + std::lock_guard lock{page_table_lock}; + + if (!CanContain(region_start, region_num_pages * PageSize, state)) { + return ResultInvalidCurrentMemory; + } + + if (region_num_pages <= needed_num_pages) { + return ResultOutOfMemory; + } + + const VAddr addr{ + AllocateVirtualMemory(region_start, region_num_pages, needed_num_pages, align)}; + if (!addr) { + return ResultOutOfMemory; + } + + if (is_map_only) { + CASCADE_CODE(Operate(addr, needed_num_pages, perm, OperationType::Map, map_addr)); + } else { + KPageLinkedList page_group; + CASCADE_CODE( + system.Kernel().MemoryManager().Allocate(page_group, needed_num_pages, memory_pool)); + CASCADE_CODE(Operate(addr, needed_num_pages, page_group, OperationType::MapGroup)); + } + + block_manager->Update(addr, needed_num_pages, state, perm); + + return MakeResult(addr); +} + +ResultCode KPageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) { + std::lock_guard lock{page_table_lock}; + + KMemoryPermission perm{}; + if (const ResultCode result{CheckMemoryState( + nullptr, &perm, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute, + KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None, + KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None, + KMemoryAttribute::DeviceSharedAndUncached)}; + result.IsError()) { + return result; + } + + block_manager->UpdateLock( + addr, size / PageSize, + [](KMemoryBlockManager::iterator block, KMemoryPermission perm) { + block->ShareToDevice(perm); + }, + perm); + + return RESULT_SUCCESS; +} + +ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) { + std::lock_guard lock{page_table_lock}; + + KMemoryPermission perm{}; + if (const ResultCode result{CheckMemoryState( + nullptr, &perm, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute, + KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None, + KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None, + KMemoryAttribute::DeviceSharedAndUncached)}; + result.IsError()) { + return result; + } + + block_manager->UpdateLock( + addr, size / PageSize, + [](KMemoryBlockManager::iterator block, KMemoryPermission perm) { + block->UnshareToDevice(perm); + }, + perm); + + return RESULT_SUCCESS; +} + +ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) { + block_manager = std::make_unique(start, end); + + return RESULT_SUCCESS; +} + +bool KPageTable::IsRegionMapped(VAddr address, u64 size) { + return CheckMemoryState(address, size, KMemoryState::All, KMemoryState::Free, + KMemoryPermission::Mask, KMemoryPermission::None, + KMemoryAttribute::Mask, KMemoryAttribute::None, + KMemoryAttribute::IpcAndDeviceMapped) + .IsError(); +} + +bool KPageTable::IsRegionContiguous(VAddr addr, u64 size) const { + auto start_ptr = system.Memory().GetPointer(addr); + for (u64 offset{}; offset < size; offset += PageSize) { + if (start_ptr != system.Memory().GetPointer(addr + offset)) { + return false; + } + start_ptr += PageSize; + } + return true; +} + +void KPageTable::AddRegionToPages(VAddr start, std::size_t num_pages, + KPageLinkedList& page_linked_list) { + VAddr addr{start}; + while (addr < start + (num_pages * PageSize)) { + const PAddr paddr{GetPhysicalAddr(addr)}; + if (!paddr) { + UNREACHABLE(); + } + page_linked_list.AddBlock(paddr, 1); + addr += PageSize; + } +} + +VAddr KPageTable::AllocateVirtualMemory(VAddr start, std::size_t region_num_pages, + u64 needed_num_pages, std::size_t align) { + if (is_aslr_enabled) { + UNIMPLEMENTED(); + } + return block_manager->FindFreeArea(start, region_num_pages, needed_num_pages, align, 0, + IsKernel() ? 1 : 4); +} + +ResultCode KPageTable::Operate(VAddr addr, std::size_t num_pages, const KPageLinkedList& page_group, + OperationType operation) { + std::lock_guard lock{page_table_lock}; + + ASSERT(Common::IsAligned(addr, PageSize)); + ASSERT(num_pages > 0); + ASSERT(num_pages == page_group.GetNumPages()); + + for (const auto& node : page_group.Nodes()) { + const std::size_t size{node.GetNumPages() * PageSize}; + + switch (operation) { + case OperationType::MapGroup: + system.Memory().MapMemoryRegion(page_table_impl, addr, size, node.GetAddress()); + break; + default: + UNREACHABLE(); + } + + addr += size; + } + + return RESULT_SUCCESS; +} + +ResultCode KPageTable::Operate(VAddr addr, std::size_t num_pages, KMemoryPermission perm, + OperationType operation, PAddr map_addr) { + std::lock_guard lock{page_table_lock}; + + ASSERT(num_pages > 0); + ASSERT(Common::IsAligned(addr, PageSize)); + ASSERT(ContainsPages(addr, num_pages)); + + switch (operation) { + case OperationType::Unmap: + system.Memory().UnmapRegion(page_table_impl, addr, num_pages * PageSize); + break; + case OperationType::Map: { + ASSERT(map_addr); + ASSERT(Common::IsAligned(map_addr, PageSize)); + system.Memory().MapMemoryRegion(page_table_impl, addr, num_pages * PageSize, map_addr); + break; + } + case OperationType::ChangePermissions: + case OperationType::ChangePermissionsAndRefresh: + break; + default: + UNREACHABLE(); + } + return RESULT_SUCCESS; +} + +constexpr VAddr KPageTable::GetRegionAddress(KMemoryState state) const { + switch (state) { + case KMemoryState::Free: + case KMemoryState::Kernel: + return address_space_start; + case KMemoryState::Normal: + return heap_region_start; + case KMemoryState::Ipc: + case KMemoryState::NonSecureIpc: + case KMemoryState::NonDeviceIpc: + return alias_region_start; + case KMemoryState::Stack: + return stack_region_start; + case KMemoryState::Io: + case KMemoryState::Static: + case KMemoryState::ThreadLocal: + return kernel_map_region_start; + case KMemoryState::Shared: + case KMemoryState::AliasCode: + case KMemoryState::AliasCodeData: + case KMemoryState::Transferred: + case KMemoryState::SharedTransferred: + case KMemoryState::SharedCode: + case KMemoryState::GeneratedCode: + case KMemoryState::CodeOut: + return alias_code_region_start; + case KMemoryState::Code: + case KMemoryState::CodeData: + return code_region_start; + default: + UNREACHABLE(); + return {}; + } +} + +constexpr std::size_t KPageTable::GetRegionSize(KMemoryState state) const { + switch (state) { + case KMemoryState::Free: + case KMemoryState::Kernel: + return address_space_end - address_space_start; + case KMemoryState::Normal: + return heap_region_end - heap_region_start; + case KMemoryState::Ipc: + case KMemoryState::NonSecureIpc: + case KMemoryState::NonDeviceIpc: + return alias_region_end - alias_region_start; + case KMemoryState::Stack: + return stack_region_end - stack_region_start; + case KMemoryState::Io: + case KMemoryState::Static: + case KMemoryState::ThreadLocal: + return kernel_map_region_end - kernel_map_region_start; + case KMemoryState::Shared: + case KMemoryState::AliasCode: + case KMemoryState::AliasCodeData: + case KMemoryState::Transferred: + case KMemoryState::SharedTransferred: + case KMemoryState::SharedCode: + case KMemoryState::GeneratedCode: + case KMemoryState::CodeOut: + return alias_code_region_end - alias_code_region_start; + case KMemoryState::Code: + case KMemoryState::CodeData: + return code_region_end - code_region_start; + default: + UNREACHABLE(); + return {}; + } +} + +constexpr bool KPageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) const { + const VAddr end{addr + size}; + const VAddr last{end - 1}; + const VAddr region_start{GetRegionAddress(state)}; + const std::size_t region_size{GetRegionSize(state)}; + const bool is_in_region{region_start <= addr && addr < end && + last <= region_start + region_size - 1}; + const bool is_in_heap{!(end <= heap_region_start || heap_region_end <= addr)}; + const bool is_in_alias{!(end <= alias_region_start || alias_region_end <= addr)}; + + switch (state) { + case KMemoryState::Free: + case KMemoryState::Kernel: + return is_in_region; + case KMemoryState::Io: + case KMemoryState::Static: + case KMemoryState::Code: + case KMemoryState::CodeData: + case KMemoryState::Shared: + case KMemoryState::AliasCode: + case KMemoryState::AliasCodeData: + case KMemoryState::Stack: + case KMemoryState::ThreadLocal: + case KMemoryState::Transferred: + case KMemoryState::SharedTransferred: + case KMemoryState::SharedCode: + case KMemoryState::GeneratedCode: + case KMemoryState::CodeOut: + return is_in_region && !is_in_heap && !is_in_alias; + case KMemoryState::Normal: + ASSERT(is_in_heap); + return is_in_region && !is_in_alias; + case KMemoryState::Ipc: + case KMemoryState::NonSecureIpc: + case KMemoryState::NonDeviceIpc: + ASSERT(is_in_alias); + return is_in_region && !is_in_heap; + default: + return false; + } +} + +constexpr ResultCode KPageTable::CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, + KMemoryState state, KMemoryPermission perm_mask, + KMemoryPermission perm, + KMemoryAttribute attr_mask, + KMemoryAttribute attr) const { + // Validate the states match expectation + if ((info.state & state_mask) != state) { + return ResultInvalidCurrentMemory; + } + if ((info.perm & perm_mask) != perm) { + return ResultInvalidCurrentMemory; + } + if ((info.attribute & attr_mask) != attr) { + return ResultInvalidCurrentMemory; + } + + return RESULT_SUCCESS; +} + +ResultCode KPageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm, + KMemoryAttribute* out_attr, VAddr addr, std::size_t size, + KMemoryState state_mask, KMemoryState state, + KMemoryPermission perm_mask, KMemoryPermission perm, + KMemoryAttribute attr_mask, KMemoryAttribute attr, + KMemoryAttribute ignore_attr) { + std::lock_guard lock{page_table_lock}; + + // Get information about the first block + const VAddr last_addr{addr + size - 1}; + KMemoryBlockManager::const_iterator it{block_manager->FindIterator(addr)}; + KMemoryInfo info{it->GetMemoryInfo()}; + + // Validate all blocks in the range have correct state + const KMemoryState first_state{info.state}; + const KMemoryPermission first_perm{info.perm}; + const KMemoryAttribute first_attr{info.attribute}; + + while (true) { + // Validate the current block + if (!(info.state == first_state)) { + return ResultInvalidCurrentMemory; + } + if (!(info.perm == first_perm)) { + return ResultInvalidCurrentMemory; + } + if (!((info.attribute | static_cast(ignore_attr)) == + (first_attr | static_cast(ignore_attr)))) { + return ResultInvalidCurrentMemory; + } + + // Validate against the provided masks + CASCADE_CODE(CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr)); + + // Break once we're done + if (last_addr <= info.GetLastAddress()) { + break; + } + + // Advance our iterator + it++; + ASSERT(it != block_manager->cend()); + info = it->GetMemoryInfo(); + } + + // Write output state + if (out_state) { + *out_state = first_state; + } + if (out_perm) { + *out_perm = first_perm; + } + if (out_attr) { + *out_attr = first_attr & static_cast(~ignore_attr); + } + + return RESULT_SUCCESS; +} + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h new file mode 100644 index 000000000..49b824379 --- /dev/null +++ b/src/core/hle/kernel/k_page_table.h @@ -0,0 +1,279 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "common/common_types.h" +#include "common/page_table.h" +#include "core/file_sys/program_metadata.h" +#include "core/hle/kernel/k_memory_block.h" +#include "core/hle/kernel/k_memory_manager.h" +#include "core/hle/result.h" + +namespace Core { +class System; +} + +namespace Kernel { + +class KMemoryBlockManager; + +class KPageTable final : NonCopyable { +public: + explicit KPageTable(Core::System& system); + + ResultCode InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr, + VAddr code_addr, std::size_t code_size, + KMemoryManager::Pool pool); + ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, KMemoryState state, + KMemoryPermission perm); + ResultCode MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); + ResultCode UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); + ResultCode MapPhysicalMemory(VAddr addr, std::size_t size); + ResultCode UnmapPhysicalMemory(VAddr addr, std::size_t size); + ResultCode UnmapMemory(VAddr addr, std::size_t size); + ResultCode Map(VAddr dst_addr, VAddr src_addr, std::size_t size); + ResultCode Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size); + ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state, + KMemoryPermission perm); + ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm); + KMemoryInfo QueryInfo(VAddr addr); + ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); + ResultCode ResetTransferMemory(VAddr addr, std::size_t size); + ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask, + KMemoryAttribute value); + ResultCode SetHeapCapacity(std::size_t new_heap_capacity); + ResultVal SetHeapSize(std::size_t size); + ResultVal AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, + bool is_map_only, VAddr region_start, + std::size_t region_num_pages, KMemoryState state, + KMemoryPermission perm, PAddr map_addr = 0); + ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size); + ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size); + + Common::PageTable& PageTableImpl() { + return page_table_impl; + } + + const Common::PageTable& PageTableImpl() const { + return page_table_impl; + } + +private: + enum class OperationType : u32 { + Map, + MapGroup, + Unmap, + ChangePermissions, + ChangePermissionsAndRefresh, + }; + + static constexpr KMemoryAttribute DefaultMemoryIgnoreAttr = KMemoryAttribute::DontCareMask | + KMemoryAttribute::IpcLocked | + KMemoryAttribute::DeviceShared; + + ResultCode InitializeMemoryLayout(VAddr start, VAddr end); + ResultCode MapPages(VAddr addr, const KPageLinkedList& page_linked_list, + KMemoryPermission perm); + void MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end); + bool IsRegionMapped(VAddr address, u64 size); + bool IsRegionContiguous(VAddr addr, u64 size) const; + void AddRegionToPages(VAddr start, std::size_t num_pages, KPageLinkedList& page_linked_list); + KMemoryInfo QueryInfoImpl(VAddr addr); + VAddr AllocateVirtualMemory(VAddr start, std::size_t region_num_pages, u64 needed_num_pages, + std::size_t align); + ResultCode Operate(VAddr addr, std::size_t num_pages, const KPageLinkedList& page_group, + OperationType operation); + ResultCode Operate(VAddr addr, std::size_t num_pages, KMemoryPermission perm, + OperationType operation, PAddr map_addr = 0); + constexpr VAddr GetRegionAddress(KMemoryState state) const; + constexpr std::size_t GetRegionSize(KMemoryState state) const; + constexpr bool CanContain(VAddr addr, std::size_t size, KMemoryState state) const; + + constexpr ResultCode CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, + KMemoryState state, KMemoryPermission perm_mask, + KMemoryPermission perm, KMemoryAttribute attr_mask, + KMemoryAttribute attr) const; + ResultCode CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm, + KMemoryAttribute* out_attr, VAddr addr, std::size_t size, + KMemoryState state_mask, KMemoryState state, + KMemoryPermission perm_mask, KMemoryPermission perm, + KMemoryAttribute attr_mask, KMemoryAttribute attr, + KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr); + ResultCode CheckMemoryState(VAddr addr, std::size_t size, KMemoryState state_mask, + KMemoryState state, KMemoryPermission perm_mask, + KMemoryPermission perm, KMemoryAttribute attr_mask, + KMemoryAttribute attr, + KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) { + return CheckMemoryState(nullptr, nullptr, nullptr, addr, size, state_mask, state, perm_mask, + perm, attr_mask, attr, ignore_attr); + } + + std::recursive_mutex page_table_lock; + std::unique_ptr block_manager; + +public: + constexpr VAddr GetAddressSpaceStart() const { + return address_space_start; + } + constexpr VAddr GetAddressSpaceEnd() const { + return address_space_end; + } + constexpr std::size_t GetAddressSpaceSize() const { + return address_space_end - address_space_start; + } + constexpr VAddr GetHeapRegionStart() const { + return heap_region_start; + } + constexpr VAddr GetHeapRegionEnd() const { + return heap_region_end; + } + constexpr std::size_t GetHeapRegionSize() const { + return heap_region_end - heap_region_start; + } + constexpr VAddr GetAliasRegionStart() const { + return alias_region_start; + } + constexpr VAddr GetAliasRegionEnd() const { + return alias_region_end; + } + constexpr std::size_t GetAliasRegionSize() const { + return alias_region_end - alias_region_start; + } + constexpr VAddr GetStackRegionStart() const { + return stack_region_start; + } + constexpr VAddr GetStackRegionEnd() const { + return stack_region_end; + } + constexpr std::size_t GetStackRegionSize() const { + return stack_region_end - stack_region_start; + } + constexpr VAddr GetKernelMapRegionStart() const { + return kernel_map_region_start; + } + constexpr VAddr GetKernelMapRegionEnd() const { + return kernel_map_region_end; + } + constexpr VAddr GetCodeRegionStart() const { + return code_region_start; + } + constexpr VAddr GetCodeRegionEnd() const { + return code_region_end; + } + constexpr VAddr GetAliasCodeRegionStart() const { + return alias_code_region_start; + } + constexpr VAddr GetAliasCodeRegionSize() const { + return alias_code_region_end - alias_code_region_start; + } + constexpr std::size_t GetAddressSpaceWidth() const { + return address_space_width; + } + constexpr std::size_t GetHeapSize() { + return current_heap_addr - heap_region_start; + } + constexpr std::size_t GetTotalHeapSize() { + return GetHeapSize() + physical_memory_usage; + } + constexpr bool IsInsideAddressSpace(VAddr address, std::size_t size) const { + return address_space_start <= address && address + size - 1 <= address_space_end - 1; + } + constexpr bool IsOutsideAliasRegion(VAddr address, std::size_t size) const { + return alias_region_start > address || address + size - 1 > alias_region_end - 1; + } + constexpr bool IsOutsideStackRegion(VAddr address, std::size_t size) const { + return stack_region_start > address || address + size - 1 > stack_region_end - 1; + } + constexpr bool IsInvalidRegion(VAddr address, std::size_t size) const { + return address + size - 1 > GetAliasCodeRegionStart() + GetAliasCodeRegionSize() - 1; + } + constexpr bool IsInsideHeapRegion(VAddr address, std::size_t size) const { + return address + size > heap_region_start && heap_region_end > address; + } + constexpr bool IsInsideAliasRegion(VAddr address, std::size_t size) const { + return address + size > alias_region_start && alias_region_end > address; + } + constexpr bool IsOutsideASLRRegion(VAddr address, std::size_t size) const { + if (IsInvalidRegion(address, size)) { + return true; + } + if (IsInsideHeapRegion(address, size)) { + return true; + } + if (IsInsideAliasRegion(address, size)) { + return true; + } + return {}; + } + constexpr bool IsInsideASLRRegion(VAddr address, std::size_t size) const { + return !IsOutsideASLRRegion(address, size); + } + constexpr PAddr GetPhysicalAddr(VAddr addr) { + return page_table_impl.backing_addr[addr >> PageBits] + addr; + } + +private: + constexpr bool Contains(VAddr addr) const { + return address_space_start <= addr && addr <= address_space_end - 1; + } + constexpr bool Contains(VAddr addr, std::size_t size) const { + return address_space_start <= addr && addr < addr + size && + addr + size - 1 <= address_space_end - 1; + } + constexpr bool IsKernel() const { + return is_kernel; + } + constexpr bool IsAslrEnabled() const { + return is_aslr_enabled; + } + + constexpr std::size_t GetNumGuardPages() const { + return IsKernel() ? 1 : 4; + } + + constexpr bool ContainsPages(VAddr addr, std::size_t num_pages) const { + return (address_space_start <= addr) && + (num_pages <= (address_space_end - address_space_start) / PageSize) && + (addr + num_pages * PageSize - 1 <= address_space_end - 1); + } + +private: + VAddr address_space_start{}; + VAddr address_space_end{}; + VAddr heap_region_start{}; + VAddr heap_region_end{}; + VAddr current_heap_end{}; + VAddr alias_region_start{}; + VAddr alias_region_end{}; + VAddr stack_region_start{}; + VAddr stack_region_end{}; + VAddr kernel_map_region_start{}; + VAddr kernel_map_region_end{}; + VAddr code_region_start{}; + VAddr code_region_end{}; + VAddr alias_code_region_start{}; + VAddr alias_code_region_end{}; + VAddr current_heap_addr{}; + + std::size_t heap_capacity{}; + std::size_t physical_memory_usage{}; + std::size_t max_heap_size{}; + std::size_t max_physical_memory_size{}; + std::size_t address_space_width{}; + + bool is_kernel{}; + bool is_aslr_enabled{}; + + KMemoryManager::Pool memory_pool{KMemoryManager::Pool::Application}; + + Common::PageTable page_table_impl; + + Core::System& system; +}; + +} // namespace Kernel diff --git a/src/core/hle/kernel/k_shared_memory.cpp b/src/core/hle/kernel/k_shared_memory.cpp index aade52764..9b14f42b5 100644 --- a/src/core/hle/kernel/k_shared_memory.cpp +++ b/src/core/hle/kernel/k_shared_memory.cpp @@ -4,10 +4,10 @@ #include "common/assert.h" #include "core/core.h" +#include "core/hle/kernel/k_page_table.h" #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/memory/page_table.h" namespace Kernel { @@ -21,8 +21,7 @@ KSharedMemory::~KSharedMemory() { std::shared_ptr KSharedMemory::Create( KernelCore& kernel, Core::DeviceMemory& device_memory, Process* owner_process, KPageLinkedList&& page_list, KMemoryPermission owner_permission, - KMemoryPermission user_permission, PAddr physical_address, std::size_t size, - std::string name) { + KMemoryPermission user_permission, PAddr physical_address, std::size_t size, std::string name) { const auto resource_limit = kernel.GetSystemResourceLimit(); KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory, diff --git a/src/core/hle/kernel/memory/page_heap.cpp b/src/core/hle/kernel/memory/page_heap.cpp deleted file mode 100644 index 8fb53a0e8..000000000 --- a/src/core/hle/kernel/memory/page_heap.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -// This file references various implementation details from Atmosphere, an open-source firmware for -// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. - -#include "core/core.h" -#include "core/hle/kernel/memory/page_heap.h" -#include "core/memory.h" - -namespace Kernel::Memory { - -void PageHeap::Initialize(VAddr address, std::size_t size, std::size_t metadata_size) { - // Check our assumptions - ASSERT(Common::IsAligned((address), PageSize)); - ASSERT(Common::IsAligned(size, PageSize)); - - // Set our members - heap_address = address; - heap_size = size; - - // Setup bitmaps - metadata.resize(metadata_size / sizeof(u64)); - u64* cur_bitmap_storage{metadata.data()}; - for (std::size_t i = 0; i < MemoryBlockPageShifts.size(); i++) { - const std::size_t cur_block_shift{MemoryBlockPageShifts[i]}; - const std::size_t next_block_shift{ - (i != MemoryBlockPageShifts.size() - 1) ? MemoryBlockPageShifts[i + 1] : 0}; - cur_bitmap_storage = blocks[i].Initialize(heap_address, heap_size, cur_block_shift, - next_block_shift, cur_bitmap_storage); - } -} - -VAddr PageHeap::AllocateBlock(s32 index, bool random) { - const std::size_t needed_size{blocks[index].GetSize()}; - - for (s32 i{index}; i < static_cast(MemoryBlockPageShifts.size()); i++) { - if (const VAddr addr{blocks[i].PopBlock(random)}; addr) { - if (const std::size_t allocated_size{blocks[i].GetSize()}; - allocated_size > needed_size) { - Free(addr + needed_size, (allocated_size - needed_size) / PageSize); - } - return addr; - } - } - - return 0; -} - -void PageHeap::FreeBlock(VAddr block, s32 index) { - do { - block = blocks[index++].PushBlock(block); - } while (block != 0); -} - -void PageHeap::Free(VAddr addr, std::size_t num_pages) { - // Freeing no pages is a no-op - if (num_pages == 0) { - return; - } - - // Find the largest block size that we can free, and free as many as possible - s32 big_index{static_cast(MemoryBlockPageShifts.size()) - 1}; - const VAddr start{addr}; - const VAddr end{(num_pages * PageSize) + addr}; - VAddr before_start{start}; - VAddr before_end{start}; - VAddr after_start{end}; - VAddr after_end{end}; - while (big_index >= 0) { - const std::size_t block_size{blocks[big_index].GetSize()}; - const VAddr big_start{Common::AlignUp((start), block_size)}; - const VAddr big_end{Common::AlignDown((end), block_size)}; - if (big_start < big_end) { - // Free as many big blocks as we can - for (auto block{big_start}; block < big_end; block += block_size) { - FreeBlock(block, big_index); - } - before_end = big_start; - after_start = big_end; - break; - } - big_index--; - } - ASSERT(big_index >= 0); - - // Free space before the big blocks - for (s32 i{big_index - 1}; i >= 0; i--) { - const std::size_t block_size{blocks[i].GetSize()}; - while (before_start + block_size <= before_end) { - before_end -= block_size; - FreeBlock(before_end, i); - } - } - - // Free space after the big blocks - for (s32 i{big_index - 1}; i >= 0; i--) { - const std::size_t block_size{blocks[i].GetSize()}; - while (after_start + block_size <= after_end) { - FreeBlock(after_start, i); - after_start += block_size; - } - } -} - -std::size_t PageHeap::CalculateManagementOverheadSize(std::size_t region_size) { - std::size_t overhead_size = 0; - for (std::size_t i = 0; i < MemoryBlockPageShifts.size(); i++) { - const std::size_t cur_block_shift{MemoryBlockPageShifts[i]}; - const std::size_t next_block_shift{ - (i != MemoryBlockPageShifts.size() - 1) ? MemoryBlockPageShifts[i + 1] : 0}; - overhead_size += PageHeap::Block::CalculateManagementOverheadSize( - region_size, cur_block_shift, next_block_shift); - } - return Common::AlignUp(overhead_size, PageSize); -} - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/page_heap.h b/src/core/hle/kernel/memory/page_heap.h deleted file mode 100644 index e21d60a54..000000000 --- a/src/core/hle/kernel/memory/page_heap.h +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -// This file references various implementation details from Atmosphere, an open-source firmware for -// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. - -#pragma once - -#include -#include -#include - -#include "common/alignment.h" -#include "common/assert.h" -#include "common/common_funcs.h" -#include "common/common_types.h" -#include "core/hle/kernel/k_page_bitmap.h" -#include "core/hle/kernel/memory_types.h" - -namespace Kernel::Memory { - -class PageHeap final : NonCopyable { -public: - static constexpr s32 GetAlignedBlockIndex(std::size_t num_pages, std::size_t align_pages) { - const auto target_pages{std::max(num_pages, align_pages)}; - for (std::size_t i = 0; i < NumMemoryBlockPageShifts; i++) { - if (target_pages <= - (static_cast(1) << MemoryBlockPageShifts[i]) / PageSize) { - return static_cast(i); - } - } - return -1; - } - - static constexpr s32 GetBlockIndex(std::size_t num_pages) { - for (s32 i{static_cast(NumMemoryBlockPageShifts) - 1}; i >= 0; i--) { - if (num_pages >= (static_cast(1) << MemoryBlockPageShifts[i]) / PageSize) { - return i; - } - } - return -1; - } - - static constexpr std::size_t GetBlockSize(std::size_t index) { - return static_cast(1) << MemoryBlockPageShifts[index]; - } - - static constexpr std::size_t GetBlockNumPages(std::size_t index) { - return GetBlockSize(index) / PageSize; - } - -private: - static constexpr std::size_t NumMemoryBlockPageShifts{7}; - static constexpr std::array MemoryBlockPageShifts{ - 0xC, 0x10, 0x15, 0x16, 0x19, 0x1D, 0x1E, - }; - - class Block final : NonCopyable { - private: - KPageBitmap bitmap; - VAddr heap_address{}; - uintptr_t end_offset{}; - std::size_t block_shift{}; - std::size_t next_block_shift{}; - - public: - Block() = default; - - constexpr std::size_t GetShift() const { - return block_shift; - } - constexpr std::size_t GetNextShift() const { - return next_block_shift; - } - constexpr std::size_t GetSize() const { - return static_cast(1) << GetShift(); - } - constexpr std::size_t GetNumPages() const { - return GetSize() / PageSize; - } - constexpr std::size_t GetNumFreeBlocks() const { - return bitmap.GetNumBits(); - } - constexpr std::size_t GetNumFreePages() const { - return GetNumFreeBlocks() * GetNumPages(); - } - - u64* Initialize(VAddr addr, std::size_t size, std::size_t bs, std::size_t nbs, - u64* bit_storage) { - // Set shifts - block_shift = bs; - next_block_shift = nbs; - - // Align up the address - VAddr end{addr + size}; - const auto align{(next_block_shift != 0) ? (1ULL << next_block_shift) - : (1ULL << block_shift)}; - addr = Common::AlignDown((addr), align); - end = Common::AlignUp((end), align); - - heap_address = addr; - end_offset = (end - addr) / (1ULL << block_shift); - return bitmap.Initialize(bit_storage, end_offset); - } - - VAddr PushBlock(VAddr address) { - // Set the bit for the free block - std::size_t offset{(address - heap_address) >> GetShift()}; - bitmap.SetBit(offset); - - // If we have a next shift, try to clear the blocks below and return the address - if (GetNextShift()) { - const auto diff{1ULL << (GetNextShift() - GetShift())}; - offset = Common::AlignDown(offset, diff); - if (bitmap.ClearRange(offset, diff)) { - return heap_address + (offset << GetShift()); - } - } - - // We couldn't coalesce, or we're already as big as possible - return 0; - } - - VAddr PopBlock(bool random) { - // Find a free block - const s64 soffset{bitmap.FindFreeBlock(random)}; - if (soffset < 0) { - return 0; - } - const auto offset{static_cast(soffset)}; - - // Update our tracking and return it - bitmap.ClearBit(offset); - return heap_address + (offset << GetShift()); - } - - public: - static constexpr std::size_t CalculateManagementOverheadSize(std::size_t region_size, - std::size_t cur_block_shift, - std::size_t next_block_shift) { - const auto cur_block_size{(1ULL << cur_block_shift)}; - const auto next_block_size{(1ULL << next_block_shift)}; - const auto align{(next_block_shift != 0) ? next_block_size : cur_block_size}; - return KPageBitmap::CalculateManagementOverheadSize( - (align * 2 + Common::AlignUp(region_size, align)) / cur_block_size); - } - }; - -public: - PageHeap() = default; - - constexpr VAddr GetAddress() const { - return heap_address; - } - constexpr std::size_t GetSize() const { - return heap_size; - } - constexpr VAddr GetEndAddress() const { - return GetAddress() + GetSize(); - } - constexpr std::size_t GetPageOffset(VAddr block) const { - return (block - GetAddress()) / PageSize; - } - - void Initialize(VAddr heap_address, std::size_t heap_size, std::size_t metadata_size); - VAddr AllocateBlock(s32 index, bool random); - void Free(VAddr addr, std::size_t num_pages); - - void UpdateUsedSize() { - used_size = heap_size - (GetNumFreePages() * PageSize); - } - - static std::size_t CalculateManagementOverheadSize(std::size_t region_size); - -private: - constexpr std::size_t GetNumFreePages() const { - std::size_t num_free{}; - - for (const auto& block : blocks) { - num_free += block.GetNumFreePages(); - } - - return num_free; - } - - void FreeBlock(VAddr block, s32 index); - - VAddr heap_address{}; - std::size_t heap_size{}; - std::size_t used_size{}; - std::array blocks{}; - std::vector metadata; -}; - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/page_table.cpp b/src/core/hle/kernel/memory/page_table.cpp deleted file mode 100644 index ef9d97413..000000000 --- a/src/core/hle/kernel/memory/page_table.cpp +++ /dev/null @@ -1,1189 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/alignment.h" -#include "common/assert.h" -#include "common/scope_exit.h" -#include "core/core.h" -#include "core/hle/kernel/k_address_space_info.h" -#include "core/hle/kernel/k_memory_block.h" -#include "core/hle/kernel/k_memory_block_manager.h" -#include "core/hle/kernel/k_page_linked_list.h" -#include "core/hle/kernel/k_resource_limit.h" -#include "core/hle/kernel/k_scoped_resource_reservation.h" -#include "core/hle/kernel/k_system_control.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/memory/page_table.h" -#include "core/hle/kernel/process.h" -#include "core/hle/kernel/svc_results.h" -#include "core/memory.h" - -namespace Kernel::Memory { - -namespace { - -constexpr std::size_t GetAddressSpaceWidthFromType(FileSys::ProgramAddressSpaceType as_type) { - switch (as_type) { - case FileSys::ProgramAddressSpaceType::Is32Bit: - case FileSys::ProgramAddressSpaceType::Is32BitNoMap: - return 32; - case FileSys::ProgramAddressSpaceType::Is36Bit: - return 36; - case FileSys::ProgramAddressSpaceType::Is39Bit: - return 39; - default: - UNREACHABLE(); - return {}; - } -} - -constexpr u64 GetAddressInRange(const KMemoryInfo& info, VAddr addr) { - if (info.GetAddress() < addr) { - return addr; - } - return info.GetAddress(); -} - -constexpr std::size_t GetSizeInRange(const KMemoryInfo& info, VAddr start, VAddr end) { - std::size_t size{info.GetSize()}; - if (info.GetAddress() < start) { - size -= start - info.GetAddress(); - } - if (info.GetEndAddress() > end) { - size -= info.GetEndAddress() - end; - } - return size; -} - -} // namespace - -PageTable::PageTable(Core::System& system) : system{system} {} - -ResultCode PageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, - bool enable_aslr, VAddr code_addr, std::size_t code_size, - KMemoryManager::Pool pool) { - - const auto GetSpaceStart = [this](KAddressSpaceInfo::Type type) { - return KAddressSpaceInfo::GetAddressSpaceStart(address_space_width, type); - }; - const auto GetSpaceSize = [this](KAddressSpaceInfo::Type type) { - return KAddressSpaceInfo::GetAddressSpaceSize(address_space_width, type); - }; - - // Set our width and heap/alias sizes - address_space_width = GetAddressSpaceWidthFromType(as_type); - const VAddr start = 0; - const VAddr end{1ULL << address_space_width}; - std::size_t alias_region_size{GetSpaceSize(KAddressSpaceInfo::Type::Alias)}; - std::size_t heap_region_size{GetSpaceSize(KAddressSpaceInfo::Type::Heap)}; - - ASSERT(start <= code_addr); - ASSERT(code_addr < code_addr + code_size); - ASSERT(code_addr + code_size - 1 <= end - 1); - - // Adjust heap/alias size if we don't have an alias region - if (as_type == FileSys::ProgramAddressSpaceType::Is32BitNoMap) { - heap_region_size += alias_region_size; - alias_region_size = 0; - } - - // Set code regions and determine remaining - constexpr std::size_t RegionAlignment{2 * 1024 * 1024}; - VAddr process_code_start{}; - VAddr process_code_end{}; - std::size_t stack_region_size{}; - std::size_t kernel_map_region_size{}; - - if (address_space_width == 39) { - alias_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Alias); - heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Heap); - stack_region_size = GetSpaceSize(KAddressSpaceInfo::Type::Stack); - kernel_map_region_size = GetSpaceSize(KAddressSpaceInfo::Type::MapSmall); - code_region_start = GetSpaceStart(KAddressSpaceInfo::Type::Map39Bit); - code_region_end = code_region_start + GetSpaceSize(KAddressSpaceInfo::Type::Map39Bit); - alias_code_region_start = code_region_start; - alias_code_region_end = code_region_end; - process_code_start = Common::AlignDown(code_addr, RegionAlignment); - process_code_end = Common::AlignUp(code_addr + code_size, RegionAlignment); - } else { - stack_region_size = 0; - kernel_map_region_size = 0; - code_region_start = GetSpaceStart(KAddressSpaceInfo::Type::MapSmall); - code_region_end = code_region_start + GetSpaceSize(KAddressSpaceInfo::Type::MapSmall); - stack_region_start = code_region_start; - alias_code_region_start = code_region_start; - alias_code_region_end = GetSpaceStart(KAddressSpaceInfo::Type::MapLarge) + - GetSpaceSize(KAddressSpaceInfo::Type::MapLarge); - stack_region_end = code_region_end; - kernel_map_region_start = code_region_start; - kernel_map_region_end = code_region_end; - process_code_start = code_region_start; - process_code_end = code_region_end; - } - - // Set other basic fields - is_aslr_enabled = enable_aslr; - address_space_start = start; - address_space_end = end; - is_kernel = false; - - // Determine the region we can place our undetermineds in - VAddr alloc_start{}; - std::size_t alloc_size{}; - if ((process_code_start - code_region_start) >= (end - process_code_end)) { - alloc_start = code_region_start; - alloc_size = process_code_start - code_region_start; - } else { - alloc_start = process_code_end; - alloc_size = end - process_code_end; - } - const std::size_t needed_size{ - (alias_region_size + heap_region_size + stack_region_size + kernel_map_region_size)}; - if (alloc_size < needed_size) { - UNREACHABLE(); - return ResultOutOfMemory; - } - - const std::size_t remaining_size{alloc_size - needed_size}; - - // Determine random placements for each region - std::size_t alias_rnd{}, heap_rnd{}, stack_rnd{}, kmap_rnd{}; - if (enable_aslr) { - alias_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * - RegionAlignment; - heap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * - RegionAlignment; - stack_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * - RegionAlignment; - kmap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * - RegionAlignment; - } - - // Setup heap and alias regions - alias_region_start = alloc_start + alias_rnd; - alias_region_end = alias_region_start + alias_region_size; - heap_region_start = alloc_start + heap_rnd; - heap_region_end = heap_region_start + heap_region_size; - - if (alias_rnd <= heap_rnd) { - heap_region_start += alias_region_size; - heap_region_end += alias_region_size; - } else { - alias_region_start += heap_region_size; - alias_region_end += heap_region_size; - } - - // Setup stack region - if (stack_region_size) { - stack_region_start = alloc_start + stack_rnd; - stack_region_end = stack_region_start + stack_region_size; - - if (alias_rnd < stack_rnd) { - stack_region_start += alias_region_size; - stack_region_end += alias_region_size; - } else { - alias_region_start += stack_region_size; - alias_region_end += stack_region_size; - } - - if (heap_rnd < stack_rnd) { - stack_region_start += heap_region_size; - stack_region_end += heap_region_size; - } else { - heap_region_start += stack_region_size; - heap_region_end += stack_region_size; - } - } - - // Setup kernel map region - if (kernel_map_region_size) { - kernel_map_region_start = alloc_start + kmap_rnd; - kernel_map_region_end = kernel_map_region_start + kernel_map_region_size; - - if (alias_rnd < kmap_rnd) { - kernel_map_region_start += alias_region_size; - kernel_map_region_end += alias_region_size; - } else { - alias_region_start += kernel_map_region_size; - alias_region_end += kernel_map_region_size; - } - - if (heap_rnd < kmap_rnd) { - kernel_map_region_start += heap_region_size; - kernel_map_region_end += heap_region_size; - } else { - heap_region_start += kernel_map_region_size; - heap_region_end += kernel_map_region_size; - } - - if (stack_region_size) { - if (stack_rnd < kmap_rnd) { - kernel_map_region_start += stack_region_size; - kernel_map_region_end += stack_region_size; - } else { - stack_region_start += kernel_map_region_size; - stack_region_end += kernel_map_region_size; - } - } - } - - // Set heap members - current_heap_end = heap_region_start; - max_heap_size = 0; - max_physical_memory_size = 0; - - // Ensure that we regions inside our address space - auto IsInAddressSpace = [&](VAddr addr) { - return address_space_start <= addr && addr <= address_space_end; - }; - ASSERT(IsInAddressSpace(alias_region_start)); - ASSERT(IsInAddressSpace(alias_region_end)); - ASSERT(IsInAddressSpace(heap_region_start)); - ASSERT(IsInAddressSpace(heap_region_end)); - ASSERT(IsInAddressSpace(stack_region_start)); - ASSERT(IsInAddressSpace(stack_region_end)); - ASSERT(IsInAddressSpace(kernel_map_region_start)); - ASSERT(IsInAddressSpace(kernel_map_region_end)); - - // Ensure that we selected regions that don't overlap - const VAddr alias_start{alias_region_start}; - const VAddr alias_last{alias_region_end - 1}; - const VAddr heap_start{heap_region_start}; - const VAddr heap_last{heap_region_end - 1}; - const VAddr stack_start{stack_region_start}; - const VAddr stack_last{stack_region_end - 1}; - const VAddr kmap_start{kernel_map_region_start}; - const VAddr kmap_last{kernel_map_region_end - 1}; - ASSERT(alias_last < heap_start || heap_last < alias_start); - ASSERT(alias_last < stack_start || stack_last < alias_start); - ASSERT(alias_last < kmap_start || kmap_last < alias_start); - ASSERT(heap_last < stack_start || stack_last < heap_start); - ASSERT(heap_last < kmap_start || kmap_last < heap_start); - - current_heap_addr = heap_region_start; - heap_capacity = 0; - physical_memory_usage = 0; - memory_pool = pool; - - page_table_impl.Resize(address_space_width, PageBits); - - return InitializeMemoryLayout(start, end); -} - -ResultCode PageTable::MapProcessCode(VAddr addr, std::size_t num_pages, KMemoryState state, - KMemoryPermission perm) { - std::lock_guard lock{page_table_lock}; - - const u64 size{num_pages * PageSize}; - - if (!CanContain(addr, size, state)) { - return ResultInvalidCurrentMemory; - } - - if (IsRegionMapped(addr, size)) { - return ResultInvalidCurrentMemory; - } - - KPageLinkedList page_linked_list; - CASCADE_CODE( - system.Kernel().MemoryManager().Allocate(page_linked_list, num_pages, memory_pool)); - CASCADE_CODE(Operate(addr, num_pages, page_linked_list, OperationType::MapGroup)); - - block_manager->Update(addr, num_pages, state, perm); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - const std::size_t num_pages{size / PageSize}; - - KMemoryState state{}; - KMemoryPermission perm{}; - CASCADE_CODE(CheckMemoryState(&state, &perm, nullptr, src_addr, size, KMemoryState::All, - KMemoryState::Normal, KMemoryPermission::Mask, - KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, - KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); - - if (IsRegionMapped(dst_addr, size)) { - return ResultInvalidCurrentMemory; - } - - KPageLinkedList page_linked_list; - AddRegionToPages(src_addr, num_pages, page_linked_list); - - { - auto block_guard = detail::ScopeExit( - [&] { Operate(src_addr, num_pages, perm, OperationType::ChangePermissions); }); - - CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::None, - OperationType::ChangePermissions)); - CASCADE_CODE(MapPages(dst_addr, page_linked_list, KMemoryPermission::None)); - - block_guard.Cancel(); - } - - block_manager->Update(src_addr, num_pages, state, KMemoryPermission::None, - KMemoryAttribute::Locked); - block_manager->Update(dst_addr, num_pages, KMemoryState::AliasCode); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - if (!size) { - return RESULT_SUCCESS; - } - - const std::size_t num_pages{size / PageSize}; - - CASCADE_CODE(CheckMemoryState(nullptr, nullptr, nullptr, src_addr, size, KMemoryState::All, - KMemoryState::Normal, KMemoryPermission::None, - KMemoryPermission::None, KMemoryAttribute::Mask, - KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); - - KMemoryState state{}; - CASCADE_CODE(CheckMemoryState( - &state, nullptr, nullptr, dst_addr, PageSize, KMemoryState::FlagCanCodeAlias, - KMemoryState::FlagCanCodeAlias, KMemoryPermission::None, KMemoryPermission::None, - KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); - CASCADE_CODE(CheckMemoryState(dst_addr, size, KMemoryState::All, state, KMemoryPermission::None, - KMemoryPermission::None, KMemoryAttribute::Mask, - KMemoryAttribute::None)); - CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap)); - - block_manager->Update(dst_addr, num_pages, KMemoryState::Free); - block_manager->Update(src_addr, num_pages, KMemoryState::Normal, - KMemoryPermission::ReadAndWrite); - - return RESULT_SUCCESS; -} - -void PageTable::MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end) { - auto node{page_linked_list.Nodes().begin()}; - PAddr map_addr{node->GetAddress()}; - std::size_t src_num_pages{node->GetNumPages()}; - - block_manager->IterateForRange(start, end, [&](const KMemoryInfo& info) { - if (info.state != KMemoryState::Free) { - return; - } - - std::size_t dst_num_pages{GetSizeInRange(info, start, end) / PageSize}; - VAddr dst_addr{GetAddressInRange(info, start)}; - - while (dst_num_pages) { - if (!src_num_pages) { - node = std::next(node); - map_addr = node->GetAddress(); - src_num_pages = node->GetNumPages(); - } - - const std::size_t num_pages{std::min(src_num_pages, dst_num_pages)}; - Operate(dst_addr, num_pages, KMemoryPermission::ReadAndWrite, OperationType::Map, - map_addr); - - dst_addr += num_pages * PageSize; - map_addr += num_pages * PageSize; - src_num_pages -= num_pages; - dst_num_pages -= num_pages; - } - }); -} - -ResultCode PageTable::MapPhysicalMemory(VAddr addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - std::size_t mapped_size{}; - const VAddr end_addr{addr + size}; - - block_manager->IterateForRange(addr, end_addr, [&](const KMemoryInfo& info) { - if (info.state != KMemoryState::Free) { - mapped_size += GetSizeInRange(info, addr, end_addr); - } - }); - - if (mapped_size == size) { - return RESULT_SUCCESS; - } - - const std::size_t remaining_size{size - mapped_size}; - const std::size_t remaining_pages{remaining_size / PageSize}; - - // Reserve the memory from the process resource limit. - KScopedResourceReservation memory_reservation( - system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory, - remaining_size); - if (!memory_reservation.Succeeded()) { - LOG_ERROR(Kernel, "Could not reserve remaining {:X} bytes", remaining_size); - return ResultResourceLimitedExceeded; - } - - KPageLinkedList page_linked_list; - - CASCADE_CODE( - system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, memory_pool)); - - // We succeeded, so commit the memory reservation. - memory_reservation.Commit(); - - MapPhysicalMemory(page_linked_list, addr, end_addr); - - physical_memory_usage += remaining_size; - - const std::size_t num_pages{size / PageSize}; - block_manager->Update(addr, num_pages, KMemoryState::Free, KMemoryPermission::None, - KMemoryAttribute::None, KMemoryState::Normal, - KMemoryPermission::ReadAndWrite, KMemoryAttribute::None); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - const VAddr end_addr{addr + size}; - ResultCode result{RESULT_SUCCESS}; - std::size_t mapped_size{}; - - // Verify that the region can be unmapped - block_manager->IterateForRange(addr, end_addr, [&](const KMemoryInfo& info) { - if (info.state == KMemoryState::Normal) { - if (info.attribute != KMemoryAttribute::None) { - result = ResultInvalidCurrentMemory; - return; - } - mapped_size += GetSizeInRange(info, addr, end_addr); - } else if (info.state != KMemoryState::Free) { - result = ResultInvalidCurrentMemory; - } - }); - - if (result.IsError()) { - return result; - } - - if (!mapped_size) { - return RESULT_SUCCESS; - } - - CASCADE_CODE(UnmapMemory(addr, size)); - - auto process{system.Kernel().CurrentProcess()}; - process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, mapped_size); - physical_memory_usage -= mapped_size; - - return RESULT_SUCCESS; -} - -ResultCode PageTable::UnmapMemory(VAddr addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - const VAddr end_addr{addr + size}; - ResultCode result{RESULT_SUCCESS}; - KPageLinkedList page_linked_list; - - // Unmap each region within the range - block_manager->IterateForRange(addr, end_addr, [&](const KMemoryInfo& info) { - if (info.state == KMemoryState::Normal) { - const std::size_t block_size{GetSizeInRange(info, addr, end_addr)}; - const std::size_t block_num_pages{block_size / PageSize}; - const VAddr block_addr{GetAddressInRange(info, addr)}; - - AddRegionToPages(block_addr, block_size / PageSize, page_linked_list); - - if (result = Operate(block_addr, block_num_pages, KMemoryPermission::None, - OperationType::Unmap); - result.IsError()) { - return; - } - } - }); - - if (result.IsError()) { - return result; - } - - const std::size_t num_pages{size / PageSize}; - system.Kernel().MemoryManager().Free(page_linked_list, num_pages, memory_pool); - - block_manager->Update(addr, num_pages, KMemoryState::Free); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::Map(VAddr dst_addr, VAddr src_addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - KMemoryState src_state{}; - CASCADE_CODE(CheckMemoryState( - &src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, - KMemoryState::FlagCanAlias, KMemoryPermission::Mask, KMemoryPermission::ReadAndWrite, - KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); - - if (IsRegionMapped(dst_addr, size)) { - return ResultInvalidCurrentMemory; - } - - KPageLinkedList page_linked_list; - const std::size_t num_pages{size / PageSize}; - - AddRegionToPages(src_addr, num_pages, page_linked_list); - - { - auto block_guard = detail::ScopeExit([&] { - Operate(src_addr, num_pages, KMemoryPermission::ReadAndWrite, - OperationType::ChangePermissions); - }); - - CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::None, - OperationType::ChangePermissions)); - CASCADE_CODE(MapPages(dst_addr, page_linked_list, KMemoryPermission::ReadAndWrite)); - - block_guard.Cancel(); - } - - block_manager->Update(src_addr, num_pages, src_state, KMemoryPermission::None, - KMemoryAttribute::Locked); - block_manager->Update(dst_addr, num_pages, KMemoryState::Stack, - KMemoryPermission::ReadAndWrite); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - KMemoryState src_state{}; - CASCADE_CODE(CheckMemoryState( - &src_state, nullptr, nullptr, src_addr, size, KMemoryState::FlagCanAlias, - KMemoryState::FlagCanAlias, KMemoryPermission::Mask, KMemoryPermission::None, - KMemoryAttribute::Mask, KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); - - KMemoryPermission dst_perm{}; - CASCADE_CODE(CheckMemoryState(nullptr, &dst_perm, nullptr, dst_addr, size, KMemoryState::All, - KMemoryState::Stack, KMemoryPermission::None, - KMemoryPermission::None, KMemoryAttribute::Mask, - KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); - - KPageLinkedList src_pages; - KPageLinkedList dst_pages; - const std::size_t num_pages{size / PageSize}; - - AddRegionToPages(src_addr, num_pages, src_pages); - AddRegionToPages(dst_addr, num_pages, dst_pages); - - if (!dst_pages.IsEqual(src_pages)) { - return ResultInvalidMemoryRange; - } - - { - auto block_guard = detail::ScopeExit([&] { MapPages(dst_addr, dst_pages, dst_perm); }); - - CASCADE_CODE(Operate(dst_addr, num_pages, KMemoryPermission::None, OperationType::Unmap)); - CASCADE_CODE(Operate(src_addr, num_pages, KMemoryPermission::ReadAndWrite, - OperationType::ChangePermissions)); - - block_guard.Cancel(); - } - - block_manager->Update(src_addr, num_pages, src_state, KMemoryPermission::ReadAndWrite); - block_manager->Update(dst_addr, num_pages, KMemoryState::Free); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::MapPages(VAddr addr, const KPageLinkedList& page_linked_list, - KMemoryPermission perm) { - VAddr cur_addr{addr}; - - for (const auto& node : page_linked_list.Nodes()) { - if (const auto result{ - Operate(cur_addr, node.GetNumPages(), perm, OperationType::Map, node.GetAddress())}; - result.IsError()) { - const std::size_t num_pages{(addr - cur_addr) / PageSize}; - - ASSERT(Operate(addr, num_pages, KMemoryPermission::None, OperationType::Unmap) - .IsSuccess()); - - return result; - } - - cur_addr += node.GetNumPages() * PageSize; - } - - return RESULT_SUCCESS; -} - -ResultCode PageTable::MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state, - KMemoryPermission perm) { - std::lock_guard lock{page_table_lock}; - - const std::size_t num_pages{page_linked_list.GetNumPages()}; - const std::size_t size{num_pages * PageSize}; - - if (!CanContain(addr, size, state)) { - return ResultInvalidCurrentMemory; - } - - if (IsRegionMapped(addr, num_pages * PageSize)) { - return ResultInvalidCurrentMemory; - } - - CASCADE_CODE(MapPages(addr, page_linked_list, perm)); - - block_manager->Update(addr, num_pages, state, perm); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::SetCodeMemoryPermission(VAddr addr, std::size_t size, - KMemoryPermission perm) { - - std::lock_guard lock{page_table_lock}; - - KMemoryState prev_state{}; - KMemoryPermission prev_perm{}; - - CASCADE_CODE(CheckMemoryState( - &prev_state, &prev_perm, nullptr, addr, size, KMemoryState::FlagCode, - KMemoryState::FlagCode, KMemoryPermission::None, KMemoryPermission::None, - KMemoryAttribute::Mask, KMemoryAttribute::None, KMemoryAttribute::IpcAndDeviceMapped)); - - KMemoryState state{prev_state}; - - // Ensure state is mutable if permission allows write - if ((perm & KMemoryPermission::Write) != KMemoryPermission::None) { - if (prev_state == KMemoryState::Code) { - state = KMemoryState::CodeData; - } else if (prev_state == KMemoryState::AliasCode) { - state = KMemoryState::AliasCodeData; - } else { - UNREACHABLE(); - } - } - - // Return early if there is nothing to change - if (state == prev_state && perm == prev_perm) { - return RESULT_SUCCESS; - } - - if ((prev_perm & KMemoryPermission::Execute) != (perm & KMemoryPermission::Execute)) { - // Memory execution state is changing, invalidate CPU cache range - system.InvalidateCpuInstructionCacheRange(addr, size); - } - - const std::size_t num_pages{size / PageSize}; - const OperationType operation{(perm & KMemoryPermission::Execute) != KMemoryPermission::None - ? OperationType::ChangePermissionsAndRefresh - : OperationType::ChangePermissions}; - - CASCADE_CODE(Operate(addr, num_pages, perm, operation)); - - block_manager->Update(addr, num_pages, state, perm); - - return RESULT_SUCCESS; -} - -KMemoryInfo PageTable::QueryInfoImpl(VAddr addr) { - std::lock_guard lock{page_table_lock}; - - return block_manager->FindBlock(addr).GetMemoryInfo(); -} - -KMemoryInfo PageTable::QueryInfo(VAddr addr) { - if (!Contains(addr, 1)) { - return {address_space_end, 0 - address_space_end, KMemoryState::Inaccessible, - KMemoryPermission::None, KMemoryAttribute::None, KMemoryPermission::None}; - } - - return QueryInfoImpl(addr); -} - -ResultCode PageTable::ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm) { - std::lock_guard lock{page_table_lock}; - - KMemoryState state{}; - KMemoryAttribute attribute{}; - - CASCADE_CODE(CheckMemoryState( - &state, nullptr, &attribute, addr, size, - KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, - KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, KMemoryPermission::Mask, - KMemoryPermission::ReadAndWrite, KMemoryAttribute::Mask, KMemoryAttribute::None, - KMemoryAttribute::IpcAndDeviceMapped)); - - block_manager->Update(addr, size / PageSize, state, perm, attribute | KMemoryAttribute::Locked); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::ResetTransferMemory(VAddr addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - KMemoryState state{}; - - CASCADE_CODE( - CheckMemoryState(&state, nullptr, nullptr, addr, size, - KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, - KMemoryState::FlagCanTransfer | KMemoryState::FlagReferenceCounted, - KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::Mask, - KMemoryAttribute::Locked, KMemoryAttribute::IpcAndDeviceMapped)); - - block_manager->Update(addr, size / PageSize, state, KMemoryPermission::ReadAndWrite); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask, - KMemoryAttribute value) { - std::lock_guard lock{page_table_lock}; - - KMemoryState state{}; - KMemoryPermission perm{}; - KMemoryAttribute attribute{}; - - CASCADE_CODE(CheckMemoryState( - &state, &perm, &attribute, addr, size, KMemoryState::FlagCanChangeAttribute, - KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None, - KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None, - KMemoryAttribute::DeviceSharedAndUncached)); - - attribute = attribute & ~mask; - attribute = attribute | (mask & value); - - block_manager->Update(addr, size / PageSize, state, perm, attribute); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::SetHeapCapacity(std::size_t new_heap_capacity) { - std::lock_guard lock{page_table_lock}; - heap_capacity = new_heap_capacity; - return RESULT_SUCCESS; -} - -ResultVal PageTable::SetHeapSize(std::size_t size) { - - if (size > heap_region_end - heap_region_start) { - return ResultOutOfMemory; - } - - const u64 previous_heap_size{GetHeapSize()}; - - UNIMPLEMENTED_IF_MSG(previous_heap_size > size, "Heap shrink is unimplemented"); - - // Increase the heap size - { - std::lock_guard lock{page_table_lock}; - - const u64 delta{size - previous_heap_size}; - - // Reserve memory for the heap extension. - KScopedResourceReservation memory_reservation( - system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory, - delta); - - if (!memory_reservation.Succeeded()) { - LOG_ERROR(Kernel, "Could not reserve heap extension of size {:X} bytes", delta); - return ResultResourceLimitedExceeded; - } - - KPageLinkedList page_linked_list; - const std::size_t num_pages{delta / PageSize}; - - CASCADE_CODE( - system.Kernel().MemoryManager().Allocate(page_linked_list, num_pages, memory_pool)); - - if (IsRegionMapped(current_heap_addr, delta)) { - return ResultInvalidCurrentMemory; - } - - CASCADE_CODE( - Operate(current_heap_addr, num_pages, page_linked_list, OperationType::MapGroup)); - - // Succeeded in allocation, commit the resource reservation - memory_reservation.Commit(); - - block_manager->Update(current_heap_addr, num_pages, KMemoryState::Normal, - KMemoryPermission::ReadAndWrite); - - current_heap_addr = heap_region_start + size; - } - - return MakeResult(heap_region_start); -} - -ResultVal PageTable::AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, - bool is_map_only, VAddr region_start, - std::size_t region_num_pages, KMemoryState state, - KMemoryPermission perm, PAddr map_addr) { - std::lock_guard lock{page_table_lock}; - - if (!CanContain(region_start, region_num_pages * PageSize, state)) { - return ResultInvalidCurrentMemory; - } - - if (region_num_pages <= needed_num_pages) { - return ResultOutOfMemory; - } - - const VAddr addr{ - AllocateVirtualMemory(region_start, region_num_pages, needed_num_pages, align)}; - if (!addr) { - return ResultOutOfMemory; - } - - if (is_map_only) { - CASCADE_CODE(Operate(addr, needed_num_pages, perm, OperationType::Map, map_addr)); - } else { - KPageLinkedList page_group; - CASCADE_CODE( - system.Kernel().MemoryManager().Allocate(page_group, needed_num_pages, memory_pool)); - CASCADE_CODE(Operate(addr, needed_num_pages, page_group, OperationType::MapGroup)); - } - - block_manager->Update(addr, needed_num_pages, state, perm); - - return MakeResult(addr); -} - -ResultCode PageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - KMemoryPermission perm{}; - if (const ResultCode result{CheckMemoryState( - nullptr, &perm, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute, - KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None, - KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None, - KMemoryAttribute::DeviceSharedAndUncached)}; - result.IsError()) { - return result; - } - - block_manager->UpdateLock( - addr, size / PageSize, - [](KMemoryBlockManager::iterator block, KMemoryPermission perm) { - block->ShareToDevice(perm); - }, - perm); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) { - std::lock_guard lock{page_table_lock}; - - KMemoryPermission perm{}; - if (const ResultCode result{CheckMemoryState( - nullptr, &perm, nullptr, addr, size, KMemoryState::FlagCanChangeAttribute, - KMemoryState::FlagCanChangeAttribute, KMemoryPermission::None, KMemoryPermission::None, - KMemoryAttribute::LockedAndIpcLocked, KMemoryAttribute::None, - KMemoryAttribute::DeviceSharedAndUncached)}; - result.IsError()) { - return result; - } - - block_manager->UpdateLock( - addr, size / PageSize, - [](KMemoryBlockManager::iterator block, KMemoryPermission perm) { - block->UnshareToDevice(perm); - }, - perm); - - return RESULT_SUCCESS; -} - -ResultCode PageTable::InitializeMemoryLayout(VAddr start, VAddr end) { - block_manager = std::make_unique(start, end); - - return RESULT_SUCCESS; -} - -bool PageTable::IsRegionMapped(VAddr address, u64 size) { - return CheckMemoryState(address, size, KMemoryState::All, KMemoryState::Free, - KMemoryPermission::Mask, KMemoryPermission::None, - KMemoryAttribute::Mask, KMemoryAttribute::None, - KMemoryAttribute::IpcAndDeviceMapped) - .IsError(); -} - -bool PageTable::IsRegionContiguous(VAddr addr, u64 size) const { - auto start_ptr = system.Memory().GetPointer(addr); - for (u64 offset{}; offset < size; offset += PageSize) { - if (start_ptr != system.Memory().GetPointer(addr + offset)) { - return false; - } - start_ptr += PageSize; - } - return true; -} - -void PageTable::AddRegionToPages(VAddr start, std::size_t num_pages, - KPageLinkedList& page_linked_list) { - VAddr addr{start}; - while (addr < start + (num_pages * PageSize)) { - const PAddr paddr{GetPhysicalAddr(addr)}; - if (!paddr) { - UNREACHABLE(); - } - page_linked_list.AddBlock(paddr, 1); - addr += PageSize; - } -} - -VAddr PageTable::AllocateVirtualMemory(VAddr start, std::size_t region_num_pages, - u64 needed_num_pages, std::size_t align) { - if (is_aslr_enabled) { - UNIMPLEMENTED(); - } - return block_manager->FindFreeArea(start, region_num_pages, needed_num_pages, align, 0, - IsKernel() ? 1 : 4); -} - -ResultCode PageTable::Operate(VAddr addr, std::size_t num_pages, const KPageLinkedList& page_group, - OperationType operation) { - std::lock_guard lock{page_table_lock}; - - ASSERT(Common::IsAligned(addr, PageSize)); - ASSERT(num_pages > 0); - ASSERT(num_pages == page_group.GetNumPages()); - - for (const auto& node : page_group.Nodes()) { - const std::size_t size{node.GetNumPages() * PageSize}; - - switch (operation) { - case OperationType::MapGroup: - system.Memory().MapMemoryRegion(page_table_impl, addr, size, node.GetAddress()); - break; - default: - UNREACHABLE(); - } - - addr += size; - } - - return RESULT_SUCCESS; -} - -ResultCode PageTable::Operate(VAddr addr, std::size_t num_pages, KMemoryPermission perm, - OperationType operation, PAddr map_addr) { - std::lock_guard lock{page_table_lock}; - - ASSERT(num_pages > 0); - ASSERT(Common::IsAligned(addr, PageSize)); - ASSERT(ContainsPages(addr, num_pages)); - - switch (operation) { - case OperationType::Unmap: - system.Memory().UnmapRegion(page_table_impl, addr, num_pages * PageSize); - break; - case OperationType::Map: { - ASSERT(map_addr); - ASSERT(Common::IsAligned(map_addr, PageSize)); - system.Memory().MapMemoryRegion(page_table_impl, addr, num_pages * PageSize, map_addr); - break; - } - case OperationType::ChangePermissions: - case OperationType::ChangePermissionsAndRefresh: - break; - default: - UNREACHABLE(); - } - return RESULT_SUCCESS; -} - -constexpr VAddr PageTable::GetRegionAddress(KMemoryState state) const { - switch (state) { - case KMemoryState::Free: - case KMemoryState::Kernel: - return address_space_start; - case KMemoryState::Normal: - return heap_region_start; - case KMemoryState::Ipc: - case KMemoryState::NonSecureIpc: - case KMemoryState::NonDeviceIpc: - return alias_region_start; - case KMemoryState::Stack: - return stack_region_start; - case KMemoryState::Io: - case KMemoryState::Static: - case KMemoryState::ThreadLocal: - return kernel_map_region_start; - case KMemoryState::Shared: - case KMemoryState::AliasCode: - case KMemoryState::AliasCodeData: - case KMemoryState::Transferred: - case KMemoryState::SharedTransferred: - case KMemoryState::SharedCode: - case KMemoryState::GeneratedCode: - case KMemoryState::CodeOut: - return alias_code_region_start; - case KMemoryState::Code: - case KMemoryState::CodeData: - return code_region_start; - default: - UNREACHABLE(); - return {}; - } -} - -constexpr std::size_t PageTable::GetRegionSize(KMemoryState state) const { - switch (state) { - case KMemoryState::Free: - case KMemoryState::Kernel: - return address_space_end - address_space_start; - case KMemoryState::Normal: - return heap_region_end - heap_region_start; - case KMemoryState::Ipc: - case KMemoryState::NonSecureIpc: - case KMemoryState::NonDeviceIpc: - return alias_region_end - alias_region_start; - case KMemoryState::Stack: - return stack_region_end - stack_region_start; - case KMemoryState::Io: - case KMemoryState::Static: - case KMemoryState::ThreadLocal: - return kernel_map_region_end - kernel_map_region_start; - case KMemoryState::Shared: - case KMemoryState::AliasCode: - case KMemoryState::AliasCodeData: - case KMemoryState::Transferred: - case KMemoryState::SharedTransferred: - case KMemoryState::SharedCode: - case KMemoryState::GeneratedCode: - case KMemoryState::CodeOut: - return alias_code_region_end - alias_code_region_start; - case KMemoryState::Code: - case KMemoryState::CodeData: - return code_region_end - code_region_start; - default: - UNREACHABLE(); - return {}; - } -} - -constexpr bool PageTable::CanContain(VAddr addr, std::size_t size, KMemoryState state) const { - const VAddr end{addr + size}; - const VAddr last{end - 1}; - const VAddr region_start{GetRegionAddress(state)}; - const std::size_t region_size{GetRegionSize(state)}; - const bool is_in_region{region_start <= addr && addr < end && - last <= region_start + region_size - 1}; - const bool is_in_heap{!(end <= heap_region_start || heap_region_end <= addr)}; - const bool is_in_alias{!(end <= alias_region_start || alias_region_end <= addr)}; - - switch (state) { - case KMemoryState::Free: - case KMemoryState::Kernel: - return is_in_region; - case KMemoryState::Io: - case KMemoryState::Static: - case KMemoryState::Code: - case KMemoryState::CodeData: - case KMemoryState::Shared: - case KMemoryState::AliasCode: - case KMemoryState::AliasCodeData: - case KMemoryState::Stack: - case KMemoryState::ThreadLocal: - case KMemoryState::Transferred: - case KMemoryState::SharedTransferred: - case KMemoryState::SharedCode: - case KMemoryState::GeneratedCode: - case KMemoryState::CodeOut: - return is_in_region && !is_in_heap && !is_in_alias; - case KMemoryState::Normal: - ASSERT(is_in_heap); - return is_in_region && !is_in_alias; - case KMemoryState::Ipc: - case KMemoryState::NonSecureIpc: - case KMemoryState::NonDeviceIpc: - ASSERT(is_in_alias); - return is_in_region && !is_in_heap; - default: - return false; - } -} - -constexpr ResultCode PageTable::CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, - KMemoryState state, KMemoryPermission perm_mask, - KMemoryPermission perm, KMemoryAttribute attr_mask, - KMemoryAttribute attr) const { - // Validate the states match expectation - if ((info.state & state_mask) != state) { - return ResultInvalidCurrentMemory; - } - if ((info.perm & perm_mask) != perm) { - return ResultInvalidCurrentMemory; - } - if ((info.attribute & attr_mask) != attr) { - return ResultInvalidCurrentMemory; - } - - return RESULT_SUCCESS; -} - -ResultCode PageTable::CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm, - KMemoryAttribute* out_attr, VAddr addr, std::size_t size, - KMemoryState state_mask, KMemoryState state, - KMemoryPermission perm_mask, KMemoryPermission perm, - KMemoryAttribute attr_mask, KMemoryAttribute attr, - KMemoryAttribute ignore_attr) { - std::lock_guard lock{page_table_lock}; - - // Get information about the first block - const VAddr last_addr{addr + size - 1}; - KMemoryBlockManager::const_iterator it{block_manager->FindIterator(addr)}; - KMemoryInfo info{it->GetMemoryInfo()}; - - // Validate all blocks in the range have correct state - const KMemoryState first_state{info.state}; - const KMemoryPermission first_perm{info.perm}; - const KMemoryAttribute first_attr{info.attribute}; - - while (true) { - // Validate the current block - if (!(info.state == first_state)) { - return ResultInvalidCurrentMemory; - } - if (!(info.perm == first_perm)) { - return ResultInvalidCurrentMemory; - } - if (!((info.attribute | static_cast(ignore_attr)) == - (first_attr | static_cast(ignore_attr)))) { - return ResultInvalidCurrentMemory; - } - - // Validate against the provided masks - CASCADE_CODE(CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr)); - - // Break once we're done - if (last_addr <= info.GetLastAddress()) { - break; - } - - // Advance our iterator - it++; - ASSERT(it != block_manager->cend()); - info = it->GetMemoryInfo(); - } - - // Write output state - if (out_state) { - *out_state = first_state; - } - if (out_perm) { - *out_perm = first_perm; - } - if (out_attr) { - *out_attr = first_attr & static_cast(~ignore_attr); - } - - return RESULT_SUCCESS; -} - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/memory/page_table.h b/src/core/hle/kernel/memory/page_table.h deleted file mode 100644 index a9e850e01..000000000 --- a/src/core/hle/kernel/memory/page_table.h +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include - -#include "common/common_types.h" -#include "common/page_table.h" -#include "core/file_sys/program_metadata.h" -#include "core/hle/kernel/k_memory_block.h" -#include "core/hle/kernel/k_memory_manager.h" -#include "core/hle/result.h" - -namespace Core { -class System; -} - -namespace Kernel { -class KMemoryBlockManager; -} - -namespace Kernel::Memory { - -class PageTable final : NonCopyable { -public: - explicit PageTable(Core::System& system); - - ResultCode InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr, - VAddr code_addr, std::size_t code_size, - KMemoryManager::Pool pool); - ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, KMemoryState state, - KMemoryPermission perm); - ResultCode MapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); - ResultCode UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, std::size_t size); - ResultCode MapPhysicalMemory(VAddr addr, std::size_t size); - ResultCode UnmapPhysicalMemory(VAddr addr, std::size_t size); - ResultCode UnmapMemory(VAddr addr, std::size_t size); - ResultCode Map(VAddr dst_addr, VAddr src_addr, std::size_t size); - ResultCode Unmap(VAddr dst_addr, VAddr src_addr, std::size_t size); - ResultCode MapPages(VAddr addr, KPageLinkedList& page_linked_list, KMemoryState state, - KMemoryPermission perm); - ResultCode SetCodeMemoryPermission(VAddr addr, std::size_t size, KMemoryPermission perm); - KMemoryInfo QueryInfo(VAddr addr); - ResultCode ReserveTransferMemory(VAddr addr, std::size_t size, KMemoryPermission perm); - ResultCode ResetTransferMemory(VAddr addr, std::size_t size); - ResultCode SetMemoryAttribute(VAddr addr, std::size_t size, KMemoryAttribute mask, - KMemoryAttribute value); - ResultCode SetHeapCapacity(std::size_t new_heap_capacity); - ResultVal SetHeapSize(std::size_t size); - ResultVal AllocateAndMapMemory(std::size_t needed_num_pages, std::size_t align, - bool is_map_only, VAddr region_start, - std::size_t region_num_pages, KMemoryState state, - KMemoryPermission perm, PAddr map_addr = 0); - ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size); - ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size); - - Common::PageTable& PageTableImpl() { - return page_table_impl; - } - - const Common::PageTable& PageTableImpl() const { - return page_table_impl; - } - -private: - enum class OperationType : u32 { - Map, - MapGroup, - Unmap, - ChangePermissions, - ChangePermissionsAndRefresh, - }; - - static constexpr KMemoryAttribute DefaultMemoryIgnoreAttr = KMemoryAttribute::DontCareMask | - KMemoryAttribute::IpcLocked | - KMemoryAttribute::DeviceShared; - - ResultCode InitializeMemoryLayout(VAddr start, VAddr end); - ResultCode MapPages(VAddr addr, const KPageLinkedList& page_linked_list, - KMemoryPermission perm); - void MapPhysicalMemory(KPageLinkedList& page_linked_list, VAddr start, VAddr end); - bool IsRegionMapped(VAddr address, u64 size); - bool IsRegionContiguous(VAddr addr, u64 size) const; - void AddRegionToPages(VAddr start, std::size_t num_pages, KPageLinkedList& page_linked_list); - KMemoryInfo QueryInfoImpl(VAddr addr); - VAddr AllocateVirtualMemory(VAddr start, std::size_t region_num_pages, u64 needed_num_pages, - std::size_t align); - ResultCode Operate(VAddr addr, std::size_t num_pages, const KPageLinkedList& page_group, - OperationType operation); - ResultCode Operate(VAddr addr, std::size_t num_pages, KMemoryPermission perm, - OperationType operation, PAddr map_addr = 0); - constexpr VAddr GetRegionAddress(KMemoryState state) const; - constexpr std::size_t GetRegionSize(KMemoryState state) const; - constexpr bool CanContain(VAddr addr, std::size_t size, KMemoryState state) const; - - constexpr ResultCode CheckMemoryState(const KMemoryInfo& info, KMemoryState state_mask, - KMemoryState state, KMemoryPermission perm_mask, - KMemoryPermission perm, KMemoryAttribute attr_mask, - KMemoryAttribute attr) const; - ResultCode CheckMemoryState(KMemoryState* out_state, KMemoryPermission* out_perm, - KMemoryAttribute* out_attr, VAddr addr, std::size_t size, - KMemoryState state_mask, KMemoryState state, - KMemoryPermission perm_mask, KMemoryPermission perm, - KMemoryAttribute attr_mask, KMemoryAttribute attr, - KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr); - ResultCode CheckMemoryState(VAddr addr, std::size_t size, KMemoryState state_mask, - KMemoryState state, KMemoryPermission perm_mask, - KMemoryPermission perm, KMemoryAttribute attr_mask, - KMemoryAttribute attr, - KMemoryAttribute ignore_attr = DefaultMemoryIgnoreAttr) { - return CheckMemoryState(nullptr, nullptr, nullptr, addr, size, state_mask, state, perm_mask, - perm, attr_mask, attr, ignore_attr); - } - - std::recursive_mutex page_table_lock; - std::unique_ptr block_manager; - -public: - constexpr VAddr GetAddressSpaceStart() const { - return address_space_start; - } - constexpr VAddr GetAddressSpaceEnd() const { - return address_space_end; - } - constexpr std::size_t GetAddressSpaceSize() const { - return address_space_end - address_space_start; - } - constexpr VAddr GetHeapRegionStart() const { - return heap_region_start; - } - constexpr VAddr GetHeapRegionEnd() const { - return heap_region_end; - } - constexpr std::size_t GetHeapRegionSize() const { - return heap_region_end - heap_region_start; - } - constexpr VAddr GetAliasRegionStart() const { - return alias_region_start; - } - constexpr VAddr GetAliasRegionEnd() const { - return alias_region_end; - } - constexpr std::size_t GetAliasRegionSize() const { - return alias_region_end - alias_region_start; - } - constexpr VAddr GetStackRegionStart() const { - return stack_region_start; - } - constexpr VAddr GetStackRegionEnd() const { - return stack_region_end; - } - constexpr std::size_t GetStackRegionSize() const { - return stack_region_end - stack_region_start; - } - constexpr VAddr GetKernelMapRegionStart() const { - return kernel_map_region_start; - } - constexpr VAddr GetKernelMapRegionEnd() const { - return kernel_map_region_end; - } - constexpr VAddr GetCodeRegionStart() const { - return code_region_start; - } - constexpr VAddr GetCodeRegionEnd() const { - return code_region_end; - } - constexpr VAddr GetAliasCodeRegionStart() const { - return alias_code_region_start; - } - constexpr VAddr GetAliasCodeRegionSize() const { - return alias_code_region_end - alias_code_region_start; - } - constexpr std::size_t GetAddressSpaceWidth() const { - return address_space_width; - } - constexpr std::size_t GetHeapSize() { - return current_heap_addr - heap_region_start; - } - constexpr std::size_t GetTotalHeapSize() { - return GetHeapSize() + physical_memory_usage; - } - constexpr bool IsInsideAddressSpace(VAddr address, std::size_t size) const { - return address_space_start <= address && address + size - 1 <= address_space_end - 1; - } - constexpr bool IsOutsideAliasRegion(VAddr address, std::size_t size) const { - return alias_region_start > address || address + size - 1 > alias_region_end - 1; - } - constexpr bool IsOutsideStackRegion(VAddr address, std::size_t size) const { - return stack_region_start > address || address + size - 1 > stack_region_end - 1; - } - constexpr bool IsInvalidRegion(VAddr address, std::size_t size) const { - return address + size - 1 > GetAliasCodeRegionStart() + GetAliasCodeRegionSize() - 1; - } - constexpr bool IsInsideHeapRegion(VAddr address, std::size_t size) const { - return address + size > heap_region_start && heap_region_end > address; - } - constexpr bool IsInsideAliasRegion(VAddr address, std::size_t size) const { - return address + size > alias_region_start && alias_region_end > address; - } - constexpr bool IsOutsideASLRRegion(VAddr address, std::size_t size) const { - if (IsInvalidRegion(address, size)) { - return true; - } - if (IsInsideHeapRegion(address, size)) { - return true; - } - if (IsInsideAliasRegion(address, size)) { - return true; - } - return {}; - } - constexpr bool IsInsideASLRRegion(VAddr address, std::size_t size) const { - return !IsOutsideASLRRegion(address, size); - } - constexpr PAddr GetPhysicalAddr(VAddr addr) { - return page_table_impl.backing_addr[addr >> PageBits] + addr; - } - -private: - constexpr bool Contains(VAddr addr) const { - return address_space_start <= addr && addr <= address_space_end - 1; - } - constexpr bool Contains(VAddr addr, std::size_t size) const { - return address_space_start <= addr && addr < addr + size && - addr + size - 1 <= address_space_end - 1; - } - constexpr bool IsKernel() const { - return is_kernel; - } - constexpr bool IsAslrEnabled() const { - return is_aslr_enabled; - } - - constexpr std::size_t GetNumGuardPages() const { - return IsKernel() ? 1 : 4; - } - - constexpr bool ContainsPages(VAddr addr, std::size_t num_pages) const { - return (address_space_start <= addr) && - (num_pages <= (address_space_end - address_space_start) / PageSize) && - (addr + num_pages * PageSize - 1 <= address_space_end - 1); - } - -private: - VAddr address_space_start{}; - VAddr address_space_end{}; - VAddr heap_region_start{}; - VAddr heap_region_end{}; - VAddr current_heap_end{}; - VAddr alias_region_start{}; - VAddr alias_region_end{}; - VAddr stack_region_start{}; - VAddr stack_region_end{}; - VAddr kernel_map_region_start{}; - VAddr kernel_map_region_end{}; - VAddr code_region_start{}; - VAddr code_region_end{}; - VAddr alias_code_region_start{}; - VAddr alias_code_region_end{}; - VAddr current_heap_addr{}; - - std::size_t heap_capacity{}; - std::size_t physical_memory_usage{}; - std::size_t max_heap_size{}; - std::size_t max_physical_memory_size{}; - std::size_t address_space_width{}; - - bool is_kernel{}; - bool is_aslr_enabled{}; - - KMemoryManager::Pool memory_pool{KMemoryManager::Pool::Application}; - - Common::PageTable page_table_impl; - - Core::System& system; -}; - -} // namespace Kernel::Memory diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index e0359eb3c..73b85d6f9 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -15,13 +15,13 @@ #include "core/file_sys/program_metadata.h" #include "core/hle/kernel/code_set.h" #include "core/hle/kernel/k_memory_block_manager.h" +#include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_slab_heap.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/lock.h" @@ -464,9 +464,9 @@ bool Process::IsSignaled() const { } Process::Process(Core::System& system) - : KSynchronizationObject{system.Kernel()}, - page_table{std::make_unique(system)}, handle_table{system.Kernel()}, - address_arbiter{system}, condition_var{system}, state_lock{system.Kernel()}, system{system} {} + : KSynchronizationObject{system.Kernel()}, page_table{std::make_unique(system)}, + handle_table{system.Kernel()}, address_arbiter{system}, condition_var{system}, + state_lock{system.Kernel()}, system{system} {} Process::~Process() = default; diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 320b0f347..45eefb90e 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -29,16 +29,13 @@ class ProgramMetadata; namespace Kernel { class KernelCore; +class KPageTable; class KResourceLimit; class KThread; class TLSPage; struct CodeSet; -namespace Memory { -class PageTable; -} - enum class MemoryRegion : u16 { APPLICATION = 1, SYSTEM = 2, @@ -104,12 +101,12 @@ public: } /// Gets a reference to the process' page table. - Memory::PageTable& PageTable() { + KPageTable& PageTable() { return *page_table; } /// Gets const a reference to the process' page table. - const Memory::PageTable& PageTable() const { + const KPageTable& PageTable() const { return *page_table; } @@ -385,7 +382,7 @@ private: ResultCode AllocateMainThreadStack(std::size_t stack_size); /// Memory manager for this process - std::unique_ptr page_table; + std::unique_ptr page_table; /// Current status of the process ProcessStatus status{}; diff --git a/src/core/hle/kernel/process_capability.cpp b/src/core/hle/kernel/process_capability.cpp index 7c567049e..3fc326eab 100644 --- a/src/core/hle/kernel/process_capability.cpp +++ b/src/core/hle/kernel/process_capability.cpp @@ -7,7 +7,7 @@ #include "common/bit_util.h" #include "common/logging/log.h" #include "core/hle/kernel/handle_table.h" -#include "core/hle/kernel/memory/page_table.h" +#include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/process_capability.h" #include "core/hle/kernel/svc_results.h" @@ -69,7 +69,7 @@ u32 GetFlagBitOffset(CapabilityType type) { ResultCode ProcessCapabilities::InitializeForKernelProcess(const u32* capabilities, std::size_t num_capabilities, - Memory::PageTable& page_table) { + KPageTable& page_table) { Clear(); // Allow all cores and priorities. @@ -82,7 +82,7 @@ ResultCode ProcessCapabilities::InitializeForKernelProcess(const u32* capabiliti ResultCode ProcessCapabilities::InitializeForUserProcess(const u32* capabilities, std::size_t num_capabilities, - Memory::PageTable& page_table) { + KPageTable& page_table) { Clear(); return ParseCapabilities(capabilities, num_capabilities, page_table); @@ -108,7 +108,7 @@ void ProcessCapabilities::InitializeForMetadatalessProcess() { ResultCode ProcessCapabilities::ParseCapabilities(const u32* capabilities, std::size_t num_capabilities, - Memory::PageTable& page_table) { + KPageTable& page_table) { u32 set_flags = 0; u32 set_svc_bits = 0; @@ -155,7 +155,7 @@ ResultCode ProcessCapabilities::ParseCapabilities(const u32* capabilities, } ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& set_svc_bits, - u32 flag, Memory::PageTable& page_table) { + u32 flag, KPageTable& page_table) { const auto type = GetCapabilityType(flag); if (type == CapabilityType::Unset) { @@ -293,12 +293,12 @@ ResultCode ProcessCapabilities::HandleSyscallFlags(u32& set_svc_bits, u32 flags) } ResultCode ProcessCapabilities::HandleMapPhysicalFlags(u32 flags, u32 size_flags, - Memory::PageTable& page_table) { + KPageTable& page_table) { // TODO(Lioncache): Implement once the memory manager can handle this. return RESULT_SUCCESS; } -ResultCode ProcessCapabilities::HandleMapIOFlags(u32 flags, Memory::PageTable& page_table) { +ResultCode ProcessCapabilities::HandleMapIOFlags(u32 flags, KPageTable& page_table) { // TODO(Lioncache): Implement once the memory manager can handle this. return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/process_capability.h b/src/core/hle/kernel/process_capability.h index ea9d12c16..73ad197fa 100644 --- a/src/core/hle/kernel/process_capability.h +++ b/src/core/hle/kernel/process_capability.h @@ -12,9 +12,7 @@ union ResultCode; namespace Kernel { -namespace Memory { -class PageTable; -} +class KPageTable; /// The possible types of programs that may be indicated /// by the program type capability descriptor. @@ -90,7 +88,7 @@ public: /// otherwise, an error code upon failure. /// ResultCode InitializeForKernelProcess(const u32* capabilities, std::size_t num_capabilities, - Memory::PageTable& page_table); + KPageTable& page_table); /// Initializes this process capabilities instance for a userland process. /// @@ -103,7 +101,7 @@ public: /// otherwise, an error code upon failure. /// ResultCode InitializeForUserProcess(const u32* capabilities, std::size_t num_capabilities, - Memory::PageTable& page_table); + KPageTable& page_table); /// Initializes this process capabilities instance for a process that does not /// have any metadata to parse. @@ -189,7 +187,7 @@ private: /// @return RESULT_SUCCESS if no errors occur, otherwise an error code. /// ResultCode ParseCapabilities(const u32* capabilities, std::size_t num_capabilities, - Memory::PageTable& page_table); + KPageTable& page_table); /// Attempts to parse a capability descriptor that is only represented by a /// single flag set. @@ -204,7 +202,7 @@ private: /// @return RESULT_SUCCESS if no errors occurred, otherwise an error code. /// ResultCode ParseSingleFlagCapability(u32& set_flags, u32& set_svc_bits, u32 flag, - Memory::PageTable& page_table); + KPageTable& page_table); /// Clears the internal state of this process capability instance. Necessary, /// to have a sane starting point due to us allowing running executables without @@ -228,10 +226,10 @@ private: ResultCode HandleSyscallFlags(u32& set_svc_bits, u32 flags); /// Handles flags related to mapping physical memory pages. - ResultCode HandleMapPhysicalFlags(u32 flags, u32 size_flags, Memory::PageTable& page_table); + ResultCode HandleMapPhysicalFlags(u32 flags, u32 size_flags, KPageTable& page_table); /// Handles flags related to mapping IO pages. - ResultCode HandleMapIOFlags(u32 flags, Memory::PageTable& page_table); + ResultCode HandleMapIOFlags(u32 flags, KPageTable& page_table); /// Handles flags related to the interrupt capability flags. ResultCode HandleInterruptFlags(u32 flags); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 4ffd65d33..cc8fa6576 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -29,6 +29,7 @@ #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_memory_block.h" #include "core/hle/kernel/k_memory_layout.h" +#include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/k_scheduler.h" @@ -39,7 +40,6 @@ #include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_writable_event.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/svc.h" @@ -67,8 +67,8 @@ constexpr bool IsValidAddressRange(VAddr address, u64 size) { // Helper function that performs the common sanity checks for svcMapMemory // and svcUnmapMemory. This is doable, as both functions perform their sanitizing // in the same order. -ResultCode MapUnmapMemorySanityChecks(const Memory::PageTable& manager, VAddr dst_addr, - VAddr src_addr, u64 size) { +ResultCode MapUnmapMemorySanityChecks(const KPageTable& manager, VAddr dst_addr, VAddr src_addr, + u64 size) { if (!Common::Is4KBAligned(dst_addr)) { LOG_ERROR(Kernel_SVC, "Destination address is not aligned to 4KB, 0x{:016X}", dst_addr); return ResultInvalidAddress; diff --git a/src/core/hle/kernel/transfer_memory.cpp b/src/core/hle/kernel/transfer_memory.cpp index b92559616..cad063e4d 100644 --- a/src/core/hle/kernel/transfer_memory.cpp +++ b/src/core/hle/kernel/transfer_memory.cpp @@ -2,9 +2,9 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/k_resource_limit.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/transfer_memory.h" #include "core/hle/result.h" diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index b42184a3b..d111c1357 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp @@ -11,8 +11,8 @@ #include "common/scope_exit.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/k_system_control.h" -#include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/svc_results.h" #include "core/hle/service/ldr/ldr.h" @@ -287,8 +287,7 @@ public: rb.Push(RESULT_SUCCESS); } - bool ValidateRegionForMap(Kernel::Memory::PageTable& page_table, VAddr start, - std::size_t size) const { + bool ValidateRegionForMap(Kernel::KPageTable& page_table, VAddr start, std::size_t size) const { constexpr std::size_t padding_size{4 * Kernel::PageSize}; const auto start_info{page_table.QueryInfo(start - 1)}; @@ -309,7 +308,7 @@ public: return (start + size + padding_size) <= (end_info.GetAddress() + end_info.GetSize()); } - VAddr GetRandomMapRegion(const Kernel::Memory::PageTable& page_table, std::size_t size) const { + VAddr GetRandomMapRegion(const Kernel::KPageTable& page_table, std::size_t size) const { VAddr addr{}; const std::size_t end_pages{(page_table.GetAliasCodeRegionSize() - size) >> Kernel::PageBits}; diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 79ebf11de..4a10211f6 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -12,8 +12,8 @@ #include "core/file_sys/control_metadata.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/romfs_factory.h" +#include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/kernel.h" -#include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/process.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/deconstructed_rom_directory.h" diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index dca1fcb18..f4a339390 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -10,7 +10,7 @@ #include "common/file_util.h" #include "common/logging/log.h" #include "core/hle/kernel/code_set.h" -#include "core/hle/kernel/memory/page_table.h" +#include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/process.h" #include "core/loader/elf.h" #include "core/memory.h" diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp index e162c4ff0..3f4ba233d 100644 --- a/src/core/loader/kip.cpp +++ b/src/core/loader/kip.cpp @@ -6,7 +6,7 @@ #include "core/file_sys/kernel_executable.h" #include "core/file_sys/program_metadata.h" #include "core/hle/kernel/code_set.h" -#include "core/hle/kernel/memory/page_table.h" +#include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/process.h" #include "core/loader/kip.h" #include "core/memory.h" diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index f976d0a9c..14618cb40 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -15,8 +15,8 @@ #include "core/file_sys/romfs_factory.h" #include "core/file_sys/vfs_offset.h" #include "core/hle/kernel/code_set.h" +#include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/process.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/nro.h" diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index ea347ea83..cbd048695 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -15,8 +15,8 @@ #include "core/core.h" #include "core/file_sys/patch_manager.h" #include "core/hle/kernel/code_set.h" +#include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/k_thread.h" -#include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/process.h" #include "core/loader/nso.h" #include "core/memory.h" diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 11609682a..b9dd3e275 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -16,7 +16,7 @@ #include "core/arm/arm_interface.h" #include "core/core.h" #include "core/device_memory.h" -#include "core/hle/kernel/memory/page_table.h" +#include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/physical_memory.h" #include "core/hle/kernel/process.h" #include "core/memory.h" diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp index 2dd0eb0f8..8eec567ab 100644 --- a/src/core/memory/cheat_engine.cpp +++ b/src/core/memory/cheat_engine.cpp @@ -10,7 +10,7 @@ #include "core/core_timing.h" #include "core/core_timing_util.h" #include "core/hardware_properties.h" -#include "core/hle/kernel/memory/page_table.h" +#include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/process.h" #include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/hid.h" diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp index f199c3362..74fb32814 100644 --- a/src/core/reporter.cpp +++ b/src/core/reporter.cpp @@ -17,7 +17,7 @@ #include "core/arm/arm_interface.h" #include "core/core.h" #include "core/hle/kernel/hle_ipc.h" -#include "core/hle/kernel/memory/page_table.h" +#include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/process.h" #include "core/hle/result.h" #include "core/memory.h" diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 44240a9c4..4eb71efbd 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp @@ -6,7 +6,7 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" -#include "core/hle/kernel/memory/page_table.h" +#include "core/hle/kernel/k_page_table.h" #include "core/hle/kernel/process.h" #include "core/memory.h" #include "video_core/gpu.h" -- cgit v1.2.3