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);