diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/core.cpp | 6 | ||||
-rw-r--r-- | src/core/core.h | 3 | ||||
-rw-r--r-- | src/core/debugger/debugger.cpp | 57 | ||||
-rw-r--r-- | src/core/debugger/debugger.h | 5 | ||||
-rw-r--r-- | src/core/debugger/debugger_interface.h | 5 | ||||
-rw-r--r-- | src/core/debugger/gdbstub.cpp | 2 | ||||
-rw-r--r-- | src/core/debugger/gdbstub.h | 1 | ||||
-rw-r--r-- | src/core/debugger/gdbstub_arch.h | 1 | ||||
-rw-r--r-- | src/core/hle/kernel/k_code_memory.cpp | 28 | ||||
-rw-r--r-- | src/core/hle/kernel/k_page_table.cpp | 111 | ||||
-rw-r--r-- | src/core/hle/kernel/k_page_table.h | 5 | ||||
-rw-r--r-- | src/core/hle/service/hid/controllers/gesture.cpp | 4 | ||||
-rw-r--r-- | src/core/hle/service/hid/controllers/gesture.h | 3 |
13 files changed, 193 insertions, 38 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp index 7d974ba65..954136adb 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -493,6 +493,12 @@ void System::Shutdown() { impl->Shutdown(); } +void System::DetachDebugger() { + if (impl->debugger) { + impl->debugger->NotifyShutdown(); + } +} + std::unique_lock<std::mutex> System::StallCPU() { return impl->StallCPU(); } diff --git a/src/core/core.h b/src/core/core.h index 94477206e..5c367349e 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -160,6 +160,9 @@ public: /// Shutdown the emulated system. void Shutdown(); + /// Forcibly detach the debugger if it is running. + void DetachDebugger(); + std::unique_lock<std::mutex> StallCPU(); void UnstallCPU(); diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp index 8d64990ed..edf991d71 100644 --- a/src/core/debugger/debugger.cpp +++ b/src/core/debugger/debugger.cpp @@ -42,6 +42,16 @@ static std::span<const u8> ReceiveInto(Readable& r, Buffer& buffer) { return received_data; } +enum class SignalType { + Stopped, + ShuttingDown, +}; + +struct SignalInfo { + SignalType type; + Kernel::KThread* thread; +}; + namespace Core { class DebuggerImpl : public DebuggerBackend { @@ -56,7 +66,7 @@ public: ShutdownServer(); } - bool NotifyThreadStopped(Kernel::KThread* thread) { + bool SignalDebugger(SignalInfo signal_info) { std::scoped_lock lk{connection_lock}; if (stopped) { @@ -64,9 +74,13 @@ public: // It should be ignored. return false; } + + // Set up the state. stopped = true; + info = signal_info; - boost::asio::write(signal_pipe, boost::asio::buffer(&thread, sizeof(thread))); + // Write a single byte into the pipe to wake up the debug interface. + boost::asio::write(signal_pipe, boost::asio::buffer(&stopped, sizeof(stopped))); return true; } @@ -96,7 +110,7 @@ private: connection_thread = std::jthread([&, port](std::stop_token stop_token) { try { // Initialize the listening socket and accept a new client. - tcp::endpoint endpoint{boost::asio::ip::address_v4::loopback(), port}; + tcp::endpoint endpoint{boost::asio::ip::address_v4::any(), port}; tcp::acceptor acceptor{io_context, endpoint}; acceptor.async_accept(client_socket, [](const auto&) {}); @@ -124,7 +138,7 @@ private: Common::SetCurrentThreadName("yuzu:Debugger"); // Set up the client signals for new data. - AsyncReceiveInto(signal_pipe, active_thread, [&](auto d) { PipeData(d); }); + AsyncReceiveInto(signal_pipe, pipe_data, [&](auto d) { PipeData(d); }); AsyncReceiveInto(client_socket, client_data, [&](auto d) { ClientData(d); }); // Stop the emulated CPU. @@ -142,9 +156,28 @@ private: } void PipeData(std::span<const u8> data) { - AllCoreStop(); - UpdateActiveThread(); - frontend->Stopped(active_thread); + switch (info.type) { + case SignalType::Stopped: + // Stop emulation. + AllCoreStop(); + + // Notify the client. + active_thread = info.thread; + UpdateActiveThread(); + frontend->Stopped(active_thread); + + break; + case SignalType::ShuttingDown: + frontend->ShuttingDown(); + + // Wait for emulation to shut down gracefully now. + suspend.reset(); + signal_pipe.close(); + client_socket.shutdown(boost::asio::socket_base::shutdown_both); + LOG_INFO(Debug_GDBStub, "Shut down server"); + + break; + } } void ClientData(std::span<const u8> data) { @@ -246,7 +279,9 @@ private: boost::asio::ip::tcp::socket client_socket; std::optional<std::unique_lock<std::mutex>> suspend; + SignalInfo info; Kernel::KThread* active_thread; + bool pipe_data; bool stopped; std::array<u8, 4096> client_data; @@ -263,7 +298,13 @@ Debugger::Debugger(Core::System& system, u16 port) { Debugger::~Debugger() = default; bool Debugger::NotifyThreadStopped(Kernel::KThread* thread) { - return impl && impl->NotifyThreadStopped(thread); + return impl && impl->SignalDebugger(SignalInfo{SignalType::Stopped, thread}); +} + +void Debugger::NotifyShutdown() { + if (impl) { + impl->SignalDebugger(SignalInfo{SignalType::ShuttingDown, nullptr}); + } } } // namespace Core diff --git a/src/core/debugger/debugger.h b/src/core/debugger/debugger.h index ea36c6ab2..f9738ca3d 100644 --- a/src/core/debugger/debugger.h +++ b/src/core/debugger/debugger.h @@ -35,6 +35,11 @@ public: */ bool NotifyThreadStopped(Kernel::KThread* thread); + /** + * Notify the debugger that a shutdown is being performed now and disconnect. + */ + void NotifyShutdown(); + private: std::unique_ptr<DebuggerImpl> impl; }; diff --git a/src/core/debugger/debugger_interface.h b/src/core/debugger/debugger_interface.h index 35ba0bc61..c0bb4ecaf 100644 --- a/src/core/debugger/debugger_interface.h +++ b/src/core/debugger/debugger_interface.h @@ -67,6 +67,11 @@ public: virtual void Stopped(Kernel::KThread* thread) = 0; /** + * Called when emulation is shutting down. + */ + virtual void ShuttingDown() = 0; + + /** * Called when new data is asynchronously received on the client socket. * A list of actions to perform is returned. */ diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp index f52d78829..52e76f659 100644 --- a/src/core/debugger/gdbstub.cpp +++ b/src/core/debugger/gdbstub.cpp @@ -106,6 +106,8 @@ GDBStub::~GDBStub() = default; void GDBStub::Connected() {} +void GDBStub::ShuttingDown() {} + void GDBStub::Stopped(Kernel::KThread* thread) { SendReply(arch->ThreadStatus(thread, GDB_STUB_SIGTRAP)); } diff --git a/src/core/debugger/gdbstub.h b/src/core/debugger/gdbstub.h index 1bb638187..ec934c77e 100644 --- a/src/core/debugger/gdbstub.h +++ b/src/core/debugger/gdbstub.h @@ -23,6 +23,7 @@ public: void Connected() override; void Stopped(Kernel::KThread* thread) override; + void ShuttingDown() override; std::vector<DebuggerAction> ClientData(std::span<const u8> data) override; private: diff --git a/src/core/debugger/gdbstub_arch.h b/src/core/debugger/gdbstub_arch.h index 4d039a9f7..2540d6456 100644 --- a/src/core/debugger/gdbstub_arch.h +++ b/src/core/debugger/gdbstub_arch.h @@ -15,6 +15,7 @@ namespace Core { class GDBStubArch { public: + virtual ~GDBStubArch() = default; virtual std::string GetTargetXML() const = 0; virtual std::string RegRead(const Kernel::KThread* thread, size_t id) const = 0; virtual void RegWrite(Kernel::KThread* thread, size_t id, std::string_view value) const = 0; diff --git a/src/core/hle/kernel/k_code_memory.cpp b/src/core/hle/kernel/k_code_memory.cpp index fd3cbfd94..4ae40ec8e 100644 --- a/src/core/hle/kernel/k_code_memory.cpp +++ b/src/core/hle/kernel/k_code_memory.cpp @@ -27,23 +27,18 @@ ResultCode KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr auto& page_table = m_owner->PageTable(); // Construct the page group. - m_page_group = - KPageLinkedList(page_table.GetPhysicalAddr(addr), Common::DivideUp(size, PageSize)); + m_page_group = {}; // Lock the memory. - R_TRY(page_table.LockForCodeMemory(addr, size)) + R_TRY(page_table.LockForCodeMemory(&m_page_group, addr, size)) // Clear the memory. - // - // FIXME: this ends up clobbering address ranges outside the scope of the mapping within - // guest memory, and is not specifically required if the guest program is correctly - // written, so disable until this is further investigated. - // - // for (const auto& block : m_page_group.Nodes()) { - // std::memset(device_memory.GetPointer(block.GetAddress()), 0xFF, block.GetSize()); - // } + for (const auto& block : m_page_group.Nodes()) { + std::memset(device_memory.GetPointer(block.GetAddress()), 0xFF, block.GetSize()); + } // Set remaining tracking members. + m_owner->Open(); m_address = addr; m_is_initialized = true; m_is_owner_mapped = false; @@ -57,8 +52,14 @@ void KCodeMemory::Finalize() { // Unlock. if (!m_is_mapped && !m_is_owner_mapped) { const size_t size = m_page_group.GetNumPages() * PageSize; - m_owner->PageTable().UnlockForCodeMemory(m_address, size); + m_owner->PageTable().UnlockForCodeMemory(m_address, size, m_page_group); } + + // Close the page group. + m_page_group = {}; + + // Close our reference to our owner. + m_owner->Close(); } ResultCode KCodeMemory::Map(VAddr address, size_t size) { @@ -118,7 +119,8 @@ ResultCode KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermis k_perm = KMemoryPermission::UserReadExecute; break; default: - break; + // Already validated by ControlCodeMemory svc + UNREACHABLE(); } // Map the memory. diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index b38ef333b..68867a2bb 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -542,6 +542,95 @@ ResultCode KPageTable::MakePageGroup(KPageLinkedList& pg, VAddr addr, size_t num return ResultSuccess; } +bool KPageTable::IsValidPageGroup(const KPageLinkedList& pg_ll, VAddr addr, size_t num_pages) { + ASSERT(this->IsLockedByCurrentThread()); + + const size_t size = num_pages * PageSize; + const auto& pg = pg_ll.Nodes(); + const auto& memory_layout = system.Kernel().MemoryLayout(); + + // Empty groups are necessarily invalid. + if (pg.empty()) { + return false; + } + + // We're going to validate that the group we'd expect is the group we see. + auto cur_it = pg.begin(); + PAddr cur_block_address = cur_it->GetAddress(); + size_t cur_block_pages = cur_it->GetNumPages(); + + auto UpdateCurrentIterator = [&]() { + if (cur_block_pages == 0) { + if ((++cur_it) == pg.end()) { + return false; + } + + cur_block_address = cur_it->GetAddress(); + cur_block_pages = cur_it->GetNumPages(); + } + return true; + }; + + // Begin traversal. + Common::PageTable::TraversalContext context; + Common::PageTable::TraversalEntry next_entry; + if (!page_table_impl.BeginTraversal(next_entry, context, addr)) { + return false; + } + + // Prepare tracking variables. + PAddr cur_addr = next_entry.phys_addr; + size_t cur_size = next_entry.block_size - (cur_addr & (next_entry.block_size - 1)); + size_t tot_size = cur_size; + + // Iterate, comparing expected to actual. + while (tot_size < size) { + if (!page_table_impl.ContinueTraversal(next_entry, context)) { + return false; + } + + if (next_entry.phys_addr != (cur_addr + cur_size)) { + const size_t cur_pages = cur_size / PageSize; + + if (!IsHeapPhysicalAddress(memory_layout, cur_addr)) { + return false; + } + + if (!UpdateCurrentIterator()) { + return false; + } + + if (cur_block_address != cur_addr || cur_block_pages < cur_pages) { + return false; + } + + cur_block_address += cur_size; + cur_block_pages -= cur_pages; + cur_addr = next_entry.phys_addr; + cur_size = next_entry.block_size; + } else { + cur_size += next_entry.block_size; + } + + tot_size += next_entry.block_size; + } + + // Ensure we compare the right amount for the last block. + if (tot_size > size) { + cur_size -= (tot_size - size); + } + + if (!IsHeapPhysicalAddress(memory_layout, cur_addr)) { + return false; + } + + if (!UpdateCurrentIterator()) { + return false; + } + + return cur_block_address == cur_addr && cur_block_pages == (cur_size / PageSize); +} + ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size, KPageTable& src_page_table, VAddr src_addr) { KScopedLightLock lk(general_lock); @@ -1687,22 +1776,22 @@ ResultCode KPageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size) return ResultSuccess; } -ResultCode KPageTable::LockForCodeMemory(VAddr addr, std::size_t size) { +ResultCode KPageTable::LockForCodeMemory(KPageLinkedList* out, VAddr addr, std::size_t size) { return this->LockMemoryAndOpen( - nullptr, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, - KMemoryState::FlagCanCodeMemory, KMemoryPermission::All, KMemoryPermission::UserReadWrite, - KMemoryAttribute::All, KMemoryAttribute::None, + out, nullptr, addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory, + KMemoryPermission::All, KMemoryPermission::UserReadWrite, KMemoryAttribute::All, + KMemoryAttribute::None, static_cast<KMemoryPermission>(KMemoryPermission::NotMapped | KMemoryPermission::KernelReadWrite), KMemoryAttribute::Locked); } -ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size) { - return this->UnlockMemory(addr, size, KMemoryState::FlagCanCodeMemory, - KMemoryState::FlagCanCodeMemory, KMemoryPermission::None, - KMemoryPermission::None, KMemoryAttribute::All, - KMemoryAttribute::Locked, KMemoryPermission::UserReadWrite, - KMemoryAttribute::Locked, nullptr); +ResultCode KPageTable::UnlockForCodeMemory(VAddr addr, std::size_t size, + const KPageLinkedList& pg) { + return this->UnlockMemory( + addr, size, KMemoryState::FlagCanCodeMemory, KMemoryState::FlagCanCodeMemory, + KMemoryPermission::None, KMemoryPermission::None, KMemoryAttribute::All, + KMemoryAttribute::Locked, KMemoryPermission::UserReadWrite, KMemoryAttribute::Locked, &pg); } ResultCode KPageTable::InitializeMemoryLayout(VAddr start, VAddr end) { @@ -2125,7 +2214,7 @@ ResultCode KPageTable::UnlockMemory(VAddr addr, size_t size, KMemoryState state_ // Check the page group. if (pg != nullptr) { - UNIMPLEMENTED_MSG("PageGroup support is unimplemented!"); + R_UNLESS(this->IsValidPageGroup(*pg, addr, num_pages), ResultInvalidMemoryRegion); } // Decide on new perm and attr. diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 52a93ce86..6312eb682 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h @@ -72,8 +72,8 @@ public: KMemoryPermission perm, PAddr map_addr = 0); ResultCode LockForDeviceAddressSpace(VAddr addr, std::size_t size); ResultCode UnlockForDeviceAddressSpace(VAddr addr, std::size_t size); - ResultCode LockForCodeMemory(VAddr addr, std::size_t size); - ResultCode UnlockForCodeMemory(VAddr addr, std::size_t size); + ResultCode LockForCodeMemory(KPageLinkedList* out, VAddr addr, std::size_t size); + ResultCode UnlockForCodeMemory(VAddr addr, std::size_t size, const KPageLinkedList& pg); ResultCode MakeAndOpenPageGroup(KPageLinkedList* out, VAddr address, size_t num_pages, KMemoryState state_mask, KMemoryState state, KMemoryPermission perm_mask, KMemoryPermission perm, @@ -178,6 +178,7 @@ private: const KPageLinkedList* pg); ResultCode MakePageGroup(KPageLinkedList& pg, VAddr addr, size_t num_pages); + bool IsValidPageGroup(const KPageLinkedList& pg, VAddr addr, size_t num_pages); bool IsLockedByCurrentThread() const { return general_lock.IsLockedByCurrentThread(); diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index 3eae1ae35..32e0708ba 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -61,6 +61,7 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { } last_update_timestamp = shared_memory->gesture_lifo.timestamp; + UpdateGestureSharedMemory(gesture, time_difference); } void Controller_Gesture::ReadTouchInput() { @@ -94,8 +95,7 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, return false; } -void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, - GestureProperties& gesture, +void Controller_Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_difference) { GestureType type = GestureType::Idle; GestureAttribute attributes{}; diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index c62a341bf..0d6099ea0 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -107,8 +107,7 @@ private: bool ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference); // Updates the shared memory to the next state - void UpdateGestureSharedMemory(u8* data, std::size_t size, GestureProperties& gesture, - f32 time_difference); + void UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_difference); // Initializes new gesture void NewGesture(GestureProperties& gesture, GestureType& type, GestureAttribute& attributes); |