mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-04-28 09:08:58 +02:00
[hle] reuse previous pagetable when initializing new processes on the same KProcessPageTable (#3891)
VirtualBuffer<> would be recreated each time due to the `operator=()` from the unique_ptr<> when initializing a new process, this change makes it so said thing doesn't happen (instead it resizes the existing buffer) this means that consecutive launches of the same process that happen to have the same process page table (or reuse it) will no longer incur a ctor/dtor path for VirtualBuffer and instead just resize the existing one Signed-off-by: lizzie <lizzie@eden-emu.dev> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3891 Reviewed-by: crueter <crueter@eden-emu.dev> Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
This commit is contained in:
parent
d33dc16820
commit
c172abfb53
5 changed files with 48 additions and 91 deletions
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
|
|
@ -142,10 +142,8 @@ struct PageTable {
|
|||
VirtualBuffer<PageEntryData> entries;
|
||||
static_assert(sizeof(PageEntryData) == 32);
|
||||
|
||||
std::size_t current_address_space_width_in_bits{};
|
||||
|
||||
u8* fastmem_arena{};
|
||||
|
||||
std::size_t current_address_space_width_in_bits{};
|
||||
std::size_t page_size{};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -21,7 +24,9 @@ public:
|
|||
// "with the current allocator");
|
||||
|
||||
constexpr VirtualBuffer() = default;
|
||||
explicit VirtualBuffer(std::size_t count) : alloc_size{count * sizeof(T)} {
|
||||
explicit VirtualBuffer(std::size_t count) noexcept
|
||||
: alloc_size{count * sizeof(T)}
|
||||
{
|
||||
base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
|
||||
}
|
||||
|
||||
|
|
@ -33,8 +38,8 @@ public:
|
|||
VirtualBuffer& operator=(const VirtualBuffer&) = delete;
|
||||
|
||||
VirtualBuffer(VirtualBuffer&& other) noexcept
|
||||
: alloc_size{std::exchange(other.alloc_size, 0)}, base_ptr{std::exchange(other.base_ptr),
|
||||
nullptr} {}
|
||||
: alloc_size{std::exchange(other.alloc_size, 0)}, base_ptr{std::exchange(other.base_ptr), nullptr}
|
||||
{}
|
||||
|
||||
VirtualBuffer& operator=(VirtualBuffer&& other) noexcept {
|
||||
alloc_size = std::exchange(other.alloc_size, 0);
|
||||
|
|
@ -42,35 +47,31 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
void resize(std::size_t count) {
|
||||
const auto new_size = count * sizeof(T);
|
||||
if (new_size == alloc_size) {
|
||||
return;
|
||||
void resize(std::size_t count) noexcept {
|
||||
if (auto const new_size = count * sizeof(T); new_size != alloc_size) {
|
||||
FreeMemoryPages(base_ptr, alloc_size);
|
||||
alloc_size = new_size;
|
||||
base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
|
||||
}
|
||||
|
||||
FreeMemoryPages(base_ptr, alloc_size);
|
||||
|
||||
alloc_size = new_size;
|
||||
base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const T& operator[](std::size_t index) const {
|
||||
[[nodiscard]] constexpr const T& operator[](std::size_t index) const noexcept {
|
||||
return base_ptr[index];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T& operator[](std::size_t index) {
|
||||
[[nodiscard]] constexpr T& operator[](std::size_t index) noexcept {
|
||||
return base_ptr[index];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr T* data() {
|
||||
[[nodiscard]] constexpr T* data() noexcept {
|
||||
return base_ptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const T* data() const {
|
||||
[[nodiscard]] constexpr const T* data() const noexcept {
|
||||
return base_ptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t size() const {
|
||||
[[nodiscard]] constexpr std::size_t size() const noexcept {
|
||||
return alloc_size / sizeof(T);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
|
|
@ -191,8 +191,7 @@ Result KPageTableBase::InitializeForKernel(bool is_64_bit, KVirtualAddress start
|
|||
m_cached_physical_heap_region = nullptr;
|
||||
|
||||
// Initialize our implementation.
|
||||
m_impl = std::make_unique<Common::PageTable>();
|
||||
m_impl->Resize(m_address_space_width, PageBits);
|
||||
m_impl.Resize(m_address_space_width, PageBits);
|
||||
|
||||
// Set the tracking memory.
|
||||
m_memory = std::addressof(memory);
|
||||
|
|
@ -202,13 +201,7 @@ Result KPageTableBase::InitializeForKernel(bool is_64_bit, KVirtualAddress start
|
|||
m_memory_block_slab_manager));
|
||||
}
|
||||
|
||||
Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool enable_aslr,
|
||||
bool enable_das_merge, bool from_back,
|
||||
KMemoryManager::Pool pool, KProcessAddress code_address,
|
||||
size_t code_size, KSystemResource* system_resource,
|
||||
KResourceLimit* resource_limit,
|
||||
Core::Memory::Memory& memory,
|
||||
KProcessAddress aslr_space_start) {
|
||||
Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource* system_resource, KResourceLimit* resource_limit, Core::Memory::Memory& memory, KProcessAddress aslr_space_start) {
|
||||
// Calculate region extents.
|
||||
const size_t as_width = GetAddressSpaceWidth(as_type);
|
||||
const KProcessAddress start = 0;
|
||||
|
|
@ -319,14 +312,10 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool
|
|||
// Determine random placements for each region.
|
||||
size_t alias_rnd = 0, heap_rnd = 0, stack_rnd = 0, kmap_rnd = 0;
|
||||
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;
|
||||
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.
|
||||
|
|
@ -445,15 +434,13 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool
|
|||
ASSERT(heap_last < kmap_start || kmap_last < heap_start);
|
||||
|
||||
// Initialize our implementation.
|
||||
m_impl = std::make_unique<Common::PageTable>();
|
||||
m_impl->Resize(m_address_space_width, PageBits);
|
||||
m_impl.Resize(m_address_space_width, PageBits);
|
||||
|
||||
// Set the tracking memory.
|
||||
m_memory = std::addressof(memory);
|
||||
|
||||
// Initialize our memory block manager.
|
||||
R_RETURN(m_memory_block_manager.Initialize(m_address_space_start, m_address_space_end,
|
||||
m_memory_block_slab_manager));
|
||||
R_RETURN(m_memory_block_manager.Initialize(m_address_space_start, m_address_space_end, m_memory_block_slab_manager));
|
||||
}
|
||||
|
||||
Result KPageTableBase::FinalizeProcess() {
|
||||
|
|
@ -476,7 +463,7 @@ void KPageTableBase::Finalize() {
|
|||
this->FinalizeProcess();
|
||||
|
||||
auto BlockCallback = [&](KProcessAddress addr, u64 size) {
|
||||
if (m_impl->fastmem_arena) {
|
||||
if (m_impl.fastmem_arena) {
|
||||
m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false);
|
||||
}
|
||||
|
||||
|
|
@ -514,9 +501,6 @@ void KPageTableBase::Finalize() {
|
|||
m_resource_limit->Release(Svc::LimitableResource::PhysicalMemoryMax,
|
||||
m_mapped_ipc_server_memory);
|
||||
}
|
||||
|
||||
// Close the backing page table, as the destructor is not called for guest objects.
|
||||
m_impl.reset();
|
||||
}
|
||||
|
||||
KProcessAddress KPageTableBase::GetRegionAddress(Svc::MemoryState state) const {
|
||||
|
|
@ -2349,7 +2333,7 @@ Result KPageTableBase::QueryPhysicalAddress(Svc::lp64::PhysicalMemoryInfo* out,
|
|||
TraversalContext context;
|
||||
TraversalEntry next_entry;
|
||||
bool traverse_valid =
|
||||
m_impl->BeginTraversal(std::addressof(next_entry), std::addressof(context), virt_addr);
|
||||
m_impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), virt_addr);
|
||||
R_UNLESS(traverse_valid, ResultInvalidCurrentMemory);
|
||||
|
||||
// Set tracking variables.
|
||||
|
|
@ -2360,7 +2344,7 @@ Result KPageTableBase::QueryPhysicalAddress(Svc::lp64::PhysicalMemoryInfo* out,
|
|||
while (true) {
|
||||
// Continue the traversal.
|
||||
traverse_valid =
|
||||
m_impl->ContinueTraversal(std::addressof(next_entry), std::addressof(context));
|
||||
m_impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context));
|
||||
if (!traverse_valid) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -5730,14 +5714,14 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
|||
this->MakePageGroup(pages_to_close, virt_addr, num_pages);
|
||||
|
||||
// Unmap.
|
||||
m_memory->UnmapRegion(*m_impl, virt_addr, num_pages * PageSize, separate_heap);
|
||||
m_memory->UnmapRegion(m_impl, virt_addr, num_pages * PageSize, separate_heap);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
case OperationType::Map: {
|
||||
ASSERT(virt_addr != 0);
|
||||
ASSERT(Common::IsAligned(GetInteger(virt_addr), PageSize));
|
||||
m_memory->MapMemoryRegion(*m_impl, virt_addr, num_pages * PageSize, phys_addr,
|
||||
m_memory->MapMemoryRegion(m_impl, virt_addr, num_pages * PageSize, phys_addr,
|
||||
ConvertToMemoryPermission(properties.perm), false);
|
||||
|
||||
// Open references to pages, if we should.
|
||||
|
|
@ -5754,7 +5738,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
|||
case OperationType::ChangePermissions:
|
||||
case OperationType::ChangePermissionsAndRefresh:
|
||||
case OperationType::ChangePermissionsAndRefreshAndFlush: {
|
||||
m_memory->ProtectRegion(*m_impl, virt_addr, num_pages * PageSize,
|
||||
m_memory->ProtectRegion(m_impl, virt_addr, num_pages * PageSize,
|
||||
ConvertToMemoryPermission(properties.perm));
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
|
@ -5788,7 +5772,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a
|
|||
const size_t size{node.GetNumPages() * PageSize};
|
||||
|
||||
// Map the pages.
|
||||
m_memory->MapMemoryRegion(*m_impl, virt_addr, size, node.GetAddress(),
|
||||
m_memory->MapMemoryRegion(m_impl, virt_addr, size, node.GetAddress(),
|
||||
ConvertToMemoryPermission(properties.perm), separate_heap);
|
||||
|
||||
virt_addr += size;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
|
|
@ -215,7 +215,7 @@ private:
|
|||
mutable KLightLock m_general_lock;
|
||||
mutable KLightLock m_map_physical_memory_lock;
|
||||
KLightLock m_device_map_lock;
|
||||
std::unique_ptr<Common::PageTable> m_impl{};
|
||||
Common::PageTable m_impl{};
|
||||
Core::Memory::Memory* m_memory{};
|
||||
KMemoryBlockManager m_memory_block_manager{};
|
||||
u32 m_allocate_option{};
|
||||
|
|
@ -300,26 +300,11 @@ public:
|
|||
}
|
||||
|
||||
public:
|
||||
Core::Memory::Memory& GetMemory() {
|
||||
return *m_memory;
|
||||
}
|
||||
|
||||
Core::Memory::Memory& GetMemory() const {
|
||||
return *m_memory;
|
||||
}
|
||||
|
||||
Common::PageTable& GetImpl() {
|
||||
return *m_impl;
|
||||
}
|
||||
|
||||
Common::PageTable& GetImpl() const {
|
||||
return *m_impl;
|
||||
}
|
||||
|
||||
size_t GetNumGuardPages() const {
|
||||
return this->IsKernel() ? 1 : 4;
|
||||
}
|
||||
|
||||
[[nodiscard]] Core::Memory::Memory& GetMemory() noexcept { return *m_memory; }
|
||||
[[nodiscard]] Core::Memory::Memory const& GetMemory() const noexcept { return *m_memory; }
|
||||
[[nodiscard]] Common::PageTable& GetImpl() noexcept { return m_impl; }
|
||||
[[nodiscard]] Common::PageTable const& GetImpl() const noexcept { return m_impl; }
|
||||
[[nodiscard]] size_t GetNumGuardPages() const noexcept { return this->IsKernel() ? 1 : 4; }
|
||||
protected:
|
||||
// NOTE: These three functions (Operate, Operate, FinalizeUpdate) are virtual functions
|
||||
// in Nintendo's kernel. We devirtualize them, since KPageTable is the only derived
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
|
|
@ -33,21 +33,10 @@ public:
|
|||
m_page_table.Finalize();
|
||||
}
|
||||
|
||||
Core::Memory::Memory& GetMemory() {
|
||||
return m_page_table.GetMemory();
|
||||
}
|
||||
|
||||
Core::Memory::Memory& GetMemory() const {
|
||||
return m_page_table.GetMemory();
|
||||
}
|
||||
|
||||
Common::PageTable& GetImpl() {
|
||||
return m_page_table.GetImpl();
|
||||
}
|
||||
|
||||
Common::PageTable& GetImpl() const {
|
||||
return m_page_table.GetImpl();
|
||||
}
|
||||
[[nodiscard]] Core::Memory::Memory& GetMemory() noexcept { return m_page_table.GetMemory(); }
|
||||
[[nodiscard]] Core::Memory::Memory const& GetMemory() const noexcept { return m_page_table.GetMemory(); }
|
||||
[[nodiscard]] Common::PageTable& GetImpl() noexcept { return m_page_table.GetImpl(); }
|
||||
[[nodiscard]] Common::PageTable const& GetImpl() const noexcept { return m_page_table.GetImpl(); }
|
||||
|
||||
size_t GetNumGuardPages() const {
|
||||
return m_page_table.GetNumGuardPages();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue