diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/kernel/k_memory_block_manager.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_memory_block_manager.h | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_page_table_base.cpp | 73 |
3 files changed, 18 insertions, 63 deletions
diff --git a/src/core/hle/kernel/k_memory_block_manager.cpp b/src/core/hle/kernel/k_memory_block_manager.cpp index 58a1e7216..f08a6e448 100644 --- a/src/core/hle/kernel/k_memory_block_manager.cpp +++ b/src/core/hle/kernel/k_memory_block_manager.cpp | |||
| @@ -28,14 +28,14 @@ Result KMemoryBlockManager::Initialize(KProcessAddress st, KProcessAddress nd, | |||
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | void KMemoryBlockManager::Finalize(KMemoryBlockSlabManager* slab_manager, | 30 | void KMemoryBlockManager::Finalize(KMemoryBlockSlabManager* slab_manager, |
| 31 | HostUnmapCallback&& host_unmap_callback) { | 31 | BlockCallback&& block_callback) { |
| 32 | // Erase every block until we have none left. | 32 | // Erase every block until we have none left. |
| 33 | auto it = m_memory_block_tree.begin(); | 33 | auto it = m_memory_block_tree.begin(); |
| 34 | while (it != m_memory_block_tree.end()) { | 34 | while (it != m_memory_block_tree.end()) { |
| 35 | KMemoryBlock* block = std::addressof(*it); | 35 | KMemoryBlock* block = std::addressof(*it); |
| 36 | it = m_memory_block_tree.erase(it); | 36 | it = m_memory_block_tree.erase(it); |
| 37 | block_callback(block->GetAddress(), block->GetSize()); | ||
| 37 | slab_manager->Free(block); | 38 | slab_manager->Free(block); |
| 38 | host_unmap_callback(block->GetAddress(), block->GetSize()); | ||
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | ASSERT(m_memory_block_tree.empty()); | 41 | ASSERT(m_memory_block_tree.empty()); |
diff --git a/src/core/hle/kernel/k_memory_block_manager.h b/src/core/hle/kernel/k_memory_block_manager.h index cb7b6f430..377628504 100644 --- a/src/core/hle/kernel/k_memory_block_manager.h +++ b/src/core/hle/kernel/k_memory_block_manager.h | |||
| @@ -85,11 +85,11 @@ public: | |||
| 85 | public: | 85 | public: |
| 86 | KMemoryBlockManager(); | 86 | KMemoryBlockManager(); |
| 87 | 87 | ||
| 88 | using HostUnmapCallback = std::function<void(Common::ProcessAddress, u64)>; | 88 | using BlockCallback = std::function<void(Common::ProcessAddress, u64)>; |
| 89 | 89 | ||
| 90 | Result Initialize(KProcessAddress st, KProcessAddress nd, | 90 | Result Initialize(KProcessAddress st, KProcessAddress nd, |
| 91 | KMemoryBlockSlabManager* slab_manager); | 91 | KMemoryBlockSlabManager* slab_manager); |
| 92 | void Finalize(KMemoryBlockSlabManager* slab_manager, HostUnmapCallback&& host_unmap_callback); | 92 | void Finalize(KMemoryBlockSlabManager* slab_manager, BlockCallback&& block_callback); |
| 93 | 93 | ||
| 94 | iterator end() { | 94 | iterator end() { |
| 95 | return m_memory_block_tree.end(); | 95 | return m_memory_block_tree.end(); |
diff --git a/src/core/hle/kernel/k_page_table_base.cpp b/src/core/hle/kernel/k_page_table_base.cpp index f01eaa164..3f0a39d33 100644 --- a/src/core/hle/kernel/k_page_table_base.cpp +++ b/src/core/hle/kernel/k_page_table_base.cpp | |||
| @@ -435,69 +435,14 @@ Result KPageTableBase::FinalizeProcess() { | |||
| 435 | // Only process tables should be finalized. | 435 | // Only process tables should be finalized. |
| 436 | ASSERT(!this->IsKernel()); | 436 | ASSERT(!this->IsKernel()); |
| 437 | 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. | 438 | // NOTE: Here Nintendo calls an unknown OnFinalize function. |
| 442 | // this->OnFinalize(); | 439 | // this->OnFinalize(); |
| 443 | 440 | ||
| 444 | // NOTE: Here Nintendo calls a second unknown OnFinalize function. | 441 | // NOTE: Here Nintendo calls a second unknown OnFinalize function. |
| 445 | // this->OnFinalize2(); | 442 | // this->OnFinalize2(); |
| 446 | 443 | ||
| 447 | // Get implementation objects. | 444 | // NOTE: Here Nintendo does a page table walk to discover heap pages to free. |
| 448 | auto& impl = this->GetImpl(); | 445 | // We will use the block manager finalization below to free them. |
| 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 | 446 | ||
| 502 | R_SUCCEED(); | 447 | R_SUCCEED(); |
| 503 | } | 448 | } |
| @@ -505,14 +450,24 @@ Result KPageTableBase::FinalizeProcess() { | |||
| 505 | void KPageTableBase::Finalize() { | 450 | void KPageTableBase::Finalize() { |
| 506 | this->FinalizeProcess(); | 451 | this->FinalizeProcess(); |
| 507 | 452 | ||
| 508 | auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) { | 453 | auto BlockCallback = [&](KProcessAddress addr, u64 size) { |
| 509 | if (m_impl->fastmem_arena) { | 454 | if (m_impl->fastmem_arena) { |
| 510 | m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false); | 455 | m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false); |
| 511 | } | 456 | } |
| 457 | |||
| 458 | // Get physical pages. | ||
| 459 | KPageGroup pg(m_kernel, m_block_info_manager); | ||
| 460 | this->MakePageGroup(pg, addr, size / PageSize); | ||
| 461 | |||
| 462 | // Free the pages. | ||
| 463 | pg.CloseAndReset(); | ||
| 512 | }; | 464 | }; |
| 513 | 465 | ||
| 514 | // Finalize memory blocks. | 466 | // Finalize memory blocks. |
| 515 | m_memory_block_manager.Finalize(m_memory_block_slab_manager, std::move(HostUnmapCallback)); | 467 | { |
| 468 | KScopedLightLock lk(m_general_lock); | ||
| 469 | m_memory_block_manager.Finalize(m_memory_block_slab_manager, std::move(BlockCallback)); | ||
| 470 | } | ||
| 516 | 471 | ||
| 517 | // Free any unsafe mapped memory. | 472 | // Free any unsafe mapped memory. |
| 518 | if (m_mapped_unsafe_physical_memory) { | 473 | if (m_mapped_unsafe_physical_memory) { |