diff --git a/libraries/libstratosphere/include/stratosphere/fs/fs_program_index_map_info.hpp b/libraries/libstratosphere/include/stratosphere/fs/fs_program_index_map_info.hpp index eea67c4eb..793aef8f6 100644 --- a/libraries/libstratosphere/include/stratosphere/fs/fs_program_index_map_info.hpp +++ b/libraries/libstratosphere/include/stratosphere/fs/fs_program_index_map_info.hpp @@ -14,7 +14,8 @@ * along with this program. If not, see . */ #pragma once -#include +#include +#include namespace ams::fs { diff --git a/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_program_registry_service.hpp b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_program_registry_service.hpp index 284b264e8..3efa84898 100644 --- a/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_program_registry_service.hpp +++ b/libraries/libstratosphere/include/stratosphere/fssrv/fssrv_program_registry_service.hpp @@ -41,6 +41,16 @@ namespace ams::fssrv { Result RegisterProgramInfo(u64 process_id, u64 program_id, u8 storage_id, const void *data, s64 data_size, const void *desc, s64 desc_size); Result UnregisterProgramInfo(u64 process_id); + + Result ResetProgramIndexMapInfo(const fs::ProgramIndexMapInfo *infos, int count); + + Result GetProgramInfo(std::shared_ptr *out, u64 process_id); + Result GetProgramInfoByProgramId(std::shared_ptr *out, u64 program_id); + + size_t GetProgramIndexMapInfoCount(); + util::optional GetProgramIndexMapInfo(const ncm::ProgramId &program_id); + + ncm::ProgramId GetProgramIdByIndex(const ncm::ProgramId &program_id, u8 index); }; } diff --git a/libraries/libstratosphere/source/fssrv/fssrv_program_registry_service.cpp b/libraries/libstratosphere/source/fssrv/fssrv_program_registry_service.cpp index 6694c61c0..6963822db 100644 --- a/libraries/libstratosphere/source/fssrv/fssrv_program_registry_service.cpp +++ b/libraries/libstratosphere/source/fssrv/fssrv_program_registry_service.cpp @@ -15,17 +15,40 @@ */ #include #include "impl/fssrv_program_info.hpp" +#include "impl/fssrv_program_registry_manager.hpp" namespace ams::fssrv { Result ProgramRegistryServiceImpl::RegisterProgramInfo(u64 process_id, u64 program_id, u8 storage_id, const void *data, s64 data_size, const void *desc, s64 desc_size) { - AMS_ABORT("TODO"); - AMS_UNUSED(process_id, program_id, storage_id, data, data_size, desc, desc_size); + return m_registry_manager->RegisterProgram(process_id, program_id, storage_id, data, data_size, desc, desc_size); } Result ProgramRegistryServiceImpl::UnregisterProgramInfo(u64 process_id) { - AMS_ABORT("TODO"); - AMS_UNUSED(process_id); + return m_registry_manager->UnregisterProgram(process_id); + } + + Result ProgramRegistryServiceImpl::ResetProgramIndexMapInfo(const fs::ProgramIndexMapInfo *infos, int count) { + return m_index_map_info_manager->Reset(infos, count); + } + + Result ProgramRegistryServiceImpl::GetProgramInfo(std::shared_ptr *out, u64 process_id) { + return m_registry_manager->GetProgramInfo(out, process_id); + } + + Result ProgramRegistryServiceImpl::GetProgramInfoByProgramId(std::shared_ptr *out, u64 program_id) { + return m_registry_manager->GetProgramInfoByProgramId(out, program_id); + } + + size_t ProgramRegistryServiceImpl::GetProgramIndexMapInfoCount() { + return m_index_map_info_manager->GetProgramCount(); + } + + util::optional ProgramRegistryServiceImpl::GetProgramIndexMapInfo(const ncm::ProgramId &program_id) { + return m_index_map_info_manager->Get(program_id); + } + + ncm::ProgramId ProgramRegistryServiceImpl::GetProgramIdByIndex(const ncm::ProgramId &program_id, u8 index) { + return m_index_map_info_manager->GetProgramId(program_id, index); } } diff --git a/libraries/libstratosphere/source/fssrv/impl/fssrv_program_info.cpp b/libraries/libstratosphere/source/fssrv/impl/fssrv_program_info.cpp index f3ae2889f..0a5b8a2bc 100644 --- a/libraries/libstratosphere/source/fssrv/impl/fssrv_program_info.cpp +++ b/libraries/libstratosphere/source/fssrv/impl/fssrv_program_info.cpp @@ -28,6 +28,34 @@ namespace ams::fssrv::impl { constinit u64 g_current_process_id = 0; + constinit std::aligned_storage<0x80>::type g_static_buffer_for_program_info_for_initial_process; + + template + class StaticAllocatorForProgramInfoForInitialProcess : public std::allocator { + public: + StaticAllocatorForProgramInfoForInitialProcess() { /* ... */ } + + template + StaticAllocatorForProgramInfoForInitialProcess(const StaticAllocatorForProgramInfoForInitialProcess &) { /* ... */ } + + template + struct rebind { + using other = StaticAllocatorForProgramInfoForInitialProcess; + }; + + [[nodiscard]] T *allocate(::std::size_t n) { + AMS_ABORT_UNLESS(sizeof(T) * n <= sizeof(g_static_buffer_for_program_info_for_initial_process)); + return reinterpret_cast(std::addressof(g_static_buffer_for_program_info_for_initial_process)); + } + + void deallocate(T *p, ::std::size_t n) { + AMS_UNUSED(p, n); + } + }; + + constexpr const u32 FileAccessControlForInitialProgram[0x1C / sizeof(u32)] = {0x00000001, 0x00000000, 0x80000000, 0x0000001C, 0x00000000, 0x0000001C, 0x00000000}; + constexpr const u32 FileAccessControlDescForInitialProgram[0x2C / sizeof(u32)] = {0x00000001, 0x00000000, 0x80000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF}; + ALWAYS_INLINE void InitializeInitialAndCurrentProcessId() { if (AMS_UNLIKELY(!g_initialized)) { std::scoped_lock lk(g_mutex); @@ -50,6 +78,28 @@ namespace ams::fssrv::impl { } + std::shared_ptr ProgramInfo::GetProgramInfoForInitialProcess() { + static constinit os::SdkMutex s_mutex; + static constinit bool s_initialized = false; + static constinit std::shared_ptr s_initial_program_info = nullptr; + + /* Ensure we've initialized the program info. */ + if (AMS_UNLIKELY(!s_initialized)) { + std::scoped_lock lk(s_mutex); + if (AMS_LIKELY(!s_initialized)) { + class ProgramInfoHelper : public ProgramInfo { + public: + ProgramInfoHelper(const void *data, s64 data_size, const void *desc, s64 desc_size) : ProgramInfo(data, data_size, desc, desc_size) { /* ... */ } + }; + + s_initial_program_info = std::allocate_shared(StaticAllocatorForProgramInfoForInitialProcess{}, FileAccessControlForInitialProgram, sizeof(FileAccessControlForInitialProgram), FileAccessControlDescForInitialProgram, sizeof(FileAccessControlDescForInitialProgram)); + s_initialized = true; + } + } + + return s_initial_program_info; + } + bool IsInitialProgram(u64 process_id) { /* Initialize/sanity check. */ InitializeInitialAndCurrentProcessId(); diff --git a/libraries/libstratosphere/source/fssrv/impl/fssrv_program_info.hpp b/libraries/libstratosphere/source/fssrv/impl/fssrv_program_info.hpp index fe445b96d..10607d7f9 100644 --- a/libraries/libstratosphere/source/fssrv/impl/fssrv_program_info.hpp +++ b/libraries/libstratosphere/source/fssrv/impl/fssrv_program_info.hpp @@ -32,6 +32,19 @@ namespace ams::fssrv::impl { /* TODO */ AMS_UNUSED(data, data_size, desc, desc_size); } + + bool Contains(u64 process_id) const { return m_process_id == process_id; } + u64 GetProcessId() const { return m_process_id; } + ncm::ProgramId GetProgramId() const { return m_program_id; } + u64 GetProgramIdValue() const { return m_program_id.value; } + ncm::StorageId GetStorageId() const { return m_storage_id; } + public: + static std::shared_ptr GetProgramInfoForInitialProcess(); + private: + ProgramInfo(const void *data, s64 data_size, const void *desc, s64 desc_size) : m_process_id(0), m_program_id(0), m_storage_id(static_cast(0)) /* TODO: m_access_control */ { + /* TODO */ + AMS_UNUSED(data, data_size, desc, desc_size); + } }; struct ProgramInfoNode : public util::IntrusiveListBaseNode, public ::ams::fs::impl::Newable { diff --git a/libraries/libstratosphere/source/fssrv/impl/fssrv_program_registry_manager.cpp b/libraries/libstratosphere/source/fssrv/impl/fssrv_program_registry_manager.cpp new file mode 100644 index 000000000..be44f1108 --- /dev/null +++ b/libraries/libstratosphere/source/fssrv/impl/fssrv_program_registry_manager.cpp @@ -0,0 +1,105 @@ +/* + * 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 "fssrv_program_registry_manager.hpp" + +namespace ams::fssrv::impl { + + Result ProgramRegistryManager::RegisterProgram(u64 process_id, u64 program_id, u8 storage_id, const void *data, s64 data_size, const void *desc, s64 desc_size) { + /* Allocate a new node. */ + std::unique_ptr new_node(new ProgramInfoNode()); + R_UNLESS(new_node != nullptr, fs::ResultAllocationFailureInProgramRegistryManagerA()); + + /* Create a new program info. */ + { + /* Allocate the new info. */ + auto new_info = fssystem::AllocateShared(process_id, program_id, storage_id, data, data_size, desc, desc_size); + R_UNLESS(new_info != nullptr, fs::ResultAllocationFailureInProgramRegistryManagerA()); + + /* Set the info in the node. */ + new_node->program_info = std::move(new_info); + } + + /* Acquire exclusive access to the registry. */ + std::scoped_lock lk(m_mutex); + + /* Check that the process isn't already in the registry. */ + for (const auto &node : m_program_info_list) { + R_UNLESS(!node.program_info->Contains(process_id), fs::ResultInvalidArgument()); + } + + /* Add the node to the registry. */ + m_program_info_list.push_back(*new_node.release()); + + return ResultSuccess(); + } + + Result ProgramRegistryManager::UnregisterProgram(u64 process_id) { + /* Acquire exclusive access to the registry. */ + std::scoped_lock lk(m_mutex); + + /* Try to find and remove the process's node. */ + for (auto &node : m_program_info_list) { + if (node.program_info->Contains(process_id)) { + m_program_info_list.erase(m_program_info_list.iterator_to(node)); + delete std::addressof(node); + return ResultSuccess(); + } + } + + /* We couldn't find/unregister the process's node. */ + return fs::ResultInvalidArgument(); + } + + Result ProgramRegistryManager::GetProgramInfo(std::shared_ptr *out, u64 process_id) { + /* Acquire exclusive access to the registry. */ + std::scoped_lock lk(m_mutex); + + /* Check if we're getting permissions for an initial program. */ + if (IsInitialProgram(process_id)) { + *out = ProgramInfo::GetProgramInfoForInitialProcess(); + return ResultSuccess(); + } + + /* Find a matching node. */ + for (const auto &node : m_program_info_list) { + if (node.program_info->Contains(process_id)) { + *out = node.program_info; + return ResultSuccess(); + } + } + + /* We didn't find the program info. */ + return fs::ResultProgramInfoNotFound(); + } + + Result ProgramRegistryManager::GetProgramInfoByProgramId(std::shared_ptr *out, u64 program_id) { + /* Acquire exclusive access to the registry. */ + std::scoped_lock lk(m_mutex); + + /* Find a matching node. */ + for (const auto &node : m_program_info_list) { + if (node.program_info->GetProgramIdValue() == program_id) { + *out = node.program_info; + return ResultSuccess(); + } + } + + /* We didn't find the program info. */ + return fs::ResultProgramInfoNotFound(); + } + +} diff --git a/libraries/libvapours/include/vapours/results/fs_results.hpp b/libraries/libvapours/include/vapours/results/fs_results.hpp index 61e728a3a..d7b602689 100644 --- a/libraries/libvapours/include/vapours/results/fs_results.hpp +++ b/libraries/libvapours/include/vapours/results/fs_results.hpp @@ -82,6 +82,7 @@ namespace ams::fs { R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemC, 3249); R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemProxyCoreImplD, 3256); R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemProxyCoreImplE, 3257); + R_DEFINE_ERROR_RESULT(AllocationFailureInProgramRegistryManagerA, 3258); R_DEFINE_ERROR_RESULT(AllocationFailureInPartitionFileSystemCreatorA, 3280); R_DEFINE_ERROR_RESULT(AllocationFailureInRomFileSystemCreatorA, 3281); R_DEFINE_ERROR_RESULT(AllocationFailureInStorageOnNcaCreatorA, 3288); @@ -375,6 +376,7 @@ namespace ams::fs { R_DEFINE_ERROR_RESULT(UserNotExist, 6465); R_DEFINE_ERROR_RANGE(NotFound, 6600, 6699); + R_DEFINE_ERROR_RESULT(ProgramInfoNotFound, 6605); R_DEFINE_ERROR_RANGE(OutOfResource, 6700, 6799); R_DEFINE_ERROR_RESULT(BufferAllocationFailed, 6705);