/* * 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 <http://www.gnu.org/licenses/>. */ #include <stratosphere.hpp> #include "sprofile_srv_profile_manager.hpp" #include "sprofile_srv_service_for_bg_agent.hpp" #include "sprofile_srv_service_for_system_process.hpp" #include "sprofile_srv_service_getter.hpp" namespace ams::sprofile::srv { namespace { constexpr const ProfileManager::SaveDataInfo SaveDataInfo = { .id = 0x8000000000000220, .mount_name = "sprof", .size = 0x1C0000, .journal_size = 0x80000, .flags = fs::SaveDataFlags_KeepAfterResettingSystemSaveData, }; constexpr const sm::ServiceName ServiceNameForBgAgent = sm::ServiceName::Encode("sprof:bg"); constexpr const sm::ServiceName ServiceNameForSystemProcess = sm::ServiceName::Encode("sprof:sp"); constexpr inline size_t BgAgentSessionCountMax = 2; constexpr inline size_t SystemProcessSessionCountMax = 10; constexpr inline size_t SessionCountMax = BgAgentSessionCountMax + SystemProcessSessionCountMax; constexpr inline size_t PortCountMax = 2; struct ServerManagerOptions { static constexpr size_t PointerBufferSize = 0x0; static constexpr size_t MaxDomains = SessionCountMax; /* NOTE: Official is 9 */ static constexpr size_t MaxDomainObjects = 16; /* NOTE: Official is 14 */ static constexpr bool CanDeferInvokeRequest = false; static constexpr bool CanManageMitmServers = false; }; using ServerManager = sf::hipc::ServerManager<PortCountMax, ServerManagerOptions, SessionCountMax>; constinit util::TypedStorage<ProfileManager> g_profile_manager = {}; constinit util::TypedStorage<sf::UnmanagedServiceObject<ISprofileServiceForBgAgent, ServiceForBgAgent>> g_bg_service_object = {}; constinit util::TypedStorage<sf::UnmanagedServiceObject<ISprofileServiceForSystemProcess, ServiceForSystemProcess>> g_sp_service_object = {}; constinit util::TypedStorage<sf::UnmanagedServiceObject<IServiceGetter, ServiceGetter>> g_bg_service_getter = {}; constinit util::TypedStorage<sf::UnmanagedServiceObject<IServiceGetter, ServiceGetter>> g_sp_service_getter = {}; constinit util::TypedStorage<ServerManager> g_server_manager = {}; alignas(os::ThreadStackAlignment) constinit u8 g_ipc_thread_stack[0x3000]; constinit u8 g_heap[16_KB]; constinit os::ThreadType g_ipc_thread = {}; constinit lmem::HeapHandle g_heap_handle = nullptr; constinit sf::ExpHeapMemoryResource g_sf_memory_resource; void IpcServerThreadFunction(void *) { /* Get the server manager. */ auto &server_manager = util::GetReference(g_server_manager); /* Resume processing. */ server_manager.ResumeProcessing(); /* Loop processing. */ server_manager.LoopProcess(); } } void Initialize() { /* Initialize heap. */ g_heap_handle = lmem::CreateExpHeap(g_heap, sizeof(g_heap), lmem::CreateOption_ThreadSafe); /* Attach the memory resource to heap. */ g_sf_memory_resource.Attach(g_heap_handle); /* Create the profile manager. */ util::ConstructAt(g_profile_manager, SaveDataInfo); /* Process profile manager savedata. */ util::GetReference(g_profile_manager).InitializeSaveData(); /* Create the service objects. */ util::ConstructAt(g_bg_service_object, std::addressof(g_sf_memory_resource), util::GetPointer(g_profile_manager)); util::ConstructAt(g_sp_service_object, std::addressof(g_sf_memory_resource), util::GetPointer(g_profile_manager)); /* Create the service getters. */ util::ConstructAt(g_bg_service_getter, util::GetReference(g_bg_service_object).GetShared(), util::GetReference(g_sp_service_object).GetShared()); util::ConstructAt(g_sp_service_getter, nullptr, util::GetReference(g_sp_service_object).GetShared()); /* Create the server manager. */ util::ConstructAt(g_server_manager); /* Create services. */ if (hos::GetVersion() >= hos::Version_14_0_0) { R_ABORT_UNLESS(util::GetReference(g_server_manager).RegisterObjectForServer(util::GetReference(g_bg_service_getter).GetShared(), ServiceNameForBgAgent, BgAgentSessionCountMax)); R_ABORT_UNLESS(util::GetReference(g_server_manager).RegisterObjectForServer(util::GetReference(g_sp_service_getter).GetShared(), ServiceNameForSystemProcess, SystemProcessSessionCountMax)); } else { R_ABORT_UNLESS(util::GetReference(g_server_manager).RegisterObjectForServer(util::GetReference(g_bg_service_object).GetShared(), ServiceNameForBgAgent, BgAgentSessionCountMax)); R_ABORT_UNLESS(util::GetReference(g_server_manager).RegisterObjectForServer(util::GetReference(g_sp_service_object).GetShared(), ServiceNameForSystemProcess, SystemProcessSessionCountMax)); } } void StartIpcServer() { /* Create the ipc server thread. */ R_ABORT_UNLESS(os::CreateThread(std::addressof(g_ipc_thread), IpcServerThreadFunction, nullptr, g_ipc_thread_stack, sizeof(g_ipc_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(sprofile, IpcServer))); os::SetThreadNamePointer(std::addressof(g_ipc_thread), AMS_GET_SYSTEM_THREAD_NAME(sprofile, IpcServer)); /* Start the ipc server thread. */ os::StartThread(std::addressof(g_ipc_thread)); } }