#include "sm_hpv.hpp" #include "os_hypervisor_private.hpp" #include "os.hpp" #include #include #include #include #include #include namespace HLE { namespace OS { namespace HPV { namespace { struct SrvService : SessionToPort { SrvService(RefCounted port, SMContext& context) : SessionToPort(port, context) { } void OnRequest(Hypervisor& hypervisor, Thread& thread, Handle session) override { namespace SMSRV = Platform::SM::SRV; const uint32_t command_header = thread.ReadTLS(0x80); auto dispatcher = RequestDispatcher<> { thread, *this, command_header }; dispatcher.DecodeRequest([&](auto&, ProcessId process_id) { Session::OnRequest(hypervisor, thread, session, fmt::format("RegisterClient, process {}", process_id)); }); dispatcher.DecodeRequest([&](auto& response) { Session::OnRequest(hypervisor, thread, session, "EnableNotification"); response.OnResponse([=](Hypervisor&, Thread& thread, Result result, Handle notification_handle) { // TODO: Check result code auto semaphore = thread.GetProcessHandleTable().FindObject(notification_handle); assert(semaphore); semaphore->name = "SMNotification"; }); }); dispatcher.DecodeRequest([&](auto& response, const Platform::SM::PortName& port_name, uint32_t max_sessions) { auto description = fmt::format("RegisterService, name=\"{}\", max_sessions={:#x}", port_name.ToString(), max_sessions); Session::OnRequest(hypervisor, thread, session, description); response.OnResponse([=](Hypervisor& hv, Thread& thread, Result result, Handle port_handle) { if (result != RESULT_OK) { throw Mikage::Exceptions::Invalid("Failed to register service {}", port_name.ToString()); } hv.SetPortName(thread.GetParentProcess().GetId(), port_handle, port_name.ToString()); auto server_port = thread.GetProcessHandleTable().FindObject(port_handle); assert(server_port); server_port->name = "SPort_" + port_name.ToString(); if (auto client_port = server_port->port->client.lock()) { client_port->name = "CPort_" + port_name.ToString(); } }); }); dispatcher.DecodeRequest([&](auto& response, const Platform::SM::PortName& port_name, uint32_t flags) { auto description = fmt::format("GetServiceHandle, name=\"{}\", flags={:#x}", port_name.ToString(), flags); Session::OnRequest(hypervisor, thread, session, description); response.OnResponse([=](Hypervisor&, Thread& thread, Result result, Handle session_handle) { if (result != RESULT_OK) { throw Mikage::Exceptions::Invalid("Failed to get handle for service {}", port_name.ToString()); } auto client_session = thread.GetProcessHandleTable().FindObject(session_handle); assert(client_session); client_session->name = "CSession_" + port_name.ToString(); }); }); dispatcher.DecodeRequest([&](auto&, uint32_t notification_id) { auto description = fmt::format("Subscribe, id={:#x}", notification_id); Session::OnRequest(hypervisor, thread, session, description); }); dispatcher.OnUnknown([&]() { Session::OnRequest(hypervisor, thread, session); }); } }; struct SrvPmService : SrvService { SrvPmService(RefCounted port, SMContext& context) : SrvService(port, context) { } void OnRequest(Hypervisor& hypervisor, Thread& thread, Handle session) override { namespace SMSRVPM = Platform::SM::SRVPM; const uint32_t command_header = thread.ReadTLS(0x80); auto dispatcher = RequestDispatcher<> { thread, *this, command_header }; dispatcher.DecodeRequest([&](auto& response, ProcessId process_id, uint32_t service_list_num_words, IPC::StaticBuffer service_list) { if (service_list_num_words * 4 > service_list.size) { throw std::runtime_error(fmt::format("RegisterProcess: {} bytes of data requested, but only {} available", service_list_num_words * 4, service_list.size)); } auto description = fmt::format("RegisterProcess, pid={}, services=[", process_id); auto read_port_name = [&](auto index) { auto addr = service_list.addr + index * 8; return Platform::SM::PortName::IPCDeserialize(thread.ReadMemory32(addr), thread.ReadMemory32(addr + 4), 8).ToString(); }; description += ranges::accumulate(ranges::view::iota(uint32_t { }, service_list_num_words / 2) | ranges::view::transform(read_port_name) | ranges::view::intersperse(", "), std::string{}); description += ']'; Session::OnRequest(hypervisor, thread, session, description); }); dispatcher.OnUnknown([&]() { SrvService::OnRequest(hypervisor, thread, session); }); } }; } // anonymous namespace HPV::RefCounted CreateSMSrvService(RefCounted port, SMContext& context) { return HPV::RefCounted(new SrvService(port, context)); } HPV::RefCounted CreateSMSrvPmService(RefCounted port, SMContext& context) { return HPV::RefCounted(new SrvPmService(port, context)); } } // namespace HPV } // namespace HOS } // namespace HLE