diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1eb43d816e..d78f907f26 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -60,6 +60,7 @@ add_library(core STATIC file_sys/fs_path_utility.h file_sys/fs_save_data_types.h file_sys/fs_string_util.h + file_sys/fs_program_index_map_info.h file_sys/fsa/fs_i_directory.h file_sys/fsa/fs_i_file.h file_sys/fsa/fs_i_filesystem.h @@ -109,6 +110,19 @@ add_library(core STATIC file_sys/fssystem/fssystem_switch_storage.h file_sys/fssystem/fssystem_utility.cpp file_sys/fssystem/fssystem_utility.h + file_sys/fssrv/impl/fssrv_program_info.cpp + file_sys/fssrv/impl/fssrv_program_info.h + file_sys/fssrv/impl/fssrv_access_control.h + file_sys/fssrv/impl/fssrv_access_control.cpp + file_sys/fssrv/impl/fssrv_access_control_bits.h + file_sys/fssrv/impl/fssrv_program_registry_manager.cpp + file_sys/fssrv/impl/fssrv_program_registry_manager.h + file_sys/fssrv/impl/fssrv_program_index_map_info_manager.h + file_sys/fssrv/impl/fssrv_save_data_properties.h + file_sys/fssrv/fssrv_program_registry_impl.h + file_sys/fssrv/fssrv_program_registry_impl.cpp + file_sys/fssrv/fssrv_program_registry_service.h + file_sys/fssrv/fssrv_program_registry_service.cpp file_sys/ips_layer.cpp file_sys/ips_layer.h file_sys/kernel_executable.cpp diff --git a/src/core/file_sys/errors.h b/src/core/file_sys/errors.h index b22767bf5b..ba697ece30 100644 --- a/src/core/file_sys/errors.h +++ b/src/core/file_sys/errors.h @@ -16,11 +16,13 @@ constexpr Result ResultPortSdCardNoDevice{ErrorModule::FS, 2001}; constexpr Result ResultNotImplemented{ErrorModule::FS, 3001}; constexpr Result ResultUnsupportedVersion{ErrorModule::FS, 3002}; constexpr Result ResultOutOfRange{ErrorModule::FS, 3005}; +constexpr Result ResultAllocationMemoryFailedInProgramRegistryManagerA{ErrorModule::FS, 3258}; constexpr Result ResultAllocationMemoryFailedInFileSystemBuddyHeapA{ErrorModule::FS, 3294}; constexpr Result ResultAllocationMemoryFailedInNcaFileSystemDriverI{ErrorModule::FS, 3341}; constexpr Result ResultAllocationMemoryFailedInNcaReaderA{ErrorModule::FS, 3363}; constexpr Result ResultAllocationMemoryFailedInAesCtrCounterExtendedStorageA{ErrorModule::FS, 3399}; constexpr Result ResultAllocationMemoryFailedInIntegrityRomFsStorageA{ErrorModule::FS, 3412}; +constexpr Result ResultAllocationMemoryFailedNew{ErrorModule::FS, 3420}; constexpr Result ResultAllocationMemoryFailedMakeUnique{ErrorModule::FS, 3422}; constexpr Result ResultAllocationMemoryFailedAllocateShared{ErrorModule::FS, 3423}; constexpr Result ResultInvalidAesCtrCounterExtendedEntryOffset{ErrorModule::FS, 4012}; @@ -92,6 +94,7 @@ constexpr Result ResultUnsupportedSetSizeForIndirectStorage{ErrorModule::FS, 632 constexpr Result ResultUnsupportedWriteForCompressedStorage{ErrorModule::FS, 6387}; constexpr Result ResultUnsupportedOperateRangeForCompressedStorage{ErrorModule::FS, 6388}; constexpr Result ResultPermissionDenied{ErrorModule::FS, 6400}; +constexpr Result ResultProgramInfoNotFound{ErrorModule::FS, 6605}; constexpr Result ResultBufferAllocationFailed{ErrorModule::FS, 6705}; } // namespace FileSys diff --git a/src/core/file_sys/fs_program_index_map_info.h b/src/core/file_sys/fs_program_index_map_info.h new file mode 100644 index 0000000000..564c36d073 --- /dev/null +++ b/src/core/file_sys/fs_program_index_map_info.h @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_funcs.h" + +namespace FileSys { + +struct ProgramIndexMapInfo { + u64 program_id; + u64 base_program_id; + u8 program_index; + INSERT_PADDING_BYTES(0xF); +}; +static_assert(std::is_trivially_copyable_v, + "Data type must be trivially copyable."); +static_assert(sizeof(ProgramIndexMapInfo) == 0x20, "ProgramIndexMapInfo has invalid size."); + +} // namespace FileSys diff --git a/src/core/file_sys/fssrv/fssrv_program_registry_impl.cpp b/src/core/file_sys/fssrv/fssrv_program_registry_impl.cpp new file mode 100644 index 0000000000..be825eefbc --- /dev/null +++ b/src/core/file_sys/fssrv/fssrv_program_registry_impl.cpp @@ -0,0 +1,77 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/file_sys/errors.h" +#include "core/file_sys/fssrv/fssrv_program_registry_impl.h" +#include "core/file_sys/fssrv/fssrv_program_registry_service.h" +#include "core/file_sys/fssrv/impl/fssrv_program_info.h" + +namespace FileSys::FsSrv { + +namespace { +constinit ProgramRegistryServiceImpl* g_impl = nullptr; +} + +// TODO: Move this to a common types file +constexpr u64 InvalidProcessIdProgramRegistry = 0xffffffffffffffffULL; + +ProgramRegistryImpl::ProgramRegistryImpl(Core::System& system_) + : m_process_id(InvalidProcessIdProgramRegistry), system{system_} {} + +ProgramRegistryImpl::~ProgramRegistryImpl() {} + +void ProgramRegistryImpl::Initialize(ProgramRegistryServiceImpl* service) { + // Check pre-conditions + ASSERT(g_impl != nullptr); + ASSERT(g_impl == nullptr); + + // Set the global service + g_impl = service; +} + +Result ProgramRegistryImpl::RegisterProgram(u64 process_id, u64 program_id, u8 storage_id, + const InBuffer data, + s64 data_size, + const InBuffer desc, + s64 desc_size) { + // Check pre-conditions + ASSERT(g_impl != nullptr); + + // Check that we're allowed to register + R_UNLESS(FsSrv::Impl::IsInitialProgram(system, m_process_id), ResultPermissionDenied); + + // Check buffer sizes + R_UNLESS(data.size() >= static_cast(data_size), ResultInvalidSize); + R_UNLESS(desc.size() >= static_cast(desc_size), ResultInvalidSize); + + // Register the program + R_RETURN(g_impl->RegisterProgramInfo(process_id, program_id, storage_id, data.data(), data_size, + desc.data(), desc_size)); +} + +Result ProgramRegistryImpl::UnregisterProgram(u64 process_id) { + // Check pre-conditions + ASSERT(g_impl != nullptr); + + // Check that we're allowed to register + R_UNLESS(FsSrv::Impl::IsInitialProgram(system, m_process_id), ResultPermissionDenied); + + // Unregister the program + R_RETURN(g_impl->UnregisterProgramInfo(process_id)); +} + +Result ProgramRegistryImpl::SetCurrentProcess(const Service::ClientProcessId& client_pid) { + // Set our process id + m_process_id = client_pid.pid; + + R_SUCCEED(); +} + +Result ProgramRegistryImpl::SetEnabledProgramVerification(bool enabled) { + // TODO: How to deal with this backwards compat? + ASSERT_MSG(false, "TODO: SetEnabledProgramVerification"); + R_THROW(ResultNotImplemented); +} + +} // namespace FileSys::FsSrv diff --git a/src/core/file_sys/fssrv/fssrv_program_registry_impl.h b/src/core/file_sys/fssrv/fssrv_program_registry_impl.h new file mode 100644 index 0000000000..c01d374285 --- /dev/null +++ b/src/core/file_sys/fssrv/fssrv_program_registry_impl.h @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_funcs.h" +#include "core/hle/result.h" +#include "core/hle/service/cmif_types.h" + +namespace Core { +class System; +} + +namespace FileSys::FsSrv { + +using namespace Service; + +class ProgramRegistryServiceImpl; + +namespace Impl { +class ProgramInfo; +} + +class ProgramRegistryImpl { + YUZU_NON_COPYABLE(ProgramRegistryImpl); + YUZU_NON_MOVEABLE(ProgramRegistryImpl); + +public: + ProgramRegistryImpl(Core::System& system_); + ~ProgramRegistryImpl(); + + static void Initialize(ProgramRegistryServiceImpl* service); + + Result RegisterProgram(u64 process_id, u64 program_id, u8 storage_id, + const InBuffer data, s64 data_size, + const InBuffer desc, s64 desc_size); + Result UnregisterProgram(u64 process_id); + Result SetCurrentProcess(const Service::ClientProcessId& client_pid); + Result SetEnabledProgramVerification(bool enabled); + +private: + u64 m_process_id; + Core::System& system; +}; + +} // namespace FileSys::FsSrv diff --git a/src/core/file_sys/fssrv/fssrv_program_registry_service.cpp b/src/core/file_sys/fssrv/fssrv_program_registry_service.cpp new file mode 100644 index 0000000000..151eb5740c --- /dev/null +++ b/src/core/file_sys/fssrv/fssrv_program_registry_service.cpp @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/file_sys/fssrv/fssrv_program_registry_service.h" +#include "core/file_sys/fssrv/impl/fssrv_program_index_map_info_manager.h" +#include "core/file_sys/fssrv/impl/fssrv_program_info.h" +#include "core/file_sys/fssrv/impl/fssrv_program_registry_manager.h" + +namespace FileSys::FsSrv { + +ProgramRegistryServiceImpl::ProgramRegistryServiceImpl(Core::System& system_, + const Configuration& cfg) + : m_config(cfg), m_registry_manager(std::make_unique(system_)), + m_index_map_info_manager(std::make_unique()) {} + +Result ProgramRegistryServiceImpl::RegisterProgramInfo(u64 process_id, u64 program_id, + u8 storage_id, const void* data, + s64 data_size, const void* desc, + s64 desc_size) { + R_RETURN(m_registry_manager->RegisterProgram(process_id, program_id, storage_id, data, + data_size, desc, desc_size)); +} + +Result ProgramRegistryServiceImpl::UnregisterProgramInfo(u64 process_id) { + R_RETURN(m_registry_manager->UnregisterProgram(process_id)); +} + +Result ProgramRegistryServiceImpl::ResetProgramIndexMapInfo(const ProgramIndexMapInfo* infos, + int count) { + R_RETURN(m_index_map_info_manager->Reset(infos, count)); +} + +Result ProgramRegistryServiceImpl::GetProgramInfo(std::shared_ptr* out, + u64 process_id) { + R_RETURN(m_registry_manager->GetProgramInfo(out, process_id)); +} + +Result ProgramRegistryServiceImpl::GetProgramInfoByProgramId( + std::shared_ptr* out, u64 program_id) { + R_RETURN(m_registry_manager->GetProgramInfoByProgramId(out, program_id)); +} + +size_t ProgramRegistryServiceImpl::GetProgramIndexMapInfoCount() { + return m_index_map_info_manager->GetProgramCount(); +} + +std::optional ProgramRegistryServiceImpl::GetProgramIndexMapInfo( + const u64& program_id) { + return m_index_map_info_manager->Get(program_id); +} + +u64 ProgramRegistryServiceImpl::GetProgramIdByIndex(const u64& program_id, u8 index) { + return m_index_map_info_manager->GetProgramId(program_id, index); +} + +} // namespace FileSys::FsSrv diff --git a/src/core/file_sys/fssrv/fssrv_program_registry_service.h b/src/core/file_sys/fssrv/fssrv_program_registry_service.h new file mode 100644 index 0000000000..69243eb731 --- /dev/null +++ b/src/core/file_sys/fssrv/fssrv_program_registry_service.h @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include "core/file_sys/fs_program_index_map_info.h" +#include "core/hle/result.h" + +namespace Core { +class System; +} + +namespace FileSys::FsSrv { + +namespace Impl { +class ProgramInfo; +class ProgramRegistryManager; +class ProgramIndexMapInfoManager; +} // namespace Impl + +class ProgramRegistryServiceImpl { +public: + struct Configuration {}; + + ProgramRegistryServiceImpl(Core::System& system_, const Configuration& cfg); + + 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 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(); + std::optional GetProgramIndexMapInfo(const u64& program_id); + + u64 GetProgramIdByIndex(const u64& program_id, u8 index); + +private: + Configuration m_config; + std::unique_ptr m_registry_manager; + std::unique_ptr m_index_map_info_manager; +}; + +} // namespace FileSys::FsSrv diff --git a/src/core/file_sys/fssrv/impl/fssrv_access_control.cpp b/src/core/file_sys/fssrv/impl/fssrv_access_control.cpp new file mode 100644 index 0000000000..fd75656460 --- /dev/null +++ b/src/core/file_sys/fssrv/impl/fssrv_access_control.cpp @@ -0,0 +1,592 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/enum_util.h" +#include "core/file_sys/fssrv/impl/fssrv_access_control.h" + +namespace FileSys::FsSrv { + +namespace { +constinit bool g_is_debug_flag_enabled = false; +} + +bool IsDebugFlagEnabled() { + return g_is_debug_flag_enabled; +} + +void SetDebugFlagEnabled(bool enabled) { + // Set global debug flag + g_is_debug_flag_enabled = enabled; +} + +namespace Impl { + +namespace { +constexpr u8 LatestFsAccessControlInfoVersion = 1; +} + +AccessControl::AccessControl(const void* data, s64 data_size, const void* desc, s64 desc_size) + : AccessControl(data, data_size, desc, desc_size, + g_is_debug_flag_enabled ? AllFlagBitsMask : DebugFlagDisableMask) {} + +AccessControl::AccessControl(const void* fac_data, s64 data_size, const void* fac_desc, + s64 desc_size, u64 flag_mask) { + // If either our data or descriptor is null, give no permissions + if (fac_data == nullptr || fac_desc == nullptr) { + m_flag_bits.emplace(Common::ToUnderlying(AccessControlBits::Bits::None)); + return; + } + + // Check that data/desc are big enough + ASSERT(data_size >= static_cast(sizeof(AccessControlDataHeader))); + ASSERT(desc_size >= static_cast(sizeof(AccessControlDescriptor))); + + // Copy in the data/descriptor + AccessControlDataHeader data = {}; + AccessControlDescriptor desc = {}; + std::memcpy(std::addressof(data), fac_data, sizeof(data)); + std::memcpy(std::addressof(desc), fac_desc, sizeof(desc)); + + // If we don't know how to parse the descriptors, don't + if (data.version != desc.version || data.version < LatestFsAccessControlInfoVersion) { + m_flag_bits.emplace(Common::ToUnderlying(AccessControlBits::Bits::None)); + return; + } + + // Restrict the descriptor's flag bits + desc.flag_bits &= flag_mask; + + // Create our flag bits + m_flag_bits.emplace(data.flag_bits & desc.flag_bits); + + // Further check sizes + ASSERT(data_size >= data.content_owner_infos_offset + data.content_owner_infos_size); + ASSERT(desc_size >= static_cast(sizeof(AccessControlDescriptor) + + desc.content_owner_id_count * sizeof(u64))); + + // Read out the content data owner infos + uintptr_t data_start = reinterpret_cast(fac_data); + uintptr_t desc_start = reinterpret_cast(fac_desc); + if (data.content_owner_infos_size > 0) { + // Get the count + const u32 num_content_owner_infos = Common::LoadLittleEndian( + reinterpret_cast(data_start + data.content_owner_infos_offset)); + + // Validate the id range + uintptr_t id_start = data_start + data.content_owner_infos_offset + sizeof(u32); + uintptr_t id_end = id_start + sizeof(u64) * num_content_owner_infos; + ASSERT(id_end == + data_start + data.content_owner_infos_offset + data.content_owner_infos_size); + + for (u32 i = 0; i < num_content_owner_infos; ++i) { + // Read the id + const u64 id = + Common::LoadLittleEndian(reinterpret_cast(id_start + i * sizeof(u64))); + + // Check that the descriptor allows it + bool allowed = false; + if (desc.content_owner_id_count != 0) { + for (u8 n = 0; n < desc.content_owner_id_count; ++n) { + if (id == + Common::LoadLittleEndian(reinterpret_cast( + desc_start + sizeof(AccessControlDescriptor) + n * sizeof(u64)))) { + allowed = true; + break; + } + } + } else if ((desc.content_owner_id_min == 0 && desc.content_owner_id_max == 0) || + (desc.content_owner_id_min <= id && id <= desc.content_owner_id_max)) { + allowed = true; + } + + // If the id is allowed, create it + if (allowed) { + if (auto* info = new ContentOwnerInfo(id); info != nullptr) { + m_content_owner_infos.push_front(*info); + } + } + } + } + + // Read out the save data owner infos + ASSERT(data_size >= data.save_data_owner_infos_offset + data.save_data_owner_infos_size); + ASSERT(desc_size >= static_cast(sizeof(AccessControlDescriptor) + + desc.content_owner_id_count * sizeof(u64) + + desc.save_data_owner_id_count * sizeof(u64))); + if (data.save_data_owner_infos_size > 0) { + // Get the count + const u32 num_save_data_owner_infos = Common::LoadLittleEndian( + reinterpret_cast(data_start + data.save_data_owner_infos_offset)); + + // Get accessibility region + uintptr_t accessibility_start = + data_start + data.save_data_owner_infos_offset + sizeof(u32); + + // Validate the id range + uintptr_t id_start = + accessibility_start + + Common::AlignUp(num_save_data_owner_infos * sizeof(Accessibility), alignof(u32)); + uintptr_t id_end = id_start + sizeof(u64) * num_save_data_owner_infos; + ASSERT(id_end == + data_start + data.save_data_owner_infos_offset + data.save_data_owner_infos_size); + + for (u32 i = 0; i < num_save_data_owner_infos; ++i) { + // Read the accessibility/id + static_assert(sizeof(Accessibility) == 1); + const Accessibility accessibility = + *reinterpret_cast(accessibility_start + i * sizeof(Accessibility)); + const u64 id = + Common::LoadLittleEndian(reinterpret_cast(id_start + i * sizeof(u64))); + + // Check that the descriptor allows it + bool allowed = false; + if (desc.save_data_owner_id_count != 0) { + for (u8 n = 0; n < desc.save_data_owner_id_count; ++n) { + if (id == Common::LoadLittleEndian(reinterpret_cast( + desc_start + sizeof(AccessControlDescriptor) + + desc.content_owner_id_count * sizeof(u64) + n * sizeof(u64)))) { + allowed = true; + break; + } + } + } else if ((desc.save_data_owner_id_min == 0 && desc.save_data_owner_id_max == 0) || + (desc.save_data_owner_id_min <= id && id <= desc.save_data_owner_id_max)) { + allowed = true; + } + + // If the id is allowed, create it + if (allowed) { + if (auto* info = new SaveDataOwnerInfo(id, accessibility); info != nullptr) { + m_save_data_owner_infos.push_front(*info); + } + } + } + } +} + +AccessControl::~AccessControl() { + // Delete all content owner infos + while (!m_content_owner_infos.empty()) { + auto* info = std::addressof(*m_content_owner_infos.rbegin()); + m_content_owner_infos.erase(m_content_owner_infos.iterator_to(*info)); + delete info; + } + + // Delete all save data owner infos + while (!m_save_data_owner_infos.empty()) { + auto* info = std::addressof(*m_save_data_owner_infos.rbegin()); + m_save_data_owner_infos.erase(m_save_data_owner_infos.iterator_to(*info)); + delete info; + } +} + +bool AccessControl::HasContentOwnerId(u64 owner_id) const { + // Check if we have a matching id + for (const auto& info : m_content_owner_infos) { + if (info.GetId() == owner_id) { + return true; + } + } + + return false; +} + +Accessibility AccessControl::GetAccessibilitySaveDataOwnedBy(u64 owner_id) const { + // Find a matching save data owner + for (const auto& info : m_save_data_owner_infos) { + if (info.GetId() == owner_id) { + return info.GetAccessibility(); + } + } + + // Default to no accessibility + return Accessibility::MakeAccessibility(false, false); +} + +void AccessControl::ListContentOwnerId(s32* out_count, u64* out_owner_ids, s32 offset, + s32 count) const { + // If we have nothing to read, just give the count + if (count == 0) { + *out_count = static_cast(m_content_owner_infos.size()); + return; + } + + // Read out the ids + s32 read_offset = 0; + s32 read_count = 0; + if (out_owner_ids != nullptr) { + auto* cur_out = out_owner_ids; + for (const auto& info : m_content_owner_infos) { + // Skip until we get to the desired offset + if (read_offset < offset) { + ++read_offset; + continue; + } + + // Set the output value + *cur_out = info.GetId(); + ++cur_out; + ++read_count; + + // If we've read as many as we can, finish + if (read_count == count) { + break; + } + } + } + + // Set the out value + *out_count = read_count; +} + +void AccessControl::ListSaveDataOwnedId(s32* out_count, u64* out_owner_ids, s32 offset, + s32 count) const { + // If we have nothing to read, just give the count + if (count == 0) { + *out_count = static_cast(m_save_data_owner_infos.size()); + return; + } + + // Read out the ids + s32 read_offset = 0; + s32 read_count = 0; + if (out_owner_ids != nullptr) { + auto* cur_out = out_owner_ids; + for (const auto& info : m_save_data_owner_infos) { + // Skip until we get to the desired offset + if (read_offset < offset) { + ++read_offset; + continue; + } + + // Set the output value + *cur_out = info.GetId(); + ++cur_out; + ++read_count; + + // If we've read as many as we can, finish + if (read_count == count) { + break; + } + } + } + + // Set the out value + *out_count = read_count; +} + +Accessibility AccessControl::GetAccessibilityFor(AccessibilityType type) const { + switch (type) { + using enum AccessibilityType; + case MountLogo: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountLogoRead(), false); + case MountContentMeta: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentMetaRead(), false); + case MountContentControl: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentControlRead(), false); + case MountContentManual: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentManualRead(), false); + case MountContentData: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentDataRead(), false); + case MountApplicationPackage: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountApplicationPackageRead(), + false); + case MountSaveDataStorage: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountSaveDataStorageRead(), + m_flag_bits->CanMountSaveDataStorageWrite()); + case MountContentStorage: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountContentStorageRead(), + m_flag_bits->CanMountContentStorageWrite()); + case MountImageAndVideoStorage: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountImageAndVideoStorageRead(), + m_flag_bits->CanMountImageAndVideoStorageWrite()); + case MountCloudBackupWorkStorage: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountCloudBackupWorkStorageRead(), + m_flag_bits->CanMountCloudBackupWorkStorageWrite()); + case MountCustomStorage: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountCustomStorage0Read(), + m_flag_bits->CanMountCustomStorage0Write()); + case MountBisCalibrationFile: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisCalibrationFileRead(), + m_flag_bits->CanMountBisCalibrationFileWrite()); + case MountBisSafeMode: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisSafeModeRead(), + m_flag_bits->CanMountBisSafeModeWrite()); + case MountBisUser: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisUserRead(), + m_flag_bits->CanMountBisUserWrite()); + case MountBisSystem: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountBisSystemRead(), + m_flag_bits->CanMountBisSystemWrite()); + case MountBisSystemProperEncryption: + return Accessibility::MakeAccessibility( + m_flag_bits->CanMountBisSystemProperEncryptionRead(), + m_flag_bits->CanMountBisSystemProperEncryptionWrite()); + case MountBisSystemProperPartition: + return Accessibility::MakeAccessibility( + m_flag_bits->CanMountBisSystemProperPartitionRead(), + m_flag_bits->CanMountBisSystemProperPartitionWrite()); + case MountSdCard: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountSdCardRead(), + m_flag_bits->CanMountSdCardWrite()); + case MountGameCard: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountGameCardRead(), false); + case MountDeviceSaveData: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountDeviceSaveDataRead(), + m_flag_bits->CanMountDeviceSaveDataWrite()); + case MountSystemSaveData: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountSystemSaveDataRead(), + m_flag_bits->CanMountSystemSaveDataWrite()); + case MountOthersSaveData: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountOthersSaveDataRead(), + m_flag_bits->CanMountOthersSaveDataWrite()); + case MountOthersSystemSaveData: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountOthersSystemSaveDataRead(), + m_flag_bits->CanMountOthersSystemSaveDataWrite()); + case OpenBisPartitionBootPartition1Root: + return Accessibility::MakeAccessibility( + m_flag_bits->CanOpenBisPartitionBootPartition1RootRead(), + m_flag_bits->CanOpenBisPartitionBootPartition1RootWrite()); + case OpenBisPartitionBootPartition2Root: + return Accessibility::MakeAccessibility( + m_flag_bits->CanOpenBisPartitionBootPartition2RootRead(), + m_flag_bits->CanOpenBisPartitionBootPartition2RootWrite()); + case OpenBisPartitionUserDataRoot: + return Accessibility::MakeAccessibility( + m_flag_bits->CanOpenBisPartitionUserDataRootRead(), + m_flag_bits->CanOpenBisPartitionUserDataRootWrite()); + case OpenBisPartitionBootConfigAndPackage2Part1: + return Accessibility::MakeAccessibility( + m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part1Read(), + m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part1Write()); + case OpenBisPartitionBootConfigAndPackage2Part2: + return Accessibility::MakeAccessibility( + m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part2Read(), + m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part2Write()); + case OpenBisPartitionBootConfigAndPackage2Part3: + return Accessibility::MakeAccessibility( + m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part3Read(), + m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part3Write()); + case OpenBisPartitionBootConfigAndPackage2Part4: + return Accessibility::MakeAccessibility( + m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part4Read(), + m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part4Write()); + case OpenBisPartitionBootConfigAndPackage2Part5: + return Accessibility::MakeAccessibility( + m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part5Read(), + m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part5Write()); + case OpenBisPartitionBootConfigAndPackage2Part6: + return Accessibility::MakeAccessibility( + m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part6Read(), + m_flag_bits->CanOpenBisPartitionBootConfigAndPackage2Part6Write()); + case OpenBisPartitionCalibrationBinary: + return Accessibility::MakeAccessibility( + m_flag_bits->CanOpenBisPartitionCalibrationBinaryRead(), + m_flag_bits->CanOpenBisPartitionCalibrationBinaryWrite()); + case OpenBisPartitionCalibrationFile: + return Accessibility::MakeAccessibility( + m_flag_bits->CanOpenBisPartitionCalibrationFileRead(), + m_flag_bits->CanOpenBisPartitionCalibrationFileWrite()); + case OpenBisPartitionSafeMode: + return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionSafeModeRead(), + m_flag_bits->CanOpenBisPartitionSafeModeWrite()); + case OpenBisPartitionUser: + return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionUserRead(), + m_flag_bits->CanOpenBisPartitionUserWrite()); + case OpenBisPartitionSystem: + return Accessibility::MakeAccessibility(m_flag_bits->CanOpenBisPartitionSystemRead(), + m_flag_bits->CanOpenBisPartitionSystemWrite()); + case OpenBisPartitionSystemProperEncryption: + return Accessibility::MakeAccessibility( + m_flag_bits->CanOpenBisPartitionSystemProperEncryptionRead(), + m_flag_bits->CanOpenBisPartitionSystemProperEncryptionWrite()); + case OpenBisPartitionSystemProperPartition: + return Accessibility::MakeAccessibility( + m_flag_bits->CanOpenBisPartitionSystemProperPartitionRead(), + m_flag_bits->CanOpenBisPartitionSystemProperPartitionWrite()); + case OpenSdCardStorage: + return Accessibility::MakeAccessibility(m_flag_bits->CanOpenSdCardStorageRead(), + m_flag_bits->CanOpenSdCardStorageWrite()); + case OpenGameCardStorage: + return Accessibility::MakeAccessibility(m_flag_bits->CanOpenGameCardStorageRead(), + m_flag_bits->CanOpenGameCardStorageWrite()); + case MountSystemDataPrivate: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountSystemDataPrivateRead(), + false); + case MountHost: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountHostRead(), + m_flag_bits->CanMountHostWrite()); + case MountRegisteredUpdatePartition: + return Accessibility::MakeAccessibility( + m_flag_bits->CanMountRegisteredUpdatePartitionRead() && g_is_debug_flag_enabled, false); + case MountSaveDataInternalStorage: + return Accessibility::MakeAccessibility(m_flag_bits->CanOpenSaveDataInternalStorageRead(), + m_flag_bits->CanOpenSaveDataInternalStorageWrite()); + case MountTemporaryDirectory: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountTemporaryDirectoryRead(), + m_flag_bits->CanMountTemporaryDirectoryWrite()); + case MountAllBaseFileSystem: + return Accessibility::MakeAccessibility(m_flag_bits->CanMountAllBaseFileSystemRead(), + m_flag_bits->CanMountAllBaseFileSystemWrite()); + case NotMount: + return Accessibility::MakeAccessibility(false, false); + default: + UNREACHABLE(); + break; + } +} + +bool AccessControl::CanCall(OperationType type) const { + switch (type) { + using enum OperationType; + case InvalidateBisCache: + return m_flag_bits->CanInvalidateBisCache(); + case EraseMmc: + return m_flag_bits->CanEraseMmc(); + case GetGameCardDeviceCertificate: + return m_flag_bits->CanGetGameCardDeviceCertificate(); + case GetGameCardIdSet: + return m_flag_bits->CanGetGameCardIdSet(); + case FinalizeGameCardDriver: + return m_flag_bits->CanFinalizeGameCardDriver(); + case GetGameCardAsicInfo: + return m_flag_bits->CanGetGameCardAsicInfo(); + case CreateSaveData: + return m_flag_bits->CanCreateSaveData(); + case DeleteSaveData: + return m_flag_bits->CanDeleteSaveData(); + case CreateSystemSaveData: + return m_flag_bits->CanCreateSystemSaveData(); + case CreateOthersSystemSaveData: + return m_flag_bits->CanCreateOthersSystemSaveData(); + case DeleteSystemSaveData: + return m_flag_bits->CanDeleteSystemSaveData(); + case OpenSaveDataInfoReader: + return m_flag_bits->CanOpenSaveDataInfoReader(); + case OpenSaveDataInfoReaderForSystem: + return m_flag_bits->CanOpenSaveDataInfoReaderForSystem(); + case OpenSaveDataInfoReaderForInternal: + return m_flag_bits->CanOpenSaveDataInfoReaderForInternal(); + case OpenSaveDataMetaFile: + return m_flag_bits->CanOpenSaveDataMetaFile(); + case SetCurrentPosixTime: + return m_flag_bits->CanSetCurrentPosixTime(); + case ReadSaveDataFileSystemExtraData: + return m_flag_bits->CanReadSaveDataFileSystemExtraData(); + case SetGlobalAccessLogMode: + return m_flag_bits->CanSetGlobalAccessLogMode(); + case SetSpeedEmulationMode: + return m_flag_bits->CanSetSpeedEmulationMode(); + case FillBis: + return m_flag_bits->CanFillBis(); + case CorruptSaveData: + return m_flag_bits->CanCorruptSaveData(); + case CorruptSystemSaveData: + return m_flag_bits->CanCorruptSystemSaveData(); + case VerifySaveData: + return m_flag_bits->CanVerifySaveData(); + case DebugSaveData: + return m_flag_bits->CanDebugSaveData(); + case FormatSdCard: + return m_flag_bits->CanFormatSdCard(); + case GetRightsId: + return m_flag_bits->CanGetRightsId(); + case RegisterExternalKey: + return m_flag_bits->CanRegisterExternalKey(); + case SetEncryptionSeed: + return m_flag_bits->CanSetEncryptionSeed(); + case WriteSaveDataFileSystemExtraDataTimeStamp: + return m_flag_bits->CanWriteSaveDataFileSystemExtraDataTimeStamp(); + case WriteSaveDataFileSystemExtraDataFlags: + return m_flag_bits->CanWriteSaveDataFileSystemExtraDataFlags(); + case WriteSaveDataFileSystemExtraDataCommitId: + return m_flag_bits->CanWriteSaveDataFileSystemExtraDataCommitId(); + case WriteSaveDataFileSystemExtraDataAll: + return m_flag_bits->CanWriteSaveDataFileSystemExtraDataAll(); + case ExtendSaveData: + return m_flag_bits->CanExtendSaveData(); + case ExtendSystemSaveData: + return m_flag_bits->CanExtendSystemSaveData(); + case ExtendOthersSystemSaveData: + return m_flag_bits->CanExtendOthersSystemSaveData(); + case RegisterUpdatePartition: + return m_flag_bits->CanRegisterUpdatePartition() && g_is_debug_flag_enabled; + case OpenSaveDataTransferManager: + return m_flag_bits->CanOpenSaveDataTransferManager(); + case OpenSaveDataTransferManagerVersion2: + return m_flag_bits->CanOpenSaveDataTransferManagerVersion2(); + case OpenSaveDataTransferManagerForSaveDataRepair: + return m_flag_bits->CanOpenSaveDataTransferManagerForSaveDataRepair(); + case OpenSaveDataTransferManagerForSaveDataRepairTool: + return m_flag_bits->CanOpenSaveDataTransferManagerForSaveDataRepairTool(); + case OpenSaveDataTransferProhibiter: + return m_flag_bits->CanOpenSaveDataTransferProhibiter(); + case OpenSaveDataMover: + return m_flag_bits->CanOpenSaveDataMover(); + case OpenBisWiper: + return m_flag_bits->CanOpenBisWiper(); + case ListAccessibleSaveDataOwnerId: + return m_flag_bits->CanListAccessibleSaveDataOwnerId(); + case ControlMmcPatrol: + return m_flag_bits->CanControlMmcPatrol(); + case OverrideSaveDataTransferTokenSignVerificationKey: + return m_flag_bits->CanOverrideSaveDataTransferTokenSignVerificationKey(); + case OpenSdCardDetectionEventNotifier: + return m_flag_bits->CanOpenSdCardDetectionEventNotifier(); + case OpenGameCardDetectionEventNotifier: + return m_flag_bits->CanOpenGameCardDetectionEventNotifier(); + case OpenSystemDataUpdateEventNotifier: + return m_flag_bits->CanOpenSystemDataUpdateEventNotifier(); + case NotifySystemDataUpdateEvent: + return m_flag_bits->CanNotifySystemDataUpdateEvent(); + case OpenAccessFailureDetectionEventNotifier: + return m_flag_bits->CanOpenAccessFailureDetectionEventNotifier(); + case GetAccessFailureDetectionEvent: + return m_flag_bits->CanGetAccessFailureDetectionEvent(); + case IsAccessFailureDetected: + return m_flag_bits->CanIsAccessFailureDetected(); + case ResolveAccessFailure: + return m_flag_bits->CanResolveAccessFailure(); + case AbandonAccessFailure: + return m_flag_bits->CanAbandonAccessFailure(); + case QuerySaveDataInternalStorageTotalSize: + return m_flag_bits->CanQuerySaveDataInternalStorageTotalSize(); + case GetSaveDataCommitId: + return m_flag_bits->CanGetSaveDataCommitId(); + case SetSdCardAccessibility: + return m_flag_bits->CanSetSdCardAccessibility(); + case SimulateDevice: + return m_flag_bits->CanSimulateDevice(); + case CreateSaveDataWithHashSalt: + return m_flag_bits->CanCreateSaveDataWithHashSalt(); + case RegisterProgramIndexMapInfo: + return m_flag_bits->CanRegisterProgramIndexMapInfo(); + case ChallengeCardExistence: + return m_flag_bits->CanChallengeCardExistence(); + case CreateOwnSaveData: + return m_flag_bits->CanCreateOwnSaveData(); + case DeleteOwnSaveData: + return m_flag_bits->CanDeleteOwnSaveData(); + case ReadOwnSaveDataFileSystemExtraData: + return m_flag_bits->CanReadOwnSaveDataFileSystemExtraData(); + case ExtendOwnSaveData: + return m_flag_bits->CanExtendOwnSaveData(); + case OpenOwnSaveDataTransferProhibiter: + return m_flag_bits->CanOpenOwnSaveDataTransferProhibiter(); + case FindOwnSaveDataWithFilter: + return m_flag_bits->CanFindOwnSaveDataWithFilter(); + case OpenSaveDataTransferManagerForRepair: + return m_flag_bits->CanOpenSaveDataTransferManagerForRepair(); + case SetDebugConfiguration: + return m_flag_bits->CanSetDebugConfiguration(); + case OpenDataStorageByPath: + return m_flag_bits->CanOpenDataStorageByPath(); + default: + UNREACHABLE(); + break; + } +} + +} // namespace Impl + +} // namespace FileSys::FsSrv diff --git a/src/core/file_sys/fssrv/impl/fssrv_access_control.h b/src/core/file_sys/fssrv/impl/fssrv_access_control.h new file mode 100644 index 0000000000..75878600a2 --- /dev/null +++ b/src/core/file_sys/fssrv/impl/fssrv_access_control.h @@ -0,0 +1,260 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/enum_util.h" +#include "common/intrusive_list.h" +#include "core/file_sys/fssrv/impl/fssrv_access_control_bits.h" + +namespace FileSys::FsSrv { + +bool IsDebugFlagEnabled(); +void SetDebugFlagEnabled(bool enabled); + +} // namespace FileSys::FsSrv + +namespace FileSys::FsSrv::Impl { + +struct Accessibility { + u8 value; + + constexpr bool CanRead() const { + return value & (1 << 0); + } + constexpr bool CanWrite() const { + return value & (1 << 1); + } + + static constexpr Accessibility MakeAccessibility(bool read, bool write) { + return {static_cast(read * (1 << 0) + write * (1 << 1))}; + } +}; +static_assert(std::is_trivial::value); + +class ContentOwnerInfo : public Common::IntrusiveListBaseNode { +private: + u64 m_id; + +public: + ContentOwnerInfo(u64 id) : m_id(id) {} + + u64 GetId() const { + return m_id; + } +}; + +class SaveDataOwnerInfo : public Common::IntrusiveListBaseNode { +private: + u64 m_id; + Accessibility m_accessibility; + +public: + SaveDataOwnerInfo(u64 id, Accessibility access) : m_id(id), m_accessibility(access) {} + + u64 GetId() const { + return m_id; + } + Accessibility GetAccessibility() const { + return m_accessibility; + } +}; + +class AccessControl { +public: + enum class AccessibilityType : u32 { + MountLogo, + MountContentMeta, + MountContentControl, + MountContentManual, + MountContentData, + MountApplicationPackage, + MountSaveDataStorage, + MountContentStorage, + MountImageAndVideoStorage, + MountCloudBackupWorkStorage, + MountCustomStorage, + MountBisCalibrationFile, + MountBisSafeMode, + MountBisUser, + MountBisSystem, + MountBisSystemProperEncryption, + MountBisSystemProperPartition, + MountSdCard, + MountGameCard, + MountDeviceSaveData, + MountSystemSaveData, + MountOthersSaveData, + MountOthersSystemSaveData, + OpenBisPartitionBootPartition1Root, + OpenBisPartitionBootPartition2Root, + OpenBisPartitionUserDataRoot, + OpenBisPartitionBootConfigAndPackage2Part1, + OpenBisPartitionBootConfigAndPackage2Part2, + OpenBisPartitionBootConfigAndPackage2Part3, + OpenBisPartitionBootConfigAndPackage2Part4, + OpenBisPartitionBootConfigAndPackage2Part5, + OpenBisPartitionBootConfigAndPackage2Part6, + OpenBisPartitionCalibrationBinary, + OpenBisPartitionCalibrationFile, + OpenBisPartitionSafeMode, + OpenBisPartitionUser, + OpenBisPartitionSystem, + OpenBisPartitionSystemProperEncryption, + OpenBisPartitionSystemProperPartition, + OpenSdCardStorage, + OpenGameCardStorage, + MountSystemDataPrivate, + MountHost, + MountRegisteredUpdatePartition, + MountSaveDataInternalStorage, + MountTemporaryDirectory, + MountAllBaseFileSystem, + NotMount, + + Count, + }; + + enum class OperationType : u32 { + InvalidateBisCache, + EraseMmc, + GetGameCardDeviceCertificate, + GetGameCardIdSet, + FinalizeGameCardDriver, + GetGameCardAsicInfo, + CreateSaveData, + DeleteSaveData, + CreateSystemSaveData, + CreateOthersSystemSaveData, + DeleteSystemSaveData, + OpenSaveDataInfoReader, + OpenSaveDataInfoReaderForSystem, + OpenSaveDataInfoReaderForInternal, + OpenSaveDataMetaFile, + SetCurrentPosixTime, + ReadSaveDataFileSystemExtraData, + SetGlobalAccessLogMode, + SetSpeedEmulationMode, + Debug, + FillBis, + CorruptSaveData, + CorruptSystemSaveData, + VerifySaveData, + DebugSaveData, + FormatSdCard, + GetRightsId, + RegisterExternalKey, + SetEncryptionSeed, + WriteSaveDataFileSystemExtraDataTimeStamp, + WriteSaveDataFileSystemExtraDataFlags, + WriteSaveDataFileSystemExtraDataCommitId, + WriteSaveDataFileSystemExtraDataAll, + ExtendSaveData, + ExtendSystemSaveData, + ExtendOthersSystemSaveData, + RegisterUpdatePartition, + OpenSaveDataTransferManager, + OpenSaveDataTransferManagerVersion2, + OpenSaveDataTransferManagerForSaveDataRepair, + OpenSaveDataTransferManagerForSaveDataRepairTool, + OpenSaveDataTransferProhibiter, + OpenSaveDataMover, + OpenBisWiper, + ListAccessibleSaveDataOwnerId, + ControlMmcPatrol, + OverrideSaveDataTransferTokenSignVerificationKey, + OpenSdCardDetectionEventNotifier, + OpenGameCardDetectionEventNotifier, + OpenSystemDataUpdateEventNotifier, + NotifySystemDataUpdateEvent, + OpenAccessFailureDetectionEventNotifier, + GetAccessFailureDetectionEvent, + IsAccessFailureDetected, + ResolveAccessFailure, + AbandonAccessFailure, + QuerySaveDataInternalStorageTotalSize, + GetSaveDataCommitId, + SetSdCardAccessibility, + SimulateDevice, + CreateSaveDataWithHashSalt, + RegisterProgramIndexMapInfo, + ChallengeCardExistence, + CreateOwnSaveData, + DeleteOwnSaveData, + ReadOwnSaveDataFileSystemExtraData, + ExtendOwnSaveData, + OpenOwnSaveDataTransferProhibiter, + FindOwnSaveDataWithFilter, + OpenSaveDataTransferManagerForRepair, + SetDebugConfiguration, + OpenDataStorageByPath, + + Count, + }; + +#pragma pack(push, 4) + struct AccessControlDataHeader { + u8 version; + u8 reserved[3]; + u64 flag_bits; + u32 content_owner_infos_offset; + u32 content_owner_infos_size; + u32 save_data_owner_infos_offset; + u32 save_data_owner_infos_size; + }; + + struct AccessControlDescriptor { + u8 version; + u8 content_owner_id_count; + u8 save_data_owner_id_count; + u8 reserved; + u64 flag_bits; + u64 content_owner_id_min; + u64 content_owner_id_max; + u64 save_data_owner_id_min; + u64 save_data_owner_id_max; + // u64 content_owner_ids[ContentOwnerIdCount]; + // u64 save_data_owner_ids[SaveDataOwnerIdCount]; + }; +#pragma pack(pop) + static_assert(std::is_trivially_copyable_v, + "Data type must be trivially copyable."); + static_assert(std::is_trivially_copyable_v, + "Data type must be trivially copyable."); + + static constexpr u64 AllFlagBitsMask = ~static_cast(0); + static constexpr u64 DebugFlagDisableMask = + AllFlagBitsMask & ~Common::ToUnderlying(AccessControlBits::Bits::Debug); + +public: + AccessControl(const void* data, s64 data_size, const void* desc, s64 desc_size); + AccessControl(const void* data, s64 data_size, const void* desc, s64 desc_size, u64 flag_mask); + ~AccessControl(); + + bool HasContentOwnerId(u64 owner_id) const; + Accessibility GetAccessibilitySaveDataOwnedBy(u64 owner_id) const; + + void ListContentOwnerId(s32* out_count, u64* out_owner_ids, s32 offset, s32 count) const; + void ListSaveDataOwnedId(s32* out_count, u64* out_owner_ids, s32 offset, s32 count) const; + + Accessibility GetAccessibilityFor(AccessibilityType type) const; + bool CanCall(OperationType type) const; + +private: + using ContentOwnerInfoList = Common::IntrusiveListBaseTraits::ListType; + using SaveDataOwnerInfoList = Common::IntrusiveListBaseTraits::ListType; + + std::optional m_flag_bits; + ContentOwnerInfoList m_content_owner_infos; + SaveDataOwnerInfoList m_save_data_owner_infos; + +public: + u64 GetRawFlagBits() const { + return m_flag_bits.value().GetValue(); + } +}; + +} // namespace FileSys::FsSrv::Impl diff --git a/src/core/file_sys/fssrv/impl/fssrv_access_control_bits.h b/src/core/file_sys/fssrv/impl/fssrv_access_control_bits.h new file mode 100644 index 0000000000..3a128f4834 --- /dev/null +++ b/src/core/file_sys/fssrv/impl/fssrv_access_control_bits.h @@ -0,0 +1,268 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/enum_util.h" + +namespace FileSys::FsSrv::Impl { + +#define YUZU_FSSRV_FOR_EACH_ACCESS_CONTROL_CAPABILITY(HANDLER, _NS_) \ + HANDLER(CanAbandonAccessFailure, _NS_::AccessFailureResolution) \ + HANDLER(CanChallengeCardExistence, _NS_::GameCard) \ + HANDLER(CanControlMmcPatrol, _NS_::None) \ + HANDLER(CanCorruptSaveData, _NS_::Debug, _NS_::CorruptSaveData) \ + HANDLER(CanCorruptSystemSaveData, _NS_::CorruptSaveData, _NS_::SaveDataManagement, \ + _NS_::SaveDataBackUp) \ + HANDLER(CanCreateOthersSystemSaveData, _NS_::SaveDataBackUp) \ + HANDLER(CanCreateOwnSaveData, _NS_::CreateOwnSaveData) \ + HANDLER(CanCreateSaveData, _NS_::CreateSaveData, _NS_::SaveDataBackUp) \ + HANDLER(CanCreateSaveDataWithHashSalt, _NS_::None) \ + HANDLER(CanCreateSystemSaveData, _NS_::SaveDataBackUp, _NS_::SystemSaveData) \ + HANDLER(CanDebugSaveData, _NS_::Debug, _NS_::SaveDataForDebug) \ + HANDLER(CanDeleteOwnSaveData, _NS_::CreateOwnSaveData) \ + HANDLER(CanDeleteSaveData, _NS_::SaveDataManagement, _NS_::SaveDataBackUp) \ + HANDLER(CanDeleteSystemSaveData, _NS_::SystemSaveDataManagement, _NS_::SaveDataBackUp, \ + _NS_::SystemSaveData) \ + HANDLER(CanEraseMmc, _NS_::BisAllRaw) \ + HANDLER(CanExtendOthersSystemSaveData, _NS_::SaveDataBackUp) \ + HANDLER(CanExtendOwnSaveData, _NS_::CreateOwnSaveData) \ + HANDLER(CanExtendSaveData, _NS_::CreateSaveData, _NS_::SaveDataBackUp) \ + HANDLER(CanExtendSystemSaveData, _NS_::SaveDataBackUp, _NS_::SystemSaveData) \ + HANDLER(CanFillBis, _NS_::Debug, _NS_::FillBis) \ + HANDLER(CanFinalizeGameCardDriver, _NS_::GameCardPrivate) \ + HANDLER(CanFindOwnSaveDataWithFilter, _NS_::CreateOwnSaveData) \ + HANDLER(CanFormatSdCard, _NS_::FormatSdCard) \ + HANDLER(CanGetAccessFailureDetectionEvent, _NS_::AccessFailureResolution) \ + HANDLER(CanGetGameCardAsicInfo, _NS_::GameCardPrivate) \ + HANDLER(CanGetGameCardDeviceCertificate, _NS_::GameCard) \ + HANDLER(CanGetGameCardIdSet, _NS_::GameCard) \ + HANDLER(CanGetRightsId, _NS_::GetRightsId) \ + HANDLER(CanGetSaveDataCommitId, _NS_::SaveDataTransferVersion2, _NS_::SaveDataBackUp) \ + HANDLER(CanInvalidateBisCache, _NS_::BisAllRaw) \ + HANDLER(CanIsAccessFailureDetected, _NS_::AccessFailureResolution) \ + HANDLER(CanListAccessibleSaveDataOwnerId, _NS_::SaveDataTransferVersion2, \ + _NS_::SaveDataTransfer, _NS_::CreateSaveData) \ + HANDLER(CanMountAllBaseFileSystemRead, _NS_::None) \ + HANDLER(CanMountAllBaseFileSystemWrite, _NS_::None) \ + HANDLER(CanMountApplicationPackageRead, _NS_::ContentManager, _NS_::ApplicationInfo) \ + HANDLER(CanMountBisCalibrationFileRead, _NS_::BisAllRaw, _NS_::Calibration) \ + HANDLER(CanMountBisCalibrationFileWrite, _NS_::BisAllRaw, _NS_::Calibration) \ + HANDLER(CanMountBisSafeModeRead, _NS_::BisAllRaw) \ + HANDLER(CanMountBisSafeModeWrite, _NS_::BisAllRaw) \ + HANDLER(CanMountBisSystemProperEncryptionRead, _NS_::BisAllRaw) \ + HANDLER(CanMountBisSystemProperEncryptionWrite, _NS_::BisAllRaw) \ + HANDLER(CanMountBisSystemProperPartitionRead, _NS_::BisFileSystem, _NS_::BisAllRaw) \ + HANDLER(CanMountBisSystemProperPartitionWrite, _NS_::BisFileSystem, _NS_::BisAllRaw) \ + HANDLER(CanMountBisSystemRead, _NS_::BisFileSystem, _NS_::BisAllRaw) \ + HANDLER(CanMountBisSystemWrite, _NS_::BisFileSystem, _NS_::BisAllRaw) \ + HANDLER(CanMountBisUserRead, _NS_::BisFileSystem, _NS_::BisAllRaw) \ + HANDLER(CanMountBisUserWrite, _NS_::BisFileSystem, _NS_::BisAllRaw) \ + HANDLER(CanMountCloudBackupWorkStorageRead, _NS_::SaveDataTransferVersion2) \ + HANDLER(CanMountCloudBackupWorkStorageWrite, _NS_::SaveDataTransferVersion2) \ + HANDLER(CanMountContentControlRead, _NS_::ContentManager, _NS_::ApplicationInfo) \ + HANDLER(CanMountContentDataRead, _NS_::ContentManager, _NS_::ApplicationInfo) \ + HANDLER(CanMountContentManualRead, _NS_::ContentManager, _NS_::ApplicationInfo) \ + HANDLER(CanMountContentMetaRead, _NS_::ContentManager, _NS_::ApplicationInfo) \ + HANDLER(CanMountContentStorageRead, _NS_::ContentManager) \ + HANDLER(CanMountContentStorageWrite, _NS_::ContentManager) \ + HANDLER(CanMountCustomStorage0Read, _NS_::None) \ + HANDLER(CanMountCustomStorage0Write, _NS_::None) \ + HANDLER(CanMountDeviceSaveDataRead, _NS_::DeviceSaveData, _NS_::SaveDataBackUp) \ + HANDLER(CanMountDeviceSaveDataWrite, _NS_::DeviceSaveData, _NS_::SaveDataBackUp) \ + HANDLER(CanMountGameCardRead, _NS_::GameCard) \ + HANDLER(CanMountHostRead, _NS_::Debug, _NS_::Host) \ + HANDLER(CanMountHostWrite, _NS_::Debug, _NS_::Host) \ + HANDLER(CanMountImageAndVideoStorageRead, _NS_::ImageManager) \ + HANDLER(CanMountImageAndVideoStorageWrite, _NS_::ImageManager) \ + HANDLER(CanMountLogoRead, _NS_::ContentManager, _NS_::ApplicationInfo) \ + HANDLER(CanMountOthersSaveDataRead, _NS_::SaveDataBackUp) \ + HANDLER(CanMountOthersSaveDataWrite, _NS_::SaveDataBackUp) \ + HANDLER(CanMountOthersSystemSaveDataRead, _NS_::SaveDataBackUp) \ + HANDLER(CanMountOthersSystemSaveDataWrite, _NS_::SaveDataBackUp) \ + HANDLER(CanMountRegisteredUpdatePartitionRead, _NS_::SystemUpdate) \ + HANDLER(CanMountSaveDataStorageRead, _NS_::None) \ + HANDLER(CanMountSaveDataStorageWrite, _NS_::None) \ + HANDLER(CanMountSdCardRead, _NS_::Debug, _NS_::SdCard) \ + HANDLER(CanMountSdCardWrite, _NS_::Debug, _NS_::SdCard) \ + HANDLER(CanMountSystemDataPrivateRead, _NS_::SystemData, _NS_::SystemSaveData) \ + HANDLER(CanMountSystemSaveDataRead, _NS_::SaveDataBackUp, _NS_::SystemSaveData) \ + HANDLER(CanMountSystemSaveDataWrite, _NS_::SaveDataBackUp, _NS_::SystemSaveData) \ + HANDLER(CanMountTemporaryDirectoryRead, _NS_::Debug) \ + HANDLER(CanMountTemporaryDirectoryWrite, _NS_::Debug) \ + HANDLER(CanNotifySystemDataUpdateEvent, _NS_::SystemUpdate) \ + HANDLER(CanOpenAccessFailureDetectionEventNotifier, _NS_::AccessFailureResolution) \ + HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part1Read, _NS_::SystemUpdate, \ + _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part1Write, _NS_::SystemUpdate, \ + _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part2Read, _NS_::SystemUpdate, \ + _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part2Write, _NS_::SystemUpdate, \ + _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part3Read, _NS_::SystemUpdate, \ + _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part3Write, _NS_::SystemUpdate, \ + _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part4Read, _NS_::SystemUpdate, \ + _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part4Write, _NS_::SystemUpdate, \ + _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part5Read, _NS_::SystemUpdate, \ + _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part5Write, _NS_::SystemUpdate, \ + _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part6Read, _NS_::SystemUpdate, \ + _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionBootConfigAndPackage2Part6Write, _NS_::SystemUpdate, \ + _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionBootPartition1RootRead, _NS_::SystemUpdate, _NS_::BisAllRaw, \ + _NS_::BootModeControl) \ + HANDLER(CanOpenBisPartitionBootPartition1RootWrite, _NS_::SystemUpdate, _NS_::BisAllRaw, \ + _NS_::BootModeControl) \ + HANDLER(CanOpenBisPartitionBootPartition2RootRead, _NS_::SystemUpdate, _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionBootPartition2RootWrite, _NS_::SystemUpdate, _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionCalibrationBinaryRead, _NS_::BisAllRaw, _NS_::Calibration) \ + HANDLER(CanOpenBisPartitionCalibrationBinaryWrite, _NS_::BisAllRaw, _NS_::Calibration) \ + HANDLER(CanOpenBisPartitionCalibrationFileRead, _NS_::BisAllRaw, _NS_::Calibration) \ + HANDLER(CanOpenBisPartitionCalibrationFileWrite, _NS_::BisAllRaw, _NS_::Calibration) \ + HANDLER(CanOpenBisPartitionSafeModeRead, _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionSafeModeWrite, _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionSystemProperEncryptionRead, _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionSystemProperEncryptionWrite, _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionSystemProperPartitionRead, _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionSystemProperPartitionWrite, _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionSystemRead, _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionSystemWrite, _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionUserDataRootRead, _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionUserDataRootWrite, _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionUserRead, _NS_::BisAllRaw) \ + HANDLER(CanOpenBisPartitionUserWrite, _NS_::BisAllRaw) \ + HANDLER(CanOpenBisWiper, _NS_::ContentManager) \ + HANDLER(CanOpenDataStorageByPath, _NS_::None) \ + HANDLER(CanOpenGameCardDetectionEventNotifier, _NS_::DeviceDetection, _NS_::GameCardRaw, \ + _NS_::GameCard) \ + HANDLER(CanOpenGameCardStorageRead, _NS_::GameCardRaw) \ + HANDLER(CanOpenGameCardStorageWrite, _NS_::GameCardRaw) \ + HANDLER(CanOpenOwnSaveDataTransferProhibiter, _NS_::CreateOwnSaveData) \ + HANDLER(CanOpenSaveDataInfoReader, _NS_::SaveDataManagement, _NS_::SaveDataBackUp) \ + HANDLER(CanOpenSaveDataInfoReaderForInternal, _NS_::SaveDataManagement) \ + HANDLER(CanOpenSaveDataInfoReaderForSystem, _NS_::SystemSaveDataManagement, \ + _NS_::SaveDataBackUp) \ + HANDLER(CanOpenSaveDataInternalStorageRead, _NS_::None) \ + HANDLER(CanOpenSaveDataInternalStorageWrite, _NS_::None) \ + HANDLER(CanOpenSaveDataMetaFile, _NS_::SaveDataMeta) \ + HANDLER(CanOpenSaveDataMover, _NS_::MoveCacheStorage) \ + HANDLER(CanOpenSaveDataTransferManager, _NS_::SaveDataTransfer) \ + HANDLER(CanOpenSaveDataTransferManagerForRepair, _NS_::SaveDataBackUp) \ + HANDLER(CanOpenSaveDataTransferManagerForSaveDataRepair, _NS_::SaveDataTransferVersion2) \ + HANDLER(CanOpenSaveDataTransferManagerForSaveDataRepairTool, _NS_::None) \ + HANDLER(CanOpenSaveDataTransferManagerVersion2, _NS_::SaveDataTransferVersion2) \ + HANDLER(CanOpenSaveDataTransferProhibiter, _NS_::SaveDataTransferVersion2, \ + _NS_::CreateSaveData) \ + HANDLER(CanOpenSdCardDetectionEventNotifier, _NS_::DeviceDetection, _NS_::SdCard) \ + HANDLER(CanOpenSdCardStorageRead, _NS_::Debug, _NS_::SdCard) \ + HANDLER(CanOpenSdCardStorageWrite, _NS_::Debug, _NS_::SdCard) \ + HANDLER(CanOpenSystemDataUpdateEventNotifier, _NS_::SystemData, _NS_::SystemSaveData) \ + HANDLER(CanOverrideSaveDataTransferTokenSignVerificationKey, _NS_::None) \ + HANDLER(CanQuerySaveDataInternalStorageTotalSize, _NS_::SaveDataTransfer) \ + HANDLER(CanReadOwnSaveDataFileSystemExtraData, _NS_::CreateOwnSaveData) \ + HANDLER(CanReadSaveDataFileSystemExtraData, _NS_::SystemSaveDataManagement, \ + _NS_::SaveDataManagement, _NS_::SaveDataBackUp) \ + HANDLER(CanRegisterExternalKey, _NS_::RegisterExternalKey) \ + HANDLER(CanRegisterProgramIndexMapInfo, _NS_::RegisterProgramIndexMapInfo) \ + HANDLER(CanRegisterUpdatePartition, _NS_::RegisterUpdatePartition) \ + HANDLER(CanResolveAccessFailure, _NS_::AccessFailureResolution) \ + HANDLER(CanSetCurrentPosixTime, _NS_::SetTime) \ + HANDLER(CanSetDebugConfiguration, _NS_::None) \ + HANDLER(CanSetEncryptionSeed, _NS_::ContentManager) \ + HANDLER(CanSetGlobalAccessLogMode, _NS_::SettingsControl) \ + HANDLER(CanSetSdCardAccessibility, _NS_::SdCard) \ + HANDLER(CanSetSpeedEmulationMode, _NS_::SettingsControl) \ + HANDLER(CanSimulateDevice, _NS_::Debug) \ + HANDLER(CanVerifySaveData, _NS_::SaveDataManagement, _NS_::SaveDataBackUp) \ + HANDLER(CanWriteSaveDataFileSystemExtraDataAll, _NS_::None) \ + HANDLER(CanWriteSaveDataFileSystemExtraDataCommitId, _NS_::SaveDataBackUp) \ + HANDLER(CanWriteSaveDataFileSystemExtraDataFlags, _NS_::SaveDataTransferVersion2, \ + _NS_::SystemSaveDataManagement, _NS_::SaveDataBackUp) \ + HANDLER(CanWriteSaveDataFileSystemExtraDataTimeStamp, _NS_::SaveDataBackUp) + +class AccessControlBits { +public: + enum class Bits : u64 { + None = 0, + + ApplicationInfo = UINT64_C(1) << 0, + BootModeControl = UINT64_C(1) << 1, + Calibration = UINT64_C(1) << 2, + SystemSaveData = UINT64_C(1) << 3, + GameCard = UINT64_C(1) << 4, + SaveDataBackUp = UINT64_C(1) << 5, + SaveDataManagement = UINT64_C(1) << 6, + BisAllRaw = UINT64_C(1) << 7, + GameCardRaw = UINT64_C(1) << 8, + GameCardPrivate = UINT64_C(1) << 9, + SetTime = UINT64_C(1) << 10, + ContentManager = UINT64_C(1) << 11, + ImageManager = UINT64_C(1) << 12, + CreateSaveData = UINT64_C(1) << 13, + SystemSaveDataManagement = UINT64_C(1) << 14, + BisFileSystem = UINT64_C(1) << 15, + SystemUpdate = UINT64_C(1) << 16, + SaveDataMeta = UINT64_C(1) << 17, + DeviceSaveData = UINT64_C(1) << 18, + SettingsControl = UINT64_C(1) << 19, + SystemData = UINT64_C(1) << 20, + SdCard = UINT64_C(1) << 21, + Host = UINT64_C(1) << 22, + FillBis = UINT64_C(1) << 23, + CorruptSaveData = UINT64_C(1) << 24, + SaveDataForDebug = UINT64_C(1) << 25, + FormatSdCard = UINT64_C(1) << 26, + GetRightsId = UINT64_C(1) << 27, + RegisterExternalKey = UINT64_C(1) << 28, + RegisterUpdatePartition = UINT64_C(1) << 29, + SaveDataTransfer = UINT64_C(1) << 30, + DeviceDetection = UINT64_C(1) << 31, + AccessFailureResolution = UINT64_C(1) << 32, + SaveDataTransferVersion2 = UINT64_C(1) << 33, + RegisterProgramIndexMapInfo = UINT64_C(1) << 34, + CreateOwnSaveData = UINT64_C(1) << 35, + MoveCacheStorage = UINT64_C(1) << 36, + + Debug = UINT64_C(1) << 62, + FullPermission = UINT64_C(1) << 63 + }; + +private: + static constexpr u64 CombineBits(Bits b) { + return Common::ToUnderlying(b); + } + + template + static constexpr u64 CombineBits(Bits b, Args... args) { + return CombineBits(b) | CombineBits(args...); + } + +private: + const u64 m_value; + +public: + constexpr AccessControlBits(u64 v) : m_value(v) {} + + constexpr u64 GetValue() const { + return m_value; + } + +#define DEFINE_ACCESS_GETTER(name, ...) \ + constexpr bool name() const { \ + constexpr u64 Mask = CombineBits(Bits::FullPermission, ##__VA_ARGS__); \ + return (m_value & Mask); \ + } + + YUZU_FSSRV_FOR_EACH_ACCESS_CONTROL_CAPABILITY(DEFINE_ACCESS_GETTER, Bits) + +#undef DEFINE_ACCESS_GETTER +}; + +} // namespace FileSys::FsSrv::Impl diff --git a/src/core/file_sys/fssrv/impl/fssrv_program_index_map_info_manager.h b/src/core/file_sys/fssrv/impl/fssrv_program_index_map_info_manager.h new file mode 100644 index 0000000000..699cf4f515 --- /dev/null +++ b/src/core/file_sys/fssrv/impl/fssrv_program_index_map_info_manager.h @@ -0,0 +1,155 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include "common/common_funcs.h" +#include "common/intrusive_list.h" +#include "core/file_sys/errors.h" +#include "core/file_sys/fs_program_index_map_info.h" +#include "core/hle/result.h" + +namespace FileSys::FsSrv::Impl { + +struct ProgramIndexMapInfoEntry : public Common::IntrusiveListBaseNode { + u64 program_id; + u64 base_program_id; + u8 program_index; +}; + +class ProgramIndexMapInfoManager { + YUZU_NON_COPYABLE(ProgramIndexMapInfoManager); + YUZU_NON_MOVEABLE(ProgramIndexMapInfoManager); + +private: + using ProgramIndexMapInfoList = + Common::IntrusiveListBaseTraits::ListType; + +private: + ProgramIndexMapInfoList m_list; + mutable std::mutex m_mutex; + +public: + ProgramIndexMapInfoManager() : m_list(), m_mutex() {} + + void Clear() { + // Acquire exclusive access to the map + std::scoped_lock lk(m_mutex); + + // Actually clear + this->ClearImpl(); + } + + size_t GetProgramCount() const { + // Acquire exclusive access to the map + std::scoped_lock lk(m_mutex); + + // Get the size + return m_list.size(); + } + + std::optional Get(const u64& program_id) const { + // Acquire exclusive access to the map + std::scoped_lock lk(m_mutex); + + // Get the entry from the map + return this->GetImpl( + [&](const ProgramIndexMapInfoEntry& entry) { return entry.program_id == program_id; }); + } + + u64 GetProgramId(const u64& program_id, u8 program_index) const { + // Acquire exclusive access to the map + std::scoped_lock lk(m_mutex); + + // Get the program info for the desired program id + const auto base_info = this->GetImpl( + [&](const ProgramIndexMapInfoEntry& entry) { return entry.program_id == program_id; }); + + // Check that an entry exists for the program id + if (!base_info.has_value()) { + return {}; + } + + // Get a program info which matches the same base program with the desired index + const auto target_info = this->GetImpl([&](const ProgramIndexMapInfoEntry& entry) { + return entry.base_program_id == base_info->base_program_id && + entry.program_index == program_index; + }); + + // Return the desired program id + if (target_info.has_value()) { + return target_info->program_id; + } else { + return {}; + } + } + + Result Reset(const ProgramIndexMapInfo* infos, int count) { + // Acquire exclusive access to the map + std::scoped_lock lk(m_mutex); + + // Clear the map, and ensure we remain clear if we fail after this point + this->ClearImpl(); + ON_RESULT_FAILURE { + this->ClearImpl(); + }; + + // Add each info to the list + for (int i = 0; i < count; ++i) { + // Allocate new entry + auto* entry = new ProgramIndexMapInfoEntry; + R_UNLESS(entry != nullptr, ResultAllocationMemoryFailedNew); + + // Copy over the info + entry->program_id = infos[i].program_id; + entry->base_program_id = infos[i].base_program_id; + entry->program_index = infos[i].program_index; + + // Add to the list + m_list.push_back(*entry); + } + + // We successfully imported the map + R_SUCCEED(); + } + +private: + void ClearImpl() { + // Delete all entries + while (!m_list.empty()) { + // Get the first entry + ProgramIndexMapInfoEntry* front = std::addressof(*m_list.begin()); + + // Erase it from the list + m_list.erase(m_list.iterator_to(*front)); + + // Delete the entry + delete front; + } + } + + template + std::optional GetImpl(F f) const { + // Try to find an entry matching the predicate + std::optional match = std::nullopt; + + for (const auto& entry : m_list) { + // If the predicate matches, we want to return the relevant info + if (f(entry)) { + match.emplace(); + + match->program_id = entry.program_id; + match->base_program_id = entry.base_program_id; + match->program_index = entry.program_index; + + break; + } + } + + return match; + } +}; + +} // namespace FileSys::FsSrv::Impl diff --git a/src/core/file_sys/fssrv/impl/fssrv_program_info.cpp b/src/core/file_sys/fssrv/impl/fssrv_program_info.cpp new file mode 100644 index 0000000000..3f38ea40b7 --- /dev/null +++ b/src/core/file_sys/fssrv/impl/fssrv_program_info.cpp @@ -0,0 +1,128 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include "common/typed_storage.h" +#include "core/core.h" +#include "core/file_sys/fssrv/impl/fssrv_program_info.h" +#include "core/hle/kernel/svc.h" + +namespace FileSys::FsSrv::Impl { + +namespace { + +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) { + ASSERT(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([[maybe_unused]] T* p, [[maybe_unused]] std::size_t n) { + // No-op + } +}; + +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}; + +constinit bool g_initialized = false; + +constinit u64 g_initial_process_id_min = 0; +constinit u64 g_initial_process_id_max = 0; + +constinit u64 g_current_process_id = 0; + +void InitializeInitialAndCurrentProcessId(Core::System& system) { + using namespace Kernel; + + if (!g_initialized) { + // Get initial process id range + ASSERT(Svc::GetSystemInfo(system, std::addressof(g_initial_process_id_min), + Svc::SystemInfoType::InitialProcessIdRange, Svc::InvalidHandle, + static_cast(Svc::InitialProcessIdRangeInfo::Minimum)) == + ResultSuccess); + ASSERT(Svc::GetSystemInfo(system, std::addressof(g_initial_process_id_max), + Svc::SystemInfoType::InitialProcessIdRange, Svc::InvalidHandle, + static_cast(Svc::InitialProcessIdRangeInfo::Maximum)) == + ResultSuccess); + + ASSERT(0 < g_initial_process_id_min); + ASSERT(g_initial_process_id_min <= g_initial_process_id_max); + + // Get current procss id + ASSERT(Svc::GetProcessId(system, std::addressof(g_current_process_id), + Svc::PseudoHandle::CurrentProcess) == ResultSuccess); + + /* Set initialized. */ + g_initialized = true; + } +} + +} // namespace + +std::shared_ptr ProgramInfo::GetProgramInfoForInitialProcess() { + 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) {} + }; + + static constinit Common::TypedStorage> + s_fls_storage_for_s_initial_program_info{}; + static constinit bool s_fls_initialized_s_initial_program_info = false; + static std::mutex s_fls_init_lock_s_initial_program_info{}; + if (!(s_fls_initialized_s_initial_program_info)) { + std::scoped_lock sl_fls_for_s_initial_program_info{s_fls_init_lock_s_initial_program_info}; + if (!(s_fls_initialized_s_initial_program_info)) { + new (Common::Impl::GetPointerForConstructAt(s_fls_storage_for_s_initial_program_info)) + std::shared_ptr(std::allocate_shared( + StaticAllocatorForProgramInfoForInitialProcess{}, + FileAccessControlForInitialProgram, sizeof(FileAccessControlForInitialProgram), + FileAccessControlDescForInitialProgram, + sizeof(FileAccessControlDescForInitialProgram))); + s_fls_initialized_s_initial_program_info = true; + } + } + std::shared_ptr& s_initial_program_info = + Common::GetReference(s_fls_storage_for_s_initial_program_info); + + return s_initial_program_info; +} + +bool IsInitialProgram(Core::System& system, u64 process_id) { + // Initialize/sanity check + InitializeInitialAndCurrentProcessId(system); + ASSERT(g_initial_process_id_min > 0); + + // Check process id in range + return g_initial_process_id_min <= process_id && process_id <= g_initial_process_id_max; +} + +bool IsCurrentProcess(Core::System& system, u64 process_id) { + // Initialize + InitializeInitialAndCurrentProcessId(system); + + return process_id == g_current_process_id; +} + +} // namespace FileSys::FsSrv::Impl diff --git a/src/core/file_sys/fssrv/impl/fssrv_program_info.h b/src/core/file_sys/fssrv/impl/fssrv_program_info.h new file mode 100644 index 0000000000..9ba8cd9423 --- /dev/null +++ b/src/core/file_sys/fssrv/impl/fssrv_program_info.h @@ -0,0 +1,65 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/file_sys/fssrv/impl/fssrv_access_control.h" +#include "core/file_sys/romfs_factory.h" + +namespace Core { +class System; +} + +namespace FileSys::FsSrv::Impl { + +constexpr u64 InvalidProcessId = 0xffffffffffffffffULL; + +class ProgramInfo { +private: + u64 m_process_id; + u64 m_program_id; + FileSys::StorageId m_storage_id; + AccessControl m_access_control; + +public: + ProgramInfo(u64 process_id, u64 program_id, u8 storage_id, const void* data, s64 data_size, + const void* desc, s64 desc_size) + : m_process_id(process_id), m_access_control(data, data_size, desc, desc_size) { + m_program_id = program_id; + m_storage_id = static_cast(storage_id); + } + + bool Contains(u64 process_id) const { + return m_process_id == process_id; + } + u64 GetProcessId() const { + return m_process_id; + } + u64 GetProgramId() const { + return m_program_id; + } + FileSys::StorageId GetStorageId() const { + return m_storage_id; + } + AccessControl& GetAccessControl() { + return m_access_control; + } + + static std::shared_ptr GetProgramInfoForInitialProcess(); + +private: + const u64 InvalidProgramId = {}; + ProgramInfo(const void* data, s64 data_size, const void* desc, s64 desc_size) + : m_process_id(InvalidProcessId), m_program_id(InvalidProgramId), + m_storage_id(static_cast(0)), + m_access_control(data, data_size, desc, desc_size, std::numeric_limits::max()) {} +}; + +struct ProgramInfoNode : public Common::IntrusiveListBaseNode { + std::shared_ptr program_info; +}; + +bool IsInitialProgram(Core::System& system, u64 process_id); +bool IsCurrentProcess(Core::System& system, u64 process_id); + +} // namespace FileSys::FsSrv::Impl diff --git a/src/core/file_sys/fssrv/impl/fssrv_program_registry_manager.cpp b/src/core/file_sys/fssrv/impl/fssrv_program_registry_manager.cpp new file mode 100644 index 0000000000..f060abfa68 --- /dev/null +++ b/src/core/file_sys/fssrv/impl/fssrv_program_registry_manager.cpp @@ -0,0 +1,100 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "core/core.h" +#include "core/file_sys/errors.h" +#include "core/file_sys/fssrv/impl/fssrv_program_registry_manager.h" + +namespace FileSys::FsSrv::Impl { + +ProgramRegistryManager::ProgramRegistryManager(Core::System& system_) : system{system_} {} + +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, ResultAllocationMemoryFailedInProgramRegistryManagerA); + + // Create a new program info + { + // Allocate the new info + std::shared_ptr new_info = std::make_shared( + process_id, program_id, storage_id, data, data_size, desc, desc_size); + R_UNLESS(new_info != nullptr, ResultAllocationMemoryFailedInProgramRegistryManagerA); + + // 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), ResultInvalidArgument); + } + + // Add the node to the registry + m_program_info_list.push_back(*new_node.release()); + + R_SUCCEED(); +} + +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); + R_SUCCEED(); + } + } + + // We couldn't find/unregister the process's node + R_THROW(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(system, process_id)) { + *out = ProgramInfo::GetProgramInfoForInitialProcess(); + R_SUCCEED(); + } + + // Find a matching node + for (const auto& node : m_program_info_list) { + if (node.program_info->Contains(process_id)) { + *out = node.program_info; + R_SUCCEED(); + } + } + + // We didn't find the program info + R_THROW(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->GetProgramId() == program_id) { + *out = node.program_info; + R_SUCCEED(); + } + } + + // We didn't find the program info + R_THROW(ResultProgramInfoNotFound); +} + +} // namespace FileSys::FsSrv::Impl diff --git a/src/core/file_sys/fssrv/impl/fssrv_program_registry_manager.h b/src/core/file_sys/fssrv/impl/fssrv_program_registry_manager.h new file mode 100644 index 0000000000..816107ede7 --- /dev/null +++ b/src/core/file_sys/fssrv/impl/fssrv_program_registry_manager.h @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include "common/common_funcs.h" +#include "common/intrusive_list.h" +#include "core/file_sys/fssrv/impl/fssrv_program_info.h" + +namespace Core { +class System; +} + +namespace FileSys::FsSrv::Impl { + +class ProgramRegistryManager { + YUZU_NON_COPYABLE(ProgramRegistryManager); + YUZU_NON_MOVEABLE(ProgramRegistryManager); + +public: + explicit ProgramRegistryManager(Core::System& system_); + + Result RegisterProgram(u64 process_id, u64 program_id, u8 storage_id, const void* data, + s64 data_size, const void* desc, s64 desc_size); + Result UnregisterProgram(u64 process_id); + + Result GetProgramInfo(std::shared_ptr* out, u64 process_id); + Result GetProgramInfoByProgramId(std::shared_ptr* out, u64 program_id); + +private: + using ProgramInfoList = Common::IntrusiveListBaseTraits::ListType; + + ProgramInfoList m_program_info_list{}; + mutable std::mutex m_mutex{}; + Core::System& system; +}; + +} // namespace FileSys::FsSrv::Impl diff --git a/src/core/file_sys/fssrv/impl/fssrv_save_data_properties.h b/src/core/file_sys/fssrv/impl/fssrv_save_data_properties.h new file mode 100644 index 0000000000..4e33632f85 --- /dev/null +++ b/src/core/file_sys/fssrv/impl/fssrv_save_data_properties.h @@ -0,0 +1,193 @@ +// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +// TODO: Properly credit LibHac before this gets merged + +#pragma once + +#include "common/assert.h" +#include "common/common_types.h" +#include "core/file_sys/savedata_factory.h" + +namespace FileSys::FsSrv::Impl { + +class SaveDataProperties { +public: + static constexpr s64 DefaultSaveDataBlockSize = 0x4000; + static constexpr s64 BcatSaveDataJournalSize = 0x200000; + + static bool IsJournalingSupported(SaveDataFormatType type) { + switch (type) { + case SaveDataFormatType::Normal: + return true; + case SaveDataFormatType::NoJournal: + return false; + default: + UNREACHABLE(); + return false; + } + } + + static bool IsJournalingSupported(SaveDataType type) { + switch (type) { + case SaveDataType::SystemSaveData: + case SaveDataType::SaveData: + case SaveDataType::BcatDeliveryCacheStorage: + case SaveDataType::DeviceSaveData: + case SaveDataType::CacheStorage: + return true; + case SaveDataType::TemporaryStorage: + return false; + default: + UNREACHABLE(); + return false; + } + } + + static bool IsMultiCommitSupported(SaveDataType type) { + switch (type) { + case SaveDataType::SystemSaveData: + case SaveDataType::SaveData: + case SaveDataType::DeviceSaveData: + return true; + case SaveDataType::BcatDeliveryCacheStorage: + case SaveDataType::TemporaryStorage: + case SaveDataType::CacheStorage: + return false; + default: + UNREACHABLE(); + return false; + } + } + + static bool IsSharedOpenNeeded(SaveDataType type) { + switch (type) { + case SaveDataType::SystemSaveData: + case SaveDataType::BcatDeliveryCacheStorage: + case SaveDataType::TemporaryStorage: + case SaveDataType::CacheStorage: + return false; + case SaveDataType::SaveData: + case SaveDataType::DeviceSaveData: + return true; + default: + UNREACHABLE(); + return false; + } + } + + static bool CanUseIndexerReservedArea(SaveDataType type) { + switch (type) { + case SaveDataType::SystemSaveData: + return true; + case SaveDataType::SaveData: + case SaveDataType::BcatDeliveryCacheStorage: + case SaveDataType::DeviceSaveData: + case SaveDataType::TemporaryStorage: + case SaveDataType::CacheStorage: + return false; + default: + UNREACHABLE(); + return false; + } + } + + static bool IsSystemSaveData(SaveDataType type) { + switch (type) { + case SaveDataType::SystemSaveData: + return true; + case SaveDataType::SaveData: + case SaveDataType::BcatDeliveryCacheStorage: + case SaveDataType::DeviceSaveData: + case SaveDataType::TemporaryStorage: + case SaveDataType::CacheStorage: + return false; + default: + UNREACHABLE(); + return false; + } + } + + static bool IsObsoleteSystemSaveData(const SaveDataInfo& info) { + constexpr std::array ObsoleteSystemSaveDataIdList = {0x8000000000000060, + 0x8000000000000075}; + return std::find(ObsoleteSystemSaveDataIdList.begin(), ObsoleteSystemSaveDataIdList.end(), + info.save_id) != ObsoleteSystemSaveDataIdList.end(); + } + + static bool IsWipingNeededAtCleanUp(const SaveDataInfo& info) { + switch (info.type) { + case SaveDataType::SystemSaveData: + break; + case SaveDataType::SaveData: + case SaveDataType::BcatDeliveryCacheStorage: + case SaveDataType::DeviceSaveData: + case SaveDataType::TemporaryStorage: + case SaveDataType::CacheStorage: + return true; + default: + UNREACHABLE(); + break; + } + + constexpr std::array SystemSaveDataIdWipingExceptionList = { + 0x8000000000000040, 0x8000000000000041, 0x8000000000000043, 0x8000000000000044, + 0x8000000000000045, 0x8000000000000046, 0x8000000000000047, 0x8000000000000048, + 0x8000000000000049, 0x800000000000004A, 0x8000000000000070, 0x8000000000000071, + 0x8000000000000072, 0x8000000000000074, 0x8000000000000076, 0x8000000000000077, + 0x8000000000000090, 0x8000000000000091, 0x8000000000000092, 0x80000000000000B0, + 0x80000000000000C1, 0x80000000000000C2, 0x8000000000000120, 0x8000000000000121, + 0x8000000000000180, 0x8000000000010003, 0x8000000000010004}; + + return std::find(SystemSaveDataIdWipingExceptionList.begin(), + SystemSaveDataIdWipingExceptionList.end(), + info.save_id) == SystemSaveDataIdWipingExceptionList.end(); + } + + static bool IsValidSpaceIdForSaveDataMover(SaveDataType type, SaveDataSpaceId space_id) { + switch (type) { + case SaveDataType::SystemSaveData: + case SaveDataType::SaveData: + case SaveDataType::BcatDeliveryCacheStorage: + case SaveDataType::DeviceSaveData: + case SaveDataType::TemporaryStorage: + return false; + case SaveDataType::CacheStorage: + return space_id == SaveDataSpaceId::NandUser || space_id == SaveDataSpaceId::SdCardUser; + default: + UNREACHABLE(); + return false; + } + } + + static bool IsReconstructible(SaveDataType type, SaveDataSpaceId space_id) { + switch (space_id) { + case SaveDataSpaceId::NandSystem: + case SaveDataSpaceId::NandUser: + case SaveDataSpaceId::ProperSystem: + case SaveDataSpaceId::SafeMode: + switch (type) { + case SaveDataType::SystemSaveData: + case SaveDataType::SaveData: + case SaveDataType::DeviceSaveData: + return false; + case SaveDataType::BcatDeliveryCacheStorage: + case SaveDataType::TemporaryStorage: + case SaveDataType::CacheStorage: + return true; + default: + UNREACHABLE(); + return false; + } + case SaveDataSpaceId::SdCardSystem: + case SaveDataSpaceId::TemporaryStorage: + case SaveDataSpaceId::SdCardUser: + return true; + default: + UNREACHABLE(); + return false; + } + } +}; + +} // namespace FileSys::FsSrv::Impl