fssrv: flesh out the program registry

This commit is contained in:
Michael Scire 2021-12-07 12:17:34 -08:00 committed by SciresM
parent e8d14eb77d
commit 28ea6555f8
7 changed files with 209 additions and 5 deletions

View file

@ -14,7 +14,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#pragma once #pragma once
#include <stratosphere/fs/fs_common.hpp> #include <vapours.hpp>
#include <stratosphere/ncm/ncm_ids.hpp>
namespace ams::fs { namespace ams::fs {

View file

@ -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 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 UnregisterProgramInfo(u64 process_id);
Result ResetProgramIndexMapInfo(const fs::ProgramIndexMapInfo *infos, int count);
Result GetProgramInfo(std::shared_ptr<impl::ProgramInfo> *out, u64 process_id);
Result GetProgramInfoByProgramId(std::shared_ptr<impl::ProgramInfo> *out, u64 program_id);
size_t GetProgramIndexMapInfoCount();
util::optional<fs::ProgramIndexMapInfo> GetProgramIndexMapInfo(const ncm::ProgramId &program_id);
ncm::ProgramId GetProgramIdByIndex(const ncm::ProgramId &program_id, u8 index);
}; };
} }

View file

@ -15,17 +15,40 @@
*/ */
#include <stratosphere.hpp> #include <stratosphere.hpp>
#include "impl/fssrv_program_info.hpp" #include "impl/fssrv_program_info.hpp"
#include "impl/fssrv_program_registry_manager.hpp"
namespace ams::fssrv { 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) { 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"); return m_registry_manager->RegisterProgram(process_id, program_id, storage_id, data, data_size, desc, desc_size);
AMS_UNUSED(process_id, program_id, storage_id, data, data_size, desc, desc_size);
} }
Result ProgramRegistryServiceImpl::UnregisterProgramInfo(u64 process_id) { Result ProgramRegistryServiceImpl::UnregisterProgramInfo(u64 process_id) {
AMS_ABORT("TODO"); return m_registry_manager->UnregisterProgram(process_id);
AMS_UNUSED(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<impl::ProgramInfo> *out, u64 process_id) {
return m_registry_manager->GetProgramInfo(out, process_id);
}
Result ProgramRegistryServiceImpl::GetProgramInfoByProgramId(std::shared_ptr<impl::ProgramInfo> *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<fs::ProgramIndexMapInfo> 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);
} }
} }

View file

@ -28,6 +28,34 @@ namespace ams::fssrv::impl {
constinit u64 g_current_process_id = 0; constinit u64 g_current_process_id = 0;
constinit std::aligned_storage<0x80>::type g_static_buffer_for_program_info_for_initial_process;
template<typename T>
class StaticAllocatorForProgramInfoForInitialProcess : public std::allocator<T> {
public:
StaticAllocatorForProgramInfoForInitialProcess() { /* ... */ }
template<typename U>
StaticAllocatorForProgramInfoForInitialProcess(const StaticAllocatorForProgramInfoForInitialProcess<U> &) { /* ... */ }
template<typename U>
struct rebind {
using other = StaticAllocatorForProgramInfoForInitialProcess<U>;
};
[[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<T *>(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() { ALWAYS_INLINE void InitializeInitialAndCurrentProcessId() {
if (AMS_UNLIKELY(!g_initialized)) { if (AMS_UNLIKELY(!g_initialized)) {
std::scoped_lock lk(g_mutex); std::scoped_lock lk(g_mutex);
@ -50,6 +78,28 @@ namespace ams::fssrv::impl {
} }
std::shared_ptr<ProgramInfo> ProgramInfo::GetProgramInfoForInitialProcess() {
static constinit os::SdkMutex s_mutex;
static constinit bool s_initialized = false;
static constinit std::shared_ptr<ProgramInfo> 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<ProgramInfoHelper>(StaticAllocatorForProgramInfoForInitialProcess<char>{}, FileAccessControlForInitialProgram, sizeof(FileAccessControlForInitialProgram), FileAccessControlDescForInitialProgram, sizeof(FileAccessControlDescForInitialProgram));
s_initialized = true;
}
}
return s_initial_program_info;
}
bool IsInitialProgram(u64 process_id) { bool IsInitialProgram(u64 process_id) {
/* Initialize/sanity check. */ /* Initialize/sanity check. */
InitializeInitialAndCurrentProcessId(); InitializeInitialAndCurrentProcessId();

View file

@ -32,6 +32,19 @@ namespace ams::fssrv::impl {
/* TODO */ /* TODO */
AMS_UNUSED(data, data_size, desc, desc_size); 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<ProgramInfo> 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<ncm::StorageId>(0)) /* TODO: m_access_control */ {
/* TODO */
AMS_UNUSED(data, data_size, desc, desc_size);
}
}; };
struct ProgramInfoNode : public util::IntrusiveListBaseNode<ProgramInfoNode>, public ::ams::fs::impl::Newable { struct ProgramInfoNode : public util::IntrusiveListBaseNode<ProgramInfoNode>, public ::ams::fs::impl::Newable {

View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
#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<ProgramInfoNode> 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<ProgramInfo>(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<ProgramInfo> *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<ProgramInfo> *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();
}
}

View file

@ -82,6 +82,7 @@ namespace ams::fs {
R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemC, 3249); R_DEFINE_ERROR_RESULT(AllocationFailureInRomFsFileSystemC, 3249);
R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemProxyCoreImplD, 3256); R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemProxyCoreImplD, 3256);
R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemProxyCoreImplE, 3257); R_DEFINE_ERROR_RESULT(AllocationFailureInFileSystemProxyCoreImplE, 3257);
R_DEFINE_ERROR_RESULT(AllocationFailureInProgramRegistryManagerA, 3258);
R_DEFINE_ERROR_RESULT(AllocationFailureInPartitionFileSystemCreatorA, 3280); R_DEFINE_ERROR_RESULT(AllocationFailureInPartitionFileSystemCreatorA, 3280);
R_DEFINE_ERROR_RESULT(AllocationFailureInRomFileSystemCreatorA, 3281); R_DEFINE_ERROR_RESULT(AllocationFailureInRomFileSystemCreatorA, 3281);
R_DEFINE_ERROR_RESULT(AllocationFailureInStorageOnNcaCreatorA, 3288); R_DEFINE_ERROR_RESULT(AllocationFailureInStorageOnNcaCreatorA, 3288);
@ -375,6 +376,7 @@ namespace ams::fs {
R_DEFINE_ERROR_RESULT(UserNotExist, 6465); R_DEFINE_ERROR_RESULT(UserNotExist, 6465);
R_DEFINE_ERROR_RANGE(NotFound, 6600, 6699); R_DEFINE_ERROR_RANGE(NotFound, 6600, 6699);
R_DEFINE_ERROR_RESULT(ProgramInfoNotFound, 6605);
R_DEFINE_ERROR_RANGE(OutOfResource, 6700, 6799); R_DEFINE_ERROR_RANGE(OutOfResource, 6700, 6799);
R_DEFINE_ERROR_RESULT(BufferAllocationFailed, 6705); R_DEFINE_ERROR_RESULT(BufferAllocationFailed, 6705);