mirror of
				https://git.suyu.dev/suyu/suyu.git
				synced 2025-10-31 06:46:40 +08:00 
			
		
		
		
	Merge pull request #12611 from liamwhite/resource-management-is-hard
kernel: fix resource management issues
This commit is contained in:
		
						commit
						0127cec371
					
				| @ -2,6 +2,7 @@ | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later
 | ||||
| 
 | ||||
| #include "common/page_table.h" | ||||
| #include "common/scope_exit.h" | ||||
| 
 | ||||
| namespace Common { | ||||
| 
 | ||||
| @ -11,29 +12,10 @@ PageTable::~PageTable() noexcept = default; | ||||
| 
 | ||||
| bool PageTable::BeginTraversal(TraversalEntry* out_entry, TraversalContext* out_context, | ||||
|                                Common::ProcessAddress address) const { | ||||
|     // Setup invalid defaults.
 | ||||
|     out_entry->phys_addr = 0; | ||||
|     out_entry->block_size = page_size; | ||||
|     out_context->next_page = 0; | ||||
|     out_context->next_offset = GetInteger(address); | ||||
|     out_context->next_page = address / page_size; | ||||
| 
 | ||||
|     // Validate that we can read the actual entry.
 | ||||
|     const auto page = address / page_size; | ||||
|     if (page >= backing_addr.size()) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     // Validate that the entry is mapped.
 | ||||
|     const auto phys_addr = backing_addr[page]; | ||||
|     if (phys_addr == 0) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     // Populate the results.
 | ||||
|     out_entry->phys_addr = phys_addr + GetInteger(address); | ||||
|     out_context->next_page = page + 1; | ||||
|     out_context->next_offset = GetInteger(address) + page_size; | ||||
| 
 | ||||
|     return true; | ||||
|     return this->ContinueTraversal(out_entry, out_context); | ||||
| } | ||||
| 
 | ||||
| bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* context) const { | ||||
| @ -41,6 +23,12 @@ bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* c | ||||
|     out_entry->phys_addr = 0; | ||||
|     out_entry->block_size = page_size; | ||||
| 
 | ||||
|     // Regardless of whether the page was mapped, advance on exit.
 | ||||
|     SCOPE_EXIT({ | ||||
|         context->next_page += 1; | ||||
|         context->next_offset += page_size; | ||||
|     }); | ||||
| 
 | ||||
|     // Validate that we can read the actual entry.
 | ||||
|     const auto page = context->next_page; | ||||
|     if (page >= backing_addr.size()) { | ||||
| @ -55,8 +43,6 @@ bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* c | ||||
| 
 | ||||
|     // Populate the results.
 | ||||
|     out_entry->phys_addr = phys_addr + context->next_offset; | ||||
|     context->next_page = page + 1; | ||||
|     context->next_offset += page_size; | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
|  | ||||
| @ -114,7 +114,7 @@ public: | ||||
|     } | ||||
| 
 | ||||
|     Kernel::KThread* GetActiveThread() override { | ||||
|         return state->active_thread; | ||||
|         return state->active_thread.GetPointerUnsafe(); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
| @ -147,11 +147,14 @@ private: | ||||
| 
 | ||||
|         std::scoped_lock lk{connection_lock}; | ||||
| 
 | ||||
|         // Find the process we are going to debug.
 | ||||
|         SetDebugProcess(); | ||||
| 
 | ||||
|         // Ensure everything is stopped.
 | ||||
|         PauseEmulation(); | ||||
| 
 | ||||
|         // Set up the new frontend.
 | ||||
|         frontend = std::make_unique<GDBStub>(*this, system); | ||||
|         frontend = std::make_unique<GDBStub>(*this, system, debug_process.GetPointerUnsafe()); | ||||
| 
 | ||||
|         // Set the new state. This will tear down any existing state.
 | ||||
|         state = ConnectionState{ | ||||
| @ -194,15 +197,20 @@ private: | ||||
|             UpdateActiveThread(); | ||||
| 
 | ||||
|             if (state->info.type == SignalType::Watchpoint) { | ||||
|                 frontend->Watchpoint(state->active_thread, *state->info.watchpoint); | ||||
|                 frontend->Watchpoint(std::addressof(*state->active_thread), | ||||
|                                      *state->info.watchpoint); | ||||
|             } else { | ||||
|                 frontend->Stopped(state->active_thread); | ||||
|                 frontend->Stopped(std::addressof(*state->active_thread)); | ||||
|             } | ||||
| 
 | ||||
|             break; | ||||
|         case SignalType::ShuttingDown: | ||||
|             frontend->ShuttingDown(); | ||||
| 
 | ||||
|             // Release members.
 | ||||
|             state->active_thread.Reset(nullptr); | ||||
|             debug_process.Reset(nullptr); | ||||
| 
 | ||||
|             // Wait for emulation to shut down gracefully now.
 | ||||
|             state->signal_pipe.close(); | ||||
|             state->client_socket.shutdown(boost::asio::socket_base::shutdown_both); | ||||
| @ -222,7 +230,7 @@ private: | ||||
|                 stopped = true; | ||||
|                 PauseEmulation(); | ||||
|                 UpdateActiveThread(); | ||||
|                 frontend->Stopped(state->active_thread); | ||||
|                 frontend->Stopped(state->active_thread.GetPointerUnsafe()); | ||||
|                 break; | ||||
|             } | ||||
|             case DebuggerAction::Continue: | ||||
| @ -232,7 +240,7 @@ private: | ||||
|                 MarkResumed([&] { | ||||
|                     state->active_thread->SetStepState(Kernel::StepState::StepPending); | ||||
|                     state->active_thread->Resume(Kernel::SuspendType::Debug); | ||||
|                     ResumeEmulation(state->active_thread); | ||||
|                     ResumeEmulation(state->active_thread.GetPointerUnsafe()); | ||||
|                 }); | ||||
|                 break; | ||||
|             case DebuggerAction::StepThreadLocked: { | ||||
| @ -255,6 +263,7 @@ private: | ||||
|     } | ||||
| 
 | ||||
|     void PauseEmulation() { | ||||
|         Kernel::KScopedLightLock ll{debug_process->GetListLock()}; | ||||
|         Kernel::KScopedSchedulerLock sl{system.Kernel()}; | ||||
| 
 | ||||
|         // Put all threads to sleep on next scheduler round.
 | ||||
| @ -264,6 +273,9 @@ private: | ||||
|     } | ||||
| 
 | ||||
|     void ResumeEmulation(Kernel::KThread* except = nullptr) { | ||||
|         Kernel::KScopedLightLock ll{debug_process->GetListLock()}; | ||||
|         Kernel::KScopedSchedulerLock sl{system.Kernel()}; | ||||
| 
 | ||||
|         // Wake up all threads.
 | ||||
|         for (auto& thread : ThreadList()) { | ||||
|             if (std::addressof(thread) == except) { | ||||
| @ -277,15 +289,16 @@ private: | ||||
| 
 | ||||
|     template <typename Callback> | ||||
|     void MarkResumed(Callback&& cb) { | ||||
|         Kernel::KScopedSchedulerLock sl{system.Kernel()}; | ||||
|         stopped = false; | ||||
|         cb(); | ||||
|     } | ||||
| 
 | ||||
|     void UpdateActiveThread() { | ||||
|         Kernel::KScopedLightLock ll{debug_process->GetListLock()}; | ||||
| 
 | ||||
|         auto& threads{ThreadList()}; | ||||
|         for (auto& thread : threads) { | ||||
|             if (std::addressof(thread) == state->active_thread) { | ||||
|             if (std::addressof(thread) == state->active_thread.GetPointerUnsafe()) { | ||||
|                 // Thread is still alive, no need to update.
 | ||||
|                 return; | ||||
|             } | ||||
| @ -293,12 +306,18 @@ private: | ||||
|         state->active_thread = std::addressof(threads.front()); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     void SetDebugProcess() { | ||||
|         debug_process = std::move(system.Kernel().GetProcessList().back()); | ||||
|     } | ||||
| 
 | ||||
|     Kernel::KProcess::ThreadList& ThreadList() { | ||||
|         return system.ApplicationProcess()->GetThreadList(); | ||||
|         return debug_process->GetThreadList(); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     System& system; | ||||
|     Kernel::KScopedAutoObject<Kernel::KProcess> debug_process; | ||||
|     std::unique_ptr<DebuggerFrontend> frontend; | ||||
| 
 | ||||
|     boost::asio::io_context io_context; | ||||
| @ -310,7 +329,7 @@ private: | ||||
|         boost::process::async_pipe signal_pipe; | ||||
| 
 | ||||
|         SignalInfo info; | ||||
|         Kernel::KThread* active_thread; | ||||
|         Kernel::KScopedAutoObject<Kernel::KThread> active_thread; | ||||
|         std::array<u8, 4096> client_data; | ||||
|         bool pipe_data; | ||||
|     }; | ||||
|  | ||||
| @ -108,9 +108,9 @@ static std::string EscapeXML(std::string_view data) { | ||||
|     return escaped; | ||||
| } | ||||
| 
 | ||||
| GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_) | ||||
|     : DebuggerFrontend(backend_), system{system_} { | ||||
|     if (system.ApplicationProcess()->Is64Bit()) { | ||||
| GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_, Kernel::KProcess* debug_process_) | ||||
|     : DebuggerFrontend(backend_), system{system_}, debug_process{debug_process_} { | ||||
|     if (GetProcess()->Is64Bit()) { | ||||
|         arch = std::make_unique<GDBStubA64>(); | ||||
|     } else { | ||||
|         arch = std::make_unique<GDBStubA32>(); | ||||
| @ -276,7 +276,7 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction | ||||
|         const size_t size{static_cast<size_t>(strtoll(command.data() + sep, nullptr, 16))}; | ||||
| 
 | ||||
|         std::vector<u8> mem(size); | ||||
|         if (system.ApplicationMemory().ReadBlock(addr, mem.data(), size)) { | ||||
|         if (GetMemory().ReadBlock(addr, mem.data(), size)) { | ||||
|             // Restore any bytes belonging to replaced instructions.
 | ||||
|             auto it = replaced_instructions.lower_bound(addr); | ||||
|             for (; it != replaced_instructions.end() && it->first < addr + size; it++) { | ||||
| @ -310,8 +310,8 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction | ||||
|         const auto mem_substr{std::string_view(command).substr(mem_sep)}; | ||||
|         const auto mem{Common::HexStringToVector(mem_substr, false)}; | ||||
| 
 | ||||
|         if (system.ApplicationMemory().WriteBlock(addr, mem.data(), size)) { | ||||
|             Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, size); | ||||
|         if (GetMemory().WriteBlock(addr, mem.data(), size)) { | ||||
|             Core::InvalidateInstructionCacheRange(GetProcess(), addr, size); | ||||
|             SendReply(GDB_STUB_REPLY_OK); | ||||
|         } else { | ||||
|             SendReply(GDB_STUB_REPLY_ERR); | ||||
| @ -353,7 +353,7 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) { | ||||
|     const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; | ||||
|     const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))}; | ||||
| 
 | ||||
|     if (!system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) { | ||||
|     if (!GetMemory().IsValidVirtualAddressRange(addr, size)) { | ||||
|         SendReply(GDB_STUB_REPLY_ERR); | ||||
|         return; | ||||
|     } | ||||
| @ -362,22 +362,20 @@ void GDBStub::HandleBreakpointInsert(std::string_view command) { | ||||
| 
 | ||||
|     switch (type) { | ||||
|     case BreakpointType::Software: | ||||
|         replaced_instructions[addr] = system.ApplicationMemory().Read32(addr); | ||||
|         system.ApplicationMemory().Write32(addr, arch->BreakpointInstruction()); | ||||
|         Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, sizeof(u32)); | ||||
|         replaced_instructions[addr] = GetMemory().Read32(addr); | ||||
|         GetMemory().Write32(addr, arch->BreakpointInstruction()); | ||||
|         Core::InvalidateInstructionCacheRange(GetProcess(), addr, sizeof(u32)); | ||||
|         success = true; | ||||
|         break; | ||||
|     case BreakpointType::WriteWatch: | ||||
|         success = system.ApplicationProcess()->InsertWatchpoint(addr, size, | ||||
|                                                                 Kernel::DebugWatchpointType::Write); | ||||
|         success = GetProcess()->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::Write); | ||||
|         break; | ||||
|     case BreakpointType::ReadWatch: | ||||
|         success = system.ApplicationProcess()->InsertWatchpoint(addr, size, | ||||
|                                                                 Kernel::DebugWatchpointType::Read); | ||||
|         success = GetProcess()->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::Read); | ||||
|         break; | ||||
|     case BreakpointType::AccessWatch: | ||||
|         success = system.ApplicationProcess()->InsertWatchpoint( | ||||
|             addr, size, Kernel::DebugWatchpointType::ReadOrWrite); | ||||
|         success = | ||||
|             GetProcess()->InsertWatchpoint(addr, size, Kernel::DebugWatchpointType::ReadOrWrite); | ||||
|         break; | ||||
|     case BreakpointType::Hardware: | ||||
|     default: | ||||
| @ -400,7 +398,7 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) { | ||||
|     const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))}; | ||||
|     const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))}; | ||||
| 
 | ||||
|     if (!system.ApplicationMemory().IsValidVirtualAddressRange(addr, size)) { | ||||
|     if (!GetMemory().IsValidVirtualAddressRange(addr, size)) { | ||||
|         SendReply(GDB_STUB_REPLY_ERR); | ||||
|         return; | ||||
|     } | ||||
| @ -411,24 +409,22 @@ void GDBStub::HandleBreakpointRemove(std::string_view command) { | ||||
|     case BreakpointType::Software: { | ||||
|         const auto orig_insn{replaced_instructions.find(addr)}; | ||||
|         if (orig_insn != replaced_instructions.end()) { | ||||
|             system.ApplicationMemory().Write32(addr, orig_insn->second); | ||||
|             Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), addr, sizeof(u32)); | ||||
|             GetMemory().Write32(addr, orig_insn->second); | ||||
|             Core::InvalidateInstructionCacheRange(GetProcess(), addr, sizeof(u32)); | ||||
|             replaced_instructions.erase(addr); | ||||
|             success = true; | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
|     case BreakpointType::WriteWatch: | ||||
|         success = system.ApplicationProcess()->RemoveWatchpoint(addr, size, | ||||
|                                                                 Kernel::DebugWatchpointType::Write); | ||||
|         success = GetProcess()->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::Write); | ||||
|         break; | ||||
|     case BreakpointType::ReadWatch: | ||||
|         success = system.ApplicationProcess()->RemoveWatchpoint(addr, size, | ||||
|                                                                 Kernel::DebugWatchpointType::Read); | ||||
|         success = GetProcess()->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::Read); | ||||
|         break; | ||||
|     case BreakpointType::AccessWatch: | ||||
|         success = system.ApplicationProcess()->RemoveWatchpoint( | ||||
|             addr, size, Kernel::DebugWatchpointType::ReadOrWrite); | ||||
|         success = | ||||
|             GetProcess()->RemoveWatchpoint(addr, size, Kernel::DebugWatchpointType::ReadOrWrite); | ||||
|         break; | ||||
|     case BreakpointType::Hardware: | ||||
|     default: | ||||
| @ -466,10 +462,10 @@ void GDBStub::HandleQuery(std::string_view command) { | ||||
|         const auto target_xml{arch->GetTargetXML()}; | ||||
|         SendReply(PaginateBuffer(target_xml, command.substr(30))); | ||||
|     } else if (command.starts_with("Offsets")) { | ||||
|         const auto main_offset = Core::FindMainModuleEntrypoint(system.ApplicationProcess()); | ||||
|         const auto main_offset = Core::FindMainModuleEntrypoint(GetProcess()); | ||||
|         SendReply(fmt::format("TextSeg={:x}", GetInteger(main_offset))); | ||||
|     } else if (command.starts_with("Xfer:libraries:read::")) { | ||||
|         auto modules = Core::FindModules(system.ApplicationProcess()); | ||||
|         auto modules = Core::FindModules(GetProcess()); | ||||
| 
 | ||||
|         std::string buffer; | ||||
|         buffer += R"(<?xml version="1.0"?>)"; | ||||
| @ -483,7 +479,7 @@ void GDBStub::HandleQuery(std::string_view command) { | ||||
|         SendReply(PaginateBuffer(buffer, command.substr(21))); | ||||
|     } else if (command.starts_with("fThreadInfo")) { | ||||
|         // beginning of list
 | ||||
|         const auto& threads = system.ApplicationProcess()->GetThreadList(); | ||||
|         const auto& threads = GetProcess()->GetThreadList(); | ||||
|         std::vector<std::string> thread_ids; | ||||
|         for (const auto& thread : threads) { | ||||
|             thread_ids.push_back(fmt::format("{:x}", thread.GetThreadId())); | ||||
| @ -497,7 +493,7 @@ void GDBStub::HandleQuery(std::string_view command) { | ||||
|         buffer += R"(<?xml version="1.0"?>)"; | ||||
|         buffer += "<threads>"; | ||||
| 
 | ||||
|         const auto& threads = system.ApplicationProcess()->GetThreadList(); | ||||
|         const auto& threads = GetProcess()->GetThreadList(); | ||||
|         for (const auto& thread : threads) { | ||||
|             auto thread_name{Core::GetThreadName(&thread)}; | ||||
|             if (!thread_name) { | ||||
| @ -613,7 +609,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) { | ||||
|     std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()}; | ||||
|     std::string reply; | ||||
| 
 | ||||
|     auto* process = system.ApplicationProcess(); | ||||
|     auto* process = GetProcess(); | ||||
|     auto& page_table = process->GetPageTable(); | ||||
| 
 | ||||
|     const char* commands = "Commands:\n" | ||||
| @ -714,7 +710,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) { | ||||
| } | ||||
| 
 | ||||
| Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { | ||||
|     auto& threads{system.ApplicationProcess()->GetThreadList()}; | ||||
|     auto& threads{GetProcess()->GetThreadList()}; | ||||
|     for (auto& thread : threads) { | ||||
|         if (thread.GetThreadId() == thread_id) { | ||||
|             return std::addressof(thread); | ||||
| @ -783,4 +779,12 @@ void GDBStub::SendStatus(char status) { | ||||
|     backend.WriteToClient(buf); | ||||
| } | ||||
| 
 | ||||
| Kernel::KProcess* GDBStub::GetProcess() { | ||||
|     return debug_process; | ||||
| } | ||||
| 
 | ||||
| Core::Memory::Memory& GDBStub::GetMemory() { | ||||
|     return GetProcess()->GetMemory(); | ||||
| } | ||||
| 
 | ||||
| } // namespace Core
 | ||||
|  | ||||
| @ -12,13 +12,22 @@ | ||||
| #include "core/debugger/debugger_interface.h" | ||||
| #include "core/debugger/gdbstub_arch.h" | ||||
| 
 | ||||
| namespace Kernel { | ||||
| class KProcess; | ||||
| } | ||||
| 
 | ||||
| namespace Core::Memory { | ||||
| class Memory; | ||||
| } | ||||
| 
 | ||||
| namespace Core { | ||||
| 
 | ||||
| class System; | ||||
| 
 | ||||
| class GDBStub : public DebuggerFrontend { | ||||
| public: | ||||
|     explicit GDBStub(DebuggerBackend& backend, Core::System& system); | ||||
|     explicit GDBStub(DebuggerBackend& backend, Core::System& system, | ||||
|                      Kernel::KProcess* debug_process); | ||||
|     ~GDBStub() override; | ||||
| 
 | ||||
|     void Connected() override; | ||||
| @ -42,8 +51,12 @@ private: | ||||
|     void SendReply(std::string_view data); | ||||
|     void SendStatus(char status); | ||||
| 
 | ||||
|     Kernel::KProcess* GetProcess(); | ||||
|     Core::Memory::Memory& GetMemory(); | ||||
| 
 | ||||
| private: | ||||
|     Core::System& system; | ||||
|     Kernel::KProcess* debug_process; | ||||
|     std::unique_ptr<GDBStubArch> arch; | ||||
|     std::vector<char> current_command; | ||||
|     std::map<VAddr, u32> replaced_instructions; | ||||
|  | ||||
| @ -28,14 +28,14 @@ Result KMemoryBlockManager::Initialize(KProcessAddress st, KProcessAddress nd, | ||||
| } | ||||
| 
 | ||||
| void KMemoryBlockManager::Finalize(KMemoryBlockSlabManager* slab_manager, | ||||
|                                    HostUnmapCallback&& host_unmap_callback) { | ||||
|                                    BlockCallback&& block_callback) { | ||||
|     // Erase every block until we have none left.
 | ||||
|     auto it = m_memory_block_tree.begin(); | ||||
|     while (it != m_memory_block_tree.end()) { | ||||
|         KMemoryBlock* block = std::addressof(*it); | ||||
|         it = m_memory_block_tree.erase(it); | ||||
|         block_callback(block->GetAddress(), block->GetSize()); | ||||
|         slab_manager->Free(block); | ||||
|         host_unmap_callback(block->GetAddress(), block->GetSize()); | ||||
|     } | ||||
| 
 | ||||
|     ASSERT(m_memory_block_tree.empty()); | ||||
|  | ||||
| @ -85,11 +85,11 @@ public: | ||||
| public: | ||||
|     KMemoryBlockManager(); | ||||
| 
 | ||||
|     using HostUnmapCallback = std::function<void(Common::ProcessAddress, u64)>; | ||||
|     using BlockCallback = std::function<void(Common::ProcessAddress, u64)>; | ||||
| 
 | ||||
|     Result Initialize(KProcessAddress st, KProcessAddress nd, | ||||
|                       KMemoryBlockSlabManager* slab_manager); | ||||
|     void Finalize(KMemoryBlockSlabManager* slab_manager, HostUnmapCallback&& host_unmap_callback); | ||||
|     void Finalize(KMemoryBlockSlabManager* slab_manager, BlockCallback&& block_callback); | ||||
| 
 | ||||
|     iterator end() { | ||||
|         return m_memory_block_tree.end(); | ||||
|  | ||||
| @ -431,15 +431,43 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool | ||||
|                                                m_memory_block_slab_manager)); | ||||
| } | ||||
| 
 | ||||
| Result KPageTableBase::FinalizeProcess() { | ||||
|     // Only process tables should be finalized.
 | ||||
|     ASSERT(!this->IsKernel()); | ||||
| 
 | ||||
|     // NOTE: Here Nintendo calls an unknown OnFinalize function.
 | ||||
|     // this->OnFinalize();
 | ||||
| 
 | ||||
|     // NOTE: Here Nintendo calls a second unknown OnFinalize function.
 | ||||
|     // this->OnFinalize2();
 | ||||
| 
 | ||||
|     // NOTE: Here Nintendo does a page table walk to discover heap pages to free.
 | ||||
|     // We will use the block manager finalization below to free them.
 | ||||
| 
 | ||||
|     R_SUCCEED(); | ||||
| } | ||||
| 
 | ||||
| void KPageTableBase::Finalize() { | ||||
|     auto HostUnmapCallback = [&](KProcessAddress addr, u64 size) { | ||||
|         if (Settings::IsFastmemEnabled()) { | ||||
|     this->FinalizeProcess(); | ||||
| 
 | ||||
|     auto BlockCallback = [&](KProcessAddress addr, u64 size) { | ||||
|         if (m_impl->fastmem_arena) { | ||||
|             m_system.DeviceMemory().buffer.Unmap(GetInteger(addr), size, false); | ||||
|         } | ||||
| 
 | ||||
|         // Get physical pages.
 | ||||
|         KPageGroup pg(m_kernel, m_block_info_manager); | ||||
|         this->MakePageGroup(pg, addr, size / PageSize); | ||||
| 
 | ||||
|         // Free the pages.
 | ||||
|         pg.CloseAndReset(); | ||||
|     }; | ||||
| 
 | ||||
|     // Finalize memory blocks.
 | ||||
|     m_memory_block_manager.Finalize(m_memory_block_slab_manager, std::move(HostUnmapCallback)); | ||||
|     { | ||||
|         KScopedLightLock lk(m_general_lock); | ||||
|         m_memory_block_manager.Finalize(m_memory_block_slab_manager, std::move(BlockCallback)); | ||||
|     } | ||||
| 
 | ||||
|     // Free any unsafe mapped memory.
 | ||||
|     if (m_mapped_unsafe_physical_memory) { | ||||
|  | ||||
| @ -241,6 +241,7 @@ public: | ||||
|                                 KResourceLimit* resource_limit, Core::Memory::Memory& memory, | ||||
|                                 KProcessAddress aslr_space_start); | ||||
| 
 | ||||
|     Result FinalizeProcess(); | ||||
|     void Finalize(); | ||||
| 
 | ||||
|     bool IsKernel() const { | ||||
|  | ||||
| @ -171,6 +171,12 @@ void KProcess::Finalize() { | ||||
|         m_resource_limit->Close(); | ||||
|     } | ||||
| 
 | ||||
|     // Clear expensive resources, as the destructor is not called for guest objects.
 | ||||
|     for (auto& interface : m_arm_interfaces) { | ||||
|         interface.reset(); | ||||
|     } | ||||
|     m_exclusive_monitor.reset(); | ||||
| 
 | ||||
|     // Perform inherited finalization.
 | ||||
|     KSynchronizationObject::Finalize(); | ||||
| } | ||||
|  | ||||
| @ -112,7 +112,14 @@ struct KernelCore::Impl { | ||||
|             old_process->Close(); | ||||
|         } | ||||
| 
 | ||||
|         { | ||||
|             std::scoped_lock lk{process_list_lock}; | ||||
|             for (auto* const process : process_list) { | ||||
|                 process->Terminate(); | ||||
|                 process->Close(); | ||||
|             } | ||||
|             process_list.clear(); | ||||
|         } | ||||
| 
 | ||||
|         next_object_id = 0; | ||||
|         next_kernel_process_id = KProcess::InitialProcessIdMin; | ||||
| @ -770,6 +777,7 @@ struct KernelCore::Impl { | ||||
|     std::atomic<u64> next_thread_id{1}; | ||||
| 
 | ||||
|     // Lists all processes that exist in the current session.
 | ||||
|     std::mutex process_list_lock; | ||||
|     std::vector<KProcess*> process_list; | ||||
|     std::atomic<KProcess*> application_process{}; | ||||
|     std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; | ||||
| @ -869,9 +877,19 @@ KResourceLimit* KernelCore::GetSystemResourceLimit() { | ||||
| } | ||||
| 
 | ||||
| void KernelCore::AppendNewProcess(KProcess* process) { | ||||
|     process->Open(); | ||||
| 
 | ||||
|     std::scoped_lock lk{impl->process_list_lock}; | ||||
|     impl->process_list.push_back(process); | ||||
| } | ||||
| 
 | ||||
| void KernelCore::RemoveProcess(KProcess* process) { | ||||
|     std::scoped_lock lk{impl->process_list_lock}; | ||||
|     if (std::erase(impl->process_list, process)) { | ||||
|         process->Close(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void KernelCore::MakeApplicationProcess(KProcess* process) { | ||||
|     impl->MakeApplicationProcess(process); | ||||
| } | ||||
| @ -884,8 +902,15 @@ const KProcess* KernelCore::ApplicationProcess() const { | ||||
|     return impl->application_process; | ||||
| } | ||||
| 
 | ||||
| const std::vector<KProcess*>& KernelCore::GetProcessList() const { | ||||
|     return impl->process_list; | ||||
| std::list<KScopedAutoObject<KProcess>> KernelCore::GetProcessList() { | ||||
|     std::list<KScopedAutoObject<KProcess>> processes; | ||||
|     std::scoped_lock lk{impl->process_list_lock}; | ||||
| 
 | ||||
|     for (auto* const process : impl->process_list) { | ||||
|         processes.emplace_back(process); | ||||
|     } | ||||
| 
 | ||||
|     return processes; | ||||
| } | ||||
| 
 | ||||
| Kernel::GlobalSchedulerContext& KernelCore::GlobalSchedulerContext() { | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| 
 | ||||
| #include <array> | ||||
| #include <functional> | ||||
| #include <list> | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <unordered_map> | ||||
| @ -116,8 +117,9 @@ public: | ||||
|     /// Retrieves a shared pointer to the system resource limit instance.
 | ||||
|     KResourceLimit* GetSystemResourceLimit(); | ||||
| 
 | ||||
|     /// Adds the given shared pointer to an internal list of active processes.
 | ||||
|     /// Adds/removes the given pointer to an internal list of active processes.
 | ||||
|     void AppendNewProcess(KProcess* process); | ||||
|     void RemoveProcess(KProcess* process); | ||||
| 
 | ||||
|     /// Makes the given process the new application process.
 | ||||
|     void MakeApplicationProcess(KProcess* process); | ||||
| @ -129,7 +131,7 @@ public: | ||||
|     const KProcess* ApplicationProcess() const; | ||||
| 
 | ||||
|     /// Retrieves the list of processes.
 | ||||
|     const std::vector<KProcess*>& GetProcessList() const; | ||||
|     std::list<KScopedAutoObject<KProcess>> GetProcessList(); | ||||
| 
 | ||||
|     /// Gets the sole instance of the global scheduler
 | ||||
|     Kernel::GlobalSchedulerContext& GlobalSchedulerContext(); | ||||
|  | ||||
| @ -74,13 +74,15 @@ Result GetProcessList(Core::System& system, s32* out_num_processes, u64 out_proc | ||||
|     } | ||||
| 
 | ||||
|     auto& memory = GetCurrentMemory(kernel); | ||||
|     const auto& process_list = kernel.GetProcessList(); | ||||
|     auto process_list = kernel.GetProcessList(); | ||||
|     auto it = process_list.begin(); | ||||
| 
 | ||||
|     const auto num_processes = process_list.size(); | ||||
|     const auto copy_amount = | ||||
|         std::min(static_cast<std::size_t>(out_process_ids_size), num_processes); | ||||
| 
 | ||||
|     for (std::size_t i = 0; i < copy_amount; ++i) { | ||||
|         memory.Write64(out_process_ids, process_list[i]->GetProcessId()); | ||||
|     for (std::size_t i = 0; i < copy_amount && it != process_list.end(); ++i, ++it) { | ||||
|         memory.Write64(out_process_ids, (*it)->GetProcessId()); | ||||
|         out_process_ids += sizeof(u64); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -15,9 +15,10 @@ | ||||
| namespace Service::Glue { | ||||
| 
 | ||||
| namespace { | ||||
| std::optional<u64> GetTitleIDForProcessID(const Core::System& system, u64 process_id) { | ||||
|     const auto& list = system.Kernel().GetProcessList(); | ||||
|     const auto iter = std::find_if(list.begin(), list.end(), [&process_id](const auto& process) { | ||||
| std::optional<u64> GetTitleIDForProcessID(Core::System& system, u64 process_id) { | ||||
|     auto list = system.Kernel().GetProcessList(); | ||||
| 
 | ||||
|     const auto iter = std::find_if(list.begin(), list.end(), [&process_id](auto& process) { | ||||
|         return process->GetProcessId() == process_id; | ||||
|     }); | ||||
| 
 | ||||
|  | ||||
| @ -22,12 +22,10 @@ void LoopProcess(Core::System& system) { | ||||
|     std::shared_ptr<HidFirmwareSettings> firmware_settings = | ||||
|         std::make_shared<HidFirmwareSettings>(); | ||||
| 
 | ||||
|     // TODO: Remove this hack until this service is emulated properly.
 | ||||
|     const auto process_list = system.Kernel().GetProcessList(); | ||||
|     if (!process_list.empty()) { | ||||
|     // TODO: Remove this hack when am is emulated properly.
 | ||||
|     resource_manager->Initialize(); | ||||
|         resource_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true); | ||||
|     } | ||||
|     resource_manager->RegisterAppletResourceUserId(system.ApplicationProcess()->GetProcessId(), | ||||
|                                                    true); | ||||
| 
 | ||||
|     server_manager->RegisterNamedService( | ||||
|         "hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings)); | ||||
|  | ||||
| @ -22,27 +22,26 @@ constexpr Result ResultProcessNotFound{ErrorModule::PM, 1}; | ||||
| 
 | ||||
| constexpr u64 NO_PROCESS_FOUND_PID{0}; | ||||
| 
 | ||||
| std::optional<Kernel::KProcess*> SearchProcessList( | ||||
|     const std::vector<Kernel::KProcess*>& process_list, | ||||
|     std::function<bool(Kernel::KProcess*)> predicate) { | ||||
| using ProcessList = std::list<Kernel::KScopedAutoObject<Kernel::KProcess>>; | ||||
| 
 | ||||
| template <typename F> | ||||
| Kernel::KScopedAutoObject<Kernel::KProcess> SearchProcessList(ProcessList& process_list, | ||||
|                                                               F&& predicate) { | ||||
|     const auto iter = std::find_if(process_list.begin(), process_list.end(), predicate); | ||||
| 
 | ||||
|     if (iter == process_list.end()) { | ||||
|         return std::nullopt; | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     return *iter; | ||||
|     return iter->GetPointerUnsafe(); | ||||
| } | ||||
| 
 | ||||
| void GetApplicationPidGeneric(HLERequestContext& ctx, | ||||
|                               const std::vector<Kernel::KProcess*>& process_list) { | ||||
|     const auto process = SearchProcessList(process_list, [](const auto& proc) { | ||||
|         return proc->GetProcessId() == Kernel::KProcess::ProcessIdMin; | ||||
|     }); | ||||
| void GetApplicationPidGeneric(HLERequestContext& ctx, ProcessList& process_list) { | ||||
|     auto process = SearchProcessList(process_list, [](auto& p) { return p->IsApplication(); }); | ||||
| 
 | ||||
|     IPC::ResponseBuilder rb{ctx, 4}; | ||||
|     rb.Push(ResultSuccess); | ||||
|     rb.Push(process.has_value() ? (*process)->GetProcessId() : NO_PROCESS_FOUND_PID); | ||||
|     rb.Push(process.IsNull() ? NO_PROCESS_FOUND_PID : process->GetProcessId()); | ||||
| } | ||||
| 
 | ||||
| } // Anonymous namespace
 | ||||
| @ -80,8 +79,7 @@ private: | ||||
| 
 | ||||
| class DebugMonitor final : public ServiceFramework<DebugMonitor> { | ||||
| public: | ||||
|     explicit DebugMonitor(Core::System& system_) | ||||
|         : ServiceFramework{system_, "pm:dmnt"}, kernel{system_.Kernel()} { | ||||
|     explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "pm:dmnt"} { | ||||
|         // clang-format off
 | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, nullptr, "GetJitDebugProcessIdList"}, | ||||
| @ -106,12 +104,11 @@ private: | ||||
| 
 | ||||
|         LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); | ||||
| 
 | ||||
|         const auto process = | ||||
|             SearchProcessList(kernel.GetProcessList(), [program_id](const auto& proc) { | ||||
|                 return proc->GetProgramId() == program_id; | ||||
|             }); | ||||
|         auto list = kernel.GetProcessList(); | ||||
|         auto process = SearchProcessList( | ||||
|             list, [program_id](auto& p) { return p->GetProgramId() == program_id; }); | ||||
| 
 | ||||
|         if (!process.has_value()) { | ||||
|         if (process.IsNull()) { | ||||
|             IPC::ResponseBuilder rb{ctx, 2}; | ||||
|             rb.Push(ResultProcessNotFound); | ||||
|             return; | ||||
| @ -119,12 +116,13 @@ private: | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 4}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push((*process)->GetProcessId()); | ||||
|         rb.Push(process->GetProcessId()); | ||||
|     } | ||||
| 
 | ||||
|     void GetApplicationProcessId(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_PM, "called"); | ||||
|         GetApplicationPidGeneric(ctx, kernel.GetProcessList()); | ||||
|         auto list = kernel.GetProcessList(); | ||||
|         GetApplicationPidGeneric(ctx, list); | ||||
|     } | ||||
| 
 | ||||
|     void AtmosphereGetProcessInfo(HLERequestContext& ctx) { | ||||
| @ -135,11 +133,10 @@ private: | ||||
| 
 | ||||
|         LOG_WARNING(Service_PM, "(Partial Implementation) called, pid={:016X}", pid); | ||||
| 
 | ||||
|         const auto process = SearchProcessList(kernel.GetProcessList(), [pid](const auto& proc) { | ||||
|             return proc->GetProcessId() == pid; | ||||
|         }); | ||||
|         auto list = kernel.GetProcessList(); | ||||
|         auto process = SearchProcessList(list, [pid](auto& p) { return p->GetProcessId() == pid; }); | ||||
| 
 | ||||
|         if (!process.has_value()) { | ||||
|         if (process.IsNull()) { | ||||
|             IPC::ResponseBuilder rb{ctx, 2}; | ||||
|             rb.Push(ResultProcessNotFound); | ||||
|             return; | ||||
| @ -159,7 +156,7 @@ private: | ||||
| 
 | ||||
|         OverrideStatus override_status{}; | ||||
|         ProgramLocation program_location{ | ||||
|             .program_id = (*process)->GetProgramId(), | ||||
|             .program_id = process->GetProgramId(), | ||||
|             .storage_id = 0, | ||||
|         }; | ||||
| 
 | ||||
| @ -169,14 +166,11 @@ private: | ||||
|         rb.PushRaw(program_location); | ||||
|         rb.PushRaw(override_status); | ||||
|     } | ||||
| 
 | ||||
|     const Kernel::KernelCore& kernel; | ||||
| }; | ||||
| 
 | ||||
| class Info final : public ServiceFramework<Info> { | ||||
| public: | ||||
|     explicit Info(Core::System& system_, const std::vector<Kernel::KProcess*>& process_list_) | ||||
|         : ServiceFramework{system_, "pm:info"}, process_list{process_list_} { | ||||
|     explicit Info(Core::System& system_) : ServiceFramework{system_, "pm:info"} { | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &Info::GetProgramId, "GetProgramId"}, | ||||
|             {65000, &Info::AtmosphereGetProcessId, "AtmosphereGetProcessId"}, | ||||
| @ -193,11 +187,11 @@ private: | ||||
| 
 | ||||
|         LOG_DEBUG(Service_PM, "called, process_id={:016X}", process_id); | ||||
| 
 | ||||
|         const auto process = SearchProcessList(process_list, [process_id](const auto& proc) { | ||||
|             return proc->GetProcessId() == process_id; | ||||
|         }); | ||||
|         auto list = kernel.GetProcessList(); | ||||
|         auto process = SearchProcessList( | ||||
|             list, [process_id](auto& p) { return p->GetProcessId() == process_id; }); | ||||
| 
 | ||||
|         if (!process.has_value()) { | ||||
|         if (process.IsNull()) { | ||||
|             IPC::ResponseBuilder rb{ctx, 2}; | ||||
|             rb.Push(ResultProcessNotFound); | ||||
|             return; | ||||
| @ -205,7 +199,7 @@ private: | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 4}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push((*process)->GetProgramId()); | ||||
|         rb.Push(process->GetProgramId()); | ||||
|     } | ||||
| 
 | ||||
|     void AtmosphereGetProcessId(HLERequestContext& ctx) { | ||||
| @ -214,11 +208,11 @@ private: | ||||
| 
 | ||||
|         LOG_DEBUG(Service_PM, "called, program_id={:016X}", program_id); | ||||
| 
 | ||||
|         const auto process = SearchProcessList(process_list, [program_id](const auto& proc) { | ||||
|             return proc->GetProgramId() == program_id; | ||||
|         }); | ||||
|         auto list = system.Kernel().GetProcessList(); | ||||
|         auto process = SearchProcessList( | ||||
|             list, [program_id](auto& p) { return p->GetProgramId() == program_id; }); | ||||
| 
 | ||||
|         if (!process.has_value()) { | ||||
|         if (process.IsNull()) { | ||||
|             IPC::ResponseBuilder rb{ctx, 2}; | ||||
|             rb.Push(ResultProcessNotFound); | ||||
|             return; | ||||
| @ -226,16 +220,13 @@ private: | ||||
| 
 | ||||
|         IPC::ResponseBuilder rb{ctx, 4}; | ||||
|         rb.Push(ResultSuccess); | ||||
|         rb.Push((*process)->GetProcessId()); | ||||
|         rb.Push(process->GetProcessId()); | ||||
|     } | ||||
| 
 | ||||
|     const std::vector<Kernel::KProcess*>& process_list; | ||||
| }; | ||||
| 
 | ||||
| class Shell final : public ServiceFramework<Shell> { | ||||
| public: | ||||
|     explicit Shell(Core::System& system_) | ||||
|         : ServiceFramework{system_, "pm:shell"}, kernel{system_.Kernel()} { | ||||
|     explicit Shell(Core::System& system_) : ServiceFramework{system_, "pm:shell"} { | ||||
|         // clang-format off
 | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, nullptr, "LaunchProgram"}, | ||||
| @ -257,10 +248,9 @@ public: | ||||
| private: | ||||
|     void GetApplicationProcessIdForShell(HLERequestContext& ctx) { | ||||
|         LOG_DEBUG(Service_PM, "called"); | ||||
|         GetApplicationPidGeneric(ctx, kernel.GetProcessList()); | ||||
|         auto list = kernel.GetProcessList(); | ||||
|         GetApplicationPidGeneric(ctx, list); | ||||
|     } | ||||
| 
 | ||||
|     const Kernel::KernelCore& kernel; | ||||
| }; | ||||
| 
 | ||||
| void LoopProcess(Core::System& system) { | ||||
| @ -268,8 +258,7 @@ void LoopProcess(Core::System& system) { | ||||
| 
 | ||||
|     server_manager->RegisterNamedService("pm:bm", std::make_shared<BootMode>(system)); | ||||
|     server_manager->RegisterNamedService("pm:dmnt", std::make_shared<DebugMonitor>(system)); | ||||
|     server_manager->RegisterNamedService( | ||||
|         "pm:info", std::make_shared<Info>(system, system.Kernel().GetProcessList())); | ||||
|     server_manager->RegisterNamedService("pm:info", std::make_shared<Info>(system)); | ||||
|     server_manager->RegisterNamedService("pm:shell", std::make_shared<Shell>(system)); | ||||
|     ServerManager::RunServer(std::move(server_manager)); | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user