summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Liam2024-01-07 13:59:48 -0500
committerGravatar Liam2024-01-12 18:31:33 -0500
commitf2fed21c1139c8d5c030bc5caee5c612dfe7979f (patch)
tree4051a2e4e1c34370fa259ecf36783b76ea66a56f /src
parentMerge pull request #12605 from german77/abstract (diff)
downloadyuzu-f2fed21c1139c8d5c030bc5caee5c612dfe7979f.tar.gz
yuzu-f2fed21c1139c8d5c030bc5caee5c612dfe7979f.tar.xz
yuzu-f2fed21c1139c8d5c030bc5caee5c612dfe7979f.zip
kernel: fix page leak on process termination
Diffstat (limited to 'src')
-rw-r--r--src/common/page_table.cpp34
-rw-r--r--src/core/hle/kernel/k_page_table_base.cpp75
-rw-r--r--src/core/hle/kernel/k_page_table_base.h1
-rw-r--r--src/core/hle/kernel/k_process.cpp6
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
6namespace Common { 7namespace Common {
7 8
@@ -11,29 +12,10 @@ PageTable::~PageTable() noexcept = default;
11 12
12bool PageTable::BeginTraversal(TraversalEntry* out_entry, TraversalContext* out_context, 13bool 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
39bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* context) const { 21bool 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
434Result 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
434void KPageTableBase::Finalize() { 505void 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}