fssrv: Add various data types and utility classes

These will be needed to reimplement the filesystem at a later point.
This commit is contained in:
FearlessTobi 2024-02-22 16:32:41 +01:00
parent 1e0e36c2c2
commit f9a67ff75d
16 changed files with 2065 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -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<ProgramIndexMapInfo>,
"Data type must be trivially copyable.");
static_assert(sizeof(ProgramIndexMapInfo) == 0x20, "ProgramIndexMapInfo has invalid size.");
} // namespace FileSys

View File

@ -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<BufferAttr_HipcMapAlias> data,
s64 data_size,
const InBuffer<BufferAttr_HipcMapAlias> 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<size_t>(data_size), ResultInvalidSize);
R_UNLESS(desc.size() >= static_cast<size_t>(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

View File

@ -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<BufferAttr_HipcMapAlias> data, s64 data_size,
const InBuffer<BufferAttr_HipcMapAlias> 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

View File

@ -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<Impl::ProgramRegistryManager>(system_)),
m_index_map_info_manager(std::make_unique<Impl::ProgramIndexMapInfoManager>()) {}
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<Impl::ProgramInfo>* out,
u64 process_id) {
R_RETURN(m_registry_manager->GetProgramInfo(out, process_id));
}
Result ProgramRegistryServiceImpl::GetProgramInfoByProgramId(
std::shared_ptr<Impl::ProgramInfo>* 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<ProgramIndexMapInfo> 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

View File

@ -0,0 +1,48 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <optional>
#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<Impl::ProgramInfo>* out, u64 process_id);
Result GetProgramInfoByProgramId(std::shared_ptr<Impl::ProgramInfo>* out, u64 program_id);
size_t GetProgramIndexMapInfoCount();
std::optional<ProgramIndexMapInfo> GetProgramIndexMapInfo(const u64& program_id);
u64 GetProgramIdByIndex(const u64& program_id, u8 index);
private:
Configuration m_config;
std::unique_ptr<Impl::ProgramRegistryManager> m_registry_manager;
std::unique_ptr<Impl::ProgramIndexMapInfoManager> m_index_map_info_manager;
};
} // namespace FileSys::FsSrv

View File

@ -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<s64>(sizeof(AccessControlDataHeader)));
ASSERT(desc_size >= static_cast<s64>(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<s64>(sizeof(AccessControlDescriptor) +
desc.content_owner_id_count * sizeof(u64)));
// Read out the content data owner infos
uintptr_t data_start = reinterpret_cast<uintptr_t>(fac_data);
uintptr_t desc_start = reinterpret_cast<uintptr_t>(fac_desc);
if (data.content_owner_infos_size > 0) {
// Get the count
const u32 num_content_owner_infos = Common::LoadLittleEndian<u32>(
reinterpret_cast<u32*>(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<u64>(reinterpret_cast<u64*>(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<u64>(reinterpret_cast<u64*>(
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<s64>(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<u32>(
reinterpret_cast<u32*>(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*>(accessibility_start + i * sizeof(Accessibility));
const u64 id =
Common::LoadLittleEndian<u64>(reinterpret_cast<u64*>(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<u64>(reinterpret_cast<u64*>(
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<s32>(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<s32>(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

View File

@ -0,0 +1,260 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <optional>
#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<u8>(read * (1 << 0) + write * (1 << 1))};
}
};
static_assert(std::is_trivial<Accessibility>::value);
class ContentOwnerInfo : public Common::IntrusiveListBaseNode<ContentOwnerInfo> {
private:
u64 m_id;
public:
ContentOwnerInfo(u64 id) : m_id(id) {}
u64 GetId() const {
return m_id;
}
};
class SaveDataOwnerInfo : public Common::IntrusiveListBaseNode<SaveDataOwnerInfo> {
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<AccessControlDataHeader>,
"Data type must be trivially copyable.");
static_assert(std::is_trivially_copyable_v<AccessControlDescriptor>,
"Data type must be trivially copyable.");
static constexpr u64 AllFlagBitsMask = ~static_cast<u64>(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<ContentOwnerInfo>::ListType;
using SaveDataOwnerInfoList = Common::IntrusiveListBaseTraits<SaveDataOwnerInfo>::ListType;
std::optional<AccessControlBits> 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

View File

@ -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 <typename... Args>
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

View File

@ -0,0 +1,155 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <mutex>
#include <optional>
#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<ProgramIndexMapInfoEntry> {
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<ProgramIndexMapInfoEntry>::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<ProgramIndexMapInfo> 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 <typename F>
std::optional<ProgramIndexMapInfo> GetImpl(F f) const {
// Try to find an entry matching the predicate
std::optional<ProgramIndexMapInfo> 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

View File

@ -0,0 +1,128 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <mutex>
#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 <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) {
ASSERT(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([[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<u64>(Svc::InitialProcessIdRangeInfo::Minimum)) ==
ResultSuccess);
ASSERT(Svc::GetSystemInfo(system, std::addressof(g_initial_process_id_max),
Svc::SystemInfoType::InitialProcessIdRange, Svc::InvalidHandle,
static_cast<u64>(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> 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<std::shared_ptr<ProgramInfo>>
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<ProgramInfo>(std::allocate_shared<ProgramInfoHelper>(
StaticAllocatorForProgramInfoForInitialProcess<char>{},
FileAccessControlForInitialProgram, sizeof(FileAccessControlForInitialProgram),
FileAccessControlDescForInitialProgram,
sizeof(FileAccessControlDescForInitialProgram)));
s_fls_initialized_s_initial_program_info = true;
}
}
std::shared_ptr<ProgramInfo>& 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

View File

@ -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<FileSys::StorageId>(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<ProgramInfo> 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<FileSys::StorageId>(0)),
m_access_control(data, data_size, desc, desc_size, std::numeric_limits<u64>::max()) {}
};
struct ProgramInfoNode : public Common::IntrusiveListBaseNode<ProgramInfoNode> {
std::shared_ptr<ProgramInfo> program_info;
};
bool IsInitialProgram(Core::System& system, u64 process_id);
bool IsCurrentProcess(Core::System& system, u64 process_id);
} // namespace FileSys::FsSrv::Impl

View File

@ -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<ProgramInfoNode> new_node(new ProgramInfoNode());
R_UNLESS(new_node != nullptr, ResultAllocationMemoryFailedInProgramRegistryManagerA);
// Create a new program info
{
// Allocate the new info
std::shared_ptr<ProgramInfo> new_info = std::make_shared<ProgramInfo>(
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<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(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<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->GetProgramId() == program_id) {
*out = node.program_info;
R_SUCCEED();
}
}
// We didn't find the program info
R_THROW(ResultProgramInfoNotFound);
}
} // namespace FileSys::FsSrv::Impl

View File

@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <mutex>
#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<ProgramInfo>* out, u64 process_id);
Result GetProgramInfoByProgramId(std::shared_ptr<ProgramInfo>* out, u64 program_id);
private:
using ProgramInfoList = Common::IntrusiveListBaseTraits<ProgramInfoNode>::ListType;
ProgramInfoList m_program_info_list{};
mutable std::mutex m_mutex{};
Core::System& system;
};
} // namespace FileSys::FsSrv::Impl

View File

@ -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<u64, 2> 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<u64, 28> 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