summaryrefslogtreecommitdiff
path: root/src/core/hle
diff options
context:
space:
mode:
authorZephyron <zephyron@citron-emu.org>2025-01-25 14:55:50 +1000
committerZephyron <zephyron@citron-emu.org>2025-01-25 14:55:50 +1000
commitc279df9cfe50ea918abaf10b0f856118a1fcb11f (patch)
treed3970a267eee5de632df44bf8947960695286bbf /src/core/hle
parent0adeac26af77c7fb0605b08ab858a7c8262ffc88 (diff)
service: mm: Refactor Memory Management service implementation
Refactors the MM (Memory Management) service implementation with improved: - Session management using a vector of Session objects instead of global vars - Type safety with proper enums and member encapsulation - Error handling with consistent patterns - Modern C++ features (std::erase_if, std::find_if, emplace_back) - Logging with detailed debug messages - Code organization and const correctness Key changes: - Add Session class with proper encapsulation - Add EventClearMode enum (Manual = 0, Auto = 1) - Update Module enum naming for consistency - Implement proper session tracking and lookup - Add detailed parameter logging - Use modern C++ algorithms for session management The implementation now properly handles multiple sessions and matches the documented nn::mmnv::IRequest interface more closely. Refs: switchbrew.org/wiki/Display_services#mm:u
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/service/mm/mm_u.cpp111
-rw-r--r--src/core/hle/service/mm/mm_u.h44
2 files changed, 117 insertions, 38 deletions
diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp
index 64e3c3eea..a99c01286 100644
--- a/src/core/hle/service/mm/mm_u.cpp
+++ b/src/core/hle/service/mm/mm_u.cpp
@@ -2,6 +2,7 @@
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include <algorithm>
#include "common/logging/log.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/mm/mm_u.h"
@@ -25,7 +26,6 @@ public:
{7, &MM_U::Get, "Get"},
};
// clang-format on
-
RegisterHandlers(functions);
}
@@ -33,11 +33,13 @@ private:
void InitializeOld(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto module = rp.PopEnum<Module>();
- const auto priority = rp.Pop<Priority>();
- const auto event_clear_mode = rp.PopEnum<EventClearMode>();
+ [[maybe_unused]] const auto priority = rp.Pop<u32>();
+ const auto clear_mode = static_cast<EventClearMode>(rp.Pop<u32>());
+
+ LOG_DEBUG(Service_MM, "called. module={:d}, clear_mode={:d}",
+ static_cast<u32>(module), static_cast<u32>(clear_mode));
- LOG_WARNING(Service_MM, "(STUBBED) called, module={:d}, priority={:d}, event_clear_mode={:d}",
- static_cast<u32>(module), priority, static_cast<u32>(event_clear_mode));
+ sessions.emplace_back(module, next_request_id++, clear_mode);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -47,7 +49,11 @@ private:
IPC::RequestParser rp{ctx};
const auto module = rp.PopEnum<Module>();
- LOG_WARNING(Service_MM, "(STUBBED) called, module={:d}", static_cast<u32>(module));
+ LOG_DEBUG(Service_MM, "called. module={:d}", static_cast<u32>(module));
+
+ std::erase_if(sessions, [&module](const auto& session) {
+ return session.GetModule() == module;
+ });
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
@@ -56,13 +62,20 @@ private:
void SetAndWaitOld(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto module = rp.PopEnum<Module>();
- min = rp.Pop<Setting>();
- max = rp.Pop<Setting>();
+ const auto min = rp.Pop<u32>();
+ const auto max = rp.Pop<s32>();
- LOG_DEBUG(Service_MM, "(STUBBED) called, module={:d}, min=0x{:X}, max=0x{:X}",
+ LOG_DEBUG(Service_MM, "called. module={:d}, min=0x{:X}, max=0x{:X}",
static_cast<u32>(module), min, max);
- current = min;
+ 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);
}
@@ -71,23 +84,48 @@ private:
IPC::RequestParser rp{ctx};
const auto module = rp.PopEnum<Module>();
- LOG_DEBUG(Service_MM, "(STUBBED) called, module={:d}", static_cast<u32>(module));
+ LOG_DEBUG(Service_MM, "called. module={:d}", static_cast<u32>(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);
+ rb.Push(current_min);
}
void Initialize(HLERequestContext& ctx) {
- LOG_WARNING(Service_MM, "(STUBBED) called");
+ IPC::RequestParser rp{ctx};
+ const auto module = rp.PopEnum<Module>();
+ [[maybe_unused]] const auto priority = rp.Pop<u32>();
+ const auto clear_mode = static_cast<EventClearMode>(rp.Pop<u32>());
+
+ LOG_DEBUG(Service_MM, "called. module={:d}, clear_mode={:d}",
+ static_cast<u32>(module), static_cast<u32>(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<u32>(id); // Any non zero value
+ rb.Push(current_id);
}
void Finalize(HLERequestContext& ctx) {
- LOG_WARNING(Service_MM, "(STUBBED) called");
+ IPC::RequestParser rp{ctx};
+ const auto request_id = rp.Pop<u32>();
+
+ 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);
@@ -95,34 +133,51 @@ private:
void SetAndWait(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- u32 input_id = rp.Pop<u32>();
- min = rp.Pop<u32>();
- max = rp.Pop<u32>();
- LOG_DEBUG(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}", input_id,
- min, max);
+ const auto request_id = rp.Pop<u32>();
+ const auto min = rp.Pop<u32>();
+ const auto max = rp.Pop<s32>();
+
+ 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);
+ }
- current = min;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Get(HLERequestContext& ctx) {
- LOG_DEBUG(Service_MM, "(STUBBED) called");
+ IPC::RequestParser rp{ctx};
+ const auto request_id = rp.Pop<u32>();
+
+ 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);
+ rb.Push(current_min);
}
- u32 min{0};
- u32 max{0};
- u32 current{0};
- u32 id{1};
+ std::vector<Session> sessions;
+ u32 next_request_id{1};
};
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
-
server_manager->RegisterNamedService("mm:u", std::make_shared<MM_U>(system));
ServerManager::RunServer(std::move(server_manager));
}
diff --git a/src/core/hle/service/mm/mm_u.h b/src/core/hle/service/mm/mm_u.h
index bae9eabf8..dd0a567cf 100644
--- a/src/core/hle/service/mm/mm_u.h
+++ b/src/core/hle/service/mm/mm_u.h
@@ -4,6 +4,7 @@
#pragma once
+#include <vector>
#include "common/common_types.h"
namespace Core {
@@ -13,22 +14,23 @@ class System;
namespace Service::MM {
enum class Module : u32 {
- Cpu = 0,
- Gpu = 1,
- Emc = 2,
- SysBus = 3,
- Mselect = 4,
- Nvdec = 5,
- Nvenc = 6,
- Nvjpg = 7,
- Test = 8,
+ CPU = 0,
+ GPU = 1,
+ EMC = 2,
+ SYS_BUS = 3,
+ M_SELECT = 4,
+ NVDEC = 5,
+ NVENC = 6,
+ NVJPG = 7,
+ TEST = 8,
};
using Priority = u32;
using Setting = u32;
enum class EventClearMode : u32 {
- // TODO: Add specific clear mode values when documented
+ Manual = 0,
+ Auto = 1,
};
// Consolidate settings into a struct for better organization
@@ -39,6 +41,28 @@ struct Settings {
u32 id{1}; // Used by newer API versions
};
+class Session {
+public:
+ explicit Session(Module module_, u32 request_id_, EventClearMode clear_mode_)
+ : module{module_}, request_id{request_id_}, clear_mode{clear_mode_} {}
+
+ void SetAndWait(u32 min_, s32 max_) {
+ min = min_;
+ max = max_;
+ }
+
+ [[nodiscard]] u32 GetMin() const { return min; }
+ [[nodiscard]] Module GetModule() const { return module; }
+ [[nodiscard]] u32 GetRequestId() const { return request_id; }
+
+private:
+ Module module;
+ u32 request_id{0};
+ u32 min{0};
+ s32 max{-1};
+ EventClearMode clear_mode;
+};
+
void LoopProcess(Core::System& system);
} // namespace Service::MM