diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/common/page_table.cpp | 34 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_page_table_base.cpp | 75 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_page_table_base.h | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_process.cpp | 6 |
4 files changed, 91 insertions, 25 deletions
diff --git a/src/common/page_table.cpp b/src/common/page_table.cpp index 166dc3dce..85dc18c11 100644 --- a/src/common/page_table.cpp +++ b/src/common/page_table.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include "common/page_table.h" | 4 | #include "common/page_table.h" |
| 5 | #include "common/scope_exit.h" | ||
| 5 | 6 | ||
| 6 | namespace Common { | 7 | namespace Common { |
| 7 | 8 | ||
| @@ -11,29 +12,10 @@ PageTable::~PageTable() noexcept = default; | |||
| 11 | 12 | ||
| 12 | bool PageTable::BeginTraversal(TraversalEntry* out_entry, TraversalContext* out_context, | 13 | bool PageTable::BeginTraversal(TraversalEntry* out_entry, TraversalContext* out_context, |
| 13 | Common::ProcessAddress address) const { | 14 | Common::ProcessAddress address) const { |
| 14 | // Setup invalid defaults. | 15 | out_context->next_offset = GetInteger(address); |
| 15 | out_entry->phys_addr = 0; | 16 | out_context->next_page = address / page_size; |
| 16 | out_entry->block_size = page_size; | ||
| 17 | out_context->next_page = 0; | ||
| 18 | |||
| 19 | // Validate that we can read the actual entry. | ||
| 20 | const auto page = address / page_size; | ||
| 21 | if (page >= backing_addr.size()) { | ||
| 22 | return false; | ||
| 23 | } | ||
| 24 | |||
| 25 | // Validate that the entry is mapped. | ||
| 26 | const auto phys_addr = backing_addr[page]; | ||
| 27 | if (phys_addr == 0) { | ||
| 28 | return false; | ||
| 29 | } | ||
| 30 | 17 | ||
| 31 | // Populate the results. | 18 | return this->ContinueTraversal(out_entry, out_context); |
| 32 | out_entry->phys_addr = phys_addr + GetInteger(address); | ||
| 33 | out_context->next_page = page + 1; | ||
| 34 | out_context->next_offset = GetInteger(address) + page_size; | ||
| 35 | |||
| 36 | return true; | ||
| 37 | } | 19 | } |
| 38 | 20 | ||
| 39 | bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* context) const { | 21 | bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* context) const { |
| @@ -41,6 +23,12 @@ bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* c | |||
| 41 | out_entry->phys_addr = 0; | 23 | out_entry->phys_addr = 0; |
| 42 | out_entry->block_size = page_size; | 24 | out_entry->block_size = page_size; |
| 43 | 25 | ||
| 26 | // Regardless of whether the page was mapped, advance on exit. | ||
| 27 | SCOPE_EXIT({ | ||
| 28 | context->next_page += 1; | ||
| 29 | context->next_offset += page_size; | ||
| 30 | }); | ||
| 31 | |||
| 44 | // Validate that we can read the actual entry. | 32 | // Validate that we can read the actual entry. |
| 45 | const auto page = context->next_page; | 33 | const auto page = context->next_page; |
| 46 | if (page >= backing_addr.size()) { | 34 | if (page >= backing_addr.size()) { |
| @@ -55,8 +43,6 @@ bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* c | |||
| 55 | 43 | ||
| 56 | // Populate the results. | 44 | // Populate the results. |
| 57 | out_entry->phys_addr = phys_addr + context->next_offset; | 45 | out_entry->phys_addr = phys_addr + context->next_offset; |
| 58 | context->next_page = page + 1; | ||
| 59 | context->next_offset += page_size; | ||
| 60 | 46 | ||
| 61 | return true; | 47 | return true; |
| 62 | } | 48 | } |
diff --git a/src/core/hle/kernel/k_page_table_base.cpp b/src/core/hle/kernel/k_page_table_base.cpp index 73fbda331..f01eaa164 100644 --- a/src/core/hle/kernel/k_page_table_base.cpp +++ b/src/core/hle/kernel/k_page_table_base.cpp | |||
| @@ -431,9 +431,82 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool | |||
| 431 | m_memory_block_slab_manager)); | 431 | m_memory_block_slab_manager)); |
| 432 | } | 432 | } |
| 433 | 433 | ||
| 434 | Result KPageTableBase::FinalizeProcess() { | ||
| 435 | // Only process tables should be finalized. | ||
| 436 | ASSERT(!this->IsKernel()); | ||
| 437 | |||
| 438 | // HLE processes don't have memory mapped. | ||
| 439 | R_SUCCEED_IF(m_impl == nullptr); | ||
| 440 | |||
| 441 | // NOTE: Here Nintendo calls an unknown OnFinalize function. | ||
| 442 | // this->OnFinalize(); | ||
| 443 | |||
| 444 | // NOTE: Here Nintendo calls a second unknown OnFinalize function. | ||
| 445 | // this->OnFinalize2(); | ||
| 446 | |||
| 447 | // Get implementation objects. | ||
| 448 | auto& impl = this->GetImpl(); | ||
| 449 | auto& mm = m_kernel.MemoryManager(); | ||
| 450 | |||
| 451 | // Traverse, freeing all pages. | ||
| 452 | { | ||
| 453 | // Get the address space size. | ||
| 454 | const size_t as_size = this->GetAddressSpaceSize(); | ||
| 455 | |||
| 456 | // Begin the traversal. | ||
| 457 | TraversalContext context; | ||
| 458 | TraversalEntry cur_entry = { | ||
| 459 | .phys_addr = 0, | ||
| 460 | .block_size = 0, | ||
| 461 | }; | ||
| 462 | |||
| 463 | bool cur_valid = false; | ||
| 464 | TraversalEntry next_entry; | ||
| 465 | bool next_valid; | ||
| 466 | size_t tot_size = 0; | ||
| 467 | |||
| 468 | next_valid = impl.BeginTraversal(std::addressof(next_entry), std::addressof(context), | ||
| 469 | this->GetAddressSpaceStart()); | ||
| 470 | |||
| 471 | // Iterate over entries. | ||
| 472 | while (true) { | ||
| 473 | if ((!next_valid && !cur_valid) || | ||
| 474 | (next_valid && cur_valid && | ||
| 475 | next_entry.phys_addr == cur_entry.phys_addr + cur_entry.block_size)) { | ||
| 476 | cur_entry.block_size += next_entry.block_size; | ||
| 477 | } else { | ||
| 478 | if (cur_valid && IsHeapPhysicalAddressForFinalize(cur_entry.phys_addr)) { | ||
| 479 | mm.Close(cur_entry.phys_addr, cur_entry.block_size / PageSize); | ||
| 480 | } | ||
| 481 | |||
| 482 | // Update tracking variables. | ||
| 483 | tot_size += cur_entry.block_size; | ||
| 484 | cur_entry = next_entry; | ||
| 485 | cur_valid = next_valid; | ||
| 486 | } | ||
| 487 | |||
| 488 | if (cur_entry.block_size + tot_size >= as_size) { | ||
| 489 | break; | ||
| 490 | } | ||
| 491 | |||
| 492 | next_valid = | ||
| 493 | impl.ContinueTraversal(std::addressof(next_entry), std::addressof(context)); | ||
| 494 | } | ||
| 495 | |||
| 496 | // Handle the last block. | ||
| 497 | if (cur_valid && IsHeapPhysicalAddressForFinalize(cur_entry.phys_addr)) { | ||
| 498 | mm.Close(cur_entry.phys_addr, cur_entry.block_size / PageSize); | ||
| 499 | } | ||
| 500 | } | ||
| 501 | |||
| 502 | R_SUCCEED(); | ||
| 503 | } | ||
| 504 | |||
| 434 | void KPageTableBase::Finalize() { | 505 | void KPageTableBase::Finalize() { |
| 506 | this->FinalizeProcess(); | ||
| 507 | |||
| 435 | auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) { | 508 | auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) { |
| 436 | if (Settings::IsFastmemEnabled()) { | 509 | if (m_impl->fastmem_arena) { |
| 437 | m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false); | 510 | m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false); |
| 438 | } | 511 | } |
| 439 | }; | 512 | }; |
diff --git a/src/core/hle/kernel/k_page_table_base.h b/src/core/hle/kernel/k_page_table_base.h index 077cafc96..748419f86 100644 --- a/src/core/hle/kernel/k_page_table_base.h +++ b/src/core/hle/kernel/k_page_table_base.h | |||
| @@ -241,6 +241,7 @@ public: | |||
| 241 | KResourceLimit* resource_limit, Core::Memory::Memory& memory, | 241 | KResourceLimit* resource_limit, Core::Memory::Memory& memory, |
| 242 | KProcessAddress aslr_space_start); | 242 | KProcessAddress aslr_space_start); |
| 243 | 243 | ||
| 244 | Result FinalizeProcess(); | ||
| 244 | void Finalize(); | 245 | void Finalize(); |
| 245 | 246 | ||
| 246 | bool IsKernel() const { | 247 | bool IsKernel() const { |
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 068e71dff..ae332a550 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp | |||
| @@ -171,6 +171,12 @@ void KProcess::Finalize() { | |||
| 171 | m_resource_limit->Close(); | 171 | m_resource_limit->Close(); |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | // Clear expensive resources, as the destructor is not called for guest objects. | ||
| 175 | for (auto& interface : m_arm_interfaces) { | ||
| 176 | interface.reset(); | ||
| 177 | } | ||
| 178 | m_exclusive_monitor.reset(); | ||
| 179 | |||
| 174 | // Perform inherited finalization. | 180 | // Perform inherited finalization. |
| 175 | KSynchronizationObject::Finalize(); | 181 | KSynchronizationObject::Finalize(); |
| 176 | } | 182 | } |