mirror of
https://git.citron-emu.org/Citron/Citron.git
synced 2025-02-07 16:56:21 +01:00
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
This commit is contained in:
parent
0adeac26af
commit
c279df9cfe
2 changed files with 117 additions and 38 deletions
|
@ -2,6 +2,7 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/hle/service/ipc_helpers.h"
|
#include "core/hle/service/ipc_helpers.h"
|
||||||
#include "core/hle/service/mm/mm_u.h"
|
#include "core/hle/service/mm/mm_u.h"
|
||||||
|
@ -25,7 +26,6 @@ public:
|
||||||
{7, &MM_U::Get, "Get"},
|
{7, &MM_U::Get, "Get"},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,11 +33,13 @@ private:
|
||||||
void InitializeOld(HLERequestContext& ctx) {
|
void InitializeOld(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto module = rp.PopEnum<Module>();
|
const auto module = rp.PopEnum<Module>();
|
||||||
const auto priority = rp.Pop<Priority>();
|
[[maybe_unused]] const auto priority = rp.Pop<u32>();
|
||||||
const auto event_clear_mode = rp.PopEnum<EventClearMode>();
|
const auto clear_mode = static_cast<EventClearMode>(rp.Pop<u32>());
|
||||||
|
|
||||||
LOG_WARNING(Service_MM, "(STUBBED) called, module={:d}, priority={:d}, event_clear_mode={:d}",
|
LOG_DEBUG(Service_MM, "called. module={:d}, clear_mode={:d}",
|
||||||
static_cast<u32>(module), priority, static_cast<u32>(event_clear_mode));
|
static_cast<u32>(module), static_cast<u32>(clear_mode));
|
||||||
|
|
||||||
|
sessions.emplace_back(module, next_request_id++, clear_mode);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
|
@ -47,7 +49,11 @@ private:
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto module = rp.PopEnum<Module>();
|
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};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
|
@ -56,13 +62,20 @@ private:
|
||||||
void SetAndWaitOld(HLERequestContext& ctx) {
|
void SetAndWaitOld(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto module = rp.PopEnum<Module>();
|
const auto module = rp.PopEnum<Module>();
|
||||||
min = rp.Pop<Setting>();
|
const auto min = rp.Pop<u32>();
|
||||||
max = rp.Pop<Setting>();
|
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);
|
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};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
}
|
}
|
||||||
|
@ -71,23 +84,48 @@ private:
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto module = rp.PopEnum<Module>();
|
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};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push(current);
|
rb.Push(current_min);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Initialize(HLERequestContext& ctx) {
|
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};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push<u32>(id); // Any non zero value
|
rb.Push(current_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Finalize(HLERequestContext& ctx) {
|
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};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
|
@ -95,34 +133,51 @@ private:
|
||||||
|
|
||||||
void SetAndWait(HLERequestContext& ctx) {
|
void SetAndWait(HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
u32 input_id = rp.Pop<u32>();
|
const auto request_id = rp.Pop<u32>();
|
||||||
min = rp.Pop<u32>();
|
const auto min = rp.Pop<u32>();
|
||||||
max = rp.Pop<u32>();
|
const auto max = rp.Pop<s32>();
|
||||||
LOG_DEBUG(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}", input_id,
|
|
||||||
min, max);
|
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};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Get(HLERequestContext& ctx) {
|
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};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.Push(current);
|
rb.Push(current_min);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 min{0};
|
std::vector<Session> sessions;
|
||||||
u32 max{0};
|
u32 next_request_id{1};
|
||||||
u32 current{0};
|
|
||||||
u32 id{1};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void LoopProcess(Core::System& system) {
|
void LoopProcess(Core::System& system) {
|
||||||
auto server_manager = std::make_unique<ServerManager>(system);
|
auto server_manager = std::make_unique<ServerManager>(system);
|
||||||
|
|
||||||
server_manager->RegisterNamedService("mm:u", std::make_shared<MM_U>(system));
|
server_manager->RegisterNamedService("mm:u", std::make_shared<MM_U>(system));
|
||||||
ServerManager::RunServer(std::move(server_manager));
|
ServerManager::RunServer(std::move(server_manager));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -13,22 +14,23 @@ class System;
|
||||||
namespace Service::MM {
|
namespace Service::MM {
|
||||||
|
|
||||||
enum class Module : u32 {
|
enum class Module : u32 {
|
||||||
Cpu = 0,
|
CPU = 0,
|
||||||
Gpu = 1,
|
GPU = 1,
|
||||||
Emc = 2,
|
EMC = 2,
|
||||||
SysBus = 3,
|
SYS_BUS = 3,
|
||||||
Mselect = 4,
|
M_SELECT = 4,
|
||||||
Nvdec = 5,
|
NVDEC = 5,
|
||||||
Nvenc = 6,
|
NVENC = 6,
|
||||||
Nvjpg = 7,
|
NVJPG = 7,
|
||||||
Test = 8,
|
TEST = 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
using Priority = u32;
|
using Priority = u32;
|
||||||
using Setting = u32;
|
using Setting = u32;
|
||||||
|
|
||||||
enum class EventClearMode : 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
|
// Consolidate settings into a struct for better organization
|
||||||
|
@ -39,6 +41,28 @@ struct Settings {
|
||||||
u32 id{1}; // Used by newer API versions
|
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);
|
void LoopProcess(Core::System& system);
|
||||||
|
|
||||||
} // namespace Service::MM
|
} // namespace Service::MM
|
||||||
|
|
Loading…
Reference in a new issue