/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include "../lm_service_name.hpp"
#include "lm_log_service_impl.hpp"
#include "lm_log_getter.hpp"
namespace ams::lm::srv {
namespace {
constexpr inline size_t LogSessionCountMax = 42;
constexpr inline size_t LogGetterSessionCountMax = 1;
constexpr inline size_t SessionCountMax = LogSessionCountMax + LogGetterSessionCountMax;
constexpr inline size_t PortCountMax = 2;
struct ServerManagerOptions {
static constexpr size_t PointerBufferSize = 0x400;
static constexpr size_t MaxDomains = 31;
static constexpr size_t MaxDomainObjects = 61;
static constexpr bool CanDeferInvokeRequest = false;
static constexpr bool CanManageMitmServers = false;
};
using ServerManager = sf::hipc::ServerManager;
constinit util::TypedStorage g_server_manager_storage = {};
constinit ServerManager *g_server_manager = nullptr;
constinit util::TypedStorage g_pm_module_storage = {};
constinit psc::PmModule *g_pm_module = nullptr;
constinit os::MultiWaitHolderType g_pm_module_holder = {};
constexpr const psc::PmModuleId PmModuleDependencies[] = { psc::PmModuleId_TmaHostIo, psc::PmModuleId_Fs };
/* Service objects. */
constinit sf::UnmanagedServiceObject g_log_service_object;
constinit sf::UnmanagedServiceObject g_log_getter_service_object;
constinit std::atomic g_is_sleeping = false;
}
bool IsSleeping() {
return g_is_sleeping;
}
void InitializeIpcServer() {
/* Check that we're not already initialized. */
AMS_ABORT_UNLESS(g_server_manager == nullptr);
AMS_ABORT_UNLESS(g_pm_module == nullptr);
/* Create and initialize the psc module. */
g_pm_module = util::ConstructAt(g_pm_module_storage);
R_ABORT_UNLESS(g_pm_module->Initialize(psc::PmModuleId_Lm, PmModuleDependencies, util::size(PmModuleDependencies), os::EventClearMode_ManualClear));
/* Create the psc module multi wait holder. */
os::InitializeMultiWaitHolder(std::addressof(g_pm_module_holder), g_pm_module->GetEventPointer()->GetBase());
os::SetMultiWaitHolderUserData(std::addressof(g_pm_module_holder), psc::PmModuleId_Lm);
/* Create the server manager. */
g_server_manager = util::ConstructAt(g_server_manager_storage);
/* Add the pm module holder. */
g_server_manager->AddUserMultiWaitHolder(std::addressof(g_pm_module_holder));
/* Create services. */
R_ABORT_UNLESS(g_server_manager->RegisterObjectForServer(g_log_service_object.GetShared(), LogServiceName, LogSessionCountMax));
R_ABORT_UNLESS(g_server_manager->RegisterObjectForServer(g_log_getter_service_object.GetShared(), LogGetterServiceName, LogGetterSessionCountMax));
/* Start the server manager. */
g_server_manager->ResumeProcessing();
}
void LoopIpcServer() {
/* Check that we're initialized. */
AMS_ABORT_UNLESS(g_server_manager != nullptr);
/* Loop forever, servicing the server. */
auto prev_state = psc::PmState_Unknown;
while (true) {
/* Get the next signaled holder. */
auto *signaled_holder = g_server_manager->WaitSignaled();
if (signaled_holder != std::addressof(g_pm_module_holder)) {
/* If ipc, process. */
R_ABORT_UNLESS(g_server_manager->Process(signaled_holder));
} else {
/* If pm module, clear the event. */
g_pm_module->GetEventPointer()->Clear();
g_server_manager->AddUserMultiWaitHolder(signaled_holder);
/* Get the power state. */
psc::PmState pm_state;
psc::PmFlagSet pm_flags;
R_ABORT_UNLESS(g_pm_module->GetRequest(std::addressof(pm_state), std::addressof(pm_flags)));
/* Handle the power state. */
if (prev_state == psc::PmState_EssentialServicesAwake && pm_state == psc::PmState_MinimumAwake) {
g_is_sleeping = false;
} else if (prev_state == psc::PmState_MinimumAwake && pm_state == psc::PmState_SleepReady) {
g_is_sleeping = true;
} else if (pm_state == psc::PmState_ShutdownReady) {
g_is_sleeping = true;
}
/* Set the previous state. */
prev_state = pm_state;
/* Acknowledge the state transition. */
R_ABORT_UNLESS(g_pm_module->Acknowledge(pm_state, ResultSuccess()));
}
}
}
void StopIpcServer() {
/* Check that we're initialized. */
AMS_ABORT_UNLESS(g_server_manager != nullptr);
/* Stop the server manager. */
g_server_manager->RequestStopProcessing();
}
void FinalizeIpcServer() {
/* Check that we're initialized. */
AMS_ABORT_UNLESS(g_server_manager != nullptr);
/* Destroy the server manager. */
std::destroy_at(g_server_manager);
g_server_manager = nullptr;
}
}