#include "fake_process.hpp" #include "ndm.hpp" #include #include namespace HLE { namespace OS { enum class ExclusiveState { None, Infrastructure, LocalCommunications, StreetPass, StreetPassData, }; struct FakeNDM { FakeNDM(FakeThread&); decltype(HLE::OS::ServiceHelper::SendReply) OnIPCRequest(Handle sender, Thread&, const IPC::CommandHeader&); // TODO: Should actually be tied to a ProcessId ExclusiveState exclusive_state = ExclusiveState::None; }; FakeNDM::FakeNDM(FakeThread& thread) { ServiceHelper service; service.Append(ServiceUtil::SetupService(thread, "ndm:u", /*2*/20)); auto InvokeCommandHandler = [&](FakeThread& thread, uint32_t signaled_index) { Platform::IPC::CommandHeader header = { thread.ReadTLS(0x80) }; return OnIPCRequest(service.handles[signaled_index], thread, header); }; service.Run(thread, std::move(InvokeCommandHandler)); } decltype(HLE::OS::ServiceHelper::SendReply) FakeNDM::OnIPCRequest(Handle sender, Thread& thread, const IPC::CommandHeader& header) { using EnterExclusiveState = IPC::IPCCommand<0x1>::add_uint32::add_process_id::response; using LeaveExclusiveState = IPC::IPCCommand<0x2>::add_process_id::response; switch (header.command_id) { case EnterExclusiveState::id: exclusive_state = static_cast(thread.ReadTLS(0x84)); if (Meta::to_underlying(exclusive_state) > Meta::to_underlying(ExclusiveState::StreetPassData)) { throw Mikage::Exceptions::Invalid("Invalid NDM exclusive state"); } thread.WriteTLS(0x80, IPC::CommandHeader::Make(0, 1, 0).raw); thread.WriteTLS(0x84, RESULT_OK); break; case LeaveExclusiveState::id: exclusive_state = ExclusiveState::None; thread.WriteTLS(0x80, IPC::CommandHeader::Make(0, 1, 0).raw); thread.WriteTLS(0x84, RESULT_OK); break; case 0x3: // QueryExclusiveMode thread.GetLogger()->info("{} received QueryExclusiveMode", ThreadPrinter{thread}); thread.WriteTLS(0x80, IPC::CommandHeader::Make(0, 2, 0).raw); thread.WriteTLS(0x84, RESULT_OK); thread.WriteTLS(0x88, Meta::to_underlying(exclusive_state)); break; case 0x6: // SuspendDaemons { thread.GetLogger()->info("{} received SuspendDaemons", ThreadPrinter{thread}); thread.WriteTLS(0x80, IPC::CommandHeader::Make(0, 1, 0).raw); thread.WriteTLS(0x84, RESULT_OK); break; } case 0x7: // ResumeDaemons { thread.GetLogger()->info("{} received ResumeDaemons", ThreadPrinter{thread}); thread.WriteTLS(0x80, IPC::CommandHeader::Make(0, 1, 0).raw); thread.WriteTLS(0x84, RESULT_OK); break; } case 0x8: // SuspendScheduler { thread.GetLogger()->info("{} received SuspendScheduler (parameter={:x})", ThreadPrinter{thread}, thread.ReadTLS(0x84)); thread.WriteTLS(0x80, IPC::CommandHeader::Make(0, 1, 0).raw); thread.WriteTLS(0x84, RESULT_OK); break; } case 0x9: // ResumeScheduler { thread.GetLogger()->info("{} received ResumeScheduler", ThreadPrinter{thread}); thread.WriteTLS(0x80, IPC::CommandHeader::Make(0, 1, 0).raw); thread.WriteTLS(0x84, RESULT_OK); break; } case 0x14: // OverrideDefaultDaemons { thread.GetLogger()->info("{} received OverrideDefaultDaemons", ThreadPrinter{thread}); thread.WriteTLS(0x80, IPC::CommandHeader::Make(0, 1, 0).raw); thread.WriteTLS(0x84, RESULT_OK); break; } case 0x15: // ResetDefaultDaemons { thread.GetLogger()->info("{} received ResetDefaultDaemons", ThreadPrinter{thread}); thread.WriteTLS(0x80, IPC::CommandHeader::Make(0, 1, 0).raw); thread.WriteTLS(0x84, RESULT_OK); break; } using ClearHalfAwakeMacFilter = IPC::IPCCommand<0x17>::response; case ClearHalfAwakeMacFilter::id: { thread.GetLogger()->info("{} received ClearHalfAwakeMacFilter", ThreadPrinter{thread}); thread.WriteTLS(0x80, IPC::CommandHeader::Make(0, 1, 0).raw); thread.WriteTLS(0x84, RESULT_OK); break; } default: throw std::runtime_error(fmt::format("Unknown ndm:u service command with header {:#010x}", header.raw)); } return HLE::OS::ServiceHelper::SendReply; } template<> std::shared_ptr CreateFakeProcessViaContext(OS& os, Interpreter::Setup& setup, uint32_t pid, const std::string& name) { return WrappedFakeProcess::CreateWithContext(os, setup, pid, name); } } // namespace OS } // namespace HLE