// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include #include #include "common/logging/log.h" #include "core/hle/service/ipc_helpers.h" #include "core/hle/service/mm/mm_u.h" #include "core/hle/service/server_manager.h" #include "core/hle/service/sm/sm.h" namespace Service::MM { class MM_U final : public ServiceFramework { public: explicit MM_U(Core::System& system_) : ServiceFramework{system_, "mm:u"} { // clang-format off static const FunctionInfo functions[] = { {0, &MM_U::InitializeOld, "InitializeOld"}, {1, &MM_U::FinalizeOld, "FinalizeOld"}, {2, &MM_U::SetAndWaitOld, "SetAndWaitOld"}, {3, &MM_U::GetOld, "GetOld"}, {4, &MM_U::Initialize, "Initialize"}, {5, &MM_U::Finalize, "Finalize"}, {6, &MM_U::SetAndWait, "SetAndWait"}, {7, &MM_U::Get, "Get"}, }; // clang-format on RegisterHandlers(functions); } private: void InitializeOld(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto module = rp.PopEnum(); [[maybe_unused]] const auto priority = rp.Pop(); const auto clear_mode = static_cast(rp.Pop()); LOG_DEBUG(Service_MM, "called. module={:d}, clear_mode={:d}", static_cast(module), static_cast(clear_mode)); sessions.emplace_back(module, next_request_id++, clear_mode); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } void FinalizeOld(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto module = rp.PopEnum(); LOG_DEBUG(Service_MM, "called. module={:d}", static_cast(module)); std::erase_if(sessions, [&module](const auto& session) { return session.GetModule() == module; }); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } void SetAndWaitOld(HLERequestContext& ctx) { LOG_WARNING(Service_MM, "(STUBBED) called."); IPC::RequestParser rp{ctx}; const auto module = rp.PopEnum(); const auto min = rp.Pop(); const auto max = rp.Pop(); LOG_DEBUG(Service_MM, "called. module={:d}, min=0x{:X}, max=0x{:X}", static_cast(module), min, max); if (auto it = std::find_if(sessions.begin(), sessions.end(), [&module](const auto& session) { return session.GetModule() == module; }); it != sessions.end()) { it->SetAndWait(min, max); } IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } void GetOld(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto module = rp.PopEnum(); LOG_DEBUG(Service_MM, "called. module={:d}", static_cast(module)); u32 current_min = 0; if (auto it = std::find_if(sessions.begin(), sessions.end(), [&module](const auto& session) { return session.GetModule() == module; }); it != sessions.end()) { current_min = it->GetMin(); } IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); rb.Push(current_min); } void Initialize(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto module = rp.PopEnum(); [[maybe_unused]] const auto priority = rp.Pop(); const auto clear_mode = static_cast(rp.Pop()); LOG_DEBUG(Service_MM, "called. module={:d}, clear_mode={:d}", static_cast(module), static_cast(clear_mode)); const u32 current_id = next_request_id++; sessions.emplace_back(module, current_id, clear_mode); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); rb.Push(current_id); } void Finalize(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto request_id = rp.Pop(); LOG_DEBUG(Service_MM, "called. request_id={:d}", request_id); std::erase_if(sessions, [&request_id](const auto& session) { return session.GetRequestId() == request_id; }); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } void SetAndWait(HLERequestContext& ctx) { LOG_WARNING(Service_MM, "(STUBBED) called."); IPC::RequestParser rp{ctx}; const auto request_id = rp.Pop(); const auto min = rp.Pop(); const auto max = rp.Pop(); LOG_DEBUG(Service_MM, "called. request_id={:d}, min=0x{:X}, max=0x{:X}", request_id, min, max); if (auto it = std::find_if(sessions.begin(), sessions.end(), [&request_id](const auto& session) { return session.GetRequestId() == request_id; }); it != sessions.end()) { it->SetAndWait(min, max); } IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } void Get(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto request_id = rp.Pop(); LOG_DEBUG(Service_MM, "called. request_id={:d}", request_id); u32 current_min = 0; if (auto it = std::find_if(sessions.begin(), sessions.end(), [&request_id](const auto& session) { return session.GetRequestId() == request_id; }); it != sessions.end()) { current_min = it->GetMin(); } IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); rb.Push(current_min); } std::vector sessions; u32 next_request_id{1}; }; void LoopProcess(Core::System& system) { auto server_manager = std::make_unique(system); server_manager->RegisterNamedService("mm:u", std::make_shared(system)); ServerManager::RunServer(std::move(server_manager)); } } // namespace Service::MM