strat: use m_ for member variables
This commit is contained in:
@@ -91,14 +91,14 @@ namespace ams::mitm::socket::resolver {
|
||||
|
||||
const char *hostname = reinterpret_cast<const char *>(name.GetPointer());
|
||||
|
||||
LogDebug("[%016lx]: GetHostByNameRequest(%s)\n", this->client_info.program_id.value, hostname);
|
||||
LogDebug("[%016lx]: GetHostByNameRequest(%s)\n", m_client_info.program_id.value, hostname);
|
||||
|
||||
R_UNLESS(hostname != nullptr, sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
ams::socket::InAddrT redirect_addr = {};
|
||||
R_UNLESS(GetRedirectedHostByName(std::addressof(redirect_addr), hostname), sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
LogDebug("[%016lx]: Redirecting %s to %u.%u.%u.%u\n", this->client_info.program_id.value, hostname, (redirect_addr >> 0) & 0xFF, (redirect_addr >> 8) & 0xFF, (redirect_addr >> 16) & 0xFF, (redirect_addr >> 24) & 0xFF);
|
||||
LogDebug("[%016lx]: Redirecting %s to %u.%u.%u.%u\n", m_client_info.program_id.value, hostname, (redirect_addr >> 0) & 0xFF, (redirect_addr >> 8) & 0xFF, (redirect_addr >> 16) & 0xFF, (redirect_addr >> 24) & 0xFF);
|
||||
const auto size = SerializeRedirectedHostEnt(out_hostent.GetPointer(), out_hostent.GetSize(), hostname, redirect_addr);
|
||||
|
||||
*out_host_error = 0;
|
||||
@@ -113,7 +113,7 @@ namespace ams::mitm::socket::resolver {
|
||||
|
||||
const char *hostname = reinterpret_cast<const char *>(node.GetPointer());
|
||||
|
||||
LogDebug("[%016lx]: GetAddrInfoRequest(%s, %s)\n", this->client_info.program_id.value, reinterpret_cast<const char *>(node.GetPointer()), reinterpret_cast<const char *>(srv.GetPointer()));
|
||||
LogDebug("[%016lx]: GetAddrInfoRequest(%s, %s)\n", m_client_info.program_id.value, reinterpret_cast<const char *>(node.GetPointer()), reinterpret_cast<const char *>(srv.GetPointer()));
|
||||
|
||||
R_UNLESS(hostname != nullptr, sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
@@ -129,7 +129,7 @@ namespace ams::mitm::socket::resolver {
|
||||
}
|
||||
}
|
||||
|
||||
LogDebug("[%016lx]: Redirecting %s:%u to %u.%u.%u.%u\n", this->client_info.program_id.value, hostname, port, (redirect_addr >> 0) & 0xFF, (redirect_addr >> 8) & 0xFF, (redirect_addr >> 16) & 0xFF, (redirect_addr >> 24) & 0xFF);
|
||||
LogDebug("[%016lx]: Redirecting %s:%u to %u.%u.%u.%u\n", m_client_info.program_id.value, hostname, port, (redirect_addr >> 0) & 0xFF, (redirect_addr >> 8) & 0xFF, (redirect_addr >> 16) & 0xFF, (redirect_addr >> 24) & 0xFF);
|
||||
|
||||
const bool use_hint = serialized_hint.GetPointer() != nullptr;
|
||||
struct addrinfo hint = {};
|
||||
@@ -152,14 +152,14 @@ namespace ams::mitm::socket::resolver {
|
||||
|
||||
const char *hostname = reinterpret_cast<const char *>(name.GetPointer());
|
||||
|
||||
LogDebug("[%016lx]: GetHostByNameRequestWithOptions(%s)\n", this->client_info.program_id.value, hostname);
|
||||
LogDebug("[%016lx]: GetHostByNameRequestWithOptions(%s)\n", m_client_info.program_id.value, hostname);
|
||||
|
||||
R_UNLESS(hostname != nullptr, sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
ams::socket::InAddrT redirect_addr = {};
|
||||
R_UNLESS(GetRedirectedHostByName(std::addressof(redirect_addr), hostname), sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
LogDebug("[%016lx]: Redirecting %s to %u.%u.%u.%u\n", this->client_info.program_id.value, hostname, (redirect_addr >> 0) & 0xFF, (redirect_addr >> 8) & 0xFF, (redirect_addr >> 16) & 0xFF, (redirect_addr >> 24) & 0xFF);
|
||||
LogDebug("[%016lx]: Redirecting %s to %u.%u.%u.%u\n", m_client_info.program_id.value, hostname, (redirect_addr >> 0) & 0xFF, (redirect_addr >> 8) & 0xFF, (redirect_addr >> 16) & 0xFF, (redirect_addr >> 24) & 0xFF);
|
||||
const auto size = SerializeRedirectedHostEnt(out_hostent.GetPointer(), out_hostent.GetSize(), hostname, redirect_addr);
|
||||
|
||||
*out_host_error = 0;
|
||||
@@ -174,7 +174,7 @@ namespace ams::mitm::socket::resolver {
|
||||
|
||||
const char *hostname = reinterpret_cast<const char *>(node.GetPointer());
|
||||
|
||||
LogDebug("[%016lx]: GetAddrInfoRequestWithOptions(%s, %s)\n", this->client_info.program_id.value, hostname, reinterpret_cast<const char *>(srv.GetPointer()));
|
||||
LogDebug("[%016lx]: GetAddrInfoRequestWithOptions(%s, %s)\n", m_client_info.program_id.value, hostname, reinterpret_cast<const char *>(srv.GetPointer()));
|
||||
|
||||
R_UNLESS(hostname != nullptr, sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
@@ -190,7 +190,7 @@ namespace ams::mitm::socket::resolver {
|
||||
}
|
||||
}
|
||||
|
||||
LogDebug("[%016lx]: Redirecting %s:%u to %u.%u.%u.%u\n", this->client_info.program_id.value, hostname, port, (redirect_addr >> 0) & 0xFF, (redirect_addr >> 8) & 0xFF, (redirect_addr >> 16) & 0xFF, (redirect_addr >> 24) & 0xFF);
|
||||
LogDebug("[%016lx]: Redirecting %s:%u to %u.%u.%u.%u\n", m_client_info.program_id.value, hostname, port, (redirect_addr >> 0) & 0xFF, (redirect_addr >> 8) & 0xFF, (redirect_addr >> 16) & 0xFF, (redirect_addr >> 24) & 0xFF);
|
||||
|
||||
const bool use_hint = serialized_hint.GetPointer() != nullptr;
|
||||
struct addrinfo hint = {};
|
||||
|
||||
@@ -217,21 +217,21 @@ namespace ams::mitm::fs {
|
||||
}
|
||||
|
||||
Result FsMitmService::OpenFileSystemWithPatch(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, ncm::ProgramId program_id, u32 _filesystem_type) {
|
||||
return OpenWebContentFileSystem(out, this->client_info.program_id, program_id, static_cast<FsFileSystemType>(_filesystem_type), this->forward_service.get(), nullptr, false, this->client_info.override_status.IsProgramSpecific());
|
||||
return OpenWebContentFileSystem(out, m_client_info.program_id, program_id, static_cast<FsFileSystemType>(_filesystem_type), m_forward_service.get(), nullptr, false, m_client_info.override_status.IsProgramSpecific());
|
||||
}
|
||||
|
||||
Result FsMitmService::OpenFileSystemWithId(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, const fssrv::sf::Path &path, ncm::ProgramId program_id, u32 _filesystem_type) {
|
||||
return OpenWebContentFileSystem(out, this->client_info.program_id, program_id, static_cast<FsFileSystemType>(_filesystem_type), this->forward_service.get(), std::addressof(path), true, this->client_info.override_status.IsProgramSpecific());
|
||||
return OpenWebContentFileSystem(out, m_client_info.program_id, program_id, static_cast<FsFileSystemType>(_filesystem_type), m_forward_service.get(), std::addressof(path), true, m_client_info.override_status.IsProgramSpecific());
|
||||
}
|
||||
|
||||
Result FsMitmService::OpenSdCardFileSystem(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out) {
|
||||
/* We only care about redirecting this for NS/emummc. */
|
||||
R_UNLESS(this->client_info.program_id == ncm::SystemProgramId::Ns, sm::mitm::ResultShouldForwardToSession());
|
||||
R_UNLESS(m_client_info.program_id == ncm::SystemProgramId::Ns, sm::mitm::ResultShouldForwardToSession());
|
||||
R_UNLESS(emummc::IsActive(), sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
/* Create a new SD card filesystem. */
|
||||
FsFileSystem sd_fs;
|
||||
R_TRY(fsOpenSdCardFileSystemFwd(this->forward_service.get(), std::addressof(sd_fs)));
|
||||
R_TRY(fsOpenSdCardFileSystemFwd(m_forward_service.get(), std::addressof(sd_fs)));
|
||||
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(sd_fs.s))};
|
||||
|
||||
/* Return output filesystem. */
|
||||
@@ -242,14 +242,14 @@ namespace ams::mitm::fs {
|
||||
|
||||
Result FsMitmService::OpenSaveDataFileSystem(sf::Out<sf::SharedPointer<ams::fssrv::sf::IFileSystem>> out, u8 _space_id, const fs::SaveDataAttribute &attribute) {
|
||||
/* We only want to intercept saves for games, right now. */
|
||||
const bool is_game_or_hbl = this->client_info.override_status.IsHbl() || ncm::IsApplicationId(this->client_info.program_id);
|
||||
const bool is_game_or_hbl = m_client_info.override_status.IsHbl() || ncm::IsApplicationId(m_client_info.program_id);
|
||||
R_UNLESS(is_game_or_hbl, sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
/* Only redirect if the appropriate system setting is set. */
|
||||
R_UNLESS(GetSettingsItemBooleanValue("atmosphere", "fsmitm_redirect_saves_to_sd"), sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
/* Only redirect if the specific title being accessed has a redirect save flag. */
|
||||
R_UNLESS(cfg::HasContentSpecificFlag(this->client_info.program_id, "redirect_save"), sm::mitm::ResultShouldForwardToSession());
|
||||
R_UNLESS(cfg::HasContentSpecificFlag(m_client_info.program_id, "redirect_save"), sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
/* Only redirect account savedata. */
|
||||
R_UNLESS(attribute.type == fs::SaveDataType::Account, sm::mitm::ResultShouldForwardToSession());
|
||||
@@ -260,7 +260,7 @@ namespace ams::mitm::fs {
|
||||
/* Verify we can open the save. */
|
||||
static_assert(sizeof(fs::SaveDataAttribute) == sizeof(::FsSaveDataAttribute));
|
||||
FsFileSystem save_fs;
|
||||
R_UNLESS(R_SUCCEEDED(fsOpenSaveDataFileSystemFwd(this->forward_service.get(), std::addressof(save_fs), space_id, reinterpret_cast<const FsSaveDataAttribute *>(std::addressof(attribute)))), sm::mitm::ResultShouldForwardToSession());
|
||||
R_UNLESS(R_SUCCEEDED(fsOpenSaveDataFileSystemFwd(m_forward_service.get(), std::addressof(save_fs), space_id, reinterpret_cast<const FsSaveDataAttribute *>(std::addressof(attribute)))), sm::mitm::ResultShouldForwardToSession());
|
||||
std::unique_ptr<fs::fsa::IFileSystem> save_ifs = std::make_unique<fs::RemoteFileSystem>(save_fs);
|
||||
|
||||
/* Mount the SD card using fs.mitm's session. */
|
||||
@@ -270,7 +270,7 @@ namespace ams::mitm::fs {
|
||||
std::shared_ptr<fs::fsa::IFileSystem> sd_ifs = std::make_shared<fs::RemoteFileSystem>(sd_fs);
|
||||
|
||||
/* Verify that we can open the save directory, and that it exists. */
|
||||
const ncm::ProgramId application_id = attribute.program_id == ncm::InvalidProgramId ? this->client_info.program_id : attribute.program_id;
|
||||
const ncm::ProgramId application_id = attribute.program_id == ncm::InvalidProgramId ? m_client_info.program_id : attribute.program_id;
|
||||
char save_dir_path[fs::EntryNameLengthMax + 1];
|
||||
R_TRY(mitm::fs::SaveUtil::GetDirectorySaveDataPath(save_dir_path, sizeof(save_dir_path), application_id, space_id, attribute));
|
||||
|
||||
@@ -310,11 +310,11 @@ namespace ams::mitm::fs {
|
||||
|
||||
/* Try to open a storage for the partition. */
|
||||
FsStorage bis_storage;
|
||||
R_TRY(fsOpenBisStorageFwd(this->forward_service.get(), std::addressof(bis_storage), bis_partition_id));
|
||||
R_TRY(fsOpenBisStorageFwd(m_forward_service.get(), std::addressof(bis_storage), bis_partition_id));
|
||||
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(bis_storage.s))};
|
||||
|
||||
const bool is_sysmodule = ncm::IsSystemProgramId(this->client_info.program_id);
|
||||
const bool is_hbl = this->client_info.override_status.IsHbl();
|
||||
const bool is_sysmodule = ncm::IsSystemProgramId(m_client_info.program_id);
|
||||
const bool is_hbl = m_client_info.override_status.IsHbl();
|
||||
const bool can_write_bis = is_sysmodule || (is_hbl && GetSettingsItemBooleanValue("atmosphere", "enable_hbl_bis_write"));
|
||||
|
||||
/* Allow HBL to write to boot1 (safe firm) + package2. */
|
||||
@@ -327,12 +327,12 @@ namespace ams::mitm::fs {
|
||||
/* Set output storage. */
|
||||
if (bis_partition_id == FsBisPartitionId_BootPartition1Root) {
|
||||
if (IsBoot0CustomPublicKey(bis_storage)) {
|
||||
out.SetValue(MakeSharedStorage(new CustomPublicKeyBoot0Storage(bis_storage, this->client_info, spl::GetSocType())), target_object_id);
|
||||
out.SetValue(MakeSharedStorage(new CustomPublicKeyBoot0Storage(bis_storage, m_client_info, spl::GetSocType())), target_object_id);
|
||||
} else {
|
||||
out.SetValue(MakeSharedStorage(new Boot0Storage(bis_storage, this->client_info)), target_object_id);
|
||||
out.SetValue(MakeSharedStorage(new Boot0Storage(bis_storage, m_client_info)), target_object_id);
|
||||
}
|
||||
} else if (bis_partition_id == FsBisPartitionId_CalibrationBinary) {
|
||||
out.SetValue(MakeSharedStorage(new CalibrationBinaryStorage(bis_storage, this->client_info)), target_object_id);
|
||||
out.SetValue(MakeSharedStorage(new CalibrationBinaryStorage(bis_storage, m_client_info)), target_object_id);
|
||||
} else {
|
||||
if (can_write_bis || can_write_bis_for_choi_support) {
|
||||
/* We can write, so create a writable storage. */
|
||||
@@ -348,14 +348,14 @@ namespace ams::mitm::fs {
|
||||
|
||||
Result FsMitmService::OpenDataStorageByCurrentProcess(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out) {
|
||||
/* Only mitm if we should override contents for the current process. */
|
||||
R_UNLESS(this->client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession());
|
||||
R_UNLESS(m_client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
/* Only mitm if there is actually an override romfs. */
|
||||
R_UNLESS(mitm::fs::HasSdRomfsContent(this->client_info.program_id), sm::mitm::ResultShouldForwardToSession());
|
||||
R_UNLESS(mitm::fs::HasSdRomfsContent(m_client_info.program_id), sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
/* Try to open the process romfs. */
|
||||
FsStorage data_storage;
|
||||
R_TRY(fsOpenDataStorageByCurrentProcessFwd(this->forward_service.get(), std::addressof(data_storage)));
|
||||
R_TRY(fsOpenDataStorageByCurrentProcessFwd(m_forward_service.get(), std::addressof(data_storage)));
|
||||
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(data_storage.s))};
|
||||
|
||||
/* Get a scoped lock. */
|
||||
@@ -363,7 +363,7 @@ namespace ams::mitm::fs {
|
||||
|
||||
/* Try to get a storage from the cache. */
|
||||
{
|
||||
std::shared_ptr<fs::IStorage> cached_storage = GetStorageCacheEntry(this->client_info.program_id);
|
||||
std::shared_ptr<fs::IStorage> cached_storage = GetStorageCacheEntry(m_client_info.program_id);
|
||||
if (cached_storage != nullptr) {
|
||||
out.SetValue(MakeSharedStorage(cached_storage), target_object_id);
|
||||
return ResultSuccess();
|
||||
@@ -376,17 +376,17 @@ namespace ams::mitm::fs {
|
||||
|
||||
/* Create the layered storage. */
|
||||
FsFile data_file;
|
||||
if (R_SUCCEEDED(OpenAtmosphereSdFile(std::addressof(data_file), this->client_info.program_id, "romfs.bin", OpenMode_Read))) {
|
||||
auto layered_storage = std::make_shared<LayeredRomfsStorage>(std::make_unique<ReadOnlyStorageAdapter>(new RemoteStorage(data_storage)), std::make_unique<ReadOnlyStorageAdapter>(new FileStorage(new RemoteFile(data_file))), this->client_info.program_id);
|
||||
if (R_SUCCEEDED(OpenAtmosphereSdFile(std::addressof(data_file), m_client_info.program_id, "romfs.bin", OpenMode_Read))) {
|
||||
auto layered_storage = std::make_shared<LayeredRomfsStorage>(std::make_unique<ReadOnlyStorageAdapter>(new RemoteStorage(data_storage)), std::make_unique<ReadOnlyStorageAdapter>(new FileStorage(new RemoteFile(data_file))), m_client_info.program_id);
|
||||
layered_storage->BeginInitialize();
|
||||
new_storage = std::move(layered_storage);
|
||||
} else {
|
||||
auto layered_storage = std::make_shared<LayeredRomfsStorage>(std::make_unique<ReadOnlyStorageAdapter>(new RemoteStorage(data_storage)), nullptr, this->client_info.program_id);
|
||||
auto layered_storage = std::make_shared<LayeredRomfsStorage>(std::make_unique<ReadOnlyStorageAdapter>(new RemoteStorage(data_storage)), nullptr, m_client_info.program_id);
|
||||
layered_storage->BeginInitialize();
|
||||
new_storage = std::move(layered_storage);
|
||||
}
|
||||
|
||||
SetStorageCacheEntry(this->client_info.program_id, std::addressof(new_storage));
|
||||
SetStorageCacheEntry(m_client_info.program_id, std::addressof(new_storage));
|
||||
out.SetValue(MakeSharedStorage(new_storage), target_object_id);
|
||||
}
|
||||
|
||||
@@ -395,7 +395,7 @@ namespace ams::mitm::fs {
|
||||
|
||||
Result FsMitmService::OpenDataStorageByDataId(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, ncm::DataId _data_id, u8 storage_id) {
|
||||
/* Only mitm if we should override contents for the current process. */
|
||||
R_UNLESS(this->client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession());
|
||||
R_UNLESS(m_client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
/* TODO: Decide how to handle DataId vs ProgramId for this API. */
|
||||
const ncm::ProgramId data_id = {_data_id.value};
|
||||
@@ -405,7 +405,7 @@ namespace ams::mitm::fs {
|
||||
|
||||
/* Try to open the process romfs. */
|
||||
FsStorage data_storage;
|
||||
R_TRY(fsOpenDataStorageByDataIdFwd(this->forward_service.get(), std::addressof(data_storage), static_cast<u64>(data_id), static_cast<NcmStorageId>(storage_id)));
|
||||
R_TRY(fsOpenDataStorageByDataIdFwd(m_forward_service.get(), std::addressof(data_storage), static_cast<u64>(data_id), static_cast<NcmStorageId>(storage_id)));
|
||||
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(data_storage.s))};
|
||||
|
||||
/* Get a scoped lock. */
|
||||
@@ -445,10 +445,10 @@ namespace ams::mitm::fs {
|
||||
|
||||
Result FsMitmService::OpenDataStorageWithProgramIndex(sf::Out<sf::SharedPointer<ams::fssrv::sf::IStorage>> out, u8 program_index) {
|
||||
/* Only mitm if we should override contents for the current process. */
|
||||
R_UNLESS(this->client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession());
|
||||
R_UNLESS(m_client_info.override_status.IsProgramSpecific(), sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
/* Get the relevant program id. */
|
||||
const ncm::ProgramId program_id = g_program_index_map_info_manager.GetProgramId(this->client_info.program_id, program_index);
|
||||
const ncm::ProgramId program_id = g_program_index_map_info_manager.GetProgramId(m_client_info.program_id, program_index);
|
||||
|
||||
/* If we don't know about the program or don't have content, forward. */
|
||||
R_UNLESS(program_id != ncm::InvalidProgramId, sm::mitm::ResultShouldForwardToSession());
|
||||
@@ -456,7 +456,7 @@ namespace ams::mitm::fs {
|
||||
|
||||
/* Try to open the process romfs. */
|
||||
FsStorage data_storage;
|
||||
R_TRY(fsOpenDataStorageWithProgramIndexFwd(this->forward_service.get(), std::addressof(data_storage), program_index));
|
||||
R_TRY(fsOpenDataStorageWithProgramIndexFwd(m_forward_service.get(), std::addressof(data_storage), program_index));
|
||||
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(data_storage.s))};
|
||||
|
||||
/* Get a scoped lock. */
|
||||
@@ -496,7 +496,7 @@ namespace ams::mitm::fs {
|
||||
|
||||
Result FsMitmService::RegisterProgramIndexMapInfo(const sf::InBuffer &info_buffer, s32 info_count) {
|
||||
/* Try to register with FS. */
|
||||
R_TRY(fsRegisterProgramIndexMapInfoFwd(this->forward_service.get(), info_buffer.GetPointer(), info_buffer.GetSize(), info_count));
|
||||
R_TRY(fsRegisterProgramIndexMapInfoFwd(m_forward_service.get(), info_buffer.GetPointer(), info_buffer.GetSize(), info_count));
|
||||
|
||||
/* Register with ourselves. */
|
||||
R_ABORT_UNLESS(g_program_index_map_info_manager.Reset(reinterpret_cast<const fs::ProgramIndexMapInfo *>(info_buffer.GetPointer()), info_count));
|
||||
|
||||
@@ -22,9 +22,9 @@ namespace ams::mitm::fs {
|
||||
|
||||
namespace {
|
||||
|
||||
os::SdkMutex g_boot0_access_mutex;
|
||||
constinit os::SdkMutex g_boot0_access_mutex;
|
||||
constinit bool g_custom_public_key = false;
|
||||
u8 g_boot0_bct_buffer[Boot0Storage::BctEndOffset];
|
||||
constinit u8 g_boot0_bct_buffer[Boot0Storage::BctEndOffset];
|
||||
|
||||
/* Recognize special public key (https://gist.github.com/SciresM/16b63ac1d80494522bdba2c57995257c). */
|
||||
/* P = 19 */
|
||||
@@ -59,11 +59,11 @@ namespace ams::mitm::fs {
|
||||
/* RCM bug patched. */
|
||||
/* Only allow NS to update the BCT pubks. */
|
||||
/* AutoRCM on a patched unit will cause a brick, so homebrew should NOT be allowed to write. */
|
||||
return this->client_info.program_id == ncm::SystemProgramId::Ns;
|
||||
return m_client_info.program_id == ncm::SystemProgramId::Ns;
|
||||
} else {
|
||||
/* RCM bug unpatched. */
|
||||
/* Allow homebrew but not NS to update the BCT pubks. */
|
||||
return this->client_info.override_status.IsHbl();
|
||||
return m_client_info.override_status.IsHbl();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ namespace ams::mitm::fs {
|
||||
return Base::Write(0, g_boot0_bct_buffer, BctEndOffset);
|
||||
}
|
||||
|
||||
CustomPublicKeyBoot0Storage::CustomPublicKeyBoot0Storage(FsStorage &s, const sm::MitmProcessInfo &c, spl::SocType soc) : Base(s), client_info(c), soc_type(soc) {
|
||||
CustomPublicKeyBoot0Storage::CustomPublicKeyBoot0Storage(FsStorage &s, const sm::MitmProcessInfo &c, spl::SocType soc) : Base(s), m_client_info(c), m_soc_type(soc) {
|
||||
std::scoped_lock lk{g_boot0_access_mutex};
|
||||
|
||||
/* We're custom public key. */
|
||||
@@ -157,7 +157,7 @@ namespace ams::mitm::fs {
|
||||
|
||||
/* Check if we're reading the first BCTs for NS. */
|
||||
/* If we are, we want to lie about the contents of BCT0/1 so that they validate. */
|
||||
if (offset < 0x8000 && this->client_info.program_id == ncm::SystemProgramId::Ns) {
|
||||
if (offset < 0x8000 && m_client_info.program_id == ncm::SystemProgramId::Ns) {
|
||||
R_TRY(Base::Read(0, g_boot0_bct_buffer, Boot0Storage::BctEndOffset));
|
||||
|
||||
/* Determine the readable size. */
|
||||
@@ -207,7 +207,7 @@ namespace ams::mitm::fs {
|
||||
}
|
||||
|
||||
/* On erista, we want to protect the EKS region. */
|
||||
if (this->soc_type == spl::SocType_Erista) {
|
||||
if (m_soc_type == spl::SocType_Erista) {
|
||||
if (offset <= Boot0Storage::EksStart) {
|
||||
if (offset + size < Boot0Storage::EksStart) {
|
||||
/* Fall through, no need to do anything here. */
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace ams::mitm::fs {
|
||||
class SectoredStorageAdapter : public Base {
|
||||
static_assert(std::is_base_of<ams::fs::IStorage, Base>::value);
|
||||
private:
|
||||
u8 sector_buf[SectorSize];
|
||||
u8 m_sector_buf[SectorSize];
|
||||
public:
|
||||
/* Inherit constructors. */
|
||||
using Base::Base;
|
||||
@@ -44,15 +44,15 @@ namespace ams::mitm::fs {
|
||||
return Base::Read(offset, buffer, size);
|
||||
}
|
||||
|
||||
R_TRY(Base::Read(seek, this->sector_buf, SectorSize));
|
||||
R_TRY(Base::Read(seek, m_sector_buf, SectorSize));
|
||||
|
||||
if (size + sector_ofs <= SectorSize) {
|
||||
/* Staying within the sector. */
|
||||
std::memcpy(buffer, this->sector_buf + sector_ofs, size);
|
||||
std::memcpy(buffer, m_sector_buf + sector_ofs, size);
|
||||
} else {
|
||||
/* Leaving the sector. */
|
||||
const size_t size_in_sector = SectorSize - sector_ofs;
|
||||
std::memcpy(buffer, this->sector_buf + sector_ofs, size_in_sector);
|
||||
std::memcpy(buffer, m_sector_buf + sector_ofs, size_in_sector);
|
||||
size -= size_in_sector;
|
||||
|
||||
/* Read as many guaranteed aligned sectors as we can. */
|
||||
@@ -64,8 +64,8 @@ namespace ams::mitm::fs {
|
||||
|
||||
/* Read any leftover data. */
|
||||
if (size) {
|
||||
R_TRY(Base::Read(offset + size_in_sector + aligned_remaining_size, this->sector_buf, SectorSize));
|
||||
std::memcpy(buffer + size_in_sector + aligned_remaining_size, this->sector_buf, size);
|
||||
R_TRY(Base::Read(offset + size_in_sector + aligned_remaining_size, m_sector_buf, SectorSize));
|
||||
std::memcpy(buffer + size_in_sector + aligned_remaining_size, m_sector_buf, size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,17 +89,17 @@ namespace ams::mitm::fs {
|
||||
}
|
||||
|
||||
/* Load existing sector data. */
|
||||
R_TRY(Base::Read(seek, this->sector_buf, SectorSize));
|
||||
R_TRY(Base::Read(seek, m_sector_buf, SectorSize));
|
||||
|
||||
if (size + sector_ofs <= SectorSize) {
|
||||
/* Staying within the sector. */
|
||||
std::memcpy(this->sector_buf + sector_ofs, buffer, size);
|
||||
R_TRY(Base::Write(seek, this->sector_buf, SectorSize));
|
||||
std::memcpy(m_sector_buf + sector_ofs, buffer, size);
|
||||
R_TRY(Base::Write(seek, m_sector_buf, SectorSize));
|
||||
} else {
|
||||
/* Leaving the sector. */
|
||||
const size_t size_in_sector = SectorSize - sector_ofs;
|
||||
std::memcpy(this->sector_buf + sector_ofs, buffer, size_in_sector);
|
||||
R_TRY(Base::Write(seek, this->sector_buf, SectorSize));
|
||||
std::memcpy(m_sector_buf + sector_ofs, buffer, size_in_sector);
|
||||
R_TRY(Base::Write(seek, m_sector_buf, SectorSize));
|
||||
size -= size_in_sector;
|
||||
|
||||
/* Write as many guaranteed aligned sectors as we can. */
|
||||
@@ -111,9 +111,9 @@ namespace ams::mitm::fs {
|
||||
|
||||
/* Write any leftover data. */
|
||||
if (size) {
|
||||
R_TRY(Base::Read(offset + size_in_sector + aligned_remaining_size, this->sector_buf, SectorSize));
|
||||
std::memcpy(this->sector_buf, buffer + size_in_sector + aligned_remaining_size, size);
|
||||
R_TRY(Base::Write(offset + size_in_sector + aligned_remaining_size, this->sector_buf, SectorSize));
|
||||
R_TRY(Base::Read(offset + size_in_sector + aligned_remaining_size, m_sector_buf, SectorSize));
|
||||
std::memcpy(m_sector_buf, buffer + size_in_sector + aligned_remaining_size, size);
|
||||
R_TRY(Base::Write(offset + size_in_sector + aligned_remaining_size, m_sector_buf, SectorSize));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,11 +136,11 @@ namespace ams::mitm::fs {
|
||||
static constexpr s64 EksSize = static_cast<s64>(ams::updater::EksSize);
|
||||
static constexpr s64 EksEnd = EksStart + EksSize;
|
||||
private:
|
||||
sm::MitmProcessInfo client_info;
|
||||
sm::MitmProcessInfo m_client_info;
|
||||
private:
|
||||
bool CanModifyBctPublicKey();
|
||||
public:
|
||||
Boot0Storage(FsStorage &s, const sm::MitmProcessInfo &c) : Base(s), client_info(c) { /* ... */ }
|
||||
Boot0Storage(FsStorage &s, const sm::MitmProcessInfo &c) : Base(s), m_client_info(c) { /* ... */ }
|
||||
public:
|
||||
virtual Result Read(s64 offset, void *_buffer, size_t size) override;
|
||||
virtual Result Write(s64 offset, const void *_buffer, size_t size) override;
|
||||
@@ -150,8 +150,8 @@ namespace ams::mitm::fs {
|
||||
public:
|
||||
using Base = SectoredStorageAdapter<ams::fs::RemoteStorage, 0x200>;
|
||||
private:
|
||||
sm::MitmProcessInfo client_info;
|
||||
spl::SocType soc_type;
|
||||
sm::MitmProcessInfo m_client_info;
|
||||
spl::SocType m_soc_type;
|
||||
public:
|
||||
CustomPublicKeyBoot0Storage(FsStorage &s, const sm::MitmProcessInfo &c, spl::SocType soc);
|
||||
public:
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace ams::mitm::fs {
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* Handle the blank region. */
|
||||
if (this->read_blank) {
|
||||
if (m_read_blank) {
|
||||
if (BlankStartOffset <= offset && offset < BlankEndOffset) {
|
||||
const size_t blank_size = std::min(size, static_cast<size_t>(BlankEndOffset - offset));
|
||||
mitm::ReadFromBlankCalibrationBinary(offset, buffer, blank_size);
|
||||
@@ -88,10 +88,10 @@ namespace ams::mitm::fs {
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* Only allow writes if we should. */
|
||||
R_UNLESS(this->allow_writes, fs::ResultUnsupportedOperation());
|
||||
R_UNLESS(m_allow_writes, fs::ResultUnsupportedOperation());
|
||||
|
||||
/* Handle the blank region. */
|
||||
if (this->read_blank) {
|
||||
if (m_read_blank) {
|
||||
if (BlankStartOffset <= offset && offset < BlankEndOffset) {
|
||||
const size_t blank_size = std::min(size, static_cast<size_t>(BlankEndOffset - offset));
|
||||
mitm::WriteToBlankCalibrationBinary(offset, buffer, blank_size);
|
||||
|
||||
@@ -34,14 +34,14 @@ namespace ams::mitm::fs {
|
||||
static constexpr s64 FakeSecureSize = static_cast<s64>(SecureCalibrationBinaryBackupSize);
|
||||
static constexpr s64 FakeSecureEndOffset = FakeSecureStartOffset + FakeSecureSize;
|
||||
private:
|
||||
sm::MitmProcessInfo client_info;
|
||||
bool read_blank;
|
||||
bool allow_writes;
|
||||
sm::MitmProcessInfo m_client_info;
|
||||
bool m_read_blank;
|
||||
bool m_allow_writes;
|
||||
public:
|
||||
CalibrationBinaryStorage(FsStorage &s, const sm::MitmProcessInfo &c)
|
||||
: Base(s), client_info(c),
|
||||
read_blank(mitm::ShouldReadBlankCalibrationBinary()),
|
||||
allow_writes(mitm::IsWriteToCalibrationBinaryAllowed())
|
||||
: Base(s), m_client_info(c),
|
||||
m_read_blank(mitm::ShouldReadBlankCalibrationBinary()),
|
||||
m_allow_writes(mitm::IsWriteToCalibrationBinaryAllowed())
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
@@ -62,40 +62,40 @@ namespace ams::mitm::fs {
|
||||
|
||||
using namespace ams::fs;
|
||||
|
||||
LayeredRomfsStorage::LayeredRomfsStorage(std::unique_ptr<IStorage> s_r, std::unique_ptr<IStorage> f_r, ncm::ProgramId pr_id) : storage_romfs(std::move(s_r)), file_romfs(std::move(f_r)), initialize_event(os::EventClearMode_ManualClear), program_id(std::move(pr_id)), is_initialized(false), started_initialize(false) {
|
||||
LayeredRomfsStorage::LayeredRomfsStorage(std::unique_ptr<IStorage> s_r, std::unique_ptr<IStorage> f_r, ncm::ProgramId pr_id) : m_storage_romfs(std::move(s_r)), m_file_romfs(std::move(f_r)), m_initialize_event(os::EventClearMode_ManualClear), m_program_id(std::move(pr_id)), m_is_initialized(false), m_started_initialize(false) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
LayeredRomfsStorage::~LayeredRomfsStorage() {
|
||||
for (size_t i = 0; i < this->source_infos.size(); i++) {
|
||||
this->source_infos[i].Cleanup();
|
||||
for (size_t i = 0; i < m_source_infos.size(); i++) {
|
||||
m_source_infos[i].Cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
void LayeredRomfsStorage::BeginInitialize() {
|
||||
AMS_ABORT_UNLESS(!this->started_initialize);
|
||||
AMS_ABORT_UNLESS(!m_started_initialize);
|
||||
RequestInitializeStorage(reinterpret_cast<uintptr_t>(this));
|
||||
this->started_initialize = true;
|
||||
m_started_initialize = true;
|
||||
}
|
||||
|
||||
void LayeredRomfsStorage::InitializeImpl() {
|
||||
/* Build new virtual romfs. */
|
||||
romfs::Builder builder(this->program_id);
|
||||
romfs::Builder builder(m_program_id);
|
||||
|
||||
if (mitm::IsInitialized()) {
|
||||
builder.AddSdFiles();
|
||||
}
|
||||
if (this->file_romfs) {
|
||||
builder.AddStorageFiles(this->file_romfs.get(), romfs::DataSourceType::File);
|
||||
if (m_file_romfs) {
|
||||
builder.AddStorageFiles(m_file_romfs.get(), romfs::DataSourceType::File);
|
||||
}
|
||||
if (this->storage_romfs) {
|
||||
builder.AddStorageFiles(this->storage_romfs.get(), romfs::DataSourceType::Storage);
|
||||
if (m_storage_romfs) {
|
||||
builder.AddStorageFiles(m_storage_romfs.get(), romfs::DataSourceType::Storage);
|
||||
}
|
||||
|
||||
builder.Build(std::addressof(this->source_infos));
|
||||
builder.Build(std::addressof(m_source_infos));
|
||||
|
||||
this->is_initialized = true;
|
||||
this->initialize_event.Signal();
|
||||
m_is_initialized = true;
|
||||
m_initialize_event.Signal();
|
||||
}
|
||||
|
||||
Result LayeredRomfsStorage::Read(s64 offset, void *buffer, size_t size) {
|
||||
@@ -103,8 +103,8 @@ namespace ams::mitm::fs {
|
||||
R_SUCCEED_IF(size == 0);
|
||||
|
||||
/* Ensure we're initialized. */
|
||||
if (!this->is_initialized) {
|
||||
this->initialize_event.Wait();
|
||||
if (!m_is_initialized) {
|
||||
m_initialize_event.Wait();
|
||||
}
|
||||
|
||||
/* Validate offset/size. */
|
||||
@@ -116,7 +116,7 @@ namespace ams::mitm::fs {
|
||||
}
|
||||
|
||||
/* Find first source info via binary search. */
|
||||
auto it = std::lower_bound(this->source_infos.begin(), this->source_infos.end(), offset);
|
||||
auto it = std::lower_bound(m_source_infos.begin(), m_source_infos.end(), offset);
|
||||
u8 *cur_dst = static_cast<u8 *>(buffer);
|
||||
|
||||
/* Our operator < compares against start of info instead of end, so we need to subtract one from lower bound. */
|
||||
@@ -132,15 +132,15 @@ namespace ams::mitm::fs {
|
||||
const size_t cur_read_size = std::min(size - read_so_far, static_cast<size_t>(cur_source.size - offset_within_source));
|
||||
switch (cur_source.source_type) {
|
||||
case romfs::DataSourceType::Storage:
|
||||
R_ABORT_UNLESS(this->storage_romfs->Read(cur_source.storage_source_info.offset + offset_within_source, cur_dst, cur_read_size));
|
||||
R_ABORT_UNLESS(m_storage_romfs->Read(cur_source.storage_source_info.offset + offset_within_source, cur_dst, cur_read_size));
|
||||
break;
|
||||
case romfs::DataSourceType::File:
|
||||
R_ABORT_UNLESS(this->file_romfs->Read(cur_source.file_source_info.offset + offset_within_source, cur_dst, cur_read_size));
|
||||
R_ABORT_UNLESS(m_file_romfs->Read(cur_source.file_source_info.offset + offset_within_source, cur_dst, cur_read_size));
|
||||
break;
|
||||
case romfs::DataSourceType::LooseSdFile:
|
||||
{
|
||||
FsFile file;
|
||||
R_ABORT_UNLESS(mitm::fs::OpenAtmosphereSdRomfsFile(std::addressof(file), this->program_id, cur_source.loose_source_info.path, OpenMode_Read));
|
||||
R_ABORT_UNLESS(mitm::fs::OpenAtmosphereSdRomfsFile(std::addressof(file), m_program_id, cur_source.loose_source_info.path, OpenMode_Read));
|
||||
ON_SCOPE_EXIT { fsFileClose(std::addressof(file)); };
|
||||
|
||||
u64 out_read = 0;
|
||||
@@ -180,8 +180,8 @@ namespace ams::mitm::fs {
|
||||
|
||||
Result LayeredRomfsStorage::GetSize(s64 *out_size) {
|
||||
/* Ensure we're initialized. */
|
||||
if (!this->is_initialized) {
|
||||
this->initialize_event.Wait();
|
||||
if (!m_is_initialized) {
|
||||
m_initialize_event.Wait();
|
||||
}
|
||||
|
||||
*out_size = this->GetSize();
|
||||
|
||||
@@ -22,16 +22,16 @@ namespace ams::mitm::fs {
|
||||
|
||||
class LayeredRomfsStorage : public std::enable_shared_from_this<LayeredRomfsStorage>, public ams::fs::IStorage {
|
||||
private:
|
||||
std::vector<romfs::SourceInfo> source_infos;
|
||||
std::unique_ptr<ams::fs::IStorage> storage_romfs;
|
||||
std::unique_ptr<ams::fs::IStorage> file_romfs;
|
||||
os::Event initialize_event;
|
||||
ncm::ProgramId program_id;
|
||||
bool is_initialized;
|
||||
bool started_initialize;
|
||||
std::vector<romfs::SourceInfo> m_source_infos;
|
||||
std::unique_ptr<ams::fs::IStorage> m_storage_romfs;
|
||||
std::unique_ptr<ams::fs::IStorage> m_file_romfs;
|
||||
os::Event m_initialize_event;
|
||||
ncm::ProgramId m_program_id;
|
||||
bool m_is_initialized;
|
||||
bool m_started_initialize;
|
||||
protected:
|
||||
inline s64 GetSize() const {
|
||||
const auto &back = this->source_infos.back();
|
||||
const auto &back = m_source_infos.back();
|
||||
return back.virtual_offset + back.size;
|
||||
}
|
||||
public:
|
||||
|
||||
@@ -20,10 +20,10 @@ namespace ams::mitm::fs {
|
||||
|
||||
class ReadOnlyLayeredFileSystem : public ams::fs::fsa::IFileSystem {
|
||||
private:
|
||||
ams::fs::ReadOnlyFileSystem fs_1;
|
||||
ams::fs::ReadOnlyFileSystem fs_2;
|
||||
ams::fs::ReadOnlyFileSystem m_fs_1;
|
||||
ams::fs::ReadOnlyFileSystem m_fs_2;
|
||||
public:
|
||||
explicit ReadOnlyLayeredFileSystem(std::unique_ptr<ams::fs::fsa::IFileSystem> a, std::unique_ptr<ams::fs::fsa::IFileSystem> b) : fs_1(std::move(a)), fs_2(std::move(b)) { /* ... */ }
|
||||
explicit ReadOnlyLayeredFileSystem(std::unique_ptr<ams::fs::fsa::IFileSystem> a, std::unique_ptr<ams::fs::fsa::IFileSystem> b) : m_fs_1(std::move(a)), m_fs_2(std::move(b)) { /* ... */ }
|
||||
|
||||
virtual ~ReadOnlyLayeredFileSystem() { /* ... */ }
|
||||
private:
|
||||
@@ -63,18 +63,18 @@ namespace ams::mitm::fs {
|
||||
}
|
||||
|
||||
virtual Result DoGetEntryType(ams::fs::DirectoryEntryType *out, const char *path) override final {
|
||||
R_SUCCEED_IF(R_SUCCEEDED(this->fs_1.GetEntryType(out, path)));
|
||||
return this->fs_2.GetEntryType(out, path);
|
||||
R_SUCCEED_IF(R_SUCCEEDED(m_fs_1.GetEntryType(out, path)));
|
||||
return m_fs_2.GetEntryType(out, path);
|
||||
}
|
||||
|
||||
virtual Result DoOpenFile(std::unique_ptr<ams::fs::fsa::IFile> *out_file, const char *path, ams::fs::OpenMode mode) override final {
|
||||
R_SUCCEED_IF(R_SUCCEEDED(this->fs_1.OpenFile(out_file, path, mode)));
|
||||
return this->fs_2.OpenFile(out_file, path, mode);
|
||||
R_SUCCEED_IF(R_SUCCEEDED(m_fs_1.OpenFile(out_file, path, mode)));
|
||||
return m_fs_2.OpenFile(out_file, path, mode);
|
||||
}
|
||||
|
||||
virtual Result DoOpenDirectory(std::unique_ptr<ams::fs::fsa::IDirectory> *out_dir, const char *path, ams::fs::OpenDirectoryMode mode) override final {
|
||||
R_SUCCEED_IF(R_SUCCEEDED(this->fs_1.OpenDirectory(out_dir, path, mode)));
|
||||
return this->fs_2.OpenDirectory(out_dir, path, mode);
|
||||
R_SUCCEED_IF(R_SUCCEEDED(m_fs_1.OpenDirectory(out_dir, path, mode)));
|
||||
return m_fs_2.OpenDirectory(out_dir, path, mode);
|
||||
}
|
||||
|
||||
virtual Result DoCommit() override final {
|
||||
@@ -97,8 +97,8 @@ namespace ams::mitm::fs {
|
||||
}
|
||||
|
||||
virtual Result DoGetFileTimeStampRaw(ams::fs::FileTimeStampRaw *out, const char *path) {
|
||||
R_SUCCEED_IF(R_SUCCEEDED(this->fs_1.GetFileTimeStampRaw(out, path)));
|
||||
return this->fs_2.GetFileTimeStampRaw(out, path);
|
||||
R_SUCCEED_IF(R_SUCCEEDED(m_fs_1.GetFileTimeStampRaw(out, path)));
|
||||
return m_fs_2.GetFileTimeStampRaw(out, path);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -72,26 +72,26 @@ namespace ams::mitm::fs {
|
||||
static constexpr size_t MaxCachedSize = (1_MB / 4);
|
||||
static constexpr size_t FallbackCacheSize = 1_KB;
|
||||
private:
|
||||
ams::fs::IStorage *storage;
|
||||
size_t offset;
|
||||
size_t size;
|
||||
size_t cache_idx;
|
||||
void *cache;
|
||||
u8 fallback_cache[FallbackCacheSize];
|
||||
ams::fs::IStorage *m_storage;
|
||||
size_t m_offset;
|
||||
size_t m_size;
|
||||
size_t m_cache_idx;
|
||||
void *m_cache;
|
||||
u8 m_fallback_cache[FallbackCacheSize];
|
||||
private:
|
||||
ALWAYS_INLINE void Read(size_t ofs, void *dst, size_t size) {
|
||||
R_ABORT_UNLESS(this->storage->Read(this->offset + ofs, dst, size));
|
||||
R_ABORT_UNLESS(m_storage->Read(m_offset + ofs, dst, size));
|
||||
}
|
||||
ALWAYS_INLINE void ReloadCacheImpl(size_t idx) {
|
||||
const size_t rel_ofs = idx * MaxCachedSize;
|
||||
AMS_ABORT_UNLESS(rel_ofs < this->size);
|
||||
const size_t new_cache_size = std::min(this->size - rel_ofs, MaxCachedSize);
|
||||
this->Read(rel_ofs, this->cache, new_cache_size);
|
||||
this->cache_idx = idx;
|
||||
AMS_ABORT_UNLESS(rel_ofs < m_size);
|
||||
const size_t new_cache_size = std::min(m_size - rel_ofs, MaxCachedSize);
|
||||
this->Read(rel_ofs, m_cache, new_cache_size);
|
||||
m_cache_idx = idx;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void ReloadCache(size_t idx) {
|
||||
if (this->cache_idx != idx) {
|
||||
if (m_cache_idx != idx) {
|
||||
this->ReloadCacheImpl(idx);
|
||||
}
|
||||
}
|
||||
@@ -100,14 +100,14 @@ namespace ams::mitm::fs {
|
||||
return ofs / MaxCachedSize;
|
||||
}
|
||||
public:
|
||||
TableReader(ams::fs::IStorage *s, size_t ofs, size_t sz) : storage(s), offset(ofs), size(sz), cache_idx(0) {
|
||||
this->cache = std::malloc(std::min(sz, MaxCachedSize));
|
||||
AMS_ABORT_UNLESS(this->cache != nullptr);
|
||||
TableReader(ams::fs::IStorage *s, size_t ofs, size_t sz) : m_storage(s), m_offset(ofs), m_size(sz), m_cache_idx(0) {
|
||||
m_cache = std::malloc(std::min(sz, MaxCachedSize));
|
||||
AMS_ABORT_UNLESS(m_cache != nullptr);
|
||||
this->ReloadCacheImpl(0);
|
||||
}
|
||||
|
||||
~TableReader() {
|
||||
std::free(this->cache);
|
||||
std::free(m_cache);
|
||||
}
|
||||
|
||||
const Entry *GetEntry(u32 entry_offset) {
|
||||
@@ -115,10 +115,10 @@ namespace ams::mitm::fs {
|
||||
|
||||
const size_t ofs = entry_offset % MaxCachedSize;
|
||||
|
||||
const Entry *entry = reinterpret_cast<const Entry *>(reinterpret_cast<uintptr_t>(this->cache) + ofs);
|
||||
const Entry *entry = reinterpret_cast<const Entry *>(reinterpret_cast<uintptr_t>(m_cache) + ofs);
|
||||
if (AMS_UNLIKELY(this->GetCacheIndex(entry_offset) != this->GetCacheIndex(entry_offset + sizeof(Entry) + entry->name_size + sizeof(u32)))) {
|
||||
this->Read(entry_offset, this->fallback_cache, std::min(this->size - entry_offset, FallbackCacheSize));
|
||||
entry = reinterpret_cast<const Entry *>(this->fallback_cache);
|
||||
this->Read(entry_offset, m_fallback_cache, std::min(m_size - entry_offset, FallbackCacheSize));
|
||||
entry = reinterpret_cast<const Entry *>(m_fallback_cache);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
@@ -132,38 +132,38 @@ namespace ams::mitm::fs {
|
||||
static constexpr size_t MaxCachedSize = (1_MB / 4);
|
||||
static constexpr size_t FallbackCacheSize = 1_KB;
|
||||
private:
|
||||
::FsFile *file;
|
||||
size_t offset;
|
||||
size_t size;
|
||||
size_t cache_idx;
|
||||
void *cache;
|
||||
u8 fallback_cache[FallbackCacheSize];
|
||||
size_t fallback_cache_entry_offset;
|
||||
size_t fallback_cache_entry_size;
|
||||
bool cache_dirty;
|
||||
bool fallback_cache_dirty;
|
||||
::FsFile *m_file;
|
||||
size_t m_offset;
|
||||
size_t m_size;
|
||||
size_t m_cache_idx;
|
||||
void *m_cache;
|
||||
u8 m_fallback_cache[FallbackCacheSize];
|
||||
size_t m_fallback_cache_entry_offset;
|
||||
size_t m_fallback_cache_entry_size;
|
||||
bool m_cache_dirty;
|
||||
bool m_fallback_cache_dirty;
|
||||
private:
|
||||
ALWAYS_INLINE void Read(size_t ofs, void *dst, size_t sz) {
|
||||
u64 read_size;
|
||||
R_ABORT_UNLESS(fsFileRead(this->file, this->offset + ofs, dst, sz, 0, std::addressof(read_size)));
|
||||
R_ABORT_UNLESS(fsFileRead(m_file, m_offset + ofs, dst, sz, 0, std::addressof(read_size)));
|
||||
AMS_ABORT_UNLESS(read_size == sz);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void Write(size_t ofs, const void *src, size_t sz) {
|
||||
R_ABORT_UNLESS(fsFileWrite(this->file, this->offset + ofs, src, sz, FsWriteOption_None));
|
||||
R_ABORT_UNLESS(fsFileWrite(m_file, m_offset + ofs, src, sz, FsWriteOption_None));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void Flush() {
|
||||
AMS_ABORT_UNLESS(!(this->cache_dirty && this->fallback_cache_dirty));
|
||||
AMS_ABORT_UNLESS(!(m_cache_dirty && m_fallback_cache_dirty));
|
||||
|
||||
if (this->cache_dirty) {
|
||||
const size_t ofs = this->cache_idx * MaxCachedSize;
|
||||
this->Write(ofs, this->cache, std::min(this->size - ofs, MaxCachedSize));
|
||||
this->cache_dirty = false;
|
||||
if (m_cache_dirty) {
|
||||
const size_t ofs = m_cache_idx * MaxCachedSize;
|
||||
this->Write(ofs, m_cache, std::min(m_size - ofs, MaxCachedSize));
|
||||
m_cache_dirty = false;
|
||||
}
|
||||
if (this->fallback_cache_dirty) {
|
||||
this->Write(this->fallback_cache_entry_offset, this->fallback_cache, this->fallback_cache_entry_size);
|
||||
this->fallback_cache_dirty = false;
|
||||
if (m_fallback_cache_dirty) {
|
||||
this->Write(m_fallback_cache_entry_offset, m_fallback_cache, m_fallback_cache_entry_size);
|
||||
m_fallback_cache_dirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,32 +172,32 @@ namespace ams::mitm::fs {
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void RefreshCacheImpl() {
|
||||
const size_t cur_cache = this->cache_idx * MaxCachedSize;
|
||||
this->Read(cur_cache, this->cache, std::min(this->size - cur_cache, MaxCachedSize));
|
||||
const size_t cur_cache = m_cache_idx * MaxCachedSize;
|
||||
this->Read(cur_cache, m_cache, std::min(m_size - cur_cache, MaxCachedSize));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void RefreshCache(u32 entry_offset) {
|
||||
if (size_t idx = this->GetCacheIndex(entry_offset); idx != this->cache_idx || this->fallback_cache_dirty) {
|
||||
if (size_t idx = this->GetCacheIndex(entry_offset); idx != m_cache_idx || m_fallback_cache_dirty) {
|
||||
this->Flush();
|
||||
this->cache_idx = idx;
|
||||
m_cache_idx = idx;
|
||||
this->RefreshCacheImpl();
|
||||
}
|
||||
}
|
||||
public:
|
||||
TableWriter(::FsFile *f, size_t ofs, size_t sz) : file(f), offset(ofs), size(sz), cache_idx(0), fallback_cache_entry_offset(), fallback_cache_entry_size(), cache_dirty(), fallback_cache_dirty() {
|
||||
TableWriter(::FsFile *f, size_t ofs, size_t sz) : m_file(f), m_offset(ofs), m_size(sz), m_cache_idx(0), m_fallback_cache_entry_offset(), m_fallback_cache_entry_size(), m_cache_dirty(), m_fallback_cache_dirty() {
|
||||
const size_t cache_size = std::min(sz, MaxCachedSize);
|
||||
this->cache = std::malloc(cache_size);
|
||||
AMS_ABORT_UNLESS(this->cache != nullptr);
|
||||
std::memset(this->cache, 0, cache_size);
|
||||
std::memset(this->fallback_cache, 0, sizeof(this->fallback_cache));
|
||||
for (size_t cur = 0; cur < this->size; cur += MaxCachedSize) {
|
||||
this->Write(cur, this->cache, std::min(this->size - cur, MaxCachedSize));
|
||||
m_cache = std::malloc(cache_size);
|
||||
AMS_ABORT_UNLESS(m_cache != nullptr);
|
||||
std::memset(m_cache, 0, cache_size);
|
||||
std::memset(m_fallback_cache, 0, sizeof(m_fallback_cache));
|
||||
for (size_t cur = 0; cur < m_size; cur += MaxCachedSize) {
|
||||
this->Write(cur, m_cache, std::min(m_size - cur, MaxCachedSize));
|
||||
}
|
||||
}
|
||||
|
||||
~TableWriter() {
|
||||
this->Flush();
|
||||
std::free(this->cache);
|
||||
std::free(m_cache);
|
||||
}
|
||||
|
||||
Entry *GetEntry(u32 entry_offset, u32 name_len) {
|
||||
@@ -205,18 +205,18 @@ namespace ams::mitm::fs {
|
||||
|
||||
const size_t ofs = entry_offset % MaxCachedSize;
|
||||
|
||||
Entry *entry = reinterpret_cast<Entry *>(reinterpret_cast<uintptr_t>(this->cache) + ofs);
|
||||
Entry *entry = reinterpret_cast<Entry *>(reinterpret_cast<uintptr_t>(m_cache) + ofs);
|
||||
if (ofs + sizeof(Entry) + util::AlignUp(name_len, sizeof(u32)) > MaxCachedSize) {
|
||||
this->Flush();
|
||||
|
||||
this->fallback_cache_entry_offset = entry_offset;
|
||||
this->fallback_cache_entry_size = sizeof(Entry) + util::AlignUp(name_len, sizeof(u32));
|
||||
this->Read(this->fallback_cache_entry_offset, this->fallback_cache, this->fallback_cache_entry_size);
|
||||
m_fallback_cache_entry_offset = entry_offset;
|
||||
m_fallback_cache_entry_size = sizeof(Entry) + util::AlignUp(name_len, sizeof(u32));
|
||||
this->Read(m_fallback_cache_entry_offset, m_fallback_cache, m_fallback_cache_entry_size);
|
||||
|
||||
entry = reinterpret_cast<Entry *>(this->fallback_cache);
|
||||
this->fallback_cache_dirty = true;
|
||||
entry = reinterpret_cast<Entry *>(m_fallback_cache);
|
||||
m_fallback_cache_dirty = true;
|
||||
} else {
|
||||
this->cache_dirty = true;
|
||||
m_cache_dirty = true;
|
||||
}
|
||||
|
||||
return entry;
|
||||
@@ -269,12 +269,12 @@ namespace ams::mitm::fs {
|
||||
|
||||
}
|
||||
|
||||
Builder::Builder(ncm::ProgramId pr_id) : program_id(pr_id), num_dirs(0), num_files(0), dir_table_size(0), file_table_size(0), dir_hash_table_size(0), file_hash_table_size(0), file_partition_size(0) {
|
||||
auto res = this->directories.emplace(std::make_unique<BuildDirectoryContext>(BuildDirectoryContext::RootTag{}));
|
||||
Builder::Builder(ncm::ProgramId pr_id) : m_program_id(pr_id), m_num_dirs(0), m_num_files(0), m_dir_table_size(0), m_file_table_size(0), m_dir_hash_table_size(0), m_file_hash_table_size(0), m_file_partition_size(0) {
|
||||
auto res = m_directories.emplace(std::make_unique<BuildDirectoryContext>(BuildDirectoryContext::RootTag{}));
|
||||
AMS_ABORT_UNLESS(res.second);
|
||||
this->root = res.first->get();
|
||||
this->num_dirs = 1;
|
||||
this->dir_table_size = 0x18;
|
||||
m_root = res.first->get();
|
||||
m_num_dirs = 1;
|
||||
m_dir_table_size = 0x18;
|
||||
}
|
||||
|
||||
void Builder::AddDirectory(BuildDirectoryContext **out, BuildDirectoryContext *parent_ctx, std::unique_ptr<BuildDirectoryContext> child_ctx) {
|
||||
@@ -282,18 +282,18 @@ namespace ams::mitm::fs {
|
||||
child_ctx->parent = parent_ctx;
|
||||
|
||||
/* Check if the directory already exists. */
|
||||
auto existing = this->directories.find(child_ctx);
|
||||
if (existing != this->directories.end()) {
|
||||
auto existing = m_directories.find(child_ctx);
|
||||
if (existing != m_directories.end()) {
|
||||
*out = existing->get();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Add a new directory. */
|
||||
this->num_dirs++;
|
||||
this->dir_table_size += sizeof(DirectoryEntry) + util::AlignUp(child_ctx->path_len, 4);
|
||||
m_num_dirs++;
|
||||
m_dir_table_size += sizeof(DirectoryEntry) + util::AlignUp(child_ctx->path_len, 4);
|
||||
|
||||
*out = child_ctx.get();
|
||||
this->directories.emplace(std::move(child_ctx));
|
||||
m_directories.emplace(std::move(child_ctx));
|
||||
}
|
||||
|
||||
void Builder::AddFile(BuildDirectoryContext *parent_ctx, std::unique_ptr<BuildFileContext> file_ctx) {
|
||||
@@ -301,14 +301,14 @@ namespace ams::mitm::fs {
|
||||
file_ctx->parent = parent_ctx;
|
||||
|
||||
/* Check if the file already exists. */
|
||||
if (this->files.find(file_ctx) != this->files.end()) {
|
||||
if (m_files.find(file_ctx) != m_files.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Add a new file. */
|
||||
this->num_files++;
|
||||
this->file_table_size += sizeof(FileEntry) + util::AlignUp(file_ctx->path_len, 4);
|
||||
this->files.emplace(std::move(file_ctx));
|
||||
m_num_files++;
|
||||
m_file_table_size += sizeof(FileEntry) + util::AlignUp(file_ctx->path_len, 4);
|
||||
m_files.emplace(std::move(file_ctx));
|
||||
}
|
||||
|
||||
void Builder::VisitDirectory(FsFileSystem *fs, BuildDirectoryContext *parent) {
|
||||
@@ -317,7 +317,7 @@ namespace ams::mitm::fs {
|
||||
/* Get number of child directories. */
|
||||
s64 num_child_dirs = 0;
|
||||
{
|
||||
OpenFileSystemRomfsDirectory(std::addressof(dir), this->program_id, parent, OpenDirectoryMode_Directory, fs);
|
||||
OpenFileSystemRomfsDirectory(std::addressof(dir), m_program_id, parent, OpenDirectoryMode_Directory, fs);
|
||||
ON_SCOPE_EXIT { fsDirClose(std::addressof(dir)); };
|
||||
R_ABORT_UNLESS(fsDirGetEntryCount(std::addressof(dir), std::addressof(num_child_dirs)));
|
||||
}
|
||||
@@ -330,27 +330,27 @@ namespace ams::mitm::fs {
|
||||
|
||||
s64 cur_child_dir_ind = 0;
|
||||
{
|
||||
OpenFileSystemRomfsDirectory(std::addressof(dir), this->program_id, parent, OpenDirectoryMode_All, fs);
|
||||
OpenFileSystemRomfsDirectory(std::addressof(dir), m_program_id, parent, OpenDirectoryMode_All, fs);
|
||||
ON_SCOPE_EXIT { fsDirClose(std::addressof(dir)); };
|
||||
|
||||
s64 read_entries = 0;
|
||||
while (true) {
|
||||
R_ABORT_UNLESS(fsDirRead(std::addressof(dir), std::addressof(read_entries), 1, std::addressof(this->dir_entry)));
|
||||
R_ABORT_UNLESS(fsDirRead(std::addressof(dir), std::addressof(read_entries), 1, std::addressof(m_dir_entry)));
|
||||
if (read_entries != 1) {
|
||||
break;
|
||||
}
|
||||
|
||||
AMS_ABORT_UNLESS(this->dir_entry.type == FsDirEntryType_Dir || this->dir_entry.type == FsDirEntryType_File);
|
||||
if (this->dir_entry.type == FsDirEntryType_Dir) {
|
||||
AMS_ABORT_UNLESS(m_dir_entry.type == FsDirEntryType_Dir || m_dir_entry.type == FsDirEntryType_File);
|
||||
if (m_dir_entry.type == FsDirEntryType_Dir) {
|
||||
AMS_ABORT_UNLESS(child_dirs != nullptr);
|
||||
|
||||
BuildDirectoryContext *real_child = nullptr;
|
||||
this->AddDirectory(std::addressof(real_child), parent, std::make_unique<BuildDirectoryContext>(this->dir_entry.name, strlen(this->dir_entry.name)));
|
||||
this->AddDirectory(std::addressof(real_child), parent, std::make_unique<BuildDirectoryContext>(m_dir_entry.name, strlen(m_dir_entry.name)));
|
||||
AMS_ABORT_UNLESS(real_child != nullptr);
|
||||
child_dirs[cur_child_dir_ind++] = real_child;
|
||||
AMS_ABORT_UNLESS(cur_child_dir_ind <= num_child_dirs);
|
||||
} else /* if (this->dir_entry.type == FsDirEntryType_File) */ {
|
||||
this->AddFile(parent, std::make_unique<BuildFileContext>(this->dir_entry.name, strlen(this->dir_entry.name), this->dir_entry.file_size, 0, this->cur_source_type));
|
||||
} else /* if (m_dir_entry.type == FsDirEntryType_File) */ {
|
||||
this->AddFile(parent, std::make_unique<BuildFileContext>(m_dir_entry.name, strlen(m_dir_entry.name), m_dir_entry.file_size, 0, m_cur_source_type));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -380,7 +380,7 @@ namespace ams::mitm::fs {
|
||||
while (cur_file_offset != EmptyEntry) {
|
||||
const FileEntry *cur_file = file_table.GetEntry(cur_file_offset);
|
||||
|
||||
this->AddFile(parent, std::make_unique<BuildFileContext>(cur_file->name, cur_file->name_size, cur_file->size, cur_file->offset, this->cur_source_type));
|
||||
this->AddFile(parent, std::make_unique<BuildFileContext>(cur_file->name, cur_file->name_size, cur_file->size, cur_file->offset, m_cur_source_type));
|
||||
|
||||
cur_file_offset = cur_file->sibling;
|
||||
}
|
||||
@@ -415,14 +415,14 @@ namespace ams::mitm::fs {
|
||||
/* If there is no romfs folder on the SD, don't bother continuing. */
|
||||
{
|
||||
FsDir dir;
|
||||
if (R_FAILED(mitm::fs::OpenAtmosphereRomfsDirectory(std::addressof(dir), this->program_id, this->root->path.get(), OpenDirectoryMode_Directory, std::addressof(sd_filesystem)))) {
|
||||
if (R_FAILED(mitm::fs::OpenAtmosphereRomfsDirectory(std::addressof(dir), m_program_id, m_root->path.get(), OpenDirectoryMode_Directory, std::addressof(sd_filesystem)))) {
|
||||
return;
|
||||
}
|
||||
fsDirClose(std::addressof(dir));
|
||||
}
|
||||
|
||||
this->cur_source_type = DataSourceType::LooseSdFile;
|
||||
this->VisitDirectory(std::addressof(sd_filesystem), this->root);
|
||||
m_cur_source_type = DataSourceType::LooseSdFile;
|
||||
this->VisitDirectory(std::addressof(sd_filesystem), m_root);
|
||||
}
|
||||
|
||||
void Builder::AddStorageFiles(ams::fs::IStorage *storage, DataSourceType source_type) {
|
||||
@@ -434,8 +434,8 @@ namespace ams::mitm::fs {
|
||||
DirectoryTableReader dir_table(storage, header.dir_table_ofs, header.dir_table_size);
|
||||
FileTableReader file_table(storage, header.file_table_ofs, header.file_table_size);
|
||||
|
||||
this->cur_source_type = source_type;
|
||||
this->VisitDirectory(this->root, 0x0, dir_table, file_table);
|
||||
m_cur_source_type = source_type;
|
||||
this->VisitDirectory(m_root, 0x0, dir_table, file_table);
|
||||
}
|
||||
|
||||
void Builder::Build(std::vector<SourceInfo> *out_infos) {
|
||||
@@ -448,19 +448,19 @@ namespace ams::mitm::fs {
|
||||
ON_SCOPE_EXIT { fsFsClose(std::addressof(sd_filesystem)); };
|
||||
|
||||
/* Calculate hash table sizes. */
|
||||
const size_t num_dir_hash_table_entries = GetHashTableSize(this->num_dirs);
|
||||
const size_t num_file_hash_table_entries = GetHashTableSize(this->num_files);
|
||||
this->dir_hash_table_size = sizeof(u32) * num_dir_hash_table_entries;
|
||||
this->file_hash_table_size = sizeof(u32) * num_file_hash_table_entries;
|
||||
const size_t num_dir_hash_table_entries = GetHashTableSize(m_num_dirs);
|
||||
const size_t num_file_hash_table_entries = GetHashTableSize(m_num_files);
|
||||
m_dir_hash_table_size = sizeof(u32) * num_dir_hash_table_entries;
|
||||
m_file_hash_table_size = sizeof(u32) * num_file_hash_table_entries;
|
||||
|
||||
/* Allocate metadata, make pointers. */
|
||||
Header *header = reinterpret_cast<Header *>(std::malloc(sizeof(Header)));
|
||||
std::memset(header, 0x00, sizeof(*header));
|
||||
|
||||
/* Open metadata file. */
|
||||
const size_t metadata_size = this->dir_hash_table_size + this->dir_table_size + this->file_hash_table_size + this->file_table_size;
|
||||
const size_t metadata_size = m_dir_hash_table_size + m_dir_table_size + m_file_hash_table_size + m_file_table_size;
|
||||
FsFile metadata_file;
|
||||
R_ABORT_UNLESS(mitm::fs::CreateAndOpenAtmosphereSdFile(std::addressof(metadata_file), this->program_id, "romfs_metadata.bin", metadata_size));
|
||||
R_ABORT_UNLESS(mitm::fs::CreateAndOpenAtmosphereSdFile(std::addressof(metadata_file), m_program_id, "romfs_metadata.bin", metadata_size));
|
||||
|
||||
/* Ensure later hash tables will have correct defaults. */
|
||||
static_assert(EmptyEntry == 0xFFFFFFFF);
|
||||
@@ -473,25 +473,25 @@ namespace ams::mitm::fs {
|
||||
u32 entry_offset = 0;
|
||||
BuildFileContext *cur_file = nullptr;
|
||||
BuildFileContext *prev_file = nullptr;
|
||||
for (const auto &it : this->files) {
|
||||
for (const auto &it : m_files) {
|
||||
cur_file = it.get();
|
||||
|
||||
/* By default, pad to 0x10 alignment. */
|
||||
this->file_partition_size = util::AlignUp(this->file_partition_size, 0x10);
|
||||
m_file_partition_size = util::AlignUp(m_file_partition_size, 0x10);
|
||||
|
||||
/* Check if extra padding is present in original source, preserve it to make our life easier. */
|
||||
const bool is_storage_or_file = cur_file->source_type == DataSourceType::Storage || cur_file->source_type == DataSourceType::File;
|
||||
if (prev_file != nullptr && prev_file->source_type == cur_file->source_type && is_storage_or_file) {
|
||||
const s64 expected = this->file_partition_size - prev_file->offset + prev_file->orig_offset;
|
||||
const s64 expected = m_file_partition_size - prev_file->offset + prev_file->orig_offset;
|
||||
if (expected != cur_file->orig_offset) {
|
||||
AMS_ABORT_UNLESS(expected <= cur_file->orig_offset);
|
||||
this->file_partition_size += cur_file->orig_offset - expected;
|
||||
m_file_partition_size += cur_file->orig_offset - expected;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate offsets. */
|
||||
cur_file->offset = this->file_partition_size;
|
||||
this->file_partition_size += cur_file->size;
|
||||
cur_file->offset = m_file_partition_size;
|
||||
m_file_partition_size += cur_file->size;
|
||||
cur_file->entry_offset = entry_offset;
|
||||
entry_offset += sizeof(FileEntry) + util::AlignUp(cur_file->path_len, 4);
|
||||
|
||||
@@ -499,7 +499,7 @@ namespace ams::mitm::fs {
|
||||
prev_file = cur_file;
|
||||
}
|
||||
/* Assign deferred parent/sibling ownership. */
|
||||
for (auto it = this->files.rbegin(); it != this->files.rend(); it++) {
|
||||
for (auto it = m_files.rbegin(); it != m_files.rend(); it++) {
|
||||
cur_file = it->get();
|
||||
cur_file->sibling = cur_file->parent->file;
|
||||
cur_file->parent->file = cur_file;
|
||||
@@ -510,15 +510,15 @@ namespace ams::mitm::fs {
|
||||
{
|
||||
u32 entry_offset = 0;
|
||||
BuildDirectoryContext *cur_dir = nullptr;
|
||||
for (const auto &it : this->directories) {
|
||||
for (const auto &it : m_directories) {
|
||||
cur_dir = it.get();
|
||||
cur_dir->entry_offset = entry_offset;
|
||||
entry_offset += sizeof(DirectoryEntry) + util::AlignUp(cur_dir->path_len, 4);
|
||||
}
|
||||
/* Assign deferred parent/sibling ownership. */
|
||||
for (auto it = this->directories.rbegin(); it != this->directories.rend(); it++) {
|
||||
for (auto it = m_directories.rbegin(); it != m_directories.rend(); it++) {
|
||||
cur_dir = it->get();
|
||||
if (cur_dir == this->root) {
|
||||
if (cur_dir == m_root) {
|
||||
continue;
|
||||
}
|
||||
cur_dir->sibling = cur_dir->parent->child;
|
||||
@@ -529,20 +529,20 @@ namespace ams::mitm::fs {
|
||||
/* Populate file tables. */
|
||||
{
|
||||
/* Allocate the hash table. */
|
||||
void *fht_buf = std::malloc(this->file_hash_table_size);
|
||||
void *fht_buf = std::malloc(m_file_hash_table_size);
|
||||
AMS_ABORT_UNLESS(fht_buf != nullptr);
|
||||
u32 *file_hash_table = reinterpret_cast<u32 *>(fht_buf);
|
||||
std::memset(file_hash_table, 0xFF, this->file_hash_table_size);
|
||||
std::memset(file_hash_table, 0xFF, m_file_hash_table_size);
|
||||
ON_SCOPE_EXIT {
|
||||
R_ABORT_UNLESS(fsFileWrite(std::addressof(metadata_file), this->dir_hash_table_size + this->dir_table_size, file_hash_table, this->file_hash_table_size, FsWriteOption_None));
|
||||
R_ABORT_UNLESS(fsFileWrite(std::addressof(metadata_file), m_dir_hash_table_size + m_dir_table_size, file_hash_table, m_file_hash_table_size, FsWriteOption_None));
|
||||
std::free(fht_buf);
|
||||
};
|
||||
|
||||
/* Write the file table. */
|
||||
{
|
||||
FileTableWriter file_table(std::addressof(metadata_file), this->dir_hash_table_size + this->dir_table_size + this->file_hash_table_size, this->file_table_size);
|
||||
FileTableWriter file_table(std::addressof(metadata_file), m_dir_hash_table_size + m_dir_table_size + m_file_hash_table_size, m_file_table_size);
|
||||
|
||||
for (const auto &it : this->files) {
|
||||
for (const auto &it : m_files) {
|
||||
BuildFileContext *cur_file = it.get();
|
||||
FileEntry *cur_entry = file_table.GetEntry(cur_file->entry_offset, cur_file->path_len);
|
||||
|
||||
@@ -597,25 +597,25 @@ namespace ams::mitm::fs {
|
||||
/* Populate directory tables. */
|
||||
{
|
||||
/* Allocate the hash table. */
|
||||
void *dht_buf = std::malloc(this->dir_hash_table_size);
|
||||
void *dht_buf = std::malloc(m_dir_hash_table_size);
|
||||
AMS_ABORT_UNLESS(dht_buf != nullptr);
|
||||
u32 *dir_hash_table = reinterpret_cast<u32 *>(dht_buf);
|
||||
std::memset(dir_hash_table, 0xFF, this->dir_hash_table_size);
|
||||
std::memset(dir_hash_table, 0xFF, m_dir_hash_table_size);
|
||||
ON_SCOPE_EXIT {
|
||||
R_ABORT_UNLESS(fsFileWrite(std::addressof(metadata_file), 0, dir_hash_table, this->dir_hash_table_size, FsWriteOption_None));
|
||||
R_ABORT_UNLESS(fsFileWrite(std::addressof(metadata_file), 0, dir_hash_table, m_dir_hash_table_size, FsWriteOption_None));
|
||||
std::free(dht_buf);
|
||||
};
|
||||
|
||||
/* Write the file table. */
|
||||
{
|
||||
DirectoryTableWriter dir_table(std::addressof(metadata_file), this->dir_hash_table_size, this->dir_table_size);
|
||||
DirectoryTableWriter dir_table(std::addressof(metadata_file), m_dir_hash_table_size, m_dir_table_size);
|
||||
|
||||
for (const auto &it : this->directories) {
|
||||
for (const auto &it : m_directories) {
|
||||
BuildDirectoryContext *cur_dir = it.get();
|
||||
DirectoryEntry *cur_entry = dir_table.GetEntry(cur_dir->entry_offset, cur_dir->path_len);
|
||||
|
||||
/* Set entry fields. */
|
||||
cur_entry->parent = cur_dir == this->root ? 0 : cur_dir->parent->entry_offset;
|
||||
cur_entry->parent = cur_dir == m_root ? 0 : cur_dir->parent->entry_offset;
|
||||
cur_entry->sibling = (cur_dir->sibling == nullptr) ? EmptyEntry : cur_dir->sibling->entry_offset;
|
||||
cur_entry->child = (cur_dir->child == nullptr) ? EmptyEntry : cur_dir->child->entry_offset;
|
||||
cur_entry->file = (cur_dir->file == nullptr) ? EmptyEntry : cur_dir->file->entry_offset;
|
||||
@@ -639,21 +639,21 @@ namespace ams::mitm::fs {
|
||||
}
|
||||
|
||||
/* Delete maps. */
|
||||
this->root = nullptr;
|
||||
this->directories.clear();
|
||||
this->files.clear();
|
||||
m_root = nullptr;
|
||||
m_directories.clear();
|
||||
m_files.clear();
|
||||
|
||||
/* Set header fields. */
|
||||
header->header_size = sizeof(*header);
|
||||
header->file_hash_table_size = this->file_hash_table_size;
|
||||
header->file_table_size = this->file_table_size;
|
||||
header->dir_hash_table_size = this->dir_hash_table_size;
|
||||
header->dir_table_size = this->dir_table_size;
|
||||
header->file_partition_ofs = FilePartitionOffset;
|
||||
header->dir_hash_table_ofs = util::AlignUp(FilePartitionOffset + this->file_partition_size, 4);
|
||||
header->dir_table_ofs = header->dir_hash_table_ofs + header->dir_hash_table_size;
|
||||
header->file_hash_table_ofs = header->dir_table_ofs + header->dir_table_size;
|
||||
header->file_table_ofs = header->file_hash_table_ofs + header->file_hash_table_size;
|
||||
header->header_size = sizeof(*header);
|
||||
header->file_hash_table_size = m_file_hash_table_size;
|
||||
header->file_table_size = m_file_table_size;
|
||||
header->dir_hash_table_size = m_dir_hash_table_size;
|
||||
header->dir_table_size = m_dir_table_size;
|
||||
header->file_partition_ofs = FilePartitionOffset;
|
||||
header->dir_hash_table_ofs = util::AlignUp(FilePartitionOffset + m_file_partition_size, 4);
|
||||
header->dir_table_ofs = header->dir_hash_table_ofs + header->dir_hash_table_size;
|
||||
header->file_hash_table_ofs = header->dir_table_ofs + header->dir_table_size;
|
||||
header->file_table_ofs = header->file_hash_table_ofs + header->file_hash_table_size;
|
||||
|
||||
/* Save metadata to the SD card, to save on memory space. */
|
||||
{
|
||||
|
||||
@@ -202,7 +202,7 @@ namespace ams::mitm::fs::romfs {
|
||||
class DirectoryTableReader;
|
||||
class FileTableReader;
|
||||
|
||||
struct Builder {
|
||||
class Builder {
|
||||
NON_COPYABLE(Builder);
|
||||
NON_MOVEABLE(Builder);
|
||||
private:
|
||||
@@ -230,20 +230,20 @@ namespace ams::mitm::fs::romfs {
|
||||
template<typename T>
|
||||
using ContextSet = std::set<std::unique_ptr<T>, Comparator<T>>;
|
||||
private:
|
||||
ncm::ProgramId program_id;
|
||||
BuildDirectoryContext *root;
|
||||
ContextSet<BuildDirectoryContext> directories;
|
||||
ContextSet<BuildFileContext> files;
|
||||
size_t num_dirs;
|
||||
size_t num_files;
|
||||
size_t dir_table_size;
|
||||
size_t file_table_size;
|
||||
size_t dir_hash_table_size;
|
||||
size_t file_hash_table_size;
|
||||
size_t file_partition_size;
|
||||
ncm::ProgramId m_program_id;
|
||||
BuildDirectoryContext *m_root;
|
||||
ContextSet<BuildDirectoryContext> m_directories;
|
||||
ContextSet<BuildFileContext> m_files;
|
||||
size_t m_num_dirs;
|
||||
size_t m_num_files;
|
||||
size_t m_dir_table_size;
|
||||
size_t m_file_table_size;
|
||||
size_t m_dir_hash_table_size;
|
||||
size_t m_file_hash_table_size;
|
||||
size_t m_file_partition_size;
|
||||
|
||||
ams::fs::DirectoryEntry dir_entry;
|
||||
DataSourceType cur_source_type;
|
||||
ams::fs::DirectoryEntry m_dir_entry;
|
||||
DataSourceType m_cur_source_type;
|
||||
private:
|
||||
void VisitDirectory(FsFileSystem *fs, BuildDirectoryContext *parent);
|
||||
void VisitDirectory(BuildDirectoryContext *parent, u32 parent_offset, DirectoryTableReader &dir_table, FileTableReader &file_table);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
namespace ams::mitm::ns {
|
||||
|
||||
Result NsAmMitmService::GetApplicationContentPath(const sf::OutBuffer &out_path, ncm::ProgramId application_id, u8 content_type) {
|
||||
return nsamGetApplicationContentPathFwd(this->forward_service.get(), out_path.GetPointer(), out_path.GetSize(), static_cast<u64>(application_id), static_cast<NcmContentType>(content_type));
|
||||
return nsamGetApplicationContentPathFwd(m_forward_service.get(), out_path.GetPointer(), out_path.GetSize(), static_cast<u64>(application_id), static_cast<NcmContentType>(content_type));
|
||||
}
|
||||
|
||||
Result NsAmMitmService::ResolveApplicationContentPath(ncm::ProgramId application_id, u8 content_type) {
|
||||
@@ -28,14 +28,14 @@ namespace ams::mitm::ns {
|
||||
/* This enables hbl html. */
|
||||
bool is_hbl;
|
||||
if (R_SUCCEEDED(pm::info::IsHblProgramId(&is_hbl, application_id)) && is_hbl) {
|
||||
nsamResolveApplicationContentPathFwd(this->forward_service.get(), static_cast<u64>(application_id), static_cast<NcmContentType>(content_type));
|
||||
nsamResolveApplicationContentPathFwd(m_forward_service.get(), static_cast<u64>(application_id), static_cast<NcmContentType>(content_type));
|
||||
return ResultSuccess();
|
||||
}
|
||||
return nsamResolveApplicationContentPathFwd(this->forward_service.get(), static_cast<u64>(application_id), static_cast<NcmContentType>(content_type));
|
||||
return nsamResolveApplicationContentPathFwd(m_forward_service.get(), static_cast<u64>(application_id), static_cast<NcmContentType>(content_type));
|
||||
}
|
||||
|
||||
Result NsAmMitmService::GetRunningApplicationProgramId(sf::Out<ncm::ProgramId> out, ncm::ProgramId application_id) {
|
||||
return nsamGetRunningApplicationProgramIdFwd(this->forward_service.get(), reinterpret_cast<u64 *>(out.GetPointer()), static_cast<u64>(application_id));
|
||||
return nsamGetRunningApplicationProgramIdFwd(m_forward_service.get(), reinterpret_cast<u64 *>(out.GetPointer()), static_cast<u64>(application_id));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
namespace ams::mitm::ns {
|
||||
|
||||
Result NsDocumentService::GetApplicationContentPath(const sf::OutBuffer &out_path, ncm::ProgramId application_id, u8 content_type) {
|
||||
return nswebGetApplicationContentPath(this->srv.get(), out_path.GetPointer(), out_path.GetSize(), static_cast<u64>(application_id), static_cast<NcmContentType>(content_type));
|
||||
return nswebGetApplicationContentPath(m_srv.get(), out_path.GetPointer(), out_path.GetSize(), static_cast<u64>(application_id), static_cast<NcmContentType>(content_type));
|
||||
}
|
||||
|
||||
Result NsDocumentService::ResolveApplicationContentPath(ncm::ProgramId application_id, u8 content_type) {
|
||||
@@ -27,23 +27,23 @@ namespace ams::mitm::ns {
|
||||
/* This enables hbl html. */
|
||||
bool is_hbl;
|
||||
if (R_SUCCEEDED(pm::info::IsHblProgramId(std::addressof(is_hbl), application_id)) && is_hbl) {
|
||||
nswebResolveApplicationContentPath(this->srv.get(), static_cast<u64>(application_id), static_cast<NcmContentType>(content_type));
|
||||
nswebResolveApplicationContentPath(m_srv.get(), static_cast<u64>(application_id), static_cast<NcmContentType>(content_type));
|
||||
return ResultSuccess();
|
||||
}
|
||||
return nswebResolveApplicationContentPath(this->srv.get(), static_cast<u64>(application_id), static_cast<NcmContentType>(content_type));
|
||||
return nswebResolveApplicationContentPath(m_srv.get(), static_cast<u64>(application_id), static_cast<NcmContentType>(content_type));
|
||||
}
|
||||
|
||||
Result NsDocumentService::GetRunningApplicationProgramId(sf::Out<ncm::ProgramId> out, ncm::ProgramId application_id) {
|
||||
return nswebGetRunningApplicationProgramId(this->srv.get(), reinterpret_cast<u64 *>(out.GetPointer()), static_cast<u64>(application_id));
|
||||
return nswebGetRunningApplicationProgramId(m_srv.get(), reinterpret_cast<u64 *>(out.GetPointer()), static_cast<u64>(application_id));
|
||||
}
|
||||
|
||||
Result NsWebMitmService::GetDocumentInterface(sf::Out<sf::SharedPointer<impl::IDocumentInterface>> out) {
|
||||
/* Open a document interface. */
|
||||
NsDocumentInterface doc;
|
||||
R_TRY(nsGetDocumentInterfaceFwd(this->forward_service.get(), std::addressof(doc)));
|
||||
R_TRY(nsGetDocumentInterfaceFwd(m_forward_service.get(), std::addressof(doc)));
|
||||
const sf::cmif::DomainObjectId target_object_id{serviceGetObjectId(std::addressof(doc.s))};
|
||||
|
||||
out.SetValue(sf::CreateSharedObjectEmplaced<impl::IDocumentInterface, NsDocumentService>(this->client_info, std::make_unique<NsDocumentInterface>(doc)), target_object_id);
|
||||
out.SetValue(sf::CreateSharedObjectEmplaced<impl::IDocumentInterface, NsDocumentService>(m_client_info, std::make_unique<NsDocumentInterface>(doc)), target_object_id);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
|
||||
@@ -34,13 +34,13 @@ namespace ams::mitm::ns {
|
||||
|
||||
class NsDocumentService {
|
||||
private:
|
||||
sm::MitmProcessInfo client_info;
|
||||
std::unique_ptr<::NsDocumentInterface> srv;
|
||||
sm::MitmProcessInfo m_client_info;
|
||||
std::unique_ptr<::NsDocumentInterface> m_srv;
|
||||
public:
|
||||
NsDocumentService(const sm::MitmProcessInfo &cl, std::unique_ptr<::NsDocumentInterface> s) : client_info(cl), srv(std::move(s)) { /* .. */ }
|
||||
NsDocumentService(const sm::MitmProcessInfo &cl, std::unique_ptr<::NsDocumentInterface> s) : m_client_info(cl), m_srv(std::move(s)) { /* .. */ }
|
||||
|
||||
virtual ~NsDocumentService() {
|
||||
nsDocumentInterfaceClose(this->srv.get());
|
||||
nsDocumentInterfaceClose(m_srv.get());
|
||||
}
|
||||
public:
|
||||
/* Actual command API. */
|
||||
|
||||
@@ -30,13 +30,13 @@ namespace ams::mitm::settings {
|
||||
}
|
||||
|
||||
SetMitmService::SetMitmService(std::shared_ptr<::Service> &&s, const sm::MitmProcessInfo &c) : sf::MitmServiceImplBase(std::forward<std::shared_ptr<::Service>>(s), c) {
|
||||
if (this->client_info.program_id == ncm::SystemProgramId::Ns) {
|
||||
if (m_client_info.program_id == ncm::SystemProgramId::Ns) {
|
||||
os::ProcessId application_process_id;
|
||||
if (R_SUCCEEDED(pm::dmnt::GetApplicationProcessId(std::addressof(application_process_id))) && g_application_process_id == application_process_id) {
|
||||
this->locale = g_application_locale;
|
||||
this->is_valid_language = g_valid_language;
|
||||
this->is_valid_region = g_valid_region;
|
||||
this->got_locale = true;
|
||||
m_locale = g_application_locale;
|
||||
m_is_valid_language = g_valid_language;
|
||||
m_is_valid_region = g_valid_region;
|
||||
m_got_locale = true;
|
||||
} else {
|
||||
this->InvalidateLocale();
|
||||
}
|
||||
@@ -47,16 +47,16 @@ namespace ams::mitm::settings {
|
||||
|
||||
Result SetMitmService::EnsureLocale() {
|
||||
/* Optimization: if locale has already been gotten, we can stop. */
|
||||
if (AMS_LIKELY(this->got_locale)) {
|
||||
if (AMS_LIKELY(m_got_locale)) {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
std::scoped_lock lk(this->lock);
|
||||
std::scoped_lock lk(m_lock);
|
||||
|
||||
const bool is_ns = this->client_info.program_id == ncm::SystemProgramId::Ns;
|
||||
const bool is_ns = m_client_info.program_id == ncm::SystemProgramId::Ns;
|
||||
|
||||
if (!this->got_locale) {
|
||||
ncm::ProgramId program_id = this->client_info.program_id;
|
||||
if (!m_got_locale) {
|
||||
ncm::ProgramId program_id = m_client_info.program_id;
|
||||
os::ProcessId application_process_id = os::InvalidProcessId;
|
||||
|
||||
if (is_ns) {
|
||||
@@ -64,15 +64,15 @@ namespace ams::mitm::settings {
|
||||
R_TRY(pm::dmnt::GetApplicationProcessId(std::addressof(application_process_id)));
|
||||
R_TRY(pm::info::GetProgramId(std::addressof(program_id), application_process_id));
|
||||
}
|
||||
this->locale = cfg::GetOverrideLocale(program_id);
|
||||
this->is_valid_language = settings::IsValidLanguageCode(this->locale.language_code);
|
||||
this->is_valid_region = settings::IsValidRegionCode(this->locale.region_code);
|
||||
this->got_locale = true;
|
||||
m_locale = cfg::GetOverrideLocale(program_id);
|
||||
m_is_valid_language = settings::IsValidLanguageCode(m_locale.language_code);
|
||||
m_is_valid_region = settings::IsValidRegionCode(m_locale.region_code);
|
||||
m_got_locale = true;
|
||||
|
||||
if (is_ns) {
|
||||
g_application_locale = this->locale;
|
||||
g_valid_language = this->is_valid_language;
|
||||
g_valid_region = this->is_valid_region;
|
||||
g_application_locale = m_locale;
|
||||
g_valid_language = m_is_valid_language;
|
||||
g_valid_region = m_is_valid_region;
|
||||
g_application_process_id = application_process_id;
|
||||
}
|
||||
}
|
||||
@@ -81,30 +81,30 @@ namespace ams::mitm::settings {
|
||||
}
|
||||
|
||||
void SetMitmService::InvalidateLocale() {
|
||||
std::scoped_lock lk(this->lock);
|
||||
std::scoped_lock lk(m_lock);
|
||||
|
||||
std::memset(std::addressof(this->locale), 0xCC, sizeof(this->locale));
|
||||
this->is_valid_language = false;
|
||||
this->is_valid_region = false;
|
||||
this->got_locale = false;
|
||||
std::memset(std::addressof(m_locale), 0xCC, sizeof(m_locale));
|
||||
m_is_valid_language = false;
|
||||
m_is_valid_region = false;
|
||||
m_got_locale = false;
|
||||
}
|
||||
|
||||
Result SetMitmService::GetLanguageCode(sf::Out<settings::LanguageCode> out) {
|
||||
this->EnsureLocale();
|
||||
|
||||
/* If there's no override locale, just use the actual one. */
|
||||
if (AMS_UNLIKELY(!this->is_valid_language)) {
|
||||
if (AMS_UNLIKELY(!m_is_valid_language)) {
|
||||
static_assert(sizeof(u64) == sizeof(settings::LanguageCode));
|
||||
R_TRY(setGetLanguageCodeFwd(this->forward_service.get(), reinterpret_cast<u64 *>(std::addressof(this->locale.language_code))));
|
||||
R_TRY(setGetLanguageCodeFwd(m_forward_service.get(), reinterpret_cast<u64 *>(std::addressof(m_locale.language_code))));
|
||||
|
||||
this->is_valid_language = true;
|
||||
if (this->client_info.program_id == ncm::SystemProgramId::Ns) {
|
||||
g_application_locale.language_code = this->locale.language_code;
|
||||
m_is_valid_language = true;
|
||||
if (m_client_info.program_id == ncm::SystemProgramId::Ns) {
|
||||
g_application_locale.language_code = m_locale.language_code;
|
||||
g_valid_language = true;
|
||||
}
|
||||
}
|
||||
|
||||
out.SetValue(this->locale.language_code);
|
||||
out.SetValue(m_locale.language_code);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
@@ -112,18 +112,18 @@ namespace ams::mitm::settings {
|
||||
this->EnsureLocale();
|
||||
|
||||
/* If there's no override locale, just use the actual one. */
|
||||
if (AMS_UNLIKELY(!this->is_valid_region)) {
|
||||
if (AMS_UNLIKELY(!m_is_valid_region)) {
|
||||
static_assert(sizeof(::SetRegion) == sizeof(settings::RegionCode));
|
||||
R_TRY(setGetRegionCodeFwd(this->forward_service.get(), reinterpret_cast<::SetRegion *>(std::addressof(this->locale.region_code))));
|
||||
R_TRY(setGetRegionCodeFwd(m_forward_service.get(), reinterpret_cast<::SetRegion *>(std::addressof(m_locale.region_code))));
|
||||
|
||||
this->is_valid_region = true;
|
||||
if (this->client_info.program_id == ncm::SystemProgramId::Ns) {
|
||||
g_application_locale.region_code = this->locale.region_code;
|
||||
m_is_valid_region = true;
|
||||
if (m_client_info.program_id == ncm::SystemProgramId::Ns) {
|
||||
g_application_locale.region_code = m_locale.region_code;
|
||||
g_valid_region = true;
|
||||
}
|
||||
}
|
||||
|
||||
out.SetValue(this->locale.region_code);
|
||||
out.SetValue(m_locale.region_code);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
|
||||
@@ -26,11 +26,11 @@ namespace ams::mitm::settings {
|
||||
|
||||
class SetMitmService : public sf::MitmServiceImplBase {
|
||||
private:
|
||||
os::SdkMutex lock{};
|
||||
cfg::OverrideLocale locale;
|
||||
bool got_locale = false;
|
||||
bool is_valid_language = false;
|
||||
bool is_valid_region = false;
|
||||
os::SdkMutex m_lock{};
|
||||
cfg::OverrideLocale m_locale;
|
||||
bool m_got_locale = false;
|
||||
bool m_is_valid_language = false;
|
||||
bool m_is_valid_region = false;
|
||||
public:
|
||||
SetMitmService(std::shared_ptr<::Service> &&s, const sm::MitmProcessInfo &c);
|
||||
public:
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace ams::mitm::settings {
|
||||
}
|
||||
|
||||
Result SetSysMitmService::GetFirmwareVersion(sf::Out<settings::FirmwareVersion> out) {
|
||||
R_TRY(GetFirmwareVersionImpl(out.GetPointer(), this->client_info));
|
||||
R_TRY(GetFirmwareVersionImpl(out.GetPointer(), m_client_info));
|
||||
|
||||
/* GetFirmwareVersion sanitizes the revision fields. */
|
||||
out.GetPointer()->revision_major = 0;
|
||||
@@ -99,7 +99,7 @@ namespace ams::mitm::settings {
|
||||
}
|
||||
|
||||
Result SetSysMitmService::GetFirmwareVersion2(sf::Out<settings::FirmwareVersion> out) {
|
||||
return GetFirmwareVersionImpl(out.GetPointer(), this->client_info);
|
||||
return GetFirmwareVersionImpl(out.GetPointer(), m_client_info);
|
||||
}
|
||||
|
||||
Result SetSysMitmService::GetSettingsItemValueSize(sf::Out<u64> out_size, const settings::SettingsName &name, const settings::SettingsItemKey &key) {
|
||||
@@ -122,7 +122,7 @@ namespace ams::mitm::settings {
|
||||
|
||||
Result SetSysMitmService::GetDebugModeFlag(sf::Out<bool> out) {
|
||||
/* If we're not processing for am, just return the real flag value. */
|
||||
R_UNLESS(this->client_info.program_id == ncm::SystemProgramId::Am, sm::mitm::ResultShouldForwardToSession());
|
||||
R_UNLESS(m_client_info.program_id == ncm::SystemProgramId::Am, sm::mitm::ResultShouldForwardToSession());
|
||||
|
||||
/* Retrieve the user configuration. */
|
||||
u8 en = 0;
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace ams::mitm::sysupdater {
|
||||
|
||||
Result SystemUpdateApplyManager::ApplyPackageTask(ncm::PackageSystemDowngradeTask *task) {
|
||||
/* Lock the apply mutex. */
|
||||
std::scoped_lock lk(this->apply_mutex);
|
||||
std::scoped_lock lk(m_apply_mutex);
|
||||
|
||||
/* NOTE: Here, Nintendo creates a system report for the update. */
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@ namespace ams::mitm::sysupdater {
|
||||
|
||||
class SystemUpdateApplyManager {
|
||||
private:
|
||||
os::SdkMutex apply_mutex;
|
||||
os::SdkMutex m_apply_mutex;
|
||||
public:
|
||||
constexpr SystemUpdateApplyManager() : apply_mutex() { /* ... */ }
|
||||
constexpr SystemUpdateApplyManager() : m_apply_mutex() { /* ... */ }
|
||||
|
||||
Result ApplyPackageTask(ncm::PackageSystemDowngradeTask *task);
|
||||
};
|
||||
|
||||
@@ -29,10 +29,10 @@ namespace ams::mitm::sysupdater {
|
||||
}
|
||||
|
||||
AsyncPrepareSdCardUpdateImpl::~AsyncPrepareSdCardUpdateImpl() {
|
||||
if (this->thread_info) {
|
||||
os::WaitThread(this->thread_info->thread);
|
||||
os::DestroyThread(this->thread_info->thread);
|
||||
GetAsyncThreadAllocator()->Free(*this->thread_info);
|
||||
if (m_thread_info) {
|
||||
os::WaitThread(m_thread_info->thread);
|
||||
os::DestroyThread(m_thread_info->thread);
|
||||
GetAsyncThreadAllocator()->Free(*m_thread_info);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,16 +46,16 @@ namespace ams::mitm::sysupdater {
|
||||
|
||||
/* Ensure that we clean up appropriately. */
|
||||
ON_SCOPE_EXIT {
|
||||
if (!this->thread_info) {
|
||||
if (!m_thread_info) {
|
||||
GetAsyncThreadAllocator()->Free(info);
|
||||
}
|
||||
};
|
||||
|
||||
/* Create a thread for the task. */
|
||||
R_TRY(os::CreateThread(info.thread, [](void *arg) {
|
||||
auto *_this = reinterpret_cast<AsyncPrepareSdCardUpdateImpl *>(arg);
|
||||
_this->result = _this->Execute();
|
||||
_this->event.Signal();
|
||||
auto *async = reinterpret_cast<AsyncPrepareSdCardUpdateImpl *>(arg);
|
||||
async->m_result = async->Execute();
|
||||
async->m_event.Signal();
|
||||
}, this, info.stack, info.stack_size, info.priority));
|
||||
|
||||
/* Set the thread name. */
|
||||
@@ -65,16 +65,16 @@ namespace ams::mitm::sysupdater {
|
||||
os::StartThread(info.thread);
|
||||
|
||||
/* Set our thread info. */
|
||||
this->thread_info = info;
|
||||
m_thread_info = info;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result AsyncPrepareSdCardUpdateImpl::Execute() {
|
||||
return this->task->PrepareAndExecute();
|
||||
return m_task->PrepareAndExecute();
|
||||
}
|
||||
|
||||
void AsyncPrepareSdCardUpdateImpl::CancelImpl() {
|
||||
this->task->Cancel();
|
||||
m_task->Cancel();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,16 +21,16 @@ namespace ams::mitm::sysupdater {
|
||||
|
||||
class ErrorContextHolder {
|
||||
private:
|
||||
err::ErrorContext error_context;
|
||||
err::ErrorContext m_error_context;
|
||||
public:
|
||||
constexpr ErrorContextHolder() : error_context{} { /* ... */ }
|
||||
constexpr ErrorContextHolder() : m_error_context{} { /* ... */ }
|
||||
|
||||
virtual ~ErrorContextHolder() { /* ... */ }
|
||||
|
||||
template<typename T>
|
||||
Result SaveErrorContextIfFailed(T &async, Result result) {
|
||||
if (R_FAILED(result)) {
|
||||
async.GetErrorContext(std::addressof(this->error_context));
|
||||
async.GetErrorContext(std::addressof(m_error_context));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace ams::mitm::sysupdater {
|
||||
template<typename T>
|
||||
Result SaveInternalTaskErrorContextIfFailed(T &async, Result result) {
|
||||
if (R_FAILED(result)) {
|
||||
async.CreateErrorContext(std::addressof(this->error_context));
|
||||
async.CreateErrorContext(std::addressof(m_error_context));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace ams::mitm::sysupdater {
|
||||
}
|
||||
|
||||
const err::ErrorContext &GetErrorContextImpl() {
|
||||
return this->error_context;
|
||||
return m_error_context;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -93,15 +93,15 @@ namespace ams::mitm::sysupdater {
|
||||
/* We don't implement the RequestServer::ManagedStop details, as we don't implement stoppable request list. */
|
||||
class AsyncPrepareSdCardUpdateImpl : public AsyncResultBase, private ErrorContextHolder {
|
||||
private:
|
||||
Result result;
|
||||
os::SystemEvent event;
|
||||
util::optional<ThreadInfo> thread_info;
|
||||
ncm::InstallTaskBase *task;
|
||||
Result m_result;
|
||||
os::SystemEvent m_event;
|
||||
util::optional<ThreadInfo> m_thread_info;
|
||||
ncm::InstallTaskBase *m_task;
|
||||
public:
|
||||
AsyncPrepareSdCardUpdateImpl(ncm::InstallTaskBase *task) : result(ResultSuccess()), event(os::EventClearMode_ManualClear, true), thread_info(), task(task) { /* ... */ }
|
||||
AsyncPrepareSdCardUpdateImpl(ncm::InstallTaskBase *task) : m_result(ResultSuccess()), m_event(os::EventClearMode_ManualClear, true), m_thread_info(), m_task(task) { /* ... */ }
|
||||
virtual ~AsyncPrepareSdCardUpdateImpl();
|
||||
|
||||
os::SystemEvent &GetEvent() { return this->event; }
|
||||
os::SystemEvent &GetEvent() { return m_event; }
|
||||
|
||||
virtual Result GetErrorContext(sf::Out<err::ErrorContext> out) override {
|
||||
*out = ErrorContextHolder::GetErrorContextImpl();
|
||||
@@ -113,7 +113,7 @@ namespace ams::mitm::sysupdater {
|
||||
Result Execute();
|
||||
|
||||
virtual void CancelImpl() override;
|
||||
virtual Result GetImpl() override { return this->result; }
|
||||
virtual Result GetImpl() override { return m_result; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -211,16 +211,16 @@ namespace ams::mitm::sysupdater {
|
||||
}
|
||||
|
||||
bool PathView::HasPrefix(util::string_view prefix) const {
|
||||
return this->path.compare(0, prefix.length(), prefix) == 0;
|
||||
return m_path.compare(0, prefix.length(), prefix) == 0;
|
||||
}
|
||||
|
||||
bool PathView::HasSuffix(util::string_view suffix) const {
|
||||
return this->path.compare(this->path.length() - suffix.length(), suffix.length(), suffix) == 0;
|
||||
return m_path.compare(m_path.length() - suffix.length(), suffix.length(), suffix) == 0;
|
||||
}
|
||||
|
||||
util::string_view PathView::GetFileName() const {
|
||||
auto pos = this->path.find_last_of("/");
|
||||
return pos != util::string_view::npos ? this->path.substr(pos + 1) : this->path;
|
||||
auto pos = m_path.find_last_of("/");
|
||||
return pos != util::string_view::npos ? m_path.substr(pos + 1) : m_path;
|
||||
}
|
||||
|
||||
Result MountSdCardContentMeta(const char *mount_name, const char *path) {
|
||||
|
||||
@@ -20,9 +20,9 @@ namespace ams::mitm::sysupdater {
|
||||
|
||||
class PathView {
|
||||
private:
|
||||
util::string_view path;
|
||||
util::string_view m_path;
|
||||
public:
|
||||
PathView(util::string_view p) : path(p) { /* ...*/ }
|
||||
PathView(util::string_view p) : m_path(p) { /* ...*/ }
|
||||
bool HasPrefix(util::string_view prefix) const;
|
||||
bool HasSuffix(util::string_view suffix) const;
|
||||
util::string_view GetFileName() const;
|
||||
|
||||
@@ -420,18 +420,18 @@ namespace ams::mitm::sysupdater {
|
||||
|
||||
Result SystemUpdateService::RequestPrepareUpdate(sf::OutCopyHandle out_event_handle, sf::Out<sf::SharedPointer<ns::impl::IAsyncResult>> out_async) {
|
||||
/* Ensure the update is setup but not prepared. */
|
||||
R_UNLESS(this->setup_update, ns::ResultCardUpdateNotSetup());
|
||||
R_UNLESS(!this->requested_update, ns::ResultPrepareCardUpdateAlreadyRequested());
|
||||
R_UNLESS(m_setup_update, ns::ResultCardUpdateNotSetup());
|
||||
R_UNLESS(!m_requested_update, ns::ResultPrepareCardUpdateAlreadyRequested());
|
||||
|
||||
/* Create the async result. */
|
||||
auto async_result = sf::CreateSharedObjectEmplaced<ns::impl::IAsyncResult, AsyncPrepareSdCardUpdateImpl>(std::addressof(*this->update_task));
|
||||
auto async_result = sf::CreateSharedObjectEmplaced<ns::impl::IAsyncResult, AsyncPrepareSdCardUpdateImpl>(std::addressof(*m_update_task));
|
||||
R_UNLESS(async_result != nullptr, ns::ResultOutOfMaxRunningTask());
|
||||
|
||||
/* Run the task. */
|
||||
R_TRY(async_result.GetImpl().Run());
|
||||
|
||||
/* We prepared the task! */
|
||||
this->requested_update = true;
|
||||
m_requested_update = true;
|
||||
out_event_handle.SetValue(async_result.GetImpl().GetEvent().GetReadableHandle(), false);
|
||||
*out_async = std::move(async_result);
|
||||
|
||||
@@ -440,38 +440,38 @@ namespace ams::mitm::sysupdater {
|
||||
|
||||
Result SystemUpdateService::GetPrepareUpdateProgress(sf::Out<SystemUpdateProgress> out) {
|
||||
/* Ensure the update is setup. */
|
||||
R_UNLESS(this->setup_update, ns::ResultCardUpdateNotSetup());
|
||||
R_UNLESS(m_setup_update, ns::ResultCardUpdateNotSetup());
|
||||
|
||||
/* Get the progress. */
|
||||
auto install_progress = this->update_task->GetProgress();
|
||||
auto install_progress = m_update_task->GetProgress();
|
||||
out.SetValue({ .current_size = install_progress.installed_size, .total_size = install_progress.total_size });
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result SystemUpdateService::HasPreparedUpdate(sf::Out<bool> out) {
|
||||
/* Ensure the update is setup. */
|
||||
R_UNLESS(this->setup_update, ns::ResultCardUpdateNotSetup());
|
||||
R_UNLESS(m_setup_update, ns::ResultCardUpdateNotSetup());
|
||||
|
||||
out.SetValue(this->update_task->GetProgress().state == ncm::InstallProgressState::Downloaded);
|
||||
out.SetValue(m_update_task->GetProgress().state == ncm::InstallProgressState::Downloaded);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result SystemUpdateService::ApplyPreparedUpdate() {
|
||||
/* Ensure the update is setup. */
|
||||
R_UNLESS(this->setup_update, ns::ResultCardUpdateNotSetup());
|
||||
R_UNLESS(m_setup_update, ns::ResultCardUpdateNotSetup());
|
||||
|
||||
/* Ensure the update is prepared. */
|
||||
R_UNLESS(this->update_task->GetProgress().state == ncm::InstallProgressState::Downloaded, ns::ResultCardUpdateNotPrepared());
|
||||
R_UNLESS(m_update_task->GetProgress().state == ncm::InstallProgressState::Downloaded, ns::ResultCardUpdateNotPrepared());
|
||||
|
||||
/* Apply the task. */
|
||||
R_TRY(this->apply_manager.ApplyPackageTask(std::addressof(*this->update_task)));
|
||||
R_TRY(m_apply_manager.ApplyPackageTask(std::addressof(*m_update_task)));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result SystemUpdateService::SetupUpdateImpl(sf::NativeHandle &&transfer_memory, u64 transfer_memory_size, const ncm::Path &path, bool exfat, ncm::FirmwareVariationId firmware_variation_id) {
|
||||
/* Ensure we don't already have an update set up. */
|
||||
R_UNLESS(!this->setup_update, ns::ResultCardUpdateAlreadySetup());
|
||||
R_UNLESS(!m_setup_update, ns::ResultCardUpdateAlreadySetup());
|
||||
|
||||
/* Destroy any existing update tasks. */
|
||||
nim::SystemUpdateTaskId id;
|
||||
@@ -484,21 +484,21 @@ namespace ams::mitm::sysupdater {
|
||||
R_TRY(InitializeUpdateTask(std::move(transfer_memory), transfer_memory_size, path, exfat, firmware_variation_id));
|
||||
|
||||
/* The update is now set up. */
|
||||
this->setup_update = true;
|
||||
m_setup_update = true;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result SystemUpdateService::InitializeUpdateTask(sf::NativeHandle &&transfer_memory, u64 transfer_memory_size, const ncm::Path &path, bool exfat, ncm::FirmwareVariationId firmware_variation_id) {
|
||||
/* Map the transfer memory. */
|
||||
const size_t tmem_buffer_size = static_cast<size_t>(transfer_memory_size);
|
||||
this->update_transfer_memory.emplace(tmem_buffer_size, transfer_memory.GetOsHandle(), transfer_memory.IsManaged());
|
||||
m_update_transfer_memory.emplace(tmem_buffer_size, transfer_memory.GetOsHandle(), transfer_memory.IsManaged());
|
||||
transfer_memory.Detach();
|
||||
|
||||
void *tmem_buffer;
|
||||
R_TRY(this->update_transfer_memory->Map(std::addressof(tmem_buffer), os::MemoryPermission_None));
|
||||
R_TRY(m_update_transfer_memory->Map(std::addressof(tmem_buffer), os::MemoryPermission_None));
|
||||
auto tmem_guard = SCOPE_GUARD {
|
||||
this->update_transfer_memory->Unmap();
|
||||
this->update_transfer_memory = util::nullopt;
|
||||
m_update_transfer_memory->Unmap();
|
||||
m_update_transfer_memory = util::nullopt;
|
||||
};
|
||||
|
||||
/* Adjust the package root. */
|
||||
@@ -510,8 +510,8 @@ namespace ams::mitm::sysupdater {
|
||||
const char *context_path = "@Sdcard:/atmosphere/update/cup.ctx";
|
||||
|
||||
/* Create and initialize the update task. */
|
||||
this->update_task.emplace();
|
||||
R_TRY(this->update_task->Initialize(package_root.str, context_path, tmem_buffer, tmem_buffer_size, exfat, firmware_variation_id));
|
||||
m_update_task.emplace();
|
||||
R_TRY(m_update_task->Initialize(package_root.str, context_path, tmem_buffer, tmem_buffer_size, exfat, firmware_variation_id));
|
||||
|
||||
/* We successfully setup the update. */
|
||||
tmem_guard.Cancel();
|
||||
|
||||
@@ -56,13 +56,13 @@ namespace ams::mitm::sysupdater {
|
||||
|
||||
class SystemUpdateService {
|
||||
private:
|
||||
SystemUpdateApplyManager apply_manager;
|
||||
util::optional<ncm::PackageSystemDowngradeTask> update_task;
|
||||
util::optional<os::TransferMemory> update_transfer_memory;
|
||||
bool setup_update;
|
||||
bool requested_update;
|
||||
SystemUpdateApplyManager m_apply_manager;
|
||||
util::optional<ncm::PackageSystemDowngradeTask> m_update_task;
|
||||
util::optional<os::TransferMemory> m_update_transfer_memory;
|
||||
bool m_setup_update;
|
||||
bool m_requested_update;
|
||||
public:
|
||||
constexpr SystemUpdateService() : apply_manager(), update_task(), update_transfer_memory(), setup_update(false), requested_update(false) { /* ... */ }
|
||||
constexpr SystemUpdateService() : m_apply_manager(), m_update_task(), m_update_transfer_memory(), m_setup_update(false), m_requested_update(false) { /* ... */ }
|
||||
private:
|
||||
Result SetupUpdateImpl(sf::NativeHandle &&transfer_memory, u64 transfer_memory_size, const ncm::Path &path, bool exfat, ncm::FirmwareVariationId firmware_variation_id);
|
||||
Result InitializeUpdateTask(sf::NativeHandle &&transfer_memory, u64 transfer_memory_size, const ncm::Path &path, bool exfat, ncm::FirmwareVariationId firmware_variation_id);
|
||||
|
||||
@@ -19,18 +19,18 @@
|
||||
namespace ams::mitm::sysupdater {
|
||||
|
||||
Result ThreadAllocator::Allocate(ThreadInfo *out) {
|
||||
std::scoped_lock lk(this->mutex);
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
for (int i = 0; i < this->thread_count; ++i) {
|
||||
for (int i = 0; i < m_thread_count; ++i) {
|
||||
const u64 mask = (static_cast<u64>(1) << i);
|
||||
if ((this->bitmap & mask) == 0) {
|
||||
if ((m_bitmap & mask) == 0) {
|
||||
*out = {
|
||||
.thread = this->thread_list + i,
|
||||
.priority = this->thread_priority,
|
||||
.stack = this->stack_heap + (this->stack_size * i),
|
||||
.stack_size = this->stack_size,
|
||||
.thread = m_thread_list + i,
|
||||
.priority = m_thread_priority,
|
||||
.stack = m_stack_heap + (m_stack_size * i),
|
||||
.stack_size = m_stack_size,
|
||||
};
|
||||
this->bitmap |= mask;
|
||||
m_bitmap |= mask;
|
||||
return ResultSuccess();
|
||||
}
|
||||
}
|
||||
@@ -39,12 +39,12 @@ namespace ams::mitm::sysupdater {
|
||||
}
|
||||
|
||||
void ThreadAllocator::Free(const ThreadInfo &info) {
|
||||
std::scoped_lock lk(this->mutex);
|
||||
std::scoped_lock lk(m_mutex);
|
||||
|
||||
for (int i = 0; i < this->thread_count; ++i) {
|
||||
if (info.thread == std::addressof(this->thread_list[i])) {
|
||||
for (int i = 0; i < m_thread_count; ++i) {
|
||||
if (info.thread == std::addressof(m_thread_list[i])) {
|
||||
const u64 mask = (static_cast<u64>(1) << i);
|
||||
this->bitmap &= ~mask;
|
||||
m_bitmap &= ~mask;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,20 +28,20 @@ namespace ams::mitm::sysupdater {
|
||||
/* NOTE: Nintendo uses a util::BitArray, but this seems excessive. */
|
||||
class ThreadAllocator {
|
||||
private:
|
||||
os::ThreadType *thread_list;
|
||||
const int thread_priority;
|
||||
const int thread_count;
|
||||
u8 *stack_heap;
|
||||
const size_t stack_heap_size;
|
||||
const size_t stack_size;
|
||||
u64 bitmap;
|
||||
os::SdkMutex mutex;
|
||||
os::ThreadType *m_thread_list;
|
||||
const int m_thread_priority;
|
||||
const int m_thread_count;
|
||||
u8 *m_stack_heap;
|
||||
const size_t m_stack_heap_size;
|
||||
const size_t m_stack_size;
|
||||
u64 m_bitmap;
|
||||
os::SdkMutex m_mutex;
|
||||
public:
|
||||
constexpr ThreadAllocator(os::ThreadType *thread_list, int count, int priority, u8 *stack_heap, size_t stack_heap_size, size_t stack_size)
|
||||
: thread_list(thread_list), thread_priority(priority), thread_count(count), stack_heap(stack_heap), stack_heap_size(stack_heap_size), stack_size(stack_size), bitmap()
|
||||
: m_thread_list(thread_list), m_thread_priority(priority), m_thread_count(count), m_stack_heap(stack_heap), m_stack_heap_size(stack_heap_size), m_stack_size(stack_size), m_bitmap()
|
||||
{
|
||||
AMS_ASSERT(count <= static_cast<int>(stack_heap_size / stack_size));
|
||||
AMS_ASSERT(count <= static_cast<int>(BITSIZEOF(this->bitmap)));
|
||||
AMS_ASSERT(count <= static_cast<int>(BITSIZEOF(m_bitmap)));
|
||||
}
|
||||
|
||||
Result Allocate(ThreadInfo *out);
|
||||
|
||||
@@ -20,54 +20,54 @@ namespace ams::boot {
|
||||
|
||||
class BatteryDriver {
|
||||
private:
|
||||
powctl::Session battery_session;
|
||||
powctl::Session m_battery_session;
|
||||
public:
|
||||
BatteryDriver() : battery_session() {
|
||||
R_ABORT_UNLESS(powctl::OpenSession(std::addressof(this->battery_session), powctl::DeviceCode_Max17050, ddsf::AccessMode_ReadWrite));
|
||||
BatteryDriver() : m_battery_session() {
|
||||
R_ABORT_UNLESS(powctl::OpenSession(std::addressof(m_battery_session), powctl::DeviceCode_Max17050, ddsf::AccessMode_ReadWrite));
|
||||
}
|
||||
|
||||
~BatteryDriver() {
|
||||
powctl::CloseSession(this->battery_session);
|
||||
powctl::CloseSession(m_battery_session);
|
||||
}
|
||||
public:
|
||||
Result IsBatteryRemoved(bool *out) {
|
||||
bool present;
|
||||
R_TRY(powctl::IsBatteryPresent(std::addressof(present), this->battery_session));
|
||||
R_TRY(powctl::IsBatteryPresent(std::addressof(present), m_battery_session));
|
||||
|
||||
*out = !present;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetSocRep(float *out) {
|
||||
return powctl::GetBatterySocRep(out, this->battery_session);
|
||||
return powctl::GetBatterySocRep(out, m_battery_session);
|
||||
}
|
||||
|
||||
Result GetAverageVCell(int *out) {
|
||||
return powctl::GetBatteryAverageVCell(out, this->battery_session);
|
||||
return powctl::GetBatteryAverageVCell(out, m_battery_session);
|
||||
}
|
||||
|
||||
Result GetOpenCircuitVoltage(int *out) {
|
||||
return powctl::GetBatteryOpenCircuitVoltage(out, this->battery_session);
|
||||
return powctl::GetBatteryOpenCircuitVoltage(out, m_battery_session);
|
||||
}
|
||||
|
||||
Result GetAverageCurrent(int *out) {
|
||||
return powctl::GetBatteryAverageCurrent(out, this->battery_session);
|
||||
return powctl::GetBatteryAverageCurrent(out, m_battery_session);
|
||||
}
|
||||
|
||||
Result GetCurrent(int *out) {
|
||||
return powctl::GetBatteryCurrent(out, this->battery_session);
|
||||
return powctl::GetBatteryCurrent(out, m_battery_session);
|
||||
}
|
||||
|
||||
Result GetTemperature(float *out) {
|
||||
return powctl::GetBatteryTemperature(out, this->battery_session);
|
||||
return powctl::GetBatteryTemperature(out, m_battery_session);
|
||||
}
|
||||
|
||||
Result IsI2cShutdownEnabled(bool *out) {
|
||||
return powctl::IsBatteryI2cShutdownEnabled(out, this->battery_session);
|
||||
return powctl::IsBatteryI2cShutdownEnabled(out, m_battery_session);
|
||||
}
|
||||
|
||||
Result SetI2cShutdownEnabled(bool en) {
|
||||
return powctl::SetBatteryI2cShutdownEnabled(this->battery_session, en);
|
||||
return powctl::SetBatteryI2cShutdownEnabled(m_battery_session, en);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -27,14 +27,14 @@ namespace ams::boot {
|
||||
|
||||
class ChargerDriver {
|
||||
private:
|
||||
powctl::Session charger_session;
|
||||
powctl::Session m_charger_session;
|
||||
public:
|
||||
ChargerDriver() : charger_session() {
|
||||
R_ABORT_UNLESS(powctl::OpenSession(std::addressof(this->charger_session), powctl::DeviceCode_Bq24193, ddsf::AccessMode_ReadWrite));
|
||||
ChargerDriver() : m_charger_session() {
|
||||
R_ABORT_UNLESS(powctl::OpenSession(std::addressof(m_charger_session), powctl::DeviceCode_Bq24193, ddsf::AccessMode_ReadWrite));
|
||||
}
|
||||
|
||||
~ChargerDriver() {
|
||||
powctl::CloseSession(this->charger_session);
|
||||
powctl::CloseSession(m_charger_session);
|
||||
}
|
||||
|
||||
Result Initialize(bool set_input_current_limit) {
|
||||
@@ -46,51 +46,51 @@ namespace ams::boot {
|
||||
|
||||
/* Set input current limit to 500 ma. */
|
||||
if (set_input_current_limit) {
|
||||
R_TRY(powctl::SetChargerInputCurrentLimit(this->charger_session, 500));
|
||||
R_TRY(powctl::SetChargerInputCurrentLimit(m_charger_session, 500));
|
||||
}
|
||||
|
||||
/* Set input voltage limit to 500 mv. */
|
||||
R_TRY(powctl::SetChargerInputVoltageLimit(this->charger_session, 500));
|
||||
R_TRY(powctl::SetChargerInputVoltageLimit(m_charger_session, 500));
|
||||
|
||||
/* Disable hi-z mode. */
|
||||
R_TRY(powctl::SetChargerHiZEnabled(this->charger_session, false));
|
||||
R_TRY(powctl::SetChargerHiZEnabled(m_charger_session, false));
|
||||
|
||||
/* Set configuration to charge battery. */
|
||||
R_TRY(powctl::SetChargerChargerConfiguration(this->charger_session, powctl::ChargerConfiguration_ChargeBattery));
|
||||
R_TRY(powctl::SetChargerChargerConfiguration(m_charger_session, powctl::ChargerConfiguration_ChargeBattery));
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetChargeCurrentState(powctl::ChargeCurrentState *out) {
|
||||
return powctl::GetChargerChargeCurrentState(out, this->charger_session);
|
||||
return powctl::GetChargerChargeCurrentState(out, m_charger_session);
|
||||
}
|
||||
|
||||
Result SetChargeCurrentState(powctl::ChargeCurrentState state) {
|
||||
return powctl::SetChargerChargeCurrentState(this->charger_session, state);
|
||||
return powctl::SetChargerChargeCurrentState(m_charger_session, state);
|
||||
}
|
||||
|
||||
Result GetInputCurrentLimit(int *out) {
|
||||
return powctl::GetChargerInputCurrentLimit(out, this->charger_session);
|
||||
return powctl::GetChargerInputCurrentLimit(out, m_charger_session);
|
||||
}
|
||||
|
||||
Result SetChargerConfiguration(powctl::ChargerConfiguration cfg) {
|
||||
return powctl::SetChargerChargerConfiguration(this->charger_session, cfg);
|
||||
return powctl::SetChargerChargerConfiguration(m_charger_session, cfg);
|
||||
}
|
||||
|
||||
Result GetFastChargeCurrentLimit(int *out) {
|
||||
return powctl::GetChargerFastChargeCurrentLimit(out, this->charger_session);
|
||||
return powctl::GetChargerFastChargeCurrentLimit(out, m_charger_session);
|
||||
}
|
||||
|
||||
Result SetFastChargeCurrentLimit(int limit) {
|
||||
return powctl::SetChargerFastChargeCurrentLimit(this->charger_session, limit);
|
||||
return powctl::SetChargerFastChargeCurrentLimit(m_charger_session, limit);
|
||||
}
|
||||
|
||||
Result GetChargeVoltageLimit(int *out) {
|
||||
return powctl::GetChargerChargeVoltageLimit(out, this->charger_session);
|
||||
return powctl::GetChargerChargeVoltageLimit(out, m_charger_session);
|
||||
}
|
||||
|
||||
Result SetChargeVoltageLimit(int limit) {
|
||||
return powctl::SetChargerChargeVoltageLimit(this->charger_session, limit);
|
||||
return powctl::SetChargerChargeVoltageLimit(m_charger_session, limit);
|
||||
}
|
||||
|
||||
Result GetChargerStatus(boot::ChargerStatus *out) {
|
||||
@@ -99,7 +99,7 @@ namespace ams::boot {
|
||||
|
||||
/* Get the powctl status. */
|
||||
powctl::ChargerStatus powctl_status;
|
||||
R_TRY(powctl::GetChargerChargerStatus(std::addressof(powctl_status), this->charger_session));
|
||||
R_TRY(powctl::GetChargerChargerStatus(std::addressof(powctl_status), m_charger_session));
|
||||
|
||||
switch (powctl_status) {
|
||||
case powctl::ChargerStatus_Charging: *out = boot::ChargerStatus_Charging; break;
|
||||
@@ -111,19 +111,19 @@ namespace ams::boot {
|
||||
}
|
||||
|
||||
Result GetBatteryCompensation(int *out) {
|
||||
return powctl::GetChargerBatteryCompensation(out, this->charger_session);
|
||||
return powctl::GetChargerBatteryCompensation(out, m_charger_session);
|
||||
}
|
||||
|
||||
Result SetBatteryCompensation(int v) {
|
||||
return powctl::SetChargerBatteryCompensation(this->charger_session, v);
|
||||
return powctl::SetChargerBatteryCompensation(m_charger_session, v);
|
||||
}
|
||||
|
||||
Result GetVoltageClamp(int *out) {
|
||||
return powctl::GetChargerVoltageClamp(out, this->charger_session);
|
||||
return powctl::GetChargerVoltageClamp(out, m_charger_session);
|
||||
}
|
||||
|
||||
Result SetVoltageClamp(int v) {
|
||||
return powctl::SetChargerVoltageClamp(this->charger_session, v);
|
||||
return powctl::SetChargerVoltageClamp(m_charger_session, v);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -42,18 +42,18 @@ namespace ams::boot {
|
||||
|
||||
class BatteryChecker {
|
||||
private:
|
||||
boot::ChargerDriver &charger_driver;
|
||||
boot::BatteryDriver &battery_driver;
|
||||
const powctl::driver::impl::ChargeParameters &charge_parameters;
|
||||
powctl::driver::impl::ChargeArbiter charge_arbiter;
|
||||
powctl::ChargeCurrentState charge_current_state;
|
||||
int fast_charge_current_limit;
|
||||
int charge_voltage_limit;
|
||||
int battery_compensation;
|
||||
int voltage_clamp;
|
||||
TimeSpan charging_done_interval;
|
||||
bool has_start_time;
|
||||
TimeSpan start_time;
|
||||
boot::ChargerDriver &m_charger_driver;
|
||||
boot::BatteryDriver &m_battery_driver;
|
||||
const powctl::driver::impl::ChargeParameters &m_charge_parameters;
|
||||
powctl::driver::impl::ChargeArbiter m_charge_arbiter;
|
||||
powctl::ChargeCurrentState m_charge_current_state;
|
||||
int m_fast_charge_current_limit;
|
||||
int m_charge_voltage_limit;
|
||||
int m_battery_compensation;
|
||||
int m_voltage_clamp;
|
||||
TimeSpan m_charging_done_interval;
|
||||
bool m_has_start_time;
|
||||
TimeSpan m_start_time;
|
||||
private:
|
||||
bool IsChargeDone();
|
||||
void UpdateChargeDoneCurrent();
|
||||
@@ -63,25 +63,25 @@ namespace ams::boot {
|
||||
|
||||
void UpdateStartTime() {
|
||||
/* Update start time. */
|
||||
this->start_time = os::ConvertToTimeSpan(os::GetSystemTick());
|
||||
this->has_start_time = true;
|
||||
m_start_time = os::ConvertToTimeSpan(os::GetSystemTick());
|
||||
m_has_start_time = true;
|
||||
}
|
||||
public:
|
||||
BatteryChecker(boot::ChargerDriver &cd, boot::BatteryDriver &bd, const powctl::driver::impl::ChargeParameters &cp, int cvl) : charger_driver(cd), battery_driver(bd), charge_parameters(cp), charge_arbiter(cp.rules, cp.num_rules, cvl), charging_done_interval(TimeSpan::FromSeconds(2)), has_start_time(false) {
|
||||
BatteryChecker(boot::ChargerDriver &cd, boot::BatteryDriver &bd, const powctl::driver::impl::ChargeParameters &cp, int cvl) : m_charger_driver(cd), m_battery_driver(bd), m_charge_parameters(cp), m_charge_arbiter(cp.rules, cp.num_rules, cvl), m_charging_done_interval(TimeSpan::FromSeconds(2)), m_has_start_time(false) {
|
||||
/* Get parameters from charger. */
|
||||
if (R_FAILED(this->charger_driver.GetChargeCurrentState(std::addressof(this->charge_current_state)))) {
|
||||
if (R_FAILED(m_charger_driver.GetChargeCurrentState(std::addressof(m_charge_current_state)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
if (R_FAILED(this->charger_driver.GetFastChargeCurrentLimit(std::addressof(this->fast_charge_current_limit)))) {
|
||||
if (R_FAILED(m_charger_driver.GetFastChargeCurrentLimit(std::addressof(m_fast_charge_current_limit)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
if (R_FAILED(this->charger_driver.GetChargeVoltageLimit(std::addressof(this->charge_voltage_limit)))) {
|
||||
if (R_FAILED(m_charger_driver.GetChargeVoltageLimit(std::addressof(m_charge_voltage_limit)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
if (R_FAILED(this->charger_driver.GetBatteryCompensation(std::addressof(this->battery_compensation)))) {
|
||||
if (R_FAILED(m_charger_driver.GetBatteryCompensation(std::addressof(m_battery_compensation)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
if (R_FAILED(this->charger_driver.GetVoltageClamp(std::addressof(this->voltage_clamp)))) {
|
||||
if (R_FAILED(m_charger_driver.GetVoltageClamp(std::addressof(m_voltage_clamp)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
|
||||
@@ -112,16 +112,16 @@ namespace ams::boot {
|
||||
/* Get various battery metrics. */
|
||||
int avg_current, current, open_circuit_voltage;
|
||||
float temp;
|
||||
if (R_FAILED(this->battery_driver.GetAverageCurrent(std::addressof(avg_current)))) {
|
||||
if (R_FAILED(m_battery_driver.GetAverageCurrent(std::addressof(avg_current)))) {
|
||||
return;
|
||||
}
|
||||
if (R_FAILED(this->battery_driver.GetCurrent(std::addressof(current)))) {
|
||||
if (R_FAILED(m_battery_driver.GetCurrent(std::addressof(current)))) {
|
||||
return;
|
||||
}
|
||||
if (R_FAILED(this->battery_driver.GetTemperature(std::addressof(temp)))) {
|
||||
if (R_FAILED(m_battery_driver.GetTemperature(std::addressof(temp)))) {
|
||||
return;
|
||||
}
|
||||
if (R_FAILED(this->battery_driver.GetOpenCircuitVoltage(std::addressof(open_circuit_voltage)))) {
|
||||
if (R_FAILED(m_battery_driver.GetOpenCircuitVoltage(std::addressof(open_circuit_voltage)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ namespace ams::boot {
|
||||
bool BatteryChecker::IsChargeDone() {
|
||||
/* Get the charger status. */
|
||||
boot::ChargerStatus charger_status;
|
||||
if (R_FAILED(this->charger_driver.GetChargerStatus(std::addressof(charger_status)))) {
|
||||
if (R_FAILED(m_charger_driver.GetChargerStatus(std::addressof(charger_status)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
|
||||
@@ -142,20 +142,20 @@ namespace ams::boot {
|
||||
}
|
||||
|
||||
/* Return whether a done current of zero is acceptable. */
|
||||
return this->charge_arbiter.IsBatteryDoneCurrentAcceptable(0);
|
||||
return m_charge_arbiter.IsBatteryDoneCurrentAcceptable(0);
|
||||
}
|
||||
|
||||
void BatteryChecker::UpdateChargeDoneCurrent() {
|
||||
int done_current = 0;
|
||||
if (this->has_start_time && (os::ConvertToTimeSpan(os::GetSystemTick()) - this->start_time) >= this->charging_done_interval) {
|
||||
if (m_has_start_time && (os::ConvertToTimeSpan(os::GetSystemTick()) - m_start_time) >= m_charging_done_interval) {
|
||||
/* Get the current. */
|
||||
if (R_FAILED(this->battery_driver.GetCurrent(std::addressof(done_current)))) {
|
||||
if (R_FAILED(m_battery_driver.GetCurrent(std::addressof(done_current)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
} else {
|
||||
/* Get the charger status. */
|
||||
boot::ChargerStatus charger_status;
|
||||
if (R_FAILED(this->charger_driver.GetChargerStatus(std::addressof(charger_status)))) {
|
||||
if (R_FAILED(m_charger_driver.GetChargerStatus(std::addressof(charger_status)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
|
||||
@@ -166,50 +166,50 @@ namespace ams::boot {
|
||||
}
|
||||
|
||||
/* Update done current. */
|
||||
this->charge_arbiter.SetBatteryDoneCurrent(done_current);
|
||||
m_charge_arbiter.SetBatteryDoneCurrent(done_current);
|
||||
}
|
||||
|
||||
void BatteryChecker::UpdateCharger() {
|
||||
/* Get the battery temperature. */
|
||||
float temp;
|
||||
if (R_FAILED(this->battery_driver.GetTemperature(std::addressof(temp)))) {
|
||||
if (R_FAILED(m_battery_driver.GetTemperature(std::addressof(temp)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
|
||||
/* Update the temperature level. */
|
||||
powctl::BatteryTemperatureLevel temp_level;
|
||||
if (temp < static_cast<float>(this->charge_parameters.temp_min)) {
|
||||
if (temp < static_cast<float>(m_charge_parameters.temp_min)) {
|
||||
temp_level = powctl::BatteryTemperatureLevel::TooLow;
|
||||
} else if (temp < static_cast<float>(this->charge_parameters.temp_low)) {
|
||||
} else if (temp < static_cast<float>(m_charge_parameters.temp_low)) {
|
||||
temp_level = powctl::BatteryTemperatureLevel::Low;
|
||||
} else if (temp < static_cast<float>(this->charge_parameters.temp_high)) {
|
||||
} else if (temp < static_cast<float>(m_charge_parameters.temp_high)) {
|
||||
temp_level = powctl::BatteryTemperatureLevel::Medium;
|
||||
} else if (temp < static_cast<float>(this->charge_parameters.temp_max)) {
|
||||
} else if (temp < static_cast<float>(m_charge_parameters.temp_max)) {
|
||||
temp_level = powctl::BatteryTemperatureLevel::High;
|
||||
} else {
|
||||
temp_level = powctl::BatteryTemperatureLevel::TooHigh;
|
||||
}
|
||||
this->charge_arbiter.SetBatteryTemperatureLevel(temp_level);
|
||||
m_charge_arbiter.SetBatteryTemperatureLevel(temp_level);
|
||||
|
||||
/* Update average voltage. */
|
||||
int avg_v_cell;
|
||||
if (R_FAILED(this->battery_driver.GetAverageVCell(std::addressof(avg_v_cell)))) {
|
||||
if (R_FAILED(m_battery_driver.GetAverageVCell(std::addressof(avg_v_cell)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
this->charge_arbiter.SetBatteryAverageVCell(avg_v_cell);
|
||||
m_charge_arbiter.SetBatteryAverageVCell(avg_v_cell);
|
||||
|
||||
/* Update open circuit voltage. */
|
||||
int ocv;
|
||||
if (R_FAILED(this->battery_driver.GetOpenCircuitVoltage(std::addressof(ocv)))) {
|
||||
if (R_FAILED(m_battery_driver.GetOpenCircuitVoltage(std::addressof(ocv)))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
this->charge_arbiter.SetBatteryOpenCircuitVoltage(ocv);
|
||||
m_charge_arbiter.SetBatteryOpenCircuitVoltage(ocv);
|
||||
|
||||
/* Update charge done current. */
|
||||
this->UpdateChargeDoneCurrent();
|
||||
|
||||
/* Update arbiter power state. */
|
||||
this->charge_arbiter.SetPowerState(powctl::PowerState::ShutdownChargeMain);
|
||||
m_charge_arbiter.SetPowerState(powctl::PowerState::ShutdownChargeMain);
|
||||
|
||||
/* Apply the newly selected rule. */
|
||||
this->ApplyArbiterRule();
|
||||
@@ -217,19 +217,19 @@ namespace ams::boot {
|
||||
|
||||
void BatteryChecker::ApplyArbiterRule() {
|
||||
/* Get the selected rule. */
|
||||
const auto *rule = this->charge_arbiter.GetSelectedRule();
|
||||
const auto *rule = m_charge_arbiter.GetSelectedRule();
|
||||
AMS_ASSERT(rule != nullptr);
|
||||
|
||||
/* Check if we need to perform charger initialization. */
|
||||
const bool reinit_charger = rule->reinitialize_charger;
|
||||
const auto cur_charge_current_state = this->charge_current_state;
|
||||
const auto cur_charge_current_state = m_charge_current_state;
|
||||
|
||||
/* Set the charger to not charging while we make changes. */
|
||||
if (!reinit_charger || cur_charge_current_state != powctl::ChargeCurrentState_NotCharging) {
|
||||
if (R_FAILED(this->charger_driver.SetChargeCurrentState(powctl::ChargeCurrentState_NotCharging))) {
|
||||
if (R_FAILED(m_charger_driver.SetChargeCurrentState(powctl::ChargeCurrentState_NotCharging))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
this->charge_current_state = powctl::ChargeCurrentState_NotCharging;
|
||||
m_charge_current_state = powctl::ChargeCurrentState_NotCharging;
|
||||
|
||||
/* Update start time. */
|
||||
this->UpdateStartTime();
|
||||
@@ -237,25 +237,25 @@ namespace ams::boot {
|
||||
|
||||
/* Process fast charge current limit when rule is smaller. */
|
||||
const auto rule_fast_charge_current_limit = rule->fast_charge_current_limit;
|
||||
const auto cur_fast_charge_current_limit = this->fast_charge_current_limit;
|
||||
const auto cur_fast_charge_current_limit = m_fast_charge_current_limit;
|
||||
if (rule_fast_charge_current_limit < cur_fast_charge_current_limit) {
|
||||
if (R_FAILED(this->charger_driver.SetFastChargeCurrentLimit(rule_fast_charge_current_limit))) {
|
||||
if (R_FAILED(m_charger_driver.SetFastChargeCurrentLimit(rule_fast_charge_current_limit))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
this->fast_charge_current_limit = rule_fast_charge_current_limit;
|
||||
m_fast_charge_current_limit = rule_fast_charge_current_limit;
|
||||
|
||||
/* Update start time. */
|
||||
this->UpdateStartTime();
|
||||
}
|
||||
|
||||
/* Process charge voltage limit when rule is smaller. */
|
||||
const auto rule_charge_voltage_limit = std::min(rule->charge_voltage_limit, this->charge_arbiter.GetChargeVoltageLimit());
|
||||
const auto cur_charge_voltage_limit = this->charge_voltage_limit;
|
||||
const auto rule_charge_voltage_limit = std::min(rule->charge_voltage_limit, m_charge_arbiter.GetChargeVoltageLimit());
|
||||
const auto cur_charge_voltage_limit = m_charge_voltage_limit;
|
||||
if (rule_charge_voltage_limit < cur_charge_voltage_limit) {
|
||||
if (R_FAILED(this->charger_driver.SetChargeVoltageLimit(rule_charge_voltage_limit))) {
|
||||
if (R_FAILED(m_charger_driver.SetChargeVoltageLimit(rule_charge_voltage_limit))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
this->charge_voltage_limit = rule_charge_voltage_limit;
|
||||
m_charge_voltage_limit = rule_charge_voltage_limit;
|
||||
|
||||
/* Update start time. */
|
||||
this->UpdateStartTime();
|
||||
@@ -263,12 +263,12 @@ namespace ams::boot {
|
||||
|
||||
/* Process battery compensation when rule is smaller. */
|
||||
const auto rule_battery_compensation = rule->battery_compensation;
|
||||
const auto cur_battery_compensation = this->battery_compensation;
|
||||
const auto cur_battery_compensation = m_battery_compensation;
|
||||
if (rule_battery_compensation < cur_battery_compensation) {
|
||||
if (R_FAILED(this->charger_driver.SetBatteryCompensation(rule_battery_compensation))) {
|
||||
if (R_FAILED(m_charger_driver.SetBatteryCompensation(rule_battery_compensation))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
this->battery_compensation = rule_battery_compensation;
|
||||
m_battery_compensation = rule_battery_compensation;
|
||||
|
||||
/* Update start time. */
|
||||
this->UpdateStartTime();
|
||||
@@ -276,12 +276,12 @@ namespace ams::boot {
|
||||
|
||||
/* Process voltage clamp when rule is smaller. */
|
||||
const auto rule_voltage_clamp = rule->voltage_clamp;
|
||||
const auto cur_voltage_clamp = this->voltage_clamp;
|
||||
const auto cur_voltage_clamp = m_voltage_clamp;
|
||||
if (rule_voltage_clamp < cur_voltage_clamp) {
|
||||
if (R_FAILED(this->charger_driver.SetVoltageClamp(rule_voltage_clamp))) {
|
||||
if (R_FAILED(m_charger_driver.SetVoltageClamp(rule_voltage_clamp))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
this->voltage_clamp = rule_voltage_clamp;
|
||||
m_voltage_clamp = rule_voltage_clamp;
|
||||
|
||||
/* Update start time. */
|
||||
this->UpdateStartTime();
|
||||
@@ -289,10 +289,10 @@ namespace ams::boot {
|
||||
|
||||
/* Process voltage clamp when rule is larger. */
|
||||
if (rule_voltage_clamp > cur_voltage_clamp) {
|
||||
if (R_FAILED(this->charger_driver.SetVoltageClamp(rule_voltage_clamp))) {
|
||||
if (R_FAILED(m_charger_driver.SetVoltageClamp(rule_voltage_clamp))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
this->voltage_clamp = rule_voltage_clamp;
|
||||
m_voltage_clamp = rule_voltage_clamp;
|
||||
|
||||
/* Update start time. */
|
||||
this->UpdateStartTime();
|
||||
@@ -300,10 +300,10 @@ namespace ams::boot {
|
||||
|
||||
/* Process battery compensation when rule is larger. */
|
||||
if (rule_battery_compensation > cur_battery_compensation) {
|
||||
if (R_FAILED(this->charger_driver.SetBatteryCompensation(rule_battery_compensation))) {
|
||||
if (R_FAILED(m_charger_driver.SetBatteryCompensation(rule_battery_compensation))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
this->battery_compensation = rule_battery_compensation;
|
||||
m_battery_compensation = rule_battery_compensation;
|
||||
|
||||
/* Update start time. */
|
||||
this->UpdateStartTime();
|
||||
@@ -311,10 +311,10 @@ namespace ams::boot {
|
||||
|
||||
/* Process fast charge current limit when rule is larger. */
|
||||
if (rule_fast_charge_current_limit > cur_fast_charge_current_limit) {
|
||||
if (R_FAILED(this->charger_driver.SetFastChargeCurrentLimit(rule_fast_charge_current_limit))) {
|
||||
if (R_FAILED(m_charger_driver.SetFastChargeCurrentLimit(rule_fast_charge_current_limit))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
this->fast_charge_current_limit = rule_fast_charge_current_limit;
|
||||
m_fast_charge_current_limit = rule_fast_charge_current_limit;
|
||||
|
||||
/* Update start time. */
|
||||
this->UpdateStartTime();
|
||||
@@ -322,10 +322,10 @@ namespace ams::boot {
|
||||
|
||||
/* Process charge voltage limit when rule is larger. */
|
||||
if (rule_charge_voltage_limit > cur_charge_voltage_limit) {
|
||||
if (R_FAILED(this->charger_driver.SetChargeVoltageLimit(rule_charge_voltage_limit))) {
|
||||
if (R_FAILED(m_charger_driver.SetChargeVoltageLimit(rule_charge_voltage_limit))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
this->charge_voltage_limit = rule_charge_voltage_limit;
|
||||
m_charge_voltage_limit = rule_charge_voltage_limit;
|
||||
|
||||
/* Update start time. */
|
||||
this->UpdateStartTime();
|
||||
@@ -333,10 +333,10 @@ namespace ams::boot {
|
||||
|
||||
/* If we're not charging and we expect to reinitialize the charger, do so. */
|
||||
if (cur_charge_current_state != powctl::ChargeCurrentState_Charging && reinit_charger) {
|
||||
if (R_FAILED(this->charger_driver.SetChargeCurrentState(powctl::ChargeCurrentState_Charging))) {
|
||||
if (R_FAILED(m_charger_driver.SetChargeCurrentState(powctl::ChargeCurrentState_Charging))) {
|
||||
boot::ShutdownSystem();
|
||||
}
|
||||
this->charge_current_state = powctl::ChargeCurrentState_Charging;
|
||||
m_charge_current_state = powctl::ChargeCurrentState_Charging;
|
||||
|
||||
/* Update start time. */
|
||||
this->UpdateStartTime();
|
||||
@@ -357,7 +357,7 @@ namespace ams::boot {
|
||||
if (show_charging_display) {
|
||||
/* Get the raw battery charge. */
|
||||
float raw_battery_charge;
|
||||
if (R_FAILED(this->battery_driver.GetSocRep(std::addressof(raw_battery_charge)))) {
|
||||
if (R_FAILED(m_battery_driver.GetSocRep(std::addressof(raw_battery_charge)))) {
|
||||
return CheckBatteryResult::Shutdown;
|
||||
}
|
||||
|
||||
@@ -372,13 +372,13 @@ namespace ams::boot {
|
||||
while (true) {
|
||||
/* Get the raw battery charge. */
|
||||
float raw_battery_charge;
|
||||
if (R_FAILED(this->battery_driver.GetSocRep(std::addressof(raw_battery_charge)))) {
|
||||
if (R_FAILED(m_battery_driver.GetSocRep(std::addressof(raw_battery_charge)))) {
|
||||
return CheckBatteryResult::Shutdown;
|
||||
}
|
||||
|
||||
/* Get the average vcell. */
|
||||
int battery_voltage;
|
||||
if (R_FAILED(this->battery_driver.GetAverageVCell(std::addressof(battery_voltage)))) {
|
||||
if (R_FAILED(m_battery_driver.GetAverageVCell(std::addressof(battery_voltage)))) {
|
||||
return CheckBatteryResult::Shutdown;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,17 +36,17 @@ namespace ams::boot {
|
||||
|
||||
Result PmicDriver::GetOnOffIrq(u8 *out) {
|
||||
const u8 addr = 0x0B;
|
||||
return ReadI2cRegister(this->i2c_session, out, sizeof(*out), std::addressof(addr), sizeof(addr));
|
||||
return ReadI2cRegister(m_i2c_session, out, sizeof(*out), std::addressof(addr), sizeof(addr));
|
||||
}
|
||||
|
||||
Result PmicDriver::GetPowerStatus(u8 *out) {
|
||||
const u8 addr = 0x15;
|
||||
return ReadI2cRegister(this->i2c_session, out, sizeof(*out), std::addressof(addr), sizeof(addr));
|
||||
return ReadI2cRegister(m_i2c_session, out, sizeof(*out), std::addressof(addr), sizeof(addr));
|
||||
}
|
||||
|
||||
Result PmicDriver::GetNvErc(u8 *out) {
|
||||
const u8 addr = 0x0C;
|
||||
return ReadI2cRegister(this->i2c_session, out, sizeof(*out), std::addressof(addr), sizeof(addr));
|
||||
return ReadI2cRegister(m_i2c_session, out, sizeof(*out), std::addressof(addr), sizeof(addr));
|
||||
}
|
||||
|
||||
Result PmicDriver::GetPowerButtonPressed(bool *out) {
|
||||
@@ -62,17 +62,17 @@ namespace ams::boot {
|
||||
|
||||
/* Get value, set or clear software reset mask. */
|
||||
u8 on_off_2_val = 0;
|
||||
R_ABORT_UNLESS(ReadI2cRegister(this->i2c_session, std::addressof(on_off_2_val), sizeof(on_off_2_val), std::addressof(on_off_2_addr), sizeof(on_off_2_addr)));
|
||||
R_ABORT_UNLESS(ReadI2cRegister(m_i2c_session, std::addressof(on_off_2_val), sizeof(on_off_2_val), std::addressof(on_off_2_addr), sizeof(on_off_2_addr)));
|
||||
if (reboot) {
|
||||
on_off_2_val |= 0x80;
|
||||
} else {
|
||||
on_off_2_val &= ~0x80;
|
||||
}
|
||||
R_ABORT_UNLESS(WriteI2cRegister(this->i2c_session, std::addressof(on_off_2_val), sizeof(on_off_2_val), std::addressof(on_off_2_addr), sizeof(on_off_2_addr)));
|
||||
R_ABORT_UNLESS(WriteI2cRegister(m_i2c_session, std::addressof(on_off_2_val), sizeof(on_off_2_val), std::addressof(on_off_2_addr), sizeof(on_off_2_addr)));
|
||||
|
||||
/* Get value, set software reset mask. */
|
||||
u8 on_off_1_val = 0;
|
||||
R_ABORT_UNLESS(ReadI2cRegister(this->i2c_session, std::addressof(on_off_1_val), sizeof(on_off_1_val), std::addressof(on_off_1_addr), sizeof(on_off_1_addr)));
|
||||
R_ABORT_UNLESS(ReadI2cRegister(m_i2c_session, std::addressof(on_off_1_val), sizeof(on_off_1_val), std::addressof(on_off_1_addr), sizeof(on_off_1_addr)));
|
||||
on_off_1_val |= 0x80;
|
||||
|
||||
/* Finalize the battery on non-Calcio. */
|
||||
@@ -82,7 +82,7 @@ namespace ams::boot {
|
||||
}
|
||||
|
||||
/* Actually write the value to trigger shutdown/reset. */
|
||||
R_ABORT_UNLESS(WriteI2cRegister(this->i2c_session, std::addressof(on_off_1_val), sizeof(on_off_1_val), std::addressof(on_off_1_addr), sizeof(on_off_1_addr)));
|
||||
R_ABORT_UNLESS(WriteI2cRegister(m_i2c_session, std::addressof(on_off_1_val), sizeof(on_off_1_val), std::addressof(on_off_1_addr), sizeof(on_off_1_addr)));
|
||||
|
||||
/* Allow up to 5 seconds for shutdown/reboot to take place. */
|
||||
os::SleepThread(TimeSpan::FromSeconds(5));
|
||||
|
||||
@@ -21,14 +21,14 @@ namespace ams::boot {
|
||||
/* Driver object. */
|
||||
class PmicDriver {
|
||||
private:
|
||||
i2c::driver::I2cSession i2c_session;
|
||||
i2c::driver::I2cSession m_i2c_session;
|
||||
public:
|
||||
PmicDriver() {
|
||||
R_ABORT_UNLESS(i2c::driver::OpenSession(std::addressof(this->i2c_session), i2c::DeviceCode_Max77620Pmic));
|
||||
R_ABORT_UNLESS(i2c::driver::OpenSession(std::addressof(m_i2c_session), i2c::DeviceCode_Max77620Pmic));
|
||||
}
|
||||
|
||||
~PmicDriver() {
|
||||
i2c::driver::CloseSession(this->i2c_session);
|
||||
i2c::driver::CloseSession(m_i2c_session);
|
||||
}
|
||||
private:
|
||||
Result GetPowerStatus(u8 *out);
|
||||
|
||||
@@ -21,14 +21,14 @@ namespace ams::boot {
|
||||
Result RtcDriver::ReadRtcRegister(u8 *out, u8 address) {
|
||||
const u8 update_addr = 0x04;
|
||||
const u8 update_val = 0x10;
|
||||
R_TRY(WriteI2cRegister(this->i2c_session, &update_val, sizeof(update_val), &update_addr, sizeof(update_addr)));
|
||||
R_TRY(WriteI2cRegister(m_i2c_session, &update_val, sizeof(update_val), &update_addr, sizeof(update_addr)));
|
||||
os::SleepThread(TimeSpan::FromMilliSeconds(16));
|
||||
return ReadI2cRegister(this->i2c_session, out, sizeof(*out), &address, sizeof(address));
|
||||
return ReadI2cRegister(m_i2c_session, out, sizeof(*out), &address, sizeof(address));
|
||||
}
|
||||
|
||||
Result RtcDriver::GetRtcIntr(u8 *out) {
|
||||
const u8 addr = 0x00;
|
||||
return ReadI2cRegister(this->i2c_session, out, sizeof(*out), &addr, sizeof(addr));
|
||||
return ReadI2cRegister(m_i2c_session, out, sizeof(*out), &addr, sizeof(addr));
|
||||
}
|
||||
|
||||
Result RtcDriver::GetRtcIntrM(u8 *out) {
|
||||
|
||||
@@ -20,14 +20,14 @@ namespace ams::boot {
|
||||
|
||||
class RtcDriver {
|
||||
private:
|
||||
i2c::driver::I2cSession i2c_session;
|
||||
i2c::driver::I2cSession m_i2c_session;
|
||||
public:
|
||||
RtcDriver() {
|
||||
R_ABORT_UNLESS(i2c::driver::OpenSession(std::addressof(this->i2c_session), i2c::DeviceCode_Max77620Rtc));
|
||||
R_ABORT_UNLESS(i2c::driver::OpenSession(std::addressof(m_i2c_session), i2c::DeviceCode_Max77620Rtc));
|
||||
}
|
||||
|
||||
~RtcDriver() {
|
||||
i2c::driver::CloseSession(this->i2c_session);
|
||||
i2c::driver::CloseSession(m_i2c_session);
|
||||
}
|
||||
private:
|
||||
Result ReadRtcRegister(u8 *out, u8 address);
|
||||
|
||||
@@ -86,31 +86,31 @@ namespace ams::creport {
|
||||
|
||||
void CrashReport::Initialize() {
|
||||
/* Initialize the heap. */
|
||||
this->heap_handle = lmem::CreateExpHeap(this->heap_storage, sizeof(this->heap_storage), lmem::CreateOption_None);
|
||||
m_heap_handle = lmem::CreateExpHeap(m_heap_storage, sizeof(m_heap_storage), lmem::CreateOption_None);
|
||||
|
||||
/* Allocate members. */
|
||||
this->module_list = std::construct_at(static_cast<ModuleList *>(lmem::AllocateFromExpHeap(this->heap_handle, sizeof(ModuleList))));
|
||||
this->thread_list = std::construct_at(static_cast<ThreadList *>(lmem::AllocateFromExpHeap(this->heap_handle, sizeof(ThreadList))));
|
||||
this->dying_message = static_cast<u8 *>(lmem::AllocateFromExpHeap(this->heap_handle, DyingMessageSizeMax));
|
||||
if (this->dying_message != nullptr) {
|
||||
std::memset(this->dying_message, 0, DyingMessageSizeMax);
|
||||
m_module_list = std::construct_at(static_cast<ModuleList *>(lmem::AllocateFromExpHeap(m_heap_handle, sizeof(ModuleList))));
|
||||
m_thread_list = std::construct_at(static_cast<ThreadList *>(lmem::AllocateFromExpHeap(m_heap_handle, sizeof(ThreadList))));
|
||||
m_dying_message = static_cast<u8 *>(lmem::AllocateFromExpHeap(m_heap_handle, DyingMessageSizeMax));
|
||||
if (m_dying_message != nullptr) {
|
||||
std::memset(m_dying_message, 0, DyingMessageSizeMax);
|
||||
}
|
||||
}
|
||||
|
||||
void CrashReport::BuildReport(os::ProcessId process_id, bool has_extra_info) {
|
||||
this->has_extra_info = has_extra_info;
|
||||
m_has_extra_info = has_extra_info;
|
||||
|
||||
if (this->OpenProcess(process_id)) {
|
||||
ON_SCOPE_EXIT { this->Close(); };
|
||||
|
||||
/* Parse info from the crashed process. */
|
||||
this->ProcessExceptions();
|
||||
this->module_list->FindModulesFromThreadInfo(this->debug_handle, this->crashed_thread);
|
||||
this->thread_list->ReadFromProcess(this->debug_handle, this->thread_tls_map, this->Is64Bit());
|
||||
m_module_list->FindModulesFromThreadInfo(m_debug_handle, m_crashed_thread);
|
||||
m_thread_list->ReadFromProcess(m_debug_handle, m_thread_tls_map, this->Is64Bit());
|
||||
|
||||
/* Associate module list to threads. */
|
||||
this->crashed_thread.SetModuleList(this->module_list);
|
||||
this->thread_list->SetModuleList(this->module_list);
|
||||
m_crashed_thread.SetModuleList(m_module_list);
|
||||
m_thread_list->SetModuleList(m_module_list);
|
||||
|
||||
/* Process dying message for applications. */
|
||||
if (this->IsApplication()) {
|
||||
@@ -119,13 +119,13 @@ namespace ams::creport {
|
||||
|
||||
/* Nintendo's creport finds extra modules by looking at all threads if application, */
|
||||
/* but there's no reason for us not to always go looking. */
|
||||
for (size_t i = 0; i < this->thread_list->GetThreadCount(); i++) {
|
||||
this->module_list->FindModulesFromThreadInfo(this->debug_handle, this->thread_list->GetThreadInfo(i));
|
||||
for (size_t i = 0; i < m_thread_list->GetThreadCount(); i++) {
|
||||
m_module_list->FindModulesFromThreadInfo(m_debug_handle, m_thread_list->GetThreadInfo(i));
|
||||
}
|
||||
|
||||
/* Cache the module base address to send to fatal. */
|
||||
if (this->module_list->GetModuleCount()) {
|
||||
this->module_base_address = this->module_list->GetModuleStartAddress(0);
|
||||
if (m_module_list->GetModuleCount()) {
|
||||
m_module_base_address = m_module_list->GetModuleStartAddress(0);
|
||||
}
|
||||
|
||||
/* Nintendo's creport saves the report to erpt here, but we'll save to SD card later. */
|
||||
@@ -139,33 +139,33 @@ namespace ams::creport {
|
||||
|
||||
/* TODO: Support generating 32-bit fatal contexts? */
|
||||
out->architecture = fatal::CpuContext::Architecture_Aarch64;
|
||||
out->type = static_cast<u32>(this->exception_info.type);
|
||||
out->type = static_cast<u32>(m_exception_info.type);
|
||||
|
||||
for (size_t i = 0; i < fatal::aarch64::RegisterName_FP; i++) {
|
||||
out->aarch64_ctx.SetRegisterValue(static_cast<fatal::aarch64::RegisterName>(i), this->crashed_thread.GetGeneralPurposeRegister(i));
|
||||
out->aarch64_ctx.SetRegisterValue(static_cast<fatal::aarch64::RegisterName>(i), m_crashed_thread.GetGeneralPurposeRegister(i));
|
||||
}
|
||||
out->aarch64_ctx.SetRegisterValue(fatal::aarch64::RegisterName_FP, this->crashed_thread.GetFP());
|
||||
out->aarch64_ctx.SetRegisterValue(fatal::aarch64::RegisterName_LR, this->crashed_thread.GetLR());
|
||||
out->aarch64_ctx.SetRegisterValue(fatal::aarch64::RegisterName_SP, this->crashed_thread.GetSP());
|
||||
out->aarch64_ctx.SetRegisterValue(fatal::aarch64::RegisterName_PC, this->crashed_thread.GetPC());
|
||||
out->aarch64_ctx.SetRegisterValue(fatal::aarch64::RegisterName_FP, m_crashed_thread.GetFP());
|
||||
out->aarch64_ctx.SetRegisterValue(fatal::aarch64::RegisterName_LR, m_crashed_thread.GetLR());
|
||||
out->aarch64_ctx.SetRegisterValue(fatal::aarch64::RegisterName_SP, m_crashed_thread.GetSP());
|
||||
out->aarch64_ctx.SetRegisterValue(fatal::aarch64::RegisterName_PC, m_crashed_thread.GetPC());
|
||||
|
||||
out->aarch64_ctx.stack_trace_size = this->crashed_thread.GetStackTraceSize();
|
||||
out->aarch64_ctx.stack_trace_size = m_crashed_thread.GetStackTraceSize();
|
||||
for (size_t i = 0; i < out->aarch64_ctx.stack_trace_size; i++) {
|
||||
out->aarch64_ctx.stack_trace[i] = this->crashed_thread.GetStackTrace(i);
|
||||
out->aarch64_ctx.stack_trace[i] = m_crashed_thread.GetStackTrace(i);
|
||||
}
|
||||
|
||||
if (this->module_base_address != 0) {
|
||||
out->aarch64_ctx.SetBaseAddress(this->module_base_address);
|
||||
if (m_module_base_address != 0) {
|
||||
out->aarch64_ctx.SetBaseAddress(m_module_base_address);
|
||||
}
|
||||
|
||||
/* For ams fatal, which doesn't use afsr0, pass program_id instead. */
|
||||
out->aarch64_ctx.SetProgramIdForAtmosphere(ncm::ProgramId{this->process_info.program_id});
|
||||
out->aarch64_ctx.SetProgramIdForAtmosphere(ncm::ProgramId{m_process_info.program_id});
|
||||
}
|
||||
|
||||
void CrashReport::ProcessExceptions() {
|
||||
/* Loop all debug events. */
|
||||
svc::DebugEventInfo d;
|
||||
while (R_SUCCEEDED(svc::GetDebugEvent(std::addressof(d), this->debug_handle))) {
|
||||
while (R_SUCCEEDED(svc::GetDebugEvent(std::addressof(d), m_debug_handle))) {
|
||||
switch (d.type) {
|
||||
case svc::DebugEvent_CreateProcess:
|
||||
this->HandleDebugEventInfoCreateProcess(d);
|
||||
@@ -183,11 +183,11 @@ namespace ams::creport {
|
||||
}
|
||||
|
||||
/* Parse crashed thread info. */
|
||||
this->crashed_thread.ReadFromProcess(this->debug_handle, this->thread_tls_map, this->crashed_thread_id, this->Is64Bit());
|
||||
m_crashed_thread.ReadFromProcess(m_debug_handle, m_thread_tls_map, m_crashed_thread_id, this->Is64Bit());
|
||||
}
|
||||
|
||||
void CrashReport::HandleDebugEventInfoCreateProcess(const svc::DebugEventInfo &d) {
|
||||
this->process_info = d.info.create_process;
|
||||
m_process_info = d.info.create_process;
|
||||
|
||||
/* On 5.0.0+, we want to parse out a dying message from application crashes. */
|
||||
if (hos::GetVersion() < hos::Version_5_0_0 || !IsApplication()) {
|
||||
@@ -195,12 +195,12 @@ namespace ams::creport {
|
||||
}
|
||||
|
||||
/* Parse out user data. */
|
||||
const u64 address = this->process_info.user_exception_context_address + DyingMessageAddressOffset;
|
||||
const u64 address = m_process_info.user_exception_context_address + DyingMessageAddressOffset;
|
||||
u64 userdata_address = 0;
|
||||
u64 userdata_size = 0;
|
||||
|
||||
/* Read userdata address. */
|
||||
if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(std::addressof(userdata_address)), this->debug_handle, address, sizeof(userdata_address)))) {
|
||||
if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(std::addressof(userdata_address)), m_debug_handle, address, sizeof(userdata_address)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -210,48 +210,48 @@ namespace ams::creport {
|
||||
}
|
||||
|
||||
/* Read userdata size. */
|
||||
if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(std::addressof(userdata_size)), this->debug_handle, address + sizeof(userdata_address), sizeof(userdata_size)))) {
|
||||
if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(std::addressof(userdata_size)), m_debug_handle, address + sizeof(userdata_address), sizeof(userdata_size)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Cap userdata size. */
|
||||
userdata_size = std::min(size_t(userdata_size), DyingMessageSizeMax);
|
||||
|
||||
this->dying_message_address = userdata_address;
|
||||
this->dying_message_size = userdata_size;
|
||||
m_dying_message_address = userdata_address;
|
||||
m_dying_message_size = userdata_size;
|
||||
}
|
||||
|
||||
void CrashReport::HandleDebugEventInfoCreateThread(const svc::DebugEventInfo &d) {
|
||||
/* Save info on the thread's TLS address for later. */
|
||||
this->thread_tls_map.SetThreadTls(d.info.create_thread.thread_id, d.info.create_thread.tls_address);
|
||||
m_thread_tls_map.SetThreadTls(d.info.create_thread.thread_id, d.info.create_thread.tls_address);
|
||||
}
|
||||
|
||||
void CrashReport::HandleDebugEventInfoException(const svc::DebugEventInfo &d) {
|
||||
switch (d.info.exception.type) {
|
||||
case svc::DebugException_UndefinedInstruction:
|
||||
this->result = creport::ResultUndefinedInstruction();
|
||||
m_result = creport::ResultUndefinedInstruction();
|
||||
break;
|
||||
case svc::DebugException_InstructionAbort:
|
||||
this->result = creport::ResultInstructionAbort();
|
||||
m_result = creport::ResultInstructionAbort();
|
||||
break;
|
||||
case svc::DebugException_DataAbort:
|
||||
this->result = creport::ResultDataAbort();
|
||||
m_result = creport::ResultDataAbort();
|
||||
break;
|
||||
case svc::DebugException_AlignmentFault:
|
||||
this->result = creport::ResultAlignmentFault();
|
||||
m_result = creport::ResultAlignmentFault();
|
||||
break;
|
||||
case svc::DebugException_UserBreak:
|
||||
this->result = creport::ResultUserBreak();
|
||||
m_result = creport::ResultUserBreak();
|
||||
/* Try to parse out the user break result. */
|
||||
if (hos::GetVersion() >= hos::Version_5_0_0) {
|
||||
svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(std::addressof(this->result)), this->debug_handle, d.info.exception.specific.user_break.address, sizeof(this->result));
|
||||
svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(std::addressof(m_result)), m_debug_handle, d.info.exception.specific.user_break.address, sizeof(m_result));
|
||||
}
|
||||
break;
|
||||
case svc::DebugException_UndefinedSystemCall:
|
||||
this->result = creport::ResultUndefinedSystemCall();
|
||||
m_result = creport::ResultUndefinedSystemCall();
|
||||
break;
|
||||
case svc::DebugException_MemorySystemError:
|
||||
this->result = creport::ResultMemorySystemError();
|
||||
m_result = creport::ResultMemorySystemError();
|
||||
break;
|
||||
case svc::DebugException_DebuggerAttached:
|
||||
case svc::DebugException_BreakPoint:
|
||||
@@ -260,8 +260,8 @@ namespace ams::creport {
|
||||
}
|
||||
|
||||
/* Save exception info. */
|
||||
this->exception_info = d.info.exception;
|
||||
this->crashed_thread_id = d.thread_id;
|
||||
m_exception_info = d.info.exception;
|
||||
m_crashed_thread_id = d.thread_id;
|
||||
}
|
||||
|
||||
void CrashReport::ProcessDyingMessage() {
|
||||
@@ -271,10 +271,10 @@ namespace ams::creport {
|
||||
}
|
||||
|
||||
/* Validate address/size. */
|
||||
if (this->dying_message_address == 0 || this->dying_message_address & 0xFFF) {
|
||||
if (m_dying_message_address == 0 || m_dying_message_address & 0xFFF) {
|
||||
return;
|
||||
}
|
||||
if (this->dying_message_size > DyingMessageSizeMax) {
|
||||
if (m_dying_message_size > DyingMessageSizeMax) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -284,12 +284,12 @@ namespace ams::creport {
|
||||
}
|
||||
|
||||
/* Verify that we have a dying message buffer. */
|
||||
if (this->dying_message == nullptr) {
|
||||
if (m_dying_message == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Read the dying message. */
|
||||
svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(this->dying_message), this->debug_handle, this->dying_message_address, this->dying_message_size);
|
||||
svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(m_dying_message), m_debug_handle, m_dying_message_address, m_dying_message_size);
|
||||
}
|
||||
|
||||
void CrashReport::SaveReport(bool enable_screenshot) {
|
||||
@@ -307,7 +307,7 @@ namespace ams::creport {
|
||||
char file_path[fs::EntryNameLengthMax + 1];
|
||||
|
||||
/* Save crash report. */
|
||||
util::SNPrintf(file_path, sizeof(file_path), "sdmc:/atmosphere/crash_reports/%011lu_%016lx.log", timestamp, this->process_info.program_id);
|
||||
util::SNPrintf(file_path, sizeof(file_path), "sdmc:/atmosphere/crash_reports/%011lu_%016lx.log", timestamp, m_process_info.program_id);
|
||||
{
|
||||
ScopedFile file(file_path);
|
||||
if (file.IsOpen()) {
|
||||
@@ -316,25 +316,25 @@ namespace ams::creport {
|
||||
}
|
||||
|
||||
/* Dump threads. */
|
||||
util::SNPrintf(file_path, sizeof(file_path), "sdmc:/atmosphere/crash_reports/dumps/%011lu_%016lx_thread_info.bin", timestamp, this->process_info.program_id);
|
||||
util::SNPrintf(file_path, sizeof(file_path), "sdmc:/atmosphere/crash_reports/dumps/%011lu_%016lx_thread_info.bin", timestamp, m_process_info.program_id);
|
||||
{
|
||||
ScopedFile file(file_path);
|
||||
if (file.IsOpen()) {
|
||||
this->thread_list->DumpBinary(file, this->crashed_thread.GetThreadId());
|
||||
m_thread_list->DumpBinary(file, m_crashed_thread.GetThreadId());
|
||||
}
|
||||
}
|
||||
|
||||
/* Finalize our heap. */
|
||||
std::destroy_at(this->module_list);
|
||||
std::destroy_at(this->thread_list);
|
||||
lmem::FreeToExpHeap(this->heap_handle, this->module_list);
|
||||
lmem::FreeToExpHeap(this->heap_handle, this->thread_list);
|
||||
if (this->dying_message != nullptr) {
|
||||
lmem::FreeToExpHeap(this->heap_handle, this->dying_message);
|
||||
std::destroy_at(m_module_list);
|
||||
std::destroy_at(m_thread_list);
|
||||
lmem::FreeToExpHeap(m_heap_handle, m_module_list);
|
||||
lmem::FreeToExpHeap(m_heap_handle, m_thread_list);
|
||||
if (m_dying_message != nullptr) {
|
||||
lmem::FreeToExpHeap(m_heap_handle, m_dying_message);
|
||||
}
|
||||
this->module_list = nullptr;
|
||||
this->thread_list = nullptr;
|
||||
this->dying_message = nullptr;
|
||||
m_module_list = nullptr;
|
||||
m_thread_list = nullptr;
|
||||
m_dying_message = nullptr;
|
||||
|
||||
/* Try to take a screenshot. */
|
||||
/* NOTE: Nintendo validates that enable_screenshot is true here, and validates that the application id is not in a blacklist. */
|
||||
@@ -345,11 +345,11 @@ namespace ams::creport {
|
||||
ON_SCOPE_EXIT { capsrv::FinalizeScreenShotControl(); };
|
||||
|
||||
u64 jpeg_size;
|
||||
if (R_SUCCEEDED(capsrv::CaptureJpegScreenshot(std::addressof(jpeg_size), this->heap_storage, sizeof(this->heap_storage), vi::LayerStack_ApplicationForDebug, TimeSpan::FromSeconds(10)))) {
|
||||
util::SNPrintf(file_path, sizeof(file_path), "sdmc:/atmosphere/crash_reports/%011lu_%016lx.jpg", timestamp, this->process_info.program_id);
|
||||
if (R_SUCCEEDED(capsrv::CaptureJpegScreenshot(std::addressof(jpeg_size), m_heap_storage, sizeof(m_heap_storage), vi::LayerStack_ApplicationForDebug, TimeSpan::FromSeconds(10)))) {
|
||||
util::SNPrintf(file_path, sizeof(file_path), "sdmc:/atmosphere/crash_reports/%011lu_%016lx.jpg", timestamp, m_process_info.program_id);
|
||||
ScopedFile file(file_path);
|
||||
if (file.IsOpen()) {
|
||||
file.Write(this->heap_storage, jpeg_size);
|
||||
file.Write(m_heap_storage, jpeg_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -360,42 +360,42 @@ namespace ams::creport {
|
||||
void CrashReport::SaveToFile(ScopedFile &file) {
|
||||
file.WriteFormat("Atmosphère Crash Report (v1.6):\n");
|
||||
|
||||
file.WriteFormat("Result: 0x%X (2%03d-%04d)\n\n", this->result.GetValue(), this->result.GetModule(), this->result.GetDescription());
|
||||
file.WriteFormat("Result: 0x%X (2%03d-%04d)\n\n", m_result.GetValue(), m_result.GetModule(), m_result.GetDescription());
|
||||
|
||||
/* Process Info. */
|
||||
char name_buf[0x10] = {};
|
||||
static_assert(sizeof(name_buf) >= sizeof(this->process_info.name), "buffer overflow!");
|
||||
std::memcpy(name_buf, this->process_info.name, sizeof(this->process_info.name));
|
||||
static_assert(sizeof(name_buf) >= sizeof(m_process_info.name), "buffer overflow!");
|
||||
std::memcpy(name_buf, m_process_info.name, sizeof(m_process_info.name));
|
||||
file.WriteFormat("Process Info:\n");
|
||||
file.WriteFormat(" Process Name: %s\n", name_buf);
|
||||
file.WriteFormat(" Program ID: %016lx\n", this->process_info.program_id);
|
||||
file.WriteFormat(" Process ID: %016lx\n", this->process_info.process_id);
|
||||
file.WriteFormat(" Process Flags: %08x\n", this->process_info.flags);
|
||||
file.WriteFormat(" Program ID: %016lx\n", m_process_info.program_id);
|
||||
file.WriteFormat(" Process ID: %016lx\n", m_process_info.process_id);
|
||||
file.WriteFormat(" Process Flags: %08x\n", m_process_info.flags);
|
||||
if (hos::GetVersion() >= hos::Version_5_0_0) {
|
||||
file.WriteFormat(" User Exception Address: %s\n", this->module_list->GetFormattedAddressString(this->process_info.user_exception_context_address));
|
||||
file.WriteFormat(" User Exception Address: %s\n", m_module_list->GetFormattedAddressString(m_process_info.user_exception_context_address));
|
||||
}
|
||||
|
||||
/* Exception Info. */
|
||||
file.WriteFormat("Exception Info:\n");
|
||||
file.WriteFormat(" Type: %s\n", GetDebugExceptionString(this->exception_info.type));
|
||||
file.WriteFormat(" Address: %s\n", this->module_list->GetFormattedAddressString(this->exception_info.address));
|
||||
switch (this->exception_info.type) {
|
||||
file.WriteFormat(" Type: %s\n", GetDebugExceptionString(m_exception_info.type));
|
||||
file.WriteFormat(" Address: %s\n", m_module_list->GetFormattedAddressString(m_exception_info.address));
|
||||
switch (m_exception_info.type) {
|
||||
case svc::DebugException_UndefinedInstruction:
|
||||
file.WriteFormat(" Opcode: %08x\n", this->exception_info.specific.undefined_instruction.insn);
|
||||
file.WriteFormat(" Opcode: %08x\n", m_exception_info.specific.undefined_instruction.insn);
|
||||
break;
|
||||
case svc::DebugException_DataAbort:
|
||||
case svc::DebugException_AlignmentFault:
|
||||
if (this->exception_info.specific.raw != this->exception_info.address) {
|
||||
file.WriteFormat(" Fault Address: %s\n", this->module_list->GetFormattedAddressString(this->exception_info.specific.raw));
|
||||
if (m_exception_info.specific.raw != m_exception_info.address) {
|
||||
file.WriteFormat(" Fault Address: %s\n", m_module_list->GetFormattedAddressString(m_exception_info.specific.raw));
|
||||
}
|
||||
break;
|
||||
case svc::DebugException_UndefinedSystemCall:
|
||||
file.WriteFormat(" Svc Id: 0x%02x\n", this->exception_info.specific.undefined_system_call.id);
|
||||
file.WriteFormat(" Svc Id: 0x%02x\n", m_exception_info.specific.undefined_system_call.id);
|
||||
break;
|
||||
case svc::DebugException_UserBreak:
|
||||
file.WriteFormat(" Break Reason: 0x%x\n", this->exception_info.specific.user_break.break_reason);
|
||||
file.WriteFormat(" Break Address: %s\n", this->module_list->GetFormattedAddressString(this->exception_info.specific.user_break.address));
|
||||
file.WriteFormat(" Break Size: 0x%lx\n", this->exception_info.specific.user_break.size);
|
||||
file.WriteFormat(" Break Reason: 0x%x\n", m_exception_info.specific.user_break.break_reason);
|
||||
file.WriteFormat(" Break Address: %s\n", m_module_list->GetFormattedAddressString(m_exception_info.specific.user_break.address));
|
||||
file.WriteFormat(" Break Size: 0x%lx\n", m_exception_info.specific.user_break.size);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -403,23 +403,23 @@ namespace ams::creport {
|
||||
|
||||
/* Crashed Thread Info. */
|
||||
file.WriteFormat("Crashed Thread Info:\n");
|
||||
this->crashed_thread.SaveToFile(file);
|
||||
m_crashed_thread.SaveToFile(file);
|
||||
|
||||
/* Dying Message. */
|
||||
if (hos::GetVersion() >= hos::Version_5_0_0 && this->dying_message_size != 0) {
|
||||
if (hos::GetVersion() >= hos::Version_5_0_0 && m_dying_message_size != 0) {
|
||||
file.WriteFormat("Dying Message Info:\n");
|
||||
file.WriteFormat(" Address: 0x%s\n", this->module_list->GetFormattedAddressString(this->dying_message_address));
|
||||
file.WriteFormat(" Size: 0x%016lx\n", this->dying_message_size);
|
||||
file.DumpMemory( " Dying Message: ", this->dying_message, this->dying_message_size);
|
||||
file.WriteFormat(" Address: 0x%s\n", m_module_list->GetFormattedAddressString(m_dying_message_address));
|
||||
file.WriteFormat(" Size: 0x%016lx\n", m_dying_message_size);
|
||||
file.DumpMemory( " Dying Message: ", m_dying_message, m_dying_message_size);
|
||||
}
|
||||
|
||||
/* Module Info. */
|
||||
file.WriteFormat("Module Info:\n");
|
||||
this->module_list->SaveToFile(file);
|
||||
m_module_list->SaveToFile(file);
|
||||
|
||||
/* Thread Info. */
|
||||
file.WriteFormat("Thread Report:\n");
|
||||
this->thread_list->SaveToFile(file);
|
||||
m_thread_list->SaveToFile(file);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,66 +25,66 @@ namespace ams::creport {
|
||||
static constexpr size_t MemoryHeapSize = 512_KB;
|
||||
static_assert(MemoryHeapSize >= DyingMessageSizeMax + sizeof(ModuleList) + sizeof(ThreadList) + os::MemoryPageSize);
|
||||
private:
|
||||
os::NativeHandle debug_handle = os::InvalidNativeHandle;
|
||||
bool has_extra_info = true;
|
||||
Result result = creport::ResultIncompleteReport();
|
||||
os::NativeHandle m_debug_handle = os::InvalidNativeHandle;
|
||||
bool m_has_extra_info = true;
|
||||
Result m_result = creport::ResultIncompleteReport();
|
||||
|
||||
/* Meta, used for building module/thread list. */
|
||||
ThreadTlsMap thread_tls_map = {};
|
||||
ThreadTlsMap m_thread_tls_map = {};
|
||||
|
||||
/* Attach process info. */
|
||||
svc::DebugInfoCreateProcess process_info = {};
|
||||
u64 dying_message_address = 0;
|
||||
u64 dying_message_size = 0;
|
||||
u8 *dying_message = nullptr;
|
||||
svc::DebugInfoCreateProcess m_process_info = {};
|
||||
u64 m_dying_message_address = 0;
|
||||
u64 m_dying_message_size = 0;
|
||||
u8 *m_dying_message = nullptr;
|
||||
|
||||
/* Exception info. */
|
||||
svc::DebugInfoException exception_info = {};
|
||||
u64 module_base_address = 0;
|
||||
u64 crashed_thread_id = 0;
|
||||
ThreadInfo crashed_thread;
|
||||
svc::DebugInfoException m_exception_info = {};
|
||||
u64 m_module_base_address = 0;
|
||||
u64 m_crashed_thread_id = 0;
|
||||
ThreadInfo m_crashed_thread;
|
||||
|
||||
/* Lists. */
|
||||
ModuleList *module_list = nullptr;
|
||||
ThreadList *thread_list = nullptr;
|
||||
ModuleList *m_module_list = nullptr;
|
||||
ThreadList *m_thread_list = nullptr;
|
||||
|
||||
/* Memory heap. */
|
||||
lmem::HeapHandle heap_handle = nullptr;
|
||||
u8 heap_storage[MemoryHeapSize] = {};
|
||||
lmem::HeapHandle m_heap_handle = nullptr;
|
||||
u8 m_heap_storage[MemoryHeapSize] = {};
|
||||
public:
|
||||
constexpr CrashReport() = default;
|
||||
|
||||
Result GetResult() const {
|
||||
return this->result;
|
||||
return m_result;
|
||||
}
|
||||
|
||||
bool IsComplete() const {
|
||||
return !ResultIncompleteReport::Includes(this->result);
|
||||
return !ResultIncompleteReport::Includes(m_result);
|
||||
}
|
||||
|
||||
bool IsOpen() const {
|
||||
return this->debug_handle != os::InvalidNativeHandle;
|
||||
return m_debug_handle != os::InvalidNativeHandle;
|
||||
}
|
||||
|
||||
bool IsApplication() const {
|
||||
return (this->process_info.flags & svc::CreateProcessFlag_IsApplication) != 0;
|
||||
return (m_process_info.flags & svc::CreateProcessFlag_IsApplication) != 0;
|
||||
}
|
||||
|
||||
bool Is64Bit() const {
|
||||
return (this->process_info.flags & svc::CreateProcessFlag_Is64Bit) != 0;
|
||||
return (m_process_info.flags & svc::CreateProcessFlag_Is64Bit) != 0;
|
||||
}
|
||||
|
||||
bool IsUserBreak() const {
|
||||
return this->exception_info.type == svc::DebugException_UserBreak;
|
||||
return m_exception_info.type == svc::DebugException_UserBreak;
|
||||
}
|
||||
|
||||
bool OpenProcess(os::ProcessId process_id) {
|
||||
return R_SUCCEEDED(svc::DebugActiveProcess(std::addressof(this->debug_handle), process_id.value));
|
||||
return R_SUCCEEDED(svc::DebugActiveProcess(std::addressof(m_debug_handle), process_id.value));
|
||||
}
|
||||
|
||||
void Close() {
|
||||
os::CloseNativeHandle(this->debug_handle);
|
||||
this->debug_handle = os::InvalidNativeHandle;
|
||||
os::CloseNativeHandle(m_debug_handle);
|
||||
m_debug_handle = os::InvalidNativeHandle;
|
||||
}
|
||||
|
||||
void Initialize();
|
||||
|
||||
@@ -46,12 +46,12 @@ namespace ams::creport {
|
||||
}
|
||||
|
||||
void ModuleList::SaveToFile(ScopedFile &file) {
|
||||
file.WriteFormat(" Number of Modules: %zu\n", this->num_modules);
|
||||
for (size_t i = 0; i < this->num_modules; i++) {
|
||||
const auto& module = this->modules[i];
|
||||
file.WriteFormat(" Number of Modules: %zu\n", m_num_modules);
|
||||
for (size_t i = 0; i < m_num_modules; i++) {
|
||||
const auto& module = m_modules[i];
|
||||
file.WriteFormat(" Module %02zu:\n", i);
|
||||
file.WriteFormat(" Address: %016lx-%016lx\n", module.start_address, module.end_address);
|
||||
if (std::strcmp(this->modules[i].name, "") != 0) {
|
||||
if (std::strcmp(m_modules[i].name, "") != 0) {
|
||||
file.WriteFormat(" Name: %s\n", module.name);
|
||||
}
|
||||
file.DumpMemory(" Build Id: ", module.build_id, sizeof(module.build_id));
|
||||
@@ -60,7 +60,7 @@ namespace ams::creport {
|
||||
|
||||
void ModuleList::FindModulesFromThreadInfo(os::NativeHandle debug_handle, const ThreadInfo &thread) {
|
||||
/* Set the debug handle, for access in other member functions. */
|
||||
this->debug_handle = debug_handle;
|
||||
m_debug_handle = debug_handle;
|
||||
|
||||
/* Try to add the thread's PC. */
|
||||
this->TryAddModule(thread.GetPC());
|
||||
@@ -82,25 +82,25 @@ namespace ams::creport {
|
||||
}
|
||||
|
||||
/* Check whether we already have this module. */
|
||||
for (size_t i = 0; i < this->num_modules; i++) {
|
||||
if (this->modules[i].start_address <= base_address && base_address < this->modules[i].end_address) {
|
||||
for (size_t i = 0; i < m_num_modules; i++) {
|
||||
if (m_modules[i].start_address <= base_address && base_address < m_modules[i].end_address) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add all contiguous modules. */
|
||||
uintptr_t cur_address = base_address;
|
||||
while (this->num_modules < ModuleCountMax) {
|
||||
while (m_num_modules < ModuleCountMax) {
|
||||
/* Get the region extents. */
|
||||
svc::MemoryInfo mi;
|
||||
svc::PageInfo pi;
|
||||
if (R_FAILED(svc::QueryDebugProcessMemory(std::addressof(mi), std::addressof(pi), this->debug_handle, cur_address))) {
|
||||
if (R_FAILED(svc::QueryDebugProcessMemory(std::addressof(mi), std::addressof(pi), m_debug_handle, cur_address))) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Parse module. */
|
||||
if (mi.permission == svc::MemoryPermission_ReadExecute) {
|
||||
auto& module = this->modules[this->num_modules++];
|
||||
auto& module = m_modules[m_num_modules++];
|
||||
module.start_address = mi.base_address;
|
||||
module.end_address = mi.base_address + mi.size;
|
||||
GetModuleName(module.name, module.start_address, module.end_address);
|
||||
@@ -129,20 +129,20 @@ namespace ams::creport {
|
||||
/* Query the memory region our guess falls in. */
|
||||
svc::MemoryInfo mi;
|
||||
svc::PageInfo pi;
|
||||
if (R_FAILED(svc::QueryDebugProcessMemory(std::addressof(mi), std::addressof(pi), this->debug_handle, guess))) {
|
||||
if (R_FAILED(svc::QueryDebugProcessMemory(std::addressof(mi), std::addressof(pi), m_debug_handle, guess))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If we fall into a RW region, it may be rwdata. Query the region before it, which may be rodata or text. */
|
||||
if (mi.permission == svc::MemoryPermission_ReadWrite) {
|
||||
if (R_FAILED(svc::QueryDebugProcessMemory(std::addressof(mi), std::addressof(pi), debug_handle, mi.base_address - 4))) {
|
||||
if (R_FAILED(svc::QueryDebugProcessMemory(std::addressof(mi), std::addressof(pi), m_debug_handle, mi.base_address - 4))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we fall into an RO region, it may be rodata. Query the region before it, which should be text. */
|
||||
if (mi.permission == svc::MemoryPermission_Read) {
|
||||
if (R_FAILED(svc::QueryDebugProcessMemory(std::addressof(mi), std::addressof(pi), debug_handle, mi.base_address - 4))) {
|
||||
if (R_FAILED(svc::QueryDebugProcessMemory(std::addressof(mi), std::addressof(pi), m_debug_handle, mi.base_address - 4))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -155,7 +155,7 @@ namespace ams::creport {
|
||||
/* Modules are a series of contiguous (text/rodata/rwdata) regions. */
|
||||
/* Iterate backwards until we find unmapped memory, to find the start of the set of modules loaded here. */
|
||||
while (mi.base_address > 0) {
|
||||
if (R_FAILED(svc::QueryDebugProcessMemory(std::addressof(mi), std::addressof(pi), debug_handle, mi.base_address - 4))) {
|
||||
if (R_FAILED(svc::QueryDebugProcessMemory(std::addressof(mi), std::addressof(pi), m_debug_handle, mi.base_address - 4))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ namespace ams::creport {
|
||||
svc::PageInfo pi;
|
||||
|
||||
/* Verify .rodata is read-only. */
|
||||
if (R_FAILED(svc::QueryDebugProcessMemory(std::addressof(mi), std::addressof(pi), this->debug_handle, ro_start_address)) || mi.permission != svc::MemoryPermission_Read) {
|
||||
if (R_FAILED(svc::QueryDebugProcessMemory(std::addressof(mi), std::addressof(pi), m_debug_handle, ro_start_address)) || mi.permission != svc::MemoryPermission_Read) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ namespace ams::creport {
|
||||
const u64 rw_start_address = mi.base_address + mi.size;
|
||||
|
||||
/* Read start of .rodata. */
|
||||
if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(std::addressof(rodata_start)), this->debug_handle, ro_start_address, sizeof(rodata_start)))) {
|
||||
if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(std::addressof(rodata_start)), m_debug_handle, ro_start_address, sizeof(rodata_start)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -228,13 +228,13 @@ namespace ams::creport {
|
||||
/* Verify .rodata is read-only. */
|
||||
svc::MemoryInfo mi;
|
||||
svc::PageInfo pi;
|
||||
if (R_FAILED(svc::QueryDebugProcessMemory(std::addressof(mi), std::addressof(pi), this->debug_handle, ro_start_address)) || mi.permission != svc::MemoryPermission_Read) {
|
||||
if (R_FAILED(svc::QueryDebugProcessMemory(std::addressof(mi), std::addressof(pi), m_debug_handle, ro_start_address)) || mi.permission != svc::MemoryPermission_Read) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* We want to read the last two pages of .rodata. */
|
||||
const size_t read_size = mi.size >= sizeof(g_last_rodata_pages) ? sizeof(g_last_rodata_pages) : (sizeof(g_last_rodata_pages) / 2);
|
||||
if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(g_last_rodata_pages), this->debug_handle, mi.base_address + mi.size - read_size, read_size))) {
|
||||
if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(g_last_rodata_pages), m_debug_handle, mi.base_address + mi.size - read_size, read_size))) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -249,18 +249,18 @@ namespace ams::creport {
|
||||
|
||||
const char *ModuleList::GetFormattedAddressString(uintptr_t address) {
|
||||
/* Print default formatted string. */
|
||||
util::SNPrintf(this->address_str_buf, sizeof(this->address_str_buf), "%016lx", address);
|
||||
util::SNPrintf(m_address_str_buf, sizeof(m_address_str_buf), "%016lx", address);
|
||||
|
||||
/* See if the address is inside a module, for pretty-printing. */
|
||||
for (size_t i = 0; i < this->num_modules; i++) {
|
||||
const auto& module = this->modules[i];
|
||||
for (size_t i = 0; i < m_num_modules; i++) {
|
||||
const auto& module = m_modules[i];
|
||||
if (module.start_address <= address && address < module.end_address) {
|
||||
util::SNPrintf(this->address_str_buf, sizeof(this->address_str_buf), "%016lx (%s + 0x%lx)", address, module.name, address - module.start_address);
|
||||
util::SNPrintf(m_address_str_buf, sizeof(m_address_str_buf), "%016lx (%s + 0x%lx)", address, module.name, address - module.start_address);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return this->address_str_buf;
|
||||
return m_address_str_buf;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,23 +32,23 @@ namespace ams::creport {
|
||||
u64 end_address;
|
||||
};
|
||||
private:
|
||||
os::NativeHandle debug_handle;
|
||||
size_t num_modules;
|
||||
ModuleInfo modules[ModuleCountMax];
|
||||
os::NativeHandle m_debug_handle;
|
||||
size_t m_num_modules;
|
||||
ModuleInfo m_modules[ModuleCountMax];
|
||||
|
||||
/* For pretty-printing. */
|
||||
char address_str_buf[0x280];
|
||||
char m_address_str_buf[0x280];
|
||||
public:
|
||||
ModuleList() : debug_handle(os::InvalidNativeHandle), num_modules(0) {
|
||||
std::memset(this->modules, 0, sizeof(this->modules));
|
||||
ModuleList() : m_debug_handle(os::InvalidNativeHandle), m_num_modules(0) {
|
||||
std::memset(m_modules, 0, sizeof(m_modules));
|
||||
}
|
||||
|
||||
size_t GetModuleCount() const {
|
||||
return this->num_modules;
|
||||
return m_num_modules;
|
||||
}
|
||||
|
||||
u64 GetModuleStartAddress(size_t i) const {
|
||||
return this->modules[i].start_address;
|
||||
return m_modules[i].start_address;
|
||||
}
|
||||
|
||||
void FindModulesFromThreadInfo(os::NativeHandle debug_handle, const ThreadInfo &thread);
|
||||
|
||||
@@ -90,8 +90,8 @@ namespace ams::creport {
|
||||
}
|
||||
|
||||
/* Advance, if we write successfully. */
|
||||
if (R_SUCCEEDED(fs::WriteFile(this->file, this->offset, data, size, fs::WriteOption::Flush))) {
|
||||
this->offset += size;
|
||||
if (R_SUCCEEDED(fs::WriteFile(m_file, m_offset, data, size, fs::WriteOption::Flush))) {
|
||||
m_offset += size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,24 +22,24 @@ namespace ams::creport {
|
||||
NON_COPYABLE(ScopedFile);
|
||||
NON_MOVEABLE(ScopedFile);
|
||||
private:
|
||||
fs::FileHandle file;
|
||||
s64 offset;
|
||||
bool opened;
|
||||
fs::FileHandle m_file;
|
||||
s64 m_offset;
|
||||
bool m_opened;
|
||||
public:
|
||||
ScopedFile(const char *path) : file(), offset(), opened(false) {
|
||||
ScopedFile(const char *path) : m_file(), m_offset(), m_opened(false) {
|
||||
if (R_SUCCEEDED(fs::CreateFile(path, 0))) {
|
||||
this->opened = R_SUCCEEDED(fs::OpenFile(std::addressof(this->file), path, fs::OpenMode_Write | fs::OpenMode_AllowAppend));
|
||||
m_opened = R_SUCCEEDED(fs::OpenFile(std::addressof(m_file), path, fs::OpenMode_Write | fs::OpenMode_AllowAppend));
|
||||
}
|
||||
}
|
||||
|
||||
~ScopedFile() {
|
||||
if (this->opened) {
|
||||
fs::CloseFile(file);
|
||||
if (m_opened) {
|
||||
fs::CloseFile(m_file);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsOpen() const {
|
||||
return this->opened;
|
||||
return m_opened;
|
||||
}
|
||||
|
||||
void WriteString(const char *str);
|
||||
|
||||
@@ -61,67 +61,67 @@ namespace ams::creport {
|
||||
}
|
||||
|
||||
void ThreadList::SaveToFile(ScopedFile &file) {
|
||||
file.WriteFormat("Number of Threads: %02zu\n", this->thread_count);
|
||||
for (size_t i = 0; i < this->thread_count; i++) {
|
||||
file.WriteFormat("Number of Threads: %02zu\n", m_thread_count);
|
||||
for (size_t i = 0; i < m_thread_count; i++) {
|
||||
file.WriteFormat("Threads[%02zu]:\n", i);
|
||||
this->threads[i].SaveToFile(file);
|
||||
m_threads[i].SaveToFile(file);
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadInfo::SaveToFile(ScopedFile &file) {
|
||||
file.WriteFormat(" Thread ID: %016lx\n", this->thread_id);
|
||||
if (std::strcmp(this->name, "") != 0) {
|
||||
file.WriteFormat(" Thread Name: %s\n", this->name);
|
||||
file.WriteFormat(" Thread ID: %016lx\n", m_thread_id);
|
||||
if (std::strcmp(m_name, "") != 0) {
|
||||
file.WriteFormat(" Thread Name: %s\n", m_name);
|
||||
}
|
||||
if (this->stack_top != 0) {
|
||||
file.WriteFormat(" Stack Region: %016lx-%016lx\n", this->stack_bottom, this->stack_top);
|
||||
if (m_stack_top != 0) {
|
||||
file.WriteFormat(" Stack Region: %016lx-%016lx\n", m_stack_bottom, m_stack_top);
|
||||
}
|
||||
file.WriteFormat(" Registers:\n");
|
||||
{
|
||||
for (unsigned int i = 0; i <= 28; i++) {
|
||||
file.WriteFormat(" X[%02u]: %s\n", i, this->module_list->GetFormattedAddressString(this->context.r[i]));
|
||||
file.WriteFormat(" X[%02u]: %s\n", i, m_module_list->GetFormattedAddressString(m_context.r[i]));
|
||||
}
|
||||
file.WriteFormat(" FP: %s\n", this->module_list->GetFormattedAddressString(this->context.fp));
|
||||
file.WriteFormat(" LR: %s\n", this->module_list->GetFormattedAddressString(this->context.lr));
|
||||
file.WriteFormat(" SP: %s\n", this->module_list->GetFormattedAddressString(this->context.sp));
|
||||
file.WriteFormat(" PC: %s\n", this->module_list->GetFormattedAddressString(this->context.pc));
|
||||
file.WriteFormat(" FP: %s\n", m_module_list->GetFormattedAddressString(m_context.fp));
|
||||
file.WriteFormat(" LR: %s\n", m_module_list->GetFormattedAddressString(m_context.lr));
|
||||
file.WriteFormat(" SP: %s\n", m_module_list->GetFormattedAddressString(m_context.sp));
|
||||
file.WriteFormat(" PC: %s\n", m_module_list->GetFormattedAddressString(m_context.pc));
|
||||
}
|
||||
if (this->stack_trace_size != 0) {
|
||||
if (m_stack_trace_size != 0) {
|
||||
file.WriteFormat(" Stack Trace:\n");
|
||||
for (size_t i = 0; i < this->stack_trace_size; i++) {
|
||||
file.WriteFormat(" ReturnAddress[%02zu]: %s\n", i, this->module_list->GetFormattedAddressString(this->stack_trace[i]));
|
||||
for (size_t i = 0; i < m_stack_trace_size; i++) {
|
||||
file.WriteFormat(" ReturnAddress[%02zu]: %s\n", i, m_module_list->GetFormattedAddressString(m_stack_trace[i]));
|
||||
}
|
||||
}
|
||||
if (this->stack_dump_base != 0) {
|
||||
if (m_stack_dump_base != 0) {
|
||||
file.WriteFormat(" Stack Dump: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
|
||||
for (size_t i = 0; i < 0x10; i++) {
|
||||
const size_t ofs = i * 0x10;
|
||||
file.WriteFormat(" %012lx %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
this->stack_dump_base + ofs, this->stack_dump[ofs + 0], this->stack_dump[ofs + 1], this->stack_dump[ofs + 2], this->stack_dump[ofs + 3], this->stack_dump[ofs + 4], this->stack_dump[ofs + 5], this->stack_dump[ofs + 6], this->stack_dump[ofs + 7],
|
||||
this->stack_dump[ofs + 8], this->stack_dump[ofs + 9], this->stack_dump[ofs + 10], this->stack_dump[ofs + 11], this->stack_dump[ofs + 12], this->stack_dump[ofs + 13], this->stack_dump[ofs + 14], this->stack_dump[ofs + 15]);
|
||||
m_stack_dump_base + ofs, m_stack_dump[ofs + 0], m_stack_dump[ofs + 1], m_stack_dump[ofs + 2], m_stack_dump[ofs + 3], m_stack_dump[ofs + 4], m_stack_dump[ofs + 5], m_stack_dump[ofs + 6], m_stack_dump[ofs + 7],
|
||||
m_stack_dump[ofs + 8], m_stack_dump[ofs + 9], m_stack_dump[ofs + 10], m_stack_dump[ofs + 11], m_stack_dump[ofs + 12], m_stack_dump[ofs + 13], m_stack_dump[ofs + 14], m_stack_dump[ofs + 15]);
|
||||
}
|
||||
}
|
||||
if (this->tls_address != 0) {
|
||||
file.WriteFormat(" TLS Address: %016lx\n", this->tls_address);
|
||||
if (m_tls_address != 0) {
|
||||
file.WriteFormat(" TLS Address: %016lx\n", m_tls_address);
|
||||
file.WriteFormat(" TLS Dump: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
|
||||
for (size_t i = 0; i < 0x10; i++) {
|
||||
const size_t ofs = i * 0x10;
|
||||
file.WriteFormat(" %012lx %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
this->tls_address + ofs, this->tls[ofs + 0], this->tls[ofs + 1], this->tls[ofs + 2], this->tls[ofs + 3], this->tls[ofs + 4], this->tls[ofs + 5], this->tls[ofs + 6], this->tls[ofs + 7],
|
||||
this->tls[ofs + 8], this->tls[ofs + 9], this->tls[ofs + 10], this->tls[ofs + 11], this->tls[ofs + 12], this->tls[ofs + 13], this->tls[ofs + 14], this->tls[ofs + 15]);
|
||||
m_tls_address + ofs, m_tls[ofs + 0], m_tls[ofs + 1], m_tls[ofs + 2], m_tls[ofs + 3], m_tls[ofs + 4], m_tls[ofs + 5], m_tls[ofs + 6], m_tls[ofs + 7],
|
||||
m_tls[ofs + 8], m_tls[ofs + 9], m_tls[ofs + 10], m_tls[ofs + 11], m_tls[ofs + 12], m_tls[ofs + 13], m_tls[ofs + 14], m_tls[ofs + 15]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ThreadInfo::ReadFromProcess(os::NativeHandle debug_handle, ThreadTlsMap &tls_map, u64 thread_id, bool is_64_bit) {
|
||||
/* Set thread id. */
|
||||
this->thread_id = thread_id;
|
||||
m_thread_id = thread_id;
|
||||
|
||||
/* Verify that the thread is running or waiting. */
|
||||
{
|
||||
u64 _;
|
||||
u32 _thread_state;
|
||||
if (R_FAILED(svc::GetDebugThreadParam(&_, &_thread_state, debug_handle, this->thread_id, svc::DebugThreadParam_State))) {
|
||||
if (R_FAILED(svc::GetDebugThreadParam(&_, &_thread_state, debug_handle, m_thread_id, svc::DebugThreadParam_State))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -132,24 +132,24 @@ namespace ams::creport {
|
||||
}
|
||||
|
||||
/* Get the thread context. */
|
||||
if (R_FAILED(svc::GetDebugThreadContext(std::addressof(this->context), debug_handle, this->thread_id, svc::ThreadContextFlag_All))) {
|
||||
if (R_FAILED(svc::GetDebugThreadContext(std::addressof(m_context), debug_handle, m_thread_id, svc::ThreadContextFlag_All))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* In aarch32 mode svc::GetDebugThreadContext does not set the LR, FP, and SP registers correctly. */
|
||||
if (!is_64_bit) {
|
||||
this->context.fp = this->context.r[11];
|
||||
this->context.sp = this->context.r[13];
|
||||
this->context.lr = this->context.r[14];
|
||||
m_context.fp = m_context.r[11];
|
||||
m_context.sp = m_context.r[13];
|
||||
m_context.lr = m_context.r[14];
|
||||
}
|
||||
|
||||
/* Read TLS, if present. */
|
||||
/* TODO: struct definitions for nnSdk's ThreadType/TLS Layout? */
|
||||
this->tls_address = 0;
|
||||
if (tls_map.GetThreadTls(std::addressof(this->tls_address), thread_id)) {
|
||||
m_tls_address = 0;
|
||||
if (tls_map.GetThreadTls(std::addressof(m_tls_address), thread_id)) {
|
||||
u8 thread_tls[sizeof(svc::ThreadLocalRegion)];
|
||||
if (R_SUCCEEDED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(thread_tls), debug_handle, this->tls_address, sizeof(thread_tls)))) {
|
||||
std::memcpy(this->tls, thread_tls, sizeof(this->tls));
|
||||
if (R_SUCCEEDED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(thread_tls), debug_handle, m_tls_address, sizeof(thread_tls)))) {
|
||||
std::memcpy(m_tls, thread_tls, sizeof(m_tls));
|
||||
/* Try to detect libnx threads, and skip name parsing then. */
|
||||
if (*(reinterpret_cast<u32 *>(std::addressof(thread_tls[0x1E0]))) != LibnxThreadVarMagic) {
|
||||
u8 thread_type[0x1C0];
|
||||
@@ -161,12 +161,12 @@ namespace ams::creport {
|
||||
/* Check thread name is actually at thread name. */
|
||||
static_assert(0x1A8 - 0x188 == NameLengthMax, "NameLengthMax definition!");
|
||||
if (*(reinterpret_cast<u64 *>(std::addressof(thread_type[0x1A8]))) == thread_type_addr + 0x188) {
|
||||
std::memcpy(this->name, thread_type + 0x188, NameLengthMax);
|
||||
std::memcpy(m_name, thread_type + 0x188, NameLengthMax);
|
||||
}
|
||||
} else if (thread_version == 1) {
|
||||
static_assert(0x1A0 - 0x180 == NameLengthMax, "NameLengthMax definition!");
|
||||
if (*(reinterpret_cast<u64 *>(std::addressof(thread_type[0x1A0]))) == thread_type_addr + 0x180) {
|
||||
std::memcpy(this->name, thread_type + 0x180, NameLengthMax);
|
||||
std::memcpy(m_name, thread_type + 0x180, NameLengthMax);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -179,9 +179,9 @@ namespace ams::creport {
|
||||
|
||||
/* Dump stack trace. */
|
||||
if (is_64_bit) {
|
||||
ReadStackTrace<u64>(std::addressof(this->stack_trace_size), this->stack_trace, StackTraceSizeMax, debug_handle, this->context.fp);
|
||||
ReadStackTrace<u64>(std::addressof(m_stack_trace_size), m_stack_trace, StackTraceSizeMax, debug_handle, m_context.fp);
|
||||
} else {
|
||||
ReadStackTrace<u32>(std::addressof(this->stack_trace_size), this->stack_trace, StackTraceSizeMax, debug_handle, this->context.fp);
|
||||
ReadStackTrace<u32>(std::addressof(m_stack_trace_size), m_stack_trace, StackTraceSizeMax, debug_handle, m_context.fp);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -191,7 +191,7 @@ namespace ams::creport {
|
||||
/* Query stack region. */
|
||||
svc::MemoryInfo mi;
|
||||
svc::PageInfo pi;
|
||||
if (R_FAILED(svc::QueryDebugProcessMemory(std::addressof(mi), std::addressof(pi), debug_handle, this->context.sp))) {
|
||||
if (R_FAILED(svc::QueryDebugProcessMemory(std::addressof(mi), std::addressof(pi), debug_handle, m_context.sp))) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -204,56 +204,56 @@ namespace ams::creport {
|
||||
}
|
||||
|
||||
/* Save stack extents. */
|
||||
this->stack_bottom = mi.base_address;
|
||||
this->stack_top = mi.base_address + mi.size;
|
||||
m_stack_bottom = mi.base_address;
|
||||
m_stack_top = mi.base_address + mi.size;
|
||||
|
||||
/* We always want to dump 0x100 of stack, starting from the lowest 0x10-byte aligned address below the stack pointer. */
|
||||
/* Note: if the stack pointer is below the stack bottom, we will start dumping from the stack bottom. */
|
||||
this->stack_dump_base = std::min(std::max(this->context.sp & ~0xFul, this->stack_bottom), this->stack_top - sizeof(this->stack_dump));
|
||||
m_stack_dump_base = std::min(std::max(m_context.sp & ~0xFul, m_stack_bottom), m_stack_top - sizeof(m_stack_dump));
|
||||
|
||||
/* Try to read stack. */
|
||||
if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(this->stack_dump), debug_handle, this->stack_dump_base, sizeof(this->stack_dump)))) {
|
||||
this->stack_dump_base = 0;
|
||||
if (R_FAILED(svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(m_stack_dump), debug_handle, m_stack_dump_base, sizeof(m_stack_dump)))) {
|
||||
m_stack_dump_base = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadInfo::DumpBinary(ScopedFile &file) {
|
||||
/* Dump id and context. */
|
||||
file.Write(std::addressof(this->thread_id), sizeof(this->thread_id));
|
||||
file.Write(std::addressof(this->context), sizeof(this->context));
|
||||
file.Write(std::addressof(m_thread_id), sizeof(m_thread_id));
|
||||
file.Write(std::addressof(m_context), sizeof(m_context));
|
||||
|
||||
/* Dump TLS info and name. */
|
||||
file.Write(std::addressof(this->tls_address), sizeof(this->tls_address));
|
||||
file.Write(std::addressof(this->tls), sizeof(this->tls));
|
||||
file.Write(std::addressof(this->name), sizeof(this->name));
|
||||
file.Write(std::addressof(m_tls_address), sizeof(m_tls_address));
|
||||
file.Write(std::addressof(m_tls), sizeof(m_tls));
|
||||
file.Write(std::addressof(m_name), sizeof(m_name));
|
||||
|
||||
/* Dump stack extents and stack dump. */
|
||||
file.Write(std::addressof(this->stack_bottom), sizeof(this->stack_bottom));
|
||||
file.Write(std::addressof(this->stack_top), sizeof(this->stack_top));
|
||||
file.Write(std::addressof(this->stack_dump_base), sizeof(this->stack_dump_base));
|
||||
file.Write(std::addressof(this->stack_dump), sizeof(this->stack_dump));
|
||||
file.Write(std::addressof(m_stack_bottom), sizeof(m_stack_bottom));
|
||||
file.Write(std::addressof(m_stack_top), sizeof(m_stack_top));
|
||||
file.Write(std::addressof(m_stack_dump_base), sizeof(m_stack_dump_base));
|
||||
file.Write(std::addressof(m_stack_dump), sizeof(m_stack_dump));
|
||||
|
||||
/* Dump stack trace. */
|
||||
{
|
||||
const u64 sts = this->stack_trace_size;
|
||||
const u64 sts = m_stack_trace_size;
|
||||
file.Write(std::addressof(sts), sizeof(sts));
|
||||
}
|
||||
file.Write(this->stack_trace, this->stack_trace_size);
|
||||
file.Write(m_stack_trace, m_stack_trace_size);
|
||||
}
|
||||
|
||||
void ThreadList::DumpBinary(ScopedFile &file, u64 crashed_thread_id) {
|
||||
const u32 magic = DumpedThreadInfoMagic;
|
||||
const u32 count = this->thread_count;
|
||||
const u32 count = m_thread_count;
|
||||
file.Write(std::addressof(magic), sizeof(magic));
|
||||
file.Write(std::addressof(count), sizeof(count));
|
||||
file.Write(std::addressof(crashed_thread_id), sizeof(crashed_thread_id));
|
||||
for (size_t i = 0; i < this->thread_count; i++) {
|
||||
this->threads[i].DumpBinary(file);
|
||||
for (size_t i = 0; i < m_thread_count; i++) {
|
||||
m_threads[i].DumpBinary(file);
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadList::ReadFromProcess(os::NativeHandle debug_handle, ThreadTlsMap &tls_map, bool is_64_bit) {
|
||||
this->thread_count = 0;
|
||||
m_thread_count = 0;
|
||||
|
||||
/* Get thread list. */
|
||||
s32 num_threads;
|
||||
@@ -267,8 +267,8 @@ namespace ams::creport {
|
||||
|
||||
/* Parse thread infos. */
|
||||
for (s32 i = 0; i < num_threads; i++) {
|
||||
if (this->threads[this->thread_count].ReadFromProcess(debug_handle, tls_map, thread_ids[i], is_64_bit)) {
|
||||
this->thread_count++;
|
||||
if (m_threads[m_thread_count].ReadFromProcess(debug_handle, tls_map, thread_ids[i], is_64_bit)) {
|
||||
m_thread_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,53 +60,53 @@ namespace ams::creport {
|
||||
static constexpr size_t StackTraceSizeMax = 0x20;
|
||||
static constexpr size_t NameLengthMax = 0x20;
|
||||
private:
|
||||
svc::ThreadContext context = {};
|
||||
u64 thread_id = 0;
|
||||
u64 stack_top = 0;
|
||||
u64 stack_bottom = 0;
|
||||
u64 stack_trace[StackTraceSizeMax] = {};
|
||||
size_t stack_trace_size = 0;
|
||||
u64 tls_address = 0;
|
||||
u8 tls[0x100] = {};
|
||||
u64 stack_dump_base = 0;
|
||||
u8 stack_dump[0x100] = {};
|
||||
char name[NameLengthMax + 1] = {};
|
||||
ModuleList *module_list = nullptr;
|
||||
svc::ThreadContext m_context = {};
|
||||
u64 m_thread_id = 0;
|
||||
u64 m_stack_top = 0;
|
||||
u64 m_stack_bottom = 0;
|
||||
u64 m_stack_trace[StackTraceSizeMax] = {};
|
||||
size_t m_stack_trace_size = 0;
|
||||
u64 m_tls_address = 0;
|
||||
u8 m_tls[0x100] = {};
|
||||
u64 m_stack_dump_base = 0;
|
||||
u8 m_stack_dump[0x100] = {};
|
||||
char m_name[NameLengthMax + 1] = {};
|
||||
ModuleList *m_module_list = nullptr;
|
||||
public:
|
||||
u64 GetGeneralPurposeRegister(size_t i) const {
|
||||
return this->context.r[i];
|
||||
return m_context.r[i];
|
||||
}
|
||||
|
||||
u64 GetPC() const {
|
||||
return this->context.pc;
|
||||
return m_context.pc;
|
||||
}
|
||||
|
||||
u64 GetLR() const {
|
||||
return this->context.lr;
|
||||
return m_context.lr;
|
||||
}
|
||||
|
||||
u64 GetFP() const {
|
||||
return this->context.fp;
|
||||
return m_context.fp;
|
||||
}
|
||||
|
||||
u64 GetSP() const {
|
||||
return this->context.sp;
|
||||
return m_context.sp;
|
||||
}
|
||||
|
||||
u64 GetThreadId() const {
|
||||
return this->thread_id;
|
||||
return m_thread_id;
|
||||
}
|
||||
|
||||
size_t GetStackTraceSize() const {
|
||||
return this->stack_trace_size;
|
||||
return m_stack_trace_size;
|
||||
}
|
||||
|
||||
u64 GetStackTrace(size_t i) const {
|
||||
return this->stack_trace[i];
|
||||
return m_stack_trace[i];
|
||||
}
|
||||
|
||||
void SetModuleList(ModuleList *ml) {
|
||||
this->module_list = ml;
|
||||
m_module_list = ml;
|
||||
}
|
||||
|
||||
bool ReadFromProcess(os::NativeHandle debug_handle, ThreadTlsMap &tls_map, u64 thread_id, bool is_64_bit);
|
||||
@@ -118,20 +118,20 @@ namespace ams::creport {
|
||||
|
||||
class ThreadList {
|
||||
private:
|
||||
size_t thread_count = 0;
|
||||
ThreadInfo threads[ThreadCountMax];
|
||||
size_t m_thread_count = 0;
|
||||
ThreadInfo m_threads[ThreadCountMax];
|
||||
public:
|
||||
size_t GetThreadCount() const {
|
||||
return this->thread_count;
|
||||
return m_thread_count;
|
||||
}
|
||||
|
||||
const ThreadInfo &GetThreadInfo(size_t i) const {
|
||||
return this->threads[i];
|
||||
return m_threads[i];
|
||||
}
|
||||
|
||||
void SetModuleList(ModuleList *ml) {
|
||||
for (size_t i = 0; i < this->thread_count; i++) {
|
||||
this->threads[i].SetModuleList(ml);
|
||||
for (size_t i = 0; i < m_thread_count; i++) {
|
||||
m_threads[i].SetModuleList(ml);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,28 +83,28 @@ namespace ams::dmnt::cheat::impl {
|
||||
private:
|
||||
static constexpr size_t ThreadStackSize = 0x4000;
|
||||
private:
|
||||
os::SdkMutex cheat_lock;
|
||||
os::Event unsafe_break_event;
|
||||
os::Event debug_events_event; /* Autoclear. */
|
||||
os::ThreadType detect_thread, debug_events_thread;
|
||||
os::SystemEvent cheat_process_event;
|
||||
os::NativeHandle cheat_process_debug_handle = os::InvalidNativeHandle;
|
||||
CheatProcessMetadata cheat_process_metadata = {};
|
||||
os::SdkMutex m_cheat_lock;
|
||||
os::Event m_unsafe_break_event;
|
||||
os::Event m_debug_events_event; /* Autoclear. */
|
||||
os::ThreadType m_detect_thread, m_debug_events_thread;
|
||||
os::SystemEvent m_cheat_process_event;
|
||||
os::NativeHandle m_cheat_process_debug_handle = os::InvalidNativeHandle;
|
||||
CheatProcessMetadata m_cheat_process_metadata = {};
|
||||
|
||||
os::ThreadType vm_thread;
|
||||
bool broken_unsafe = false;
|
||||
bool needs_reload_vm = false;
|
||||
CheatVirtualMachine cheat_vm;
|
||||
os::ThreadType m_vm_thread;
|
||||
bool m_broken_unsafe = false;
|
||||
bool m_needs_reload_vm = false;
|
||||
CheatVirtualMachine m_cheat_vm;
|
||||
|
||||
bool enable_cheats_by_default = true;
|
||||
bool always_save_cheat_toggles = false;
|
||||
bool should_save_cheat_toggles = false;
|
||||
CheatEntry cheat_entries[MaxCheatCount] = {};
|
||||
FrozenAddressMap frozen_addresses_map = {};
|
||||
bool m_enable_cheats_by_default = true;
|
||||
bool m_always_save_cheat_toggles = false;
|
||||
bool m_should_save_cheat_toggles = false;
|
||||
CheatEntry m_cheat_entries[MaxCheatCount] = {};
|
||||
FrozenAddressMap m_frozen_addresses_map = {};
|
||||
|
||||
alignas(os::MemoryPageSize) u8 detect_thread_stack[ThreadStackSize] = {};
|
||||
alignas(os::MemoryPageSize) u8 debug_events_thread_stack[ThreadStackSize] = {};
|
||||
alignas(os::MemoryPageSize) u8 vm_thread_stack[ThreadStackSize] = {};
|
||||
alignas(os::MemoryPageSize) u8 m_detect_thread_stack[ThreadStackSize] = {};
|
||||
alignas(os::MemoryPageSize) u8 m_debug_events_thread_stack[ThreadStackSize] = {};
|
||||
alignas(os::MemoryPageSize) u8 m_vm_thread_stack[ThreadStackSize] = {};
|
||||
private:
|
||||
static void DetectLaunchThread(void *_this);
|
||||
static void VirtualMachineThread(void *_this);
|
||||
@@ -119,18 +119,18 @@ namespace ams::dmnt::cheat::impl {
|
||||
void SaveCheatToggles(const ncm::ProgramId program_id);
|
||||
|
||||
bool GetNeedsReloadVm() const {
|
||||
return this->needs_reload_vm;
|
||||
return m_needs_reload_vm;
|
||||
}
|
||||
|
||||
void SetNeedsReloadVm(bool reload) {
|
||||
this->needs_reload_vm = reload;
|
||||
m_needs_reload_vm = reload;
|
||||
}
|
||||
|
||||
|
||||
void ResetCheatEntry(size_t i) {
|
||||
if (i < MaxCheatCount) {
|
||||
std::memset(this->cheat_entries + i, 0, sizeof(this->cheat_entries[i]));
|
||||
this->cheat_entries[i].cheat_id = i;
|
||||
std::memset(m_cheat_entries + i, 0, sizeof(m_cheat_entries[i]));
|
||||
m_cheat_entries[i].cheat_id = i;
|
||||
|
||||
this->SetNeedsReloadVm(true);
|
||||
}
|
||||
@@ -141,12 +141,12 @@ namespace ams::dmnt::cheat::impl {
|
||||
this->ResetCheatEntry(i);
|
||||
}
|
||||
|
||||
this->cheat_vm.ResetStaticRegisters();
|
||||
m_cheat_vm.ResetStaticRegisters();
|
||||
}
|
||||
|
||||
CheatEntry *GetCheatEntryById(size_t i) {
|
||||
if (i < MaxCheatCount) {
|
||||
return this->cheat_entries + i;
|
||||
return m_cheat_entries + i;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@@ -155,8 +155,8 @@ namespace ams::dmnt::cheat::impl {
|
||||
CheatEntry *GetCheatEntryByReadableName(const char *readable_name) {
|
||||
/* Check all non-master cheats for match. */
|
||||
for (size_t i = 1; i < MaxCheatCount; i++) {
|
||||
if (std::strncmp(this->cheat_entries[i].definition.readable_name, readable_name, sizeof(this->cheat_entries[i].definition.readable_name)) == 0) {
|
||||
return this->cheat_entries + i;
|
||||
if (std::strncmp(m_cheat_entries[i].definition.readable_name, readable_name, sizeof(m_cheat_entries[i].definition.readable_name)) == 0) {
|
||||
return m_cheat_entries + i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,8 +166,8 @@ namespace ams::dmnt::cheat::impl {
|
||||
CheatEntry *GetFreeCheatEntry() {
|
||||
/* Check all non-master cheats for availability. */
|
||||
for (size_t i = 1; i < MaxCheatCount; i++) {
|
||||
if (this->cheat_entries[i].definition.num_opcodes == 0) {
|
||||
return this->cheat_entries + i;
|
||||
if (m_cheat_entries[i].definition.num_opcodes == 0) {
|
||||
return m_cheat_entries + i;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,53 +175,53 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
void CloseActiveCheatProcess() {
|
||||
if (this->cheat_process_debug_handle != os::InvalidNativeHandle) {
|
||||
if (m_cheat_process_debug_handle != os::InvalidNativeHandle) {
|
||||
/* We don't need to do any unsafe brekaing. */
|
||||
this->broken_unsafe = false;
|
||||
this->unsafe_break_event.Signal();
|
||||
m_broken_unsafe = false;
|
||||
m_unsafe_break_event.Signal();
|
||||
|
||||
/* Knock out the debug events thread. */
|
||||
os::CancelThreadSynchronization(std::addressof(this->debug_events_thread));
|
||||
os::CancelThreadSynchronization(std::addressof(m_debug_events_thread));
|
||||
|
||||
/* Close resources. */
|
||||
R_ABORT_UNLESS(svc::CloseHandle(this->cheat_process_debug_handle));
|
||||
this->cheat_process_debug_handle = os::InvalidNativeHandle;
|
||||
R_ABORT_UNLESS(svc::CloseHandle(m_cheat_process_debug_handle));
|
||||
m_cheat_process_debug_handle = os::InvalidNativeHandle;
|
||||
|
||||
/* Save cheat toggles. */
|
||||
if (this->always_save_cheat_toggles || this->should_save_cheat_toggles) {
|
||||
this->SaveCheatToggles(this->cheat_process_metadata.program_id);
|
||||
this->should_save_cheat_toggles = false;
|
||||
if (m_always_save_cheat_toggles || m_should_save_cheat_toggles) {
|
||||
this->SaveCheatToggles(m_cheat_process_metadata.program_id);
|
||||
m_should_save_cheat_toggles = false;
|
||||
}
|
||||
|
||||
/* Clear metadata. */
|
||||
static_assert(util::is_pod<decltype(this->cheat_process_metadata)>::value, "CheatProcessMetadata definition!");
|
||||
std::memset(std::addressof(this->cheat_process_metadata), 0, sizeof(this->cheat_process_metadata));
|
||||
static_assert(util::is_pod<decltype(m_cheat_process_metadata)>::value, "CheatProcessMetadata definition!");
|
||||
std::memset(std::addressof(m_cheat_process_metadata), 0, sizeof(m_cheat_process_metadata));
|
||||
|
||||
/* Clear cheat list. */
|
||||
this->ResetAllCheatEntries();
|
||||
|
||||
/* Clear frozen addresses. */
|
||||
{
|
||||
auto it = this->frozen_addresses_map.begin();
|
||||
while (it != this->frozen_addresses_map.end()) {
|
||||
auto it = m_frozen_addresses_map.begin();
|
||||
while (it != m_frozen_addresses_map.end()) {
|
||||
FrozenAddressMapEntry *entry = std::addressof(*it);
|
||||
it = this->frozen_addresses_map.erase(it);
|
||||
it = m_frozen_addresses_map.erase(it);
|
||||
DeallocateFrozenAddress(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/* Signal to our fans. */
|
||||
this->cheat_process_event.Signal();
|
||||
m_cheat_process_event.Signal();
|
||||
}
|
||||
}
|
||||
|
||||
bool HasActiveCheatProcess() {
|
||||
/* Note: This function *MUST* be called only with the cheat lock held. */
|
||||
os::ProcessId pid;
|
||||
bool has_cheat_process = this->cheat_process_debug_handle != os::InvalidNativeHandle;
|
||||
has_cheat_process &= R_SUCCEEDED(os::GetProcessId(std::addressof(pid), this->cheat_process_debug_handle));
|
||||
bool has_cheat_process = m_cheat_process_debug_handle != os::InvalidNativeHandle;
|
||||
has_cheat_process &= R_SUCCEEDED(os::GetProcessId(std::addressof(pid), m_cheat_process_debug_handle));
|
||||
has_cheat_process &= R_SUCCEEDED(pm::dmnt::GetApplicationProcessId(std::addressof(pid)));
|
||||
has_cheat_process &= (pid == this->cheat_process_metadata.process_id);
|
||||
has_cheat_process &= (pid == m_cheat_process_metadata.process_id);
|
||||
|
||||
if (!has_cheat_process) {
|
||||
this->CloseActiveCheatProcess();
|
||||
@@ -236,7 +236,7 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
os::NativeHandle GetCheatProcessHandle() const {
|
||||
return this->cheat_process_debug_handle;
|
||||
return m_cheat_process_debug_handle;
|
||||
}
|
||||
|
||||
os::NativeHandle HookToCreateApplicationProcess() const {
|
||||
@@ -250,50 +250,50 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
public:
|
||||
CheatProcessManager() : cheat_lock(), unsafe_break_event(os::EventClearMode_ManualClear), debug_events_event(os::EventClearMode_AutoClear), cheat_process_event(os::EventClearMode_AutoClear, true) {
|
||||
CheatProcessManager() : m_cheat_lock(), m_unsafe_break_event(os::EventClearMode_ManualClear), m_debug_events_event(os::EventClearMode_AutoClear), m_cheat_process_event(os::EventClearMode_AutoClear, true) {
|
||||
/* Learn whether we should enable cheats by default. */
|
||||
{
|
||||
u8 en = 0;
|
||||
if (settings::fwdbg::GetSettingsItemValue(std::addressof(en), sizeof(en), "atmosphere", "dmnt_cheats_enabled_by_default") == sizeof(en)) {
|
||||
this->enable_cheats_by_default = (en != 0);
|
||||
m_enable_cheats_by_default = (en != 0);
|
||||
}
|
||||
|
||||
en = 0;
|
||||
if (settings::fwdbg::GetSettingsItemValue( std::addressof(en), sizeof(en), "atmosphere", "dmnt_always_save_cheat_toggles") == sizeof(en)) {
|
||||
this->always_save_cheat_toggles = (en != 0);
|
||||
m_always_save_cheat_toggles = (en != 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Spawn application detection thread, spawn cheat vm thread. */
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(this->detect_thread), DetectLaunchThread, this, this->detect_thread_stack, ThreadStackSize, AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, CheatDetect)));
|
||||
os::SetThreadNamePointer(std::addressof(this->detect_thread), AMS_GET_SYSTEM_THREAD_NAME(dmnt, CheatDetect));
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(this->vm_thread), VirtualMachineThread, this, this->vm_thread_stack, ThreadStackSize, AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, CheatVirtualMachine)));
|
||||
os::SetThreadNamePointer(std::addressof(this->vm_thread), AMS_GET_SYSTEM_THREAD_NAME(dmnt, CheatVirtualMachine));
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(this->debug_events_thread), DebugEventsThread, this, this->debug_events_thread_stack, ThreadStackSize, AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, CheatDebugEvents)));
|
||||
os::SetThreadNamePointer(std::addressof(this->debug_events_thread), AMS_GET_SYSTEM_THREAD_NAME(dmnt, CheatDebugEvents));
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(m_detect_thread), DetectLaunchThread, this, m_detect_thread_stack, ThreadStackSize, AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, CheatDetect)));
|
||||
os::SetThreadNamePointer(std::addressof(m_detect_thread), AMS_GET_SYSTEM_THREAD_NAME(dmnt, CheatDetect));
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(m_vm_thread), VirtualMachineThread, this, m_vm_thread_stack, ThreadStackSize, AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, CheatVirtualMachine)));
|
||||
os::SetThreadNamePointer(std::addressof(m_vm_thread), AMS_GET_SYSTEM_THREAD_NAME(dmnt, CheatVirtualMachine));
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(m_debug_events_thread), DebugEventsThread, this, m_debug_events_thread_stack, ThreadStackSize, AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, CheatDebugEvents)));
|
||||
os::SetThreadNamePointer(std::addressof(m_debug_events_thread), AMS_GET_SYSTEM_THREAD_NAME(dmnt, CheatDebugEvents));
|
||||
|
||||
/* Start threads. */
|
||||
os::StartThread(std::addressof(this->detect_thread));
|
||||
os::StartThread(std::addressof(this->vm_thread));
|
||||
os::StartThread(std::addressof(this->debug_events_thread));
|
||||
os::StartThread(std::addressof(m_detect_thread));
|
||||
os::StartThread(std::addressof(m_vm_thread));
|
||||
os::StartThread(std::addressof(m_debug_events_thread));
|
||||
}
|
||||
|
||||
bool GetHasActiveCheatProcess() {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
return this->HasActiveCheatProcess();
|
||||
}
|
||||
|
||||
os::NativeHandle GetCheatProcessEventHandle() const {
|
||||
return this->cheat_process_event.GetReadableHandle();
|
||||
return m_cheat_process_event.GetReadableHandle();
|
||||
}
|
||||
|
||||
Result GetCheatProcessMetadata(CheatProcessMetadata *out) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
std::memcpy(out, std::addressof(this->cheat_process_metadata), sizeof(*out));
|
||||
std::memcpy(out, std::addressof(m_cheat_process_metadata), sizeof(*out));
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ namespace ams::dmnt::cheat::impl {
|
||||
Result WriteCheatProcessMemoryUnsafe(u64 proc_addr, const void *data, size_t size) {
|
||||
R_TRY(svc::WriteDebugProcessMemory(this->GetCheatProcessHandle(), reinterpret_cast<uintptr_t>(data), proc_addr, size));
|
||||
|
||||
for (auto &entry : this->frozen_addresses_map) {
|
||||
for (auto &entry : m_frozen_addresses_map) {
|
||||
/* Get address/value. */
|
||||
const u64 address = entry.GetAddress();
|
||||
auto &value = entry.GetValue();
|
||||
@@ -335,20 +335,20 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
Result PauseCheatProcessUnsafe() {
|
||||
this->broken_unsafe = true;
|
||||
this->unsafe_break_event.Clear();
|
||||
m_broken_unsafe = true;
|
||||
m_unsafe_break_event.Clear();
|
||||
return svc::BreakDebugProcess(this->GetCheatProcessHandle());
|
||||
}
|
||||
|
||||
Result ResumeCheatProcessUnsafe() {
|
||||
this->broken_unsafe = false;
|
||||
this->unsafe_break_event.Signal();
|
||||
m_broken_unsafe = false;
|
||||
m_unsafe_break_event.Signal();
|
||||
dmnt::cheat::impl::ContinueCheatProcess(this->GetCheatProcessHandle());
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetCheatProcessMappingCount(u64 *out_count) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
@@ -372,7 +372,7 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
Result GetCheatProcessMappings(svc::MemoryInfo *mappings, size_t max_count, u64 *out_count, u64 offset) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
@@ -399,7 +399,7 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
Result ReadCheatProcessMemory(u64 proc_addr, void *out_data, size_t size) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
@@ -407,7 +407,7 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
Result WriteCheatProcessMemory(u64 proc_addr, const void *data, size_t size) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
@@ -415,7 +415,7 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
Result QueryCheatProcessMemory(svc::MemoryInfo *mapping, u64 address) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
@@ -424,7 +424,7 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
Result PauseCheatProcess() {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
@@ -432,7 +432,7 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
Result ResumeCheatProcess() {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
@@ -440,13 +440,13 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
Result GetCheatCount(u64 *out_count) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
size_t count = 0;
|
||||
for (size_t i = 0; i < MaxCheatCount; i++) {
|
||||
if (this->cheat_entries[i].definition.num_opcodes) {
|
||||
if (m_cheat_entries[i].definition.num_opcodes) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
@@ -456,16 +456,16 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
Result GetCheats(CheatEntry *out_cheats, size_t max_count, u64 *out_count, u64 offset) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
size_t count = 0, total_count = 0;
|
||||
for (size_t i = 0; i < MaxCheatCount && count < max_count; i++) {
|
||||
if (this->cheat_entries[i].definition.num_opcodes) {
|
||||
if (m_cheat_entries[i].definition.num_opcodes) {
|
||||
total_count++;
|
||||
if (total_count > offset) {
|
||||
out_cheats[count++] = this->cheat_entries[i];
|
||||
out_cheats[count++] = m_cheat_entries[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -475,7 +475,7 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
Result GetCheatById(CheatEntry *out_cheat, u32 cheat_id) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
@@ -488,7 +488,7 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
Result ToggleCheat(u32 cheat_id) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
@@ -507,7 +507,7 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
Result AddCheat(u32 *out_id, const CheatDefinition &def, bool enabled) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
@@ -530,7 +530,7 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
Result RemoveCheat(u32 cheat_id) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
R_UNLESS(cheat_id < MaxCheatCount, dmnt::cheat::ResultCheatUnknownId());
|
||||
@@ -544,14 +544,14 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
Result SetMasterCheat(const CheatDefinition &def) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
R_UNLESS(def.num_opcodes != 0, dmnt::cheat::ResultCheatInvalid());
|
||||
R_UNLESS(def.num_opcodes <= util::size(def.opcodes), dmnt::cheat::ResultCheatInvalid());
|
||||
|
||||
CheatEntry *master_entry = this->cheat_entries + 0;
|
||||
CheatEntry *master_entry = m_cheat_entries + 0;
|
||||
|
||||
master_entry->enabled = true;
|
||||
master_entry->definition = def;
|
||||
@@ -563,50 +563,50 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
Result ReadStaticRegister(u64 *out, size_t which) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
R_UNLESS(which < CheatVirtualMachine::NumStaticRegisters, dmnt::cheat::ResultCheatInvalid());
|
||||
|
||||
*out = this->cheat_vm.GetStaticRegister(which);
|
||||
*out = m_cheat_vm.GetStaticRegister(which);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result WriteStaticRegister(size_t which, u64 value) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
R_UNLESS(which < CheatVirtualMachine::NumStaticRegisters, dmnt::cheat::ResultCheatInvalid());
|
||||
|
||||
this->cheat_vm.SetStaticRegister(which, value);
|
||||
m_cheat_vm.SetStaticRegister(which, value);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ResetStaticRegisters() {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
this->cheat_vm.ResetStaticRegisters();
|
||||
m_cheat_vm.ResetStaticRegisters();
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetFrozenAddressCount(u64 *out_count) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
*out_count = std::distance(this->frozen_addresses_map.begin(), this->frozen_addresses_map.end());
|
||||
*out_count = std::distance(m_frozen_addresses_map.begin(), m_frozen_addresses_map.end());
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result GetFrozenAddresses(FrozenAddressEntry *frz_addrs, size_t max_count, u64 *out_count, u64 offset) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
u64 total_count = 0, written_count = 0;
|
||||
for (const auto &entry : this->frozen_addresses_map) {
|
||||
for (const auto &entry : m_frozen_addresses_map) {
|
||||
if (written_count >= max_count) {
|
||||
break;
|
||||
}
|
||||
@@ -624,12 +624,12 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
Result GetFrozenAddress(FrozenAddressEntry *frz_addr, u64 address) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
const auto it = this->frozen_addresses_map.find_key(address);
|
||||
R_UNLESS(it != this->frozen_addresses_map.end(), dmnt::cheat::ResultFrozenAddressNotFound());
|
||||
const auto it = m_frozen_addresses_map.find_key(address);
|
||||
R_UNLESS(it != m_frozen_addresses_map.end(), dmnt::cheat::ResultFrozenAddressNotFound());
|
||||
|
||||
frz_addr->address = it->GetAddress();
|
||||
frz_addr->value = it->GetValue();
|
||||
@@ -637,12 +637,12 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
Result EnableFrozenAddress(u64 *out_value, u64 address, u64 width) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
const auto it = this->frozen_addresses_map.find_key(address);
|
||||
R_UNLESS(it == this->frozen_addresses_map.end(), dmnt::cheat::ResultFrozenAddressAlreadyExists());
|
||||
const auto it = m_frozen_addresses_map.find_key(address);
|
||||
R_UNLESS(it == m_frozen_addresses_map.end(), dmnt::cheat::ResultFrozenAddressAlreadyExists());
|
||||
|
||||
FrozenAddressValue value = {};
|
||||
value.width = width;
|
||||
@@ -651,21 +651,21 @@ namespace ams::dmnt::cheat::impl {
|
||||
FrozenAddressMapEntry *entry = AllocateFrozenAddress(address, value);
|
||||
R_UNLESS(entry != nullptr, dmnt::cheat::ResultFrozenAddressOutOfResource());
|
||||
|
||||
this->frozen_addresses_map.insert(*entry);
|
||||
m_frozen_addresses_map.insert(*entry);
|
||||
*out_value = value.value;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result DisableFrozenAddress(u64 address) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
const auto it = this->frozen_addresses_map.find_key(address);
|
||||
R_UNLESS(it != this->frozen_addresses_map.end(), dmnt::cheat::ResultFrozenAddressNotFound());
|
||||
const auto it = m_frozen_addresses_map.find_key(address);
|
||||
R_UNLESS(it != m_frozen_addresses_map.end(), dmnt::cheat::ResultFrozenAddressNotFound());
|
||||
|
||||
FrozenAddressMapEntry *entry = std::addressof(*it);
|
||||
this->frozen_addresses_map.erase(it);
|
||||
m_frozen_addresses_map.erase(it);
|
||||
DeallocateFrozenAddress(entry);
|
||||
|
||||
return ResultSuccess();
|
||||
@@ -674,37 +674,37 @@ namespace ams::dmnt::cheat::impl {
|
||||
};
|
||||
|
||||
void CheatProcessManager::DetectLaunchThread(void *_this) {
|
||||
CheatProcessManager *this_ptr = reinterpret_cast<CheatProcessManager *>(_this);
|
||||
CheatProcessManager *manager = reinterpret_cast<CheatProcessManager *>(_this);
|
||||
Event hook;
|
||||
while (true) {
|
||||
eventLoadRemote(std::addressof(hook), this_ptr->HookToCreateApplicationProcess(), true);
|
||||
eventLoadRemote(std::addressof(hook), manager->HookToCreateApplicationProcess(), true);
|
||||
if (R_SUCCEEDED(eventWait(std::addressof(hook), std::numeric_limits<u64>::max()))) {
|
||||
this_ptr->AttachToApplicationProcess(true);
|
||||
manager->AttachToApplicationProcess(true);
|
||||
}
|
||||
eventClose(std::addressof(hook));
|
||||
}
|
||||
}
|
||||
|
||||
void CheatProcessManager::DebugEventsThread(void *_this) {
|
||||
CheatProcessManager *this_ptr = reinterpret_cast<CheatProcessManager *>(_this);
|
||||
CheatProcessManager *manager = reinterpret_cast<CheatProcessManager *>(_this);
|
||||
while (true) {
|
||||
/* Atomically wait (and clear) signal for new process. */
|
||||
this_ptr->debug_events_event.Wait();
|
||||
manager->m_debug_events_event.Wait();
|
||||
while (true) {
|
||||
os::NativeHandle cheat_process_handle = this_ptr->GetCheatProcessHandle();
|
||||
os::NativeHandle cheat_process_handle = manager->GetCheatProcessHandle();
|
||||
s32 dummy;
|
||||
while (cheat_process_handle != os::InvalidNativeHandle && R_SUCCEEDED(svc::WaitSynchronization(std::addressof(dummy), std::addressof(cheat_process_handle), 1, std::numeric_limits<u64>::max()))) {
|
||||
this_ptr->cheat_lock.Lock();
|
||||
ON_SCOPE_EXIT { this_ptr->cheat_lock.Unlock(); };
|
||||
manager->m_cheat_lock.Lock();
|
||||
ON_SCOPE_EXIT { manager->m_cheat_lock.Unlock(); };
|
||||
{
|
||||
ON_SCOPE_EXIT { cheat_process_handle = this_ptr->GetCheatProcessHandle(); };
|
||||
ON_SCOPE_EXIT { cheat_process_handle = manager->GetCheatProcessHandle(); };
|
||||
|
||||
/* If we did an unsafe break, wait until we're not broken. */
|
||||
if (this_ptr->broken_unsafe) {
|
||||
this_ptr->cheat_lock.Unlock();
|
||||
this_ptr->unsafe_break_event.Wait();
|
||||
this_ptr->cheat_lock.Lock();
|
||||
if (this_ptr->GetCheatProcessHandle() != os::InvalidNativeHandle) {
|
||||
if (manager->m_broken_unsafe) {
|
||||
manager->m_cheat_lock.Unlock();
|
||||
manager->m_unsafe_break_event.Wait();
|
||||
manager->m_cheat_lock.Lock();
|
||||
if (manager->GetCheatProcessHandle() != os::InvalidNativeHandle) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
@@ -712,10 +712,10 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
/* Handle any pending debug events. */
|
||||
if (this_ptr->HasActiveCheatProcess()) {
|
||||
R_TRY_CATCH(dmnt::cheat::impl::ContinueCheatProcess(this_ptr->GetCheatProcessHandle())) {
|
||||
if (manager->HasActiveCheatProcess()) {
|
||||
R_TRY_CATCH(dmnt::cheat::impl::ContinueCheatProcess(manager->GetCheatProcessHandle())) {
|
||||
R_CATCH(svc::ResultProcessTerminated) {
|
||||
this_ptr->CloseActiveCheatProcess();
|
||||
manager->CloseActiveCheatProcess();
|
||||
break;
|
||||
}
|
||||
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
|
||||
@@ -725,8 +725,8 @@ namespace ams::dmnt::cheat::impl {
|
||||
|
||||
/* WaitSynchronization failed. This means someone canceled our synchronization, possibly us. */
|
||||
/* Let's check if we should quit! */
|
||||
std::scoped_lock lk(this_ptr->cheat_lock);
|
||||
if (!this_ptr->HasActiveCheatProcess()) {
|
||||
std::scoped_lock lk(manager->m_cheat_lock);
|
||||
if (!manager->HasActiveCheatProcess()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -734,30 +734,30 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
void CheatProcessManager::VirtualMachineThread(void *_this) {
|
||||
CheatProcessManager *this_ptr = reinterpret_cast<CheatProcessManager *>(_this);
|
||||
CheatProcessManager *manager = reinterpret_cast<CheatProcessManager *>(_this);
|
||||
while (true) {
|
||||
/* Apply cheats. */
|
||||
{
|
||||
std::scoped_lock lk(this_ptr->cheat_lock);
|
||||
std::scoped_lock lk(manager->m_cheat_lock);
|
||||
|
||||
if (this_ptr->HasActiveCheatProcess()) {
|
||||
if (manager->HasActiveCheatProcess()) {
|
||||
/* Execute VM. */
|
||||
if (!this_ptr->GetNeedsReloadVm() || this_ptr->cheat_vm.LoadProgram(this_ptr->cheat_entries, util::size(this_ptr->cheat_entries))) {
|
||||
this_ptr->SetNeedsReloadVm(false);
|
||||
if (!manager->GetNeedsReloadVm() || manager->m_cheat_vm.LoadProgram(manager->m_cheat_entries, util::size(manager->m_cheat_entries))) {
|
||||
manager->SetNeedsReloadVm(false);
|
||||
|
||||
/* Execute program only if it has opcodes. */
|
||||
if (this_ptr->cheat_vm.GetProgramSize()) {
|
||||
this_ptr->cheat_vm.Execute(std::addressof(this_ptr->cheat_process_metadata));
|
||||
if (manager->m_cheat_vm.GetProgramSize()) {
|
||||
manager->m_cheat_vm.Execute(std::addressof(manager->m_cheat_process_metadata));
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply frozen addresses. */
|
||||
for (const auto &entry : this_ptr->frozen_addresses_map) {
|
||||
for (const auto &entry : manager->m_frozen_addresses_map) {
|
||||
const auto address = entry.GetAddress();
|
||||
const auto &value = entry.GetValue();
|
||||
|
||||
/* Use Write SVC directly, to avoid the usual frozen address update logic. */
|
||||
svc::WriteDebugProcessMemory(this_ptr->GetCheatProcessHandle(), reinterpret_cast<uintptr_t>(std::addressof(value.value)), address, value.width);
|
||||
svc::WriteDebugProcessMemory(manager->GetCheatProcessHandle(), reinterpret_cast<uintptr_t>(std::addressof(value.value)), address, value.width);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -778,7 +778,7 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
Result CheatProcessManager::AttachToApplicationProcess(bool on_process_launch) {
|
||||
std::scoped_lock lk(this->cheat_lock);
|
||||
std::scoped_lock lk(m_cheat_lock);
|
||||
|
||||
/* Close the active process, if needed. */
|
||||
{
|
||||
@@ -792,12 +792,12 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
/* Get the application process's ID. */
|
||||
R_ABORT_UNLESS_IF_NEW_PROCESS(pm::dmnt::GetApplicationProcessId(std::addressof(this->cheat_process_metadata.process_id)));
|
||||
R_ABORT_UNLESS_IF_NEW_PROCESS(pm::dmnt::GetApplicationProcessId(std::addressof(m_cheat_process_metadata.process_id)));
|
||||
auto proc_guard = SCOPE_GUARD {
|
||||
if (on_process_launch) {
|
||||
this->StartProcess(this->cheat_process_metadata.process_id);
|
||||
this->StartProcess(m_cheat_process_metadata.process_id);
|
||||
}
|
||||
this->cheat_process_metadata.process_id = os::ProcessId{};
|
||||
m_cheat_process_metadata.process_id = os::ProcessId{};
|
||||
};
|
||||
|
||||
/* Get process handle, use it to learn memory extents. */
|
||||
@@ -806,17 +806,17 @@ namespace ams::dmnt::cheat::impl {
|
||||
ncm::ProgramLocation loc = {};
|
||||
cfg::OverrideStatus status = {};
|
||||
|
||||
R_ABORT_UNLESS_IF_NEW_PROCESS(pm::dmnt::AtmosphereGetProcessInfo(std::addressof(proc_h), std::addressof(loc), std::addressof(status), this->cheat_process_metadata.process_id));
|
||||
R_ABORT_UNLESS_IF_NEW_PROCESS(pm::dmnt::AtmosphereGetProcessInfo(std::addressof(proc_h), std::addressof(loc), std::addressof(status), m_cheat_process_metadata.process_id));
|
||||
ON_SCOPE_EXIT { os::CloseNativeHandle(proc_h); };
|
||||
|
||||
this->cheat_process_metadata.program_id = loc.program_id;
|
||||
m_cheat_process_metadata.program_id = loc.program_id;
|
||||
|
||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(this->cheat_process_metadata.heap_extents.base), svc::InfoType_HeapRegionAddress, proc_h, 0));
|
||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(this->cheat_process_metadata.heap_extents.size), svc::InfoType_HeapRegionSize, proc_h, 0));
|
||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(this->cheat_process_metadata.alias_extents.base), svc::InfoType_AliasRegionAddress, proc_h, 0));
|
||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(this->cheat_process_metadata.alias_extents.size), svc::InfoType_AliasRegionSize, proc_h, 0));
|
||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(this->cheat_process_metadata.aslr_extents.base), svc::InfoType_AslrRegionAddress, proc_h, 0));
|
||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(this->cheat_process_metadata.aslr_extents.size), svc::InfoType_AslrRegionSize, proc_h, 0));
|
||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(m_cheat_process_metadata.heap_extents.base), svc::InfoType_HeapRegionAddress, proc_h, 0));
|
||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(m_cheat_process_metadata.heap_extents.size), svc::InfoType_HeapRegionSize, proc_h, 0));
|
||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(m_cheat_process_metadata.alias_extents.base), svc::InfoType_AliasRegionAddress, proc_h, 0));
|
||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(m_cheat_process_metadata.alias_extents.size), svc::InfoType_AliasRegionSize, proc_h, 0));
|
||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(m_cheat_process_metadata.aslr_extents.base), svc::InfoType_AslrRegionAddress, proc_h, 0));
|
||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(m_cheat_process_metadata.aslr_extents.size), svc::InfoType_AslrRegionSize, proc_h, 0));
|
||||
|
||||
/* If new process launch, we may not want to actually attach. */
|
||||
if (on_process_launch) {
|
||||
@@ -830,7 +830,7 @@ namespace ams::dmnt::cheat::impl {
|
||||
s32 num_modules;
|
||||
|
||||
/* TODO: ldr::dmnt:: */
|
||||
R_ABORT_UNLESS_IF_NEW_PROCESS(ldrDmntGetProcessModuleInfo(static_cast<u64>(this->cheat_process_metadata.process_id), proc_modules, util::size(proc_modules), std::addressof(num_modules)));
|
||||
R_ABORT_UNLESS_IF_NEW_PROCESS(ldrDmntGetProcessModuleInfo(static_cast<u64>(m_cheat_process_metadata.process_id), proc_modules, util::size(proc_modules), std::addressof(num_modules)));
|
||||
|
||||
/* All applications must have two modules. */
|
||||
/* Only accept one (which means we're attaching to HBL) */
|
||||
@@ -844,42 +844,42 @@ namespace ams::dmnt::cheat::impl {
|
||||
return dmnt::cheat::ResultCheatNotAttached();
|
||||
}
|
||||
|
||||
this->cheat_process_metadata.main_nso_extents.base = proc_module->base_address;
|
||||
this->cheat_process_metadata.main_nso_extents.size = proc_module->size;
|
||||
std::memcpy(this->cheat_process_metadata.main_nso_build_id, proc_module->build_id, sizeof(this->cheat_process_metadata.main_nso_build_id));
|
||||
m_cheat_process_metadata.main_nso_extents.base = proc_module->base_address;
|
||||
m_cheat_process_metadata.main_nso_extents.size = proc_module->size;
|
||||
std::memcpy(m_cheat_process_metadata.main_nso_build_id, proc_module->build_id, sizeof(m_cheat_process_metadata.main_nso_build_id));
|
||||
}
|
||||
|
||||
/* Read cheats off the SD. */
|
||||
if (!this->LoadCheats(this->cheat_process_metadata.program_id, this->cheat_process_metadata.main_nso_build_id) ||
|
||||
!this->LoadCheatToggles(this->cheat_process_metadata.program_id)) {
|
||||
if (!this->LoadCheats(m_cheat_process_metadata.program_id, m_cheat_process_metadata.main_nso_build_id) ||
|
||||
!this->LoadCheatToggles(m_cheat_process_metadata.program_id)) {
|
||||
/* If new process launch, require success. */
|
||||
R_UNLESS(!on_process_launch, dmnt::cheat::ResultCheatNotAttached());
|
||||
}
|
||||
|
||||
/* Open a debug handle. */
|
||||
svc::Handle debug_handle = svc::InvalidHandle;
|
||||
R_ABORT_UNLESS_IF_NEW_PROCESS(svc::DebugActiveProcess(std::addressof(debug_handle), this->cheat_process_metadata.process_id.value));
|
||||
R_ABORT_UNLESS_IF_NEW_PROCESS(svc::DebugActiveProcess(std::addressof(debug_handle), m_cheat_process_metadata.process_id.value));
|
||||
|
||||
/* Set our debug handle. */
|
||||
this->cheat_process_debug_handle = debug_handle;
|
||||
m_cheat_process_debug_handle = debug_handle;
|
||||
|
||||
/* Cancel process guard. */
|
||||
proc_guard.Cancel();
|
||||
|
||||
/* Reset broken state. */
|
||||
this->broken_unsafe = false;
|
||||
this->unsafe_break_event.Signal();
|
||||
m_broken_unsafe = false;
|
||||
m_unsafe_break_event.Signal();
|
||||
|
||||
/* If new process, start the process. */
|
||||
if (on_process_launch) {
|
||||
this->StartProcess(this->cheat_process_metadata.process_id);
|
||||
this->StartProcess(m_cheat_process_metadata.process_id);
|
||||
}
|
||||
|
||||
/* Signal to the debug events thread. */
|
||||
this->debug_events_event.Signal();
|
||||
m_debug_events_event.Signal();
|
||||
|
||||
/* Signal to our fans. */
|
||||
this->cheat_process_event.Signal();
|
||||
m_cheat_process_event.Signal();
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
@@ -922,7 +922,7 @@ namespace ams::dmnt::cheat::impl {
|
||||
i = j + 1;
|
||||
} else if (s[i] == '{') {
|
||||
/* We're parsing a master cheat. */
|
||||
cur_entry = std::addressof(this->cheat_entries[0]);
|
||||
cur_entry = std::addressof(m_cheat_entries[0]);
|
||||
|
||||
/* There can only be one master cheat. */
|
||||
if (cur_entry->definition.num_opcodes > 0) {
|
||||
@@ -978,14 +978,14 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
/* Master cheat can't be disabled. */
|
||||
if (this->cheat_entries[0].definition.num_opcodes > 0) {
|
||||
this->cheat_entries[0].enabled = true;
|
||||
if (m_cheat_entries[0].definition.num_opcodes > 0) {
|
||||
m_cheat_entries[0].enabled = true;
|
||||
}
|
||||
|
||||
/* Enable all entries we parsed. */
|
||||
for (size_t i = 1; i < MaxCheatCount; i++) {
|
||||
if (this->cheat_entries[i].definition.num_opcodes > 0) {
|
||||
this->cheat_entries[i].enabled = this->enable_cheats_by_default;
|
||||
if (m_cheat_entries[i].definition.num_opcodes > 0) {
|
||||
m_cheat_entries[i].enabled = m_enable_cheats_by_default;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1098,7 +1098,7 @@ namespace ams::dmnt::cheat::impl {
|
||||
|
||||
bool CheatProcessManager::LoadCheatToggles(const ncm::ProgramId program_id) {
|
||||
/* Unless we successfully parse, don't save toggles on close. */
|
||||
this->should_save_cheat_toggles = false;
|
||||
m_should_save_cheat_toggles = false;
|
||||
|
||||
/* Open the file for program_id. */
|
||||
fs::FileHandle file;
|
||||
@@ -1130,8 +1130,8 @@ namespace ams::dmnt::cheat::impl {
|
||||
g_text_file_buffer[file_size] = '\x00';
|
||||
|
||||
/* Parse toggle buffer. */
|
||||
this->should_save_cheat_toggles = this->ParseCheatToggles(g_text_file_buffer, std::strlen(g_text_file_buffer));
|
||||
return this->should_save_cheat_toggles;
|
||||
m_should_save_cheat_toggles = this->ParseCheatToggles(g_text_file_buffer, std::strlen(g_text_file_buffer));
|
||||
return m_should_save_cheat_toggles;
|
||||
}
|
||||
|
||||
void CheatProcessManager::SaveCheatToggles(const ncm::ProgramId program_id) {
|
||||
@@ -1153,14 +1153,14 @@ namespace ams::dmnt::cheat::impl {
|
||||
|
||||
/* Save all non-master cheats. */
|
||||
for (size_t i = 1; i < MaxCheatCount; i++) {
|
||||
if (this->cheat_entries[i].definition.num_opcodes != 0) {
|
||||
util::SNPrintf(buf, sizeof(buf), "[%s]\n", this->cheat_entries[i].definition.readable_name);
|
||||
if (m_cheat_entries[i].definition.num_opcodes != 0) {
|
||||
util::SNPrintf(buf, sizeof(buf), "[%s]\n", m_cheat_entries[i].definition.readable_name);
|
||||
const size_t name_len = std::strlen(buf);
|
||||
if (R_SUCCEEDED(fs::WriteFile(file, offset, buf, name_len, fs::WriteOption::Flush))) {
|
||||
offset += name_len;
|
||||
}
|
||||
|
||||
const char *entry = this->cheat_entries[i].enabled ? "true\n" : "false\n";
|
||||
const char *entry = m_cheat_entries[i].enabled ? "true\n" : "false\n";
|
||||
const size_t entry_len = std::strlen(entry);
|
||||
if (R_SUCCEEDED(fs::WriteFile(file, offset, entry, entry_len, fs::WriteOption::Flush))) {
|
||||
offset += entry_len;
|
||||
|
||||
@@ -27,13 +27,13 @@ namespace ams::dmnt::cheat::impl {
|
||||
static constexpr size_t NumCores = 4;
|
||||
static constexpr size_t ThreadStackSize = os::MemoryPageSize;
|
||||
private:
|
||||
std::array<uintptr_t, NumCores> handle_message_queue_buffers;
|
||||
std::array<uintptr_t, NumCores> result_message_queue_buffers;
|
||||
std::array<os::MessageQueue, NumCores> handle_message_queues;
|
||||
std::array<os::MessageQueue, NumCores> result_message_queues;
|
||||
std::array<os::ThreadType, NumCores> threads;
|
||||
std::array<uintptr_t, NumCores> m_handle_message_queue_buffers;
|
||||
std::array<uintptr_t, NumCores> m_result_message_queue_buffers;
|
||||
std::array<os::MessageQueue, NumCores> m_handle_message_queues;
|
||||
std::array<os::MessageQueue, NumCores> m_result_message_queues;
|
||||
std::array<os::ThreadType, NumCores> m_threads;
|
||||
|
||||
alignas(os::MemoryPageSize) u8 thread_stacks[NumCores][ThreadStackSize];
|
||||
alignas(os::MemoryPageSize) u8 m_thread_stacks[NumCores][ThreadStackSize];
|
||||
private:
|
||||
static void PerCoreThreadFunction(void *_this) {
|
||||
/* This thread will wait on the appropriate message queue. */
|
||||
@@ -73,12 +73,12 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
void SendHandle(size_t target_core, os::NativeHandle debug_handle) {
|
||||
this->handle_message_queues[target_core].Send(static_cast<uintptr_t>(debug_handle));
|
||||
m_handle_message_queues[target_core].Send(static_cast<uintptr_t>(debug_handle));
|
||||
}
|
||||
|
||||
os::NativeHandle WaitReceiveHandle(size_t core_id) {
|
||||
uintptr_t x = 0;
|
||||
this->handle_message_queues[core_id].Receive(&x);
|
||||
m_handle_message_queues[core_id].Receive(&x);
|
||||
return static_cast<os::NativeHandle>(x);
|
||||
}
|
||||
|
||||
@@ -91,38 +91,38 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
void SendContinueResult(size_t target_core, Result result) {
|
||||
this->result_message_queues[target_core].Send(static_cast<uintptr_t>(result.GetValue()));
|
||||
m_result_message_queues[target_core].Send(static_cast<uintptr_t>(result.GetValue()));
|
||||
}
|
||||
|
||||
Result GetContinueResult(size_t core_id) {
|
||||
uintptr_t x = 0;
|
||||
this->result_message_queues[core_id].Receive(&x);
|
||||
m_result_message_queues[core_id].Receive(&x);
|
||||
return static_cast<Result>(x);
|
||||
}
|
||||
public:
|
||||
DebugEventsManager()
|
||||
: handle_message_queues{
|
||||
os::MessageQueue(std::addressof(handle_message_queue_buffers[0]), 1),
|
||||
os::MessageQueue(std::addressof(handle_message_queue_buffers[1]), 1),
|
||||
os::MessageQueue(std::addressof(handle_message_queue_buffers[2]), 1),
|
||||
os::MessageQueue(std::addressof(handle_message_queue_buffers[3]), 1)},
|
||||
result_message_queues{
|
||||
os::MessageQueue(std::addressof(result_message_queue_buffers[0]), 1),
|
||||
os::MessageQueue(std::addressof(result_message_queue_buffers[1]), 1),
|
||||
os::MessageQueue(std::addressof(result_message_queue_buffers[2]), 1),
|
||||
os::MessageQueue(std::addressof(result_message_queue_buffers[3]), 1)},
|
||||
thread_stacks{}
|
||||
: m_handle_message_queues{
|
||||
os::MessageQueue(std::addressof(m_handle_message_queue_buffers[0]), 1),
|
||||
os::MessageQueue(std::addressof(m_handle_message_queue_buffers[1]), 1),
|
||||
os::MessageQueue(std::addressof(m_handle_message_queue_buffers[2]), 1),
|
||||
os::MessageQueue(std::addressof(m_handle_message_queue_buffers[3]), 1)},
|
||||
m_result_message_queues{
|
||||
os::MessageQueue(std::addressof(m_result_message_queue_buffers[0]), 1),
|
||||
os::MessageQueue(std::addressof(m_result_message_queue_buffers[1]), 1),
|
||||
os::MessageQueue(std::addressof(m_result_message_queue_buffers[2]), 1),
|
||||
os::MessageQueue(std::addressof(m_result_message_queue_buffers[3]), 1)},
|
||||
m_thread_stacks{}
|
||||
{
|
||||
for (size_t i = 0; i < NumCores; i++) {
|
||||
/* Create thread. */
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(this->threads[i]), PerCoreThreadFunction, this, this->thread_stacks[i], ThreadStackSize, AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, MultiCoreEventManager), i));
|
||||
os::SetThreadNamePointer(std::addressof(this->threads[i]), AMS_GET_SYSTEM_THREAD_NAME(dmnt, MultiCoreEventManager));
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(m_threads[i]), PerCoreThreadFunction, this, m_thread_stacks[i], ThreadStackSize, AMS_GET_SYSTEM_THREAD_PRIORITY(dmnt, MultiCoreEventManager), i));
|
||||
os::SetThreadNamePointer(std::addressof(m_threads[i]), AMS_GET_SYSTEM_THREAD_NAME(dmnt, MultiCoreEventManager));
|
||||
|
||||
/* Set core mask. */
|
||||
os::SetThreadCoreMask(std::addressof(this->threads[i]), i, (1u << i));
|
||||
os::SetThreadCoreMask(std::addressof(m_threads[i]), i, (1u << i));
|
||||
|
||||
/* Start thread. */
|
||||
os::StartThread(std::addressof(this->threads[i]));
|
||||
os::StartThread(std::addressof(m_threads[i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,41 +46,41 @@ namespace ams::dmnt::cheat::impl {
|
||||
void CheatVirtualMachine::OpenDebugLogFile() {
|
||||
#ifdef DMNT_CHEAT_VM_DEBUG_LOG
|
||||
CloseDebugLogFile();
|
||||
R_ABORT_UNLESS(fs::OpenFile(std::addressof(this->debug_log_file), "sdmc:/atmosphere/cheat_vm_logs/debug_log.txt"));
|
||||
this->debug_log_file_offset = 0;
|
||||
R_ABORT_UNLESS(fs::OpenFile(std::addressof(m_debug_log_file), "sdmc:/atmosphere/cheat_vm_logs/debug_log.txt"));
|
||||
m_debug_log_file_offset = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CheatVirtualMachine::CloseDebugLogFile() {
|
||||
#ifdef DMNT_CHEAT_VM_DEBUG_LOG
|
||||
if (this->has_debug_log_file) {
|
||||
fs::CloseFile(this->debug_log_file);
|
||||
if (m_has_debug_log_file) {
|
||||
fs::CloseFile(m_debug_log_file);
|
||||
}
|
||||
this->has_debug_log_file = false;
|
||||
m_has_debug_log_file = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CheatVirtualMachine::LogToDebugFile(const char *format, ...) {
|
||||
#ifdef DMNT_CHEAT_VM_DEBUG_LOG
|
||||
if (!this->has_debug_log_file) {
|
||||
if (!m_has_debug_log_file) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
std::va_list vl;
|
||||
va_start(vl, format);
|
||||
util::VSNPrintf(this->debug_log_format_buf, sizeof(this->debug_log_format_buf) - 1, format, vl);
|
||||
util::VSNPrintf(m_debug_log_format_buf, sizeof(m_debug_log_format_buf) - 1, format, vl);
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
size_t fmt_len = std::strlen(this->debug_log_format_buf);
|
||||
if (this->debug_log_format_buf[fmt_len - 1] != '\n') {
|
||||
this->debug_log_format_buf[fmt_len + 0] = '\n';
|
||||
this->debug_log_format_buf[fmt_len + 1] = '\x00';
|
||||
size_t fmt_len = std::strlen(m_debug_log_format_buf);
|
||||
if (m_debug_log_format_buf[fmt_len - 1] != '\n') {
|
||||
m_debug_log_format_buf[fmt_len + 0] = '\n';
|
||||
m_debug_log_format_buf[fmt_len + 1] = '\x00';
|
||||
fmt_len += 1;
|
||||
}
|
||||
|
||||
fs::WriteFile(this->debug_log_file, this->debug_log_offset, this->debug_log_format_buf, fmt_len, fs::WriteOption::Flush);
|
||||
fs::WriteFile(m_debug_log_file, m_debug_log_offset, m_debug_log_format_buf, fmt_len, fs::WriteOption::Flush);
|
||||
#else
|
||||
AMS_UNUSED(format);
|
||||
#endif
|
||||
@@ -295,10 +295,10 @@ namespace ams::dmnt::cheat::impl {
|
||||
|
||||
bool CheatVirtualMachine::DecodeNextOpcode(CheatVmOpcode *out) {
|
||||
/* If we've ever seen a decode failure, return false. */
|
||||
bool valid = this->decode_success;
|
||||
bool valid = m_decode_success;
|
||||
CheatVmOpcode opcode = {};
|
||||
ON_SCOPE_EXIT {
|
||||
this->decode_success &= valid;
|
||||
m_decode_success &= valid;
|
||||
if (valid) {
|
||||
*out = opcode;
|
||||
}
|
||||
@@ -306,11 +306,11 @@ namespace ams::dmnt::cheat::impl {
|
||||
|
||||
/* Helper function for getting instruction dwords. */
|
||||
auto GetNextDword = [&]() {
|
||||
if (this->instruction_ptr >= this->num_opcodes) {
|
||||
if (m_instruction_ptr >= m_num_opcodes) {
|
||||
valid = false;
|
||||
return static_cast<u32>(0);
|
||||
}
|
||||
return this->program[this->instruction_ptr++];
|
||||
return m_program[m_instruction_ptr++];
|
||||
};
|
||||
|
||||
/* Helper function for parsing a VmInt. */
|
||||
@@ -671,12 +671,12 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
void CheatVirtualMachine::SkipConditionalBlock(bool is_if) {
|
||||
if (this->condition_depth > 0) {
|
||||
if (m_condition_depth > 0) {
|
||||
/* We want to continue until we're out of the current block. */
|
||||
const size_t desired_depth = this->condition_depth - 1;
|
||||
const size_t desired_depth = m_condition_depth - 1;
|
||||
|
||||
CheatVmOpcode skip_opcode;
|
||||
while (this->condition_depth > desired_depth && this->DecodeNextOpcode(std::addressof(skip_opcode))) {
|
||||
while (m_condition_depth > desired_depth && this->DecodeNextOpcode(std::addressof(skip_opcode))) {
|
||||
/* Decode instructions until we see end of the current conditional block. */
|
||||
/* NOTE: This is broken in gateway's implementation. */
|
||||
/* Gateway currently checks for "0x2" instead of "0x20000000" */
|
||||
@@ -685,18 +685,18 @@ namespace ams::dmnt::cheat::impl {
|
||||
|
||||
/* We also support nesting of conditional blocks, and Gateway does not. */
|
||||
if (skip_opcode.begin_conditional_block) {
|
||||
this->condition_depth++;
|
||||
m_condition_depth++;
|
||||
} else if (skip_opcode.opcode == CheatVmOpcodeType_EndConditionalBlock) {
|
||||
if (!skip_opcode.end_cond.is_else) {
|
||||
this->condition_depth--;
|
||||
} else if (is_if && this->condition_depth - 1 == desired_depth) {
|
||||
m_condition_depth--;
|
||||
} else if (is_if && m_condition_depth - 1 == desired_depth) {
|
||||
/* An if will continue to an else at the same depth. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Skipping, but this->condition_depth = 0. */
|
||||
/* Skipping, but m_condition_depth = 0. */
|
||||
/* This is an error condition. */
|
||||
/* This could occur with a mismatched "else" opcode, for example. */
|
||||
R_ABORT_UNLESS(ResultVirtualMachineInvalidConditionDepth());
|
||||
@@ -735,29 +735,29 @@ namespace ams::dmnt::cheat::impl {
|
||||
|
||||
void CheatVirtualMachine::ResetState() {
|
||||
for (size_t i = 0; i < CheatVirtualMachine::NumRegisters; i++) {
|
||||
this->registers[i] = 0;
|
||||
this->saved_values[i] = 0;
|
||||
this->loop_tops[i] = 0;
|
||||
m_registers[i] = 0;
|
||||
m_saved_values[i] = 0;
|
||||
m_loop_tops[i] = 0;
|
||||
}
|
||||
this->instruction_ptr = 0;
|
||||
this->condition_depth = 0;
|
||||
this->decode_success = true;
|
||||
m_instruction_ptr = 0;
|
||||
m_condition_depth = 0;
|
||||
m_decode_success = true;
|
||||
}
|
||||
|
||||
bool CheatVirtualMachine::LoadProgram(const CheatEntry *cheats, size_t num_cheats) {
|
||||
/* Reset opcode count. */
|
||||
this->num_opcodes = 0;
|
||||
m_num_opcodes = 0;
|
||||
|
||||
for (size_t i = 0; i < num_cheats; i++) {
|
||||
if (cheats[i].enabled) {
|
||||
/* Bounds check. */
|
||||
if (cheats[i].definition.num_opcodes + this->num_opcodes > MaximumProgramOpcodeCount) {
|
||||
this->num_opcodes = 0;
|
||||
if (cheats[i].definition.num_opcodes + m_num_opcodes > MaximumProgramOpcodeCount) {
|
||||
m_num_opcodes = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t n = 0; n < cheats[i].definition.num_opcodes; n++) {
|
||||
this->program[this->num_opcodes++] = cheats[i].definition.opcodes[n];
|
||||
m_program[m_num_opcodes++] = cheats[i].definition.opcodes[n];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -785,27 +785,27 @@ namespace ams::dmnt::cheat::impl {
|
||||
|
||||
/* Loop until program finishes. */
|
||||
while (this->DecodeNextOpcode(std::addressof(cur_opcode))) {
|
||||
this->LogToDebugFile("Instruction Ptr: %04x\n", (u32)this->instruction_ptr);
|
||||
this->LogToDebugFile("Instruction Ptr: %04x\n", (u32)m_instruction_ptr);
|
||||
|
||||
for (size_t i = 0; i < NumRegisters; i++) {
|
||||
this->LogToDebugFile("Registers[%02x]: %016lx\n", i, this->registers[i]);
|
||||
this->LogToDebugFile("Registers[%02x]: %016lx\n", i, m_registers[i]);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < NumRegisters; i++) {
|
||||
this->LogToDebugFile("SavedRegs[%02x]: %016lx\n", i, this->saved_values[i]);
|
||||
this->LogToDebugFile("SavedRegs[%02x]: %016lx\n", i, m_saved_values[i]);
|
||||
}
|
||||
this->LogOpcode(std::addressof(cur_opcode));
|
||||
|
||||
/* Increment conditional depth, if relevant. */
|
||||
if (cur_opcode.begin_conditional_block) {
|
||||
this->condition_depth++;
|
||||
m_condition_depth++;
|
||||
}
|
||||
|
||||
switch (cur_opcode.opcode) {
|
||||
case CheatVmOpcodeType_StoreStatic:
|
||||
{
|
||||
/* Calculate address, write value to memory. */
|
||||
u64 dst_address = GetCheatProcessAddress(metadata, cur_opcode.store_static.mem_type, cur_opcode.store_static.rel_address + this->registers[cur_opcode.store_static.offset_register]);
|
||||
u64 dst_address = GetCheatProcessAddress(metadata, cur_opcode.store_static.mem_type, cur_opcode.store_static.rel_address + m_registers[cur_opcode.store_static.offset_register]);
|
||||
u64 dst_value = GetVmInt(cur_opcode.store_static.value, cur_opcode.store_static.bit_width);
|
||||
switch (cur_opcode.store_static.bit_width) {
|
||||
case 1:
|
||||
@@ -866,34 +866,34 @@ namespace ams::dmnt::cheat::impl {
|
||||
} else {
|
||||
/* Decrement the condition depth. */
|
||||
/* We will assume, graciously, that mismatched conditional block ends are a nop. */
|
||||
if (this->condition_depth > 0) {
|
||||
this->condition_depth--;
|
||||
if (m_condition_depth > 0) {
|
||||
m_condition_depth--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_ControlLoop:
|
||||
if (cur_opcode.ctrl_loop.start_loop) {
|
||||
/* Start a loop. */
|
||||
this->registers[cur_opcode.ctrl_loop.reg_index] = cur_opcode.ctrl_loop.num_iters;
|
||||
this->loop_tops[cur_opcode.ctrl_loop.reg_index] = this->instruction_ptr;
|
||||
m_registers[cur_opcode.ctrl_loop.reg_index] = cur_opcode.ctrl_loop.num_iters;
|
||||
m_loop_tops[cur_opcode.ctrl_loop.reg_index] = m_instruction_ptr;
|
||||
} else {
|
||||
/* End a loop. */
|
||||
this->registers[cur_opcode.ctrl_loop.reg_index]--;
|
||||
if (this->registers[cur_opcode.ctrl_loop.reg_index] != 0) {
|
||||
this->instruction_ptr = this->loop_tops[cur_opcode.ctrl_loop.reg_index];
|
||||
m_registers[cur_opcode.ctrl_loop.reg_index]--;
|
||||
if (m_registers[cur_opcode.ctrl_loop.reg_index] != 0) {
|
||||
m_instruction_ptr = m_loop_tops[cur_opcode.ctrl_loop.reg_index];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_LoadRegisterStatic:
|
||||
/* Set a register to a static value. */
|
||||
this->registers[cur_opcode.ldr_static.reg_index] = cur_opcode.ldr_static.value;
|
||||
m_registers[cur_opcode.ldr_static.reg_index] = cur_opcode.ldr_static.value;
|
||||
break;
|
||||
case CheatVmOpcodeType_LoadRegisterMemory:
|
||||
{
|
||||
/* Choose source address. */
|
||||
u64 src_address;
|
||||
if (cur_opcode.ldr_memory.load_from_reg) {
|
||||
src_address = this->registers[cur_opcode.ldr_memory.reg_index] + cur_opcode.ldr_memory.rel_address;
|
||||
src_address = m_registers[cur_opcode.ldr_memory.reg_index] + cur_opcode.ldr_memory.rel_address;
|
||||
} else {
|
||||
src_address = GetCheatProcessAddress(metadata, cur_opcode.ldr_memory.mem_type, cur_opcode.ldr_memory.rel_address);
|
||||
}
|
||||
@@ -903,7 +903,7 @@ namespace ams::dmnt::cheat::impl {
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
dmnt::cheat::impl::ReadCheatProcessMemoryUnsafe(src_address, std::addressof(this->registers[cur_opcode.ldr_memory.reg_index]), cur_opcode.ldr_memory.bit_width);
|
||||
dmnt::cheat::impl::ReadCheatProcessMemoryUnsafe(src_address, std::addressof(m_registers[cur_opcode.ldr_memory.reg_index]), cur_opcode.ldr_memory.bit_width);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -911,10 +911,10 @@ namespace ams::dmnt::cheat::impl {
|
||||
case CheatVmOpcodeType_StoreStaticToAddress:
|
||||
{
|
||||
/* Calculate address. */
|
||||
u64 dst_address = this->registers[cur_opcode.str_static.reg_index];
|
||||
u64 dst_address = m_registers[cur_opcode.str_static.reg_index];
|
||||
u64 dst_value = cur_opcode.str_static.value;
|
||||
if (cur_opcode.str_static.add_offset_reg) {
|
||||
dst_address += this->registers[cur_opcode.str_static.offset_reg_index];
|
||||
dst_address += m_registers[cur_opcode.str_static.offset_reg_index];
|
||||
}
|
||||
/* Write value to memory. Gateway only writes on valid bitwidth. */
|
||||
switch (cur_opcode.str_static.bit_width) {
|
||||
@@ -927,7 +927,7 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
/* Increment register if relevant. */
|
||||
if (cur_opcode.str_static.increment_reg) {
|
||||
this->registers[cur_opcode.str_static.reg_index] += cur_opcode.str_static.bit_width;
|
||||
m_registers[cur_opcode.str_static.reg_index] += cur_opcode.str_static.bit_width;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -936,19 +936,19 @@ namespace ams::dmnt::cheat::impl {
|
||||
/* Do requested math. */
|
||||
switch (cur_opcode.perform_math_static.math_type) {
|
||||
case RegisterArithmeticType_Addition:
|
||||
this->registers[cur_opcode.perform_math_static.reg_index] += (u64)cur_opcode.perform_math_static.value;
|
||||
m_registers[cur_opcode.perform_math_static.reg_index] += (u64)cur_opcode.perform_math_static.value;
|
||||
break;
|
||||
case RegisterArithmeticType_Subtraction:
|
||||
this->registers[cur_opcode.perform_math_static.reg_index] -= (u64)cur_opcode.perform_math_static.value;
|
||||
m_registers[cur_opcode.perform_math_static.reg_index] -= (u64)cur_opcode.perform_math_static.value;
|
||||
break;
|
||||
case RegisterArithmeticType_Multiplication:
|
||||
this->registers[cur_opcode.perform_math_static.reg_index] *= (u64)cur_opcode.perform_math_static.value;
|
||||
m_registers[cur_opcode.perform_math_static.reg_index] *= (u64)cur_opcode.perform_math_static.value;
|
||||
break;
|
||||
case RegisterArithmeticType_LeftShift:
|
||||
this->registers[cur_opcode.perform_math_static.reg_index] <<= (u64)cur_opcode.perform_math_static.value;
|
||||
m_registers[cur_opcode.perform_math_static.reg_index] <<= (u64)cur_opcode.perform_math_static.value;
|
||||
break;
|
||||
case RegisterArithmeticType_RightShift:
|
||||
this->registers[cur_opcode.perform_math_static.reg_index] >>= (u64)cur_opcode.perform_math_static.value;
|
||||
m_registers[cur_opcode.perform_math_static.reg_index] >>= (u64)cur_opcode.perform_math_static.value;
|
||||
break;
|
||||
default:
|
||||
/* Do not handle extensions here. */
|
||||
@@ -957,16 +957,16 @@ namespace ams::dmnt::cheat::impl {
|
||||
/* Apply bit width. */
|
||||
switch (cur_opcode.perform_math_static.bit_width) {
|
||||
case 1:
|
||||
this->registers[cur_opcode.perform_math_static.reg_index] = static_cast<u8>(this->registers[cur_opcode.perform_math_static.reg_index]);
|
||||
m_registers[cur_opcode.perform_math_static.reg_index] = static_cast<u8>(m_registers[cur_opcode.perform_math_static.reg_index]);
|
||||
break;
|
||||
case 2:
|
||||
this->registers[cur_opcode.perform_math_static.reg_index] = static_cast<u16>(this->registers[cur_opcode.perform_math_static.reg_index]);
|
||||
m_registers[cur_opcode.perform_math_static.reg_index] = static_cast<u16>(m_registers[cur_opcode.perform_math_static.reg_index]);
|
||||
break;
|
||||
case 4:
|
||||
this->registers[cur_opcode.perform_math_static.reg_index] = static_cast<u32>(this->registers[cur_opcode.perform_math_static.reg_index]);
|
||||
m_registers[cur_opcode.perform_math_static.reg_index] = static_cast<u32>(m_registers[cur_opcode.perform_math_static.reg_index]);
|
||||
break;
|
||||
case 8:
|
||||
this->registers[cur_opcode.perform_math_static.reg_index] = static_cast<u64>(this->registers[cur_opcode.perform_math_static.reg_index]);
|
||||
m_registers[cur_opcode.perform_math_static.reg_index] = static_cast<u64>(m_registers[cur_opcode.perform_math_static.reg_index]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -980,10 +980,10 @@ namespace ams::dmnt::cheat::impl {
|
||||
break;
|
||||
case CheatVmOpcodeType_PerformArithmeticRegister:
|
||||
{
|
||||
const u64 operand_1_value = this->registers[cur_opcode.perform_math_reg.src_reg_1_index];
|
||||
const u64 operand_1_value = m_registers[cur_opcode.perform_math_reg.src_reg_1_index];
|
||||
const u64 operand_2_value = cur_opcode.perform_math_reg.has_immediate ?
|
||||
GetVmInt(cur_opcode.perform_math_reg.value, cur_opcode.perform_math_reg.bit_width) :
|
||||
this->registers[cur_opcode.perform_math_reg.src_reg_2_index];
|
||||
m_registers[cur_opcode.perform_math_reg.src_reg_2_index];
|
||||
|
||||
u64 res_val = 0;
|
||||
/* Do requested math. */
|
||||
@@ -1038,32 +1038,32 @@ namespace ams::dmnt::cheat::impl {
|
||||
}
|
||||
|
||||
/* Save to register. */
|
||||
this->registers[cur_opcode.perform_math_reg.dst_reg_index] = res_val;
|
||||
m_registers[cur_opcode.perform_math_reg.dst_reg_index] = res_val;
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_StoreRegisterToAddress:
|
||||
{
|
||||
/* Calculate address. */
|
||||
u64 dst_value = this->registers[cur_opcode.str_register.str_reg_index];
|
||||
u64 dst_address = this->registers[cur_opcode.str_register.addr_reg_index];
|
||||
u64 dst_value = m_registers[cur_opcode.str_register.str_reg_index];
|
||||
u64 dst_address = m_registers[cur_opcode.str_register.addr_reg_index];
|
||||
switch (cur_opcode.str_register.ofs_type) {
|
||||
case StoreRegisterOffsetType_None:
|
||||
/* Nothing more to do */
|
||||
break;
|
||||
case StoreRegisterOffsetType_Reg:
|
||||
dst_address += this->registers[cur_opcode.str_register.ofs_reg_index];
|
||||
dst_address += m_registers[cur_opcode.str_register.ofs_reg_index];
|
||||
break;
|
||||
case StoreRegisterOffsetType_Imm:
|
||||
dst_address += cur_opcode.str_register.rel_address;
|
||||
break;
|
||||
case StoreRegisterOffsetType_MemReg:
|
||||
dst_address = GetCheatProcessAddress(metadata, cur_opcode.str_register.mem_type, this->registers[cur_opcode.str_register.addr_reg_index]);
|
||||
dst_address = GetCheatProcessAddress(metadata, cur_opcode.str_register.mem_type, m_registers[cur_opcode.str_register.addr_reg_index]);
|
||||
break;
|
||||
case StoreRegisterOffsetType_MemImm:
|
||||
dst_address = GetCheatProcessAddress(metadata, cur_opcode.str_register.mem_type, cur_opcode.str_register.rel_address);
|
||||
break;
|
||||
case StoreRegisterOffsetType_MemImmReg:
|
||||
dst_address = GetCheatProcessAddress(metadata, cur_opcode.str_register.mem_type, this->registers[cur_opcode.str_register.addr_reg_index] + cur_opcode.str_register.rel_address);
|
||||
dst_address = GetCheatProcessAddress(metadata, cur_opcode.str_register.mem_type, m_registers[cur_opcode.str_register.addr_reg_index] + cur_opcode.str_register.rel_address);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1079,7 +1079,7 @@ namespace ams::dmnt::cheat::impl {
|
||||
|
||||
/* Increment register if relevant. */
|
||||
if (cur_opcode.str_register.increment_reg) {
|
||||
this->registers[cur_opcode.str_register.addr_reg_index] += cur_opcode.str_register.bit_width;
|
||||
m_registers[cur_opcode.str_register.addr_reg_index] += cur_opcode.str_register.bit_width;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1089,16 +1089,16 @@ namespace ams::dmnt::cheat::impl {
|
||||
u64 src_value = 0;
|
||||
switch (cur_opcode.begin_reg_cond.bit_width) {
|
||||
case 1:
|
||||
src_value = static_cast<u8>(this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFul);
|
||||
src_value = static_cast<u8>(m_registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFul);
|
||||
break;
|
||||
case 2:
|
||||
src_value = static_cast<u16>(this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFFFul);
|
||||
src_value = static_cast<u16>(m_registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFFFul);
|
||||
break;
|
||||
case 4:
|
||||
src_value = static_cast<u32>(this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFFFFFFFul);
|
||||
src_value = static_cast<u32>(m_registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFFFFFFFul);
|
||||
break;
|
||||
case 8:
|
||||
src_value = static_cast<u64>(this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFFFFFFFFFFFFFFFul);
|
||||
src_value = static_cast<u64>(m_registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFFFFFFFFFFFFFFFul);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1109,16 +1109,16 @@ namespace ams::dmnt::cheat::impl {
|
||||
} else if (cur_opcode.begin_reg_cond.comp_type == CompareRegisterValueType_OtherRegister) {
|
||||
switch (cur_opcode.begin_reg_cond.bit_width) {
|
||||
case 1:
|
||||
cond_value = static_cast<u8>(this->registers[cur_opcode.begin_reg_cond.other_reg_index] & 0xFFul);
|
||||
cond_value = static_cast<u8>(m_registers[cur_opcode.begin_reg_cond.other_reg_index] & 0xFFul);
|
||||
break;
|
||||
case 2:
|
||||
cond_value = static_cast<u16>(this->registers[cur_opcode.begin_reg_cond.other_reg_index] & 0xFFFFul);
|
||||
cond_value = static_cast<u16>(m_registers[cur_opcode.begin_reg_cond.other_reg_index] & 0xFFFFul);
|
||||
break;
|
||||
case 4:
|
||||
cond_value = static_cast<u32>(this->registers[cur_opcode.begin_reg_cond.other_reg_index] & 0xFFFFFFFFul);
|
||||
cond_value = static_cast<u32>(m_registers[cur_opcode.begin_reg_cond.other_reg_index] & 0xFFFFFFFFul);
|
||||
break;
|
||||
case 8:
|
||||
cond_value = static_cast<u64>(this->registers[cur_opcode.begin_reg_cond.other_reg_index] & 0xFFFFFFFFFFFFFFFFul);
|
||||
cond_value = static_cast<u64>(m_registers[cur_opcode.begin_reg_cond.other_reg_index] & 0xFFFFFFFFFFFFFFFFul);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@@ -1128,13 +1128,13 @@ namespace ams::dmnt::cheat::impl {
|
||||
cond_address = GetCheatProcessAddress(metadata, cur_opcode.begin_reg_cond.mem_type, cur_opcode.begin_reg_cond.rel_address);
|
||||
break;
|
||||
case CompareRegisterValueType_MemoryOfsReg:
|
||||
cond_address = GetCheatProcessAddress(metadata, cur_opcode.begin_reg_cond.mem_type, this->registers[cur_opcode.begin_reg_cond.ofs_reg_index]);
|
||||
cond_address = GetCheatProcessAddress(metadata, cur_opcode.begin_reg_cond.mem_type, m_registers[cur_opcode.begin_reg_cond.ofs_reg_index]);
|
||||
break;
|
||||
case CompareRegisterValueType_RegisterRelAddr:
|
||||
cond_address = this->registers[cur_opcode.begin_reg_cond.addr_reg_index] + cur_opcode.begin_reg_cond.rel_address;
|
||||
cond_address = m_registers[cur_opcode.begin_reg_cond.addr_reg_index] + cur_opcode.begin_reg_cond.rel_address;
|
||||
break;
|
||||
case CompareRegisterValueType_RegisterOfsReg:
|
||||
cond_address = this->registers[cur_opcode.begin_reg_cond.addr_reg_index] + this->registers[cur_opcode.begin_reg_cond.ofs_reg_index];
|
||||
cond_address = m_registers[cur_opcode.begin_reg_cond.addr_reg_index] + m_registers[cur_opcode.begin_reg_cond.ofs_reg_index];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -1182,17 +1182,17 @@ namespace ams::dmnt::cheat::impl {
|
||||
/* Save or restore a register. */
|
||||
switch (cur_opcode.save_restore_reg.op_type) {
|
||||
case SaveRestoreRegisterOpType_ClearRegs:
|
||||
this->registers[cur_opcode.save_restore_reg.dst_index] = 0ul;
|
||||
m_registers[cur_opcode.save_restore_reg.dst_index] = 0ul;
|
||||
break;
|
||||
case SaveRestoreRegisterOpType_ClearSaved:
|
||||
this->saved_values[cur_opcode.save_restore_reg.dst_index] = 0ul;
|
||||
m_saved_values[cur_opcode.save_restore_reg.dst_index] = 0ul;
|
||||
break;
|
||||
case SaveRestoreRegisterOpType_Save:
|
||||
this->saved_values[cur_opcode.save_restore_reg.dst_index] = this->registers[cur_opcode.save_restore_reg.src_index];
|
||||
m_saved_values[cur_opcode.save_restore_reg.dst_index] = m_registers[cur_opcode.save_restore_reg.src_index];
|
||||
break;
|
||||
case SaveRestoreRegisterOpType_Restore:
|
||||
default:
|
||||
this->registers[cur_opcode.save_restore_reg.dst_index] = this->saved_values[cur_opcode.save_restore_reg.src_index];
|
||||
m_registers[cur_opcode.save_restore_reg.dst_index] = m_saved_values[cur_opcode.save_restore_reg.src_index];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -1203,14 +1203,14 @@ namespace ams::dmnt::cheat::impl {
|
||||
switch (cur_opcode.save_restore_regmask.op_type) {
|
||||
case SaveRestoreRegisterOpType_ClearSaved:
|
||||
case SaveRestoreRegisterOpType_Save:
|
||||
src = this->registers;
|
||||
dst = this->saved_values;
|
||||
src = m_registers;
|
||||
dst = m_saved_values;
|
||||
break;
|
||||
case SaveRestoreRegisterOpType_ClearRegs:
|
||||
case SaveRestoreRegisterOpType_Restore:
|
||||
default:
|
||||
src = this->saved_values;
|
||||
dst = this->registers;
|
||||
src = m_saved_values;
|
||||
dst = m_registers;
|
||||
break;
|
||||
}
|
||||
for (size_t i = 0; i < NumRegisters; i++) {
|
||||
@@ -1232,10 +1232,10 @@ namespace ams::dmnt::cheat::impl {
|
||||
case CheatVmOpcodeType_ReadWriteStaticRegister:
|
||||
if (cur_opcode.rw_static_reg.static_idx < NumReadableStaticRegisters) {
|
||||
/* Load a register with a static register. */
|
||||
this->registers[cur_opcode.rw_static_reg.idx] = this->static_registers[cur_opcode.rw_static_reg.static_idx];
|
||||
m_registers[cur_opcode.rw_static_reg.idx] = m_static_registers[cur_opcode.rw_static_reg.static_idx];
|
||||
} else {
|
||||
/* Store a register to a static register. */
|
||||
this->static_registers[cur_opcode.rw_static_reg.static_idx] = this->registers[cur_opcode.rw_static_reg.idx];
|
||||
m_static_registers[cur_opcode.rw_static_reg.static_idx] = m_registers[cur_opcode.rw_static_reg.idx];
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_PauseProcess:
|
||||
@@ -1251,16 +1251,16 @@ namespace ams::dmnt::cheat::impl {
|
||||
if (cur_opcode.debug_log.val_type == DebugLogValueType_RegisterValue) {
|
||||
switch (cur_opcode.debug_log.bit_width) {
|
||||
case 1:
|
||||
log_value = static_cast<u8>(this->registers[cur_opcode.debug_log.val_reg_index] & 0xFFul);
|
||||
log_value = static_cast<u8>(m_registers[cur_opcode.debug_log.val_reg_index] & 0xFFul);
|
||||
break;
|
||||
case 2:
|
||||
log_value = static_cast<u16>(this->registers[cur_opcode.debug_log.val_reg_index] & 0xFFFFul);
|
||||
log_value = static_cast<u16>(m_registers[cur_opcode.debug_log.val_reg_index] & 0xFFFFul);
|
||||
break;
|
||||
case 4:
|
||||
log_value = static_cast<u32>(this->registers[cur_opcode.debug_log.val_reg_index] & 0xFFFFFFFFul);
|
||||
log_value = static_cast<u32>(m_registers[cur_opcode.debug_log.val_reg_index] & 0xFFFFFFFFul);
|
||||
break;
|
||||
case 8:
|
||||
log_value = static_cast<u64>(this->registers[cur_opcode.debug_log.val_reg_index] & 0xFFFFFFFFFFFFFFFFul);
|
||||
log_value = static_cast<u64>(m_registers[cur_opcode.debug_log.val_reg_index] & 0xFFFFFFFFFFFFFFFFul);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@@ -1270,13 +1270,13 @@ namespace ams::dmnt::cheat::impl {
|
||||
val_address = GetCheatProcessAddress(metadata, cur_opcode.debug_log.mem_type, cur_opcode.debug_log.rel_address);
|
||||
break;
|
||||
case DebugLogValueType_MemoryOfsReg:
|
||||
val_address = GetCheatProcessAddress(metadata, cur_opcode.debug_log.mem_type, this->registers[cur_opcode.debug_log.ofs_reg_index]);
|
||||
val_address = GetCheatProcessAddress(metadata, cur_opcode.debug_log.mem_type, m_registers[cur_opcode.debug_log.ofs_reg_index]);
|
||||
break;
|
||||
case DebugLogValueType_RegisterRelAddr:
|
||||
val_address = this->registers[cur_opcode.debug_log.addr_reg_index] + cur_opcode.debug_log.rel_address;
|
||||
val_address = m_registers[cur_opcode.debug_log.addr_reg_index] + cur_opcode.debug_log.rel_address;
|
||||
break;
|
||||
case DebugLogValueType_RegisterOfsReg:
|
||||
val_address = this->registers[cur_opcode.debug_log.addr_reg_index] + this->registers[cur_opcode.debug_log.ofs_reg_index];
|
||||
val_address = m_registers[cur_opcode.debug_log.addr_reg_index] + m_registers[cur_opcode.debug_log.ofs_reg_index];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -277,15 +277,15 @@ namespace ams::dmnt::cheat::impl {
|
||||
constexpr static size_t NumWritableStaticRegisters = 0x80;
|
||||
constexpr static size_t NumStaticRegisters = NumReadableStaticRegisters + NumWritableStaticRegisters;
|
||||
private:
|
||||
size_t num_opcodes = 0;
|
||||
size_t instruction_ptr = 0;
|
||||
size_t condition_depth = 0;
|
||||
bool decode_success = false;
|
||||
u32 program[MaximumProgramOpcodeCount] = {0};
|
||||
u64 registers[NumRegisters] = {0};
|
||||
u64 saved_values[NumRegisters] = {0};
|
||||
u64 static_registers[NumStaticRegisters] = {0};
|
||||
size_t loop_tops[NumRegisters] = {0};
|
||||
size_t m_num_opcodes = 0;
|
||||
size_t m_instruction_ptr = 0;
|
||||
size_t m_condition_depth = 0;
|
||||
bool m_decode_success = false;
|
||||
u32 m_program[MaximumProgramOpcodeCount] = {0};
|
||||
u64 m_registers[NumRegisters] = {0};
|
||||
u64 m_saved_values[NumRegisters] = {0};
|
||||
u64 m_static_registers[NumStaticRegisters] = {0};
|
||||
size_t m_loop_tops[NumRegisters] = {0};
|
||||
private:
|
||||
bool DecodeNextOpcode(CheatVmOpcode *out);
|
||||
void SkipConditionalBlock(bool is_if);
|
||||
@@ -303,32 +303,32 @@ namespace ams::dmnt::cheat::impl {
|
||||
static u64 GetVmInt(VmInt value, u32 bit_width);
|
||||
static u64 GetCheatProcessAddress(const CheatProcessMetadata* metadata, MemoryAccessType mem_type, u64 rel_address);
|
||||
public:
|
||||
CheatVirtualMachine() { }
|
||||
constexpr CheatVirtualMachine() = default;
|
||||
|
||||
size_t GetProgramSize() {
|
||||
return this->num_opcodes;
|
||||
return m_num_opcodes;
|
||||
}
|
||||
|
||||
bool LoadProgram(const CheatEntry *cheats, size_t num_cheats);
|
||||
void Execute(const CheatProcessMetadata *metadata);
|
||||
|
||||
u64 GetStaticRegister(size_t which) const {
|
||||
return this->static_registers[which];
|
||||
return m_static_registers[which];
|
||||
}
|
||||
|
||||
void SetStaticRegister(size_t which, u64 value) {
|
||||
this->static_registers[which] = value;
|
||||
m_static_registers[which] = value;
|
||||
}
|
||||
|
||||
void ResetStaticRegisters() {
|
||||
std::memset(this->static_registers, 0, sizeof(this->static_registers));
|
||||
std::memset(m_static_registers, 0, sizeof(m_static_registers));
|
||||
}
|
||||
#ifdef DMNT_CHEAT_VM_DEBUG_LOG
|
||||
private:
|
||||
fs::FileHandle debug_log_file;
|
||||
s64 debug_log_file_offset;
|
||||
bool has_debug_log_file;
|
||||
char debug_log_format_buf[0x100];
|
||||
fs::FileHandle m_debug_log_file = {};
|
||||
s64 m_debug_log_file_offset = 0;
|
||||
bool m_has_debug_log_file = false;
|
||||
char m_debug_log_format_buf[0x100] = {0};
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -75,43 +75,43 @@ namespace ams::fatal::srv {
|
||||
|
||||
FatalConfig::FatalConfig() {
|
||||
/* Get information from set. */
|
||||
settings::system::GetSerialNumber(std::addressof(this->serial_number));
|
||||
settings::system::GetFirmwareVersion(std::addressof(this->firmware_version));
|
||||
setsysGetQuestFlag(std::addressof(this->quest_flag));
|
||||
settings::system::GetSerialNumber(std::addressof(m_serial_number));
|
||||
settings::system::GetFirmwareVersion(std::addressof(m_firmware_version));
|
||||
setsysGetQuestFlag(std::addressof(m_quest_flag));
|
||||
this->UpdateLanguageCode();
|
||||
|
||||
/* Read information from settings. */
|
||||
settings::fwdbg::GetSettingsItemValue(std::addressof(this->transition_to_fatal), sizeof(this->transition_to_fatal), "fatal", "transition_to_fatal");
|
||||
settings::fwdbg::GetSettingsItemValue(std::addressof(this->show_extra_info), sizeof(this->show_extra_info), "fatal", "show_extra_info");
|
||||
settings::fwdbg::GetSettingsItemValue(std::addressof(m_transition_to_fatal), sizeof(m_transition_to_fatal), "fatal", "transition_to_fatal");
|
||||
settings::fwdbg::GetSettingsItemValue(std::addressof(m_show_extra_info), sizeof(m_show_extra_info), "fatal", "show_extra_info");
|
||||
|
||||
u64 quest_interval_second;
|
||||
settings::fwdbg::GetSettingsItemValue(std::addressof(quest_interval_second), sizeof(quest_interval_second), "fatal", "quest_reboot_interval_second");
|
||||
this->quest_reboot_interval = TimeSpan::FromSeconds(quest_interval_second);
|
||||
m_quest_reboot_interval = TimeSpan::FromSeconds(quest_interval_second);
|
||||
|
||||
/* Atmosphere extension for automatic reboot. */
|
||||
u64 auto_reboot_ms;
|
||||
if (settings::fwdbg::GetSettingsItemValue(std::addressof(auto_reboot_ms), sizeof(auto_reboot_ms), "atmosphere", "fatal_auto_reboot_interval") == sizeof(auto_reboot_ms)) {
|
||||
this->fatal_auto_reboot_interval = TimeSpan::FromMilliSeconds(auto_reboot_ms);
|
||||
this->fatal_auto_reboot_enabled = auto_reboot_ms != 0;
|
||||
m_fatal_auto_reboot_interval = TimeSpan::FromMilliSeconds(auto_reboot_ms);
|
||||
m_fatal_auto_reboot_enabled = auto_reboot_ms != 0;
|
||||
}
|
||||
|
||||
/* Setup messages. */
|
||||
{
|
||||
this->error_msg = "Error Code: 2%03d-%04d (0x%x)\n";
|
||||
m_error_msg = "Error Code: 2%03d-%04d (0x%x)\n";
|
||||
|
||||
this->error_desc = "An error has occurred.\n\n"
|
||||
"Please press the POWER Button to restart the console normally, or a VOL button\n"
|
||||
"to reboot to a payload (or RCM, if none is present). If you are unable to\n"
|
||||
"restart the console, hold the POWER Button for 12 seconds to turn the console off.\n\n"
|
||||
"If the problem persists, refer to the Nintendo Support Website.\n"
|
||||
"support.nintendo.com/switch/error\n";
|
||||
m_error_desc = "An error has occurred.\n\n"
|
||||
"Please press the POWER Button to restart the console normally, or a VOL button\n"
|
||||
"to reboot to a payload (or RCM, if none is present). If you are unable to\n"
|
||||
"restart the console, hold the POWER Button for 12 seconds to turn the console off.\n\n"
|
||||
"If the problem persists, refer to the Nintendo Support Website.\n"
|
||||
"support.nintendo.com/switch/error\n";
|
||||
|
||||
/* If you're running Atmosphere on a quest unit for some reason, talk to me on discord. */
|
||||
this->quest_desc = "Please call 1-800-875-1852 for service.\n\n"
|
||||
"Also, please be aware that running Atmosphere on a Quest device is not fully\n"
|
||||
"supported. Perhaps try booting your device without Atmosphere before calling\n"
|
||||
"an official Nintendo service hotline. If you encounter further issues, please\n"
|
||||
"contact SciresM#0524 on Discord, or via some other means.\n";
|
||||
m_quest_desc = "Please call 1-800-875-1852 for service.\n\n"
|
||||
"Also, please be aware that running Atmosphere on a Quest device is not fully\n"
|
||||
"supported. Perhaps try booting your device without Atmosphere before calling\n"
|
||||
"an official Nintendo service hotline. If you encounter further issues, please\n"
|
||||
"contact SciresM#0524 on Discord, or via some other means.\n";
|
||||
|
||||
/* TODO: Try to load dynamically? */
|
||||
/* FsStorage message_storage; */
|
||||
|
||||
@@ -20,70 +20,70 @@ namespace ams::fatal::srv {
|
||||
|
||||
class FatalConfig {
|
||||
private:
|
||||
settings::system::SerialNumber serial_number{};
|
||||
settings::system::FirmwareVersion firmware_version{};
|
||||
u64 language_code{};
|
||||
TimeSpan quest_reboot_interval{};
|
||||
bool transition_to_fatal{};
|
||||
bool show_extra_info{};
|
||||
bool quest_flag{};
|
||||
const char *error_msg{};
|
||||
const char *error_desc{};
|
||||
const char *quest_desc{};
|
||||
TimeSpan fatal_auto_reboot_interval{};
|
||||
bool fatal_auto_reboot_enabled{};
|
||||
settings::system::SerialNumber m_serial_number{};
|
||||
settings::system::FirmwareVersion m_firmware_version{};
|
||||
u64 m_language_code{};
|
||||
TimeSpan m_quest_reboot_interval{};
|
||||
bool m_transition_to_fatal{};
|
||||
bool m_show_extra_info{};
|
||||
bool m_quest_flag{};
|
||||
const char *m_error_msg{};
|
||||
const char *m_error_desc{};
|
||||
const char *m_quest_desc{};
|
||||
TimeSpan m_fatal_auto_reboot_interval{};
|
||||
bool m_fatal_auto_reboot_enabled{};
|
||||
public:
|
||||
FatalConfig();
|
||||
|
||||
const settings::system::SerialNumber &GetSerialNumber() const {
|
||||
return this->serial_number;
|
||||
return m_serial_number;
|
||||
}
|
||||
|
||||
const settings::system::FirmwareVersion &GetFirmwareVersion() const {
|
||||
return this->firmware_version;
|
||||
return m_firmware_version;
|
||||
}
|
||||
|
||||
void UpdateLanguageCode() {
|
||||
setGetLanguageCode(&this->language_code);
|
||||
setGetLanguageCode(&m_language_code);
|
||||
}
|
||||
|
||||
u64 GetLanguageCode() const {
|
||||
return this->language_code;
|
||||
return m_language_code;
|
||||
}
|
||||
|
||||
bool ShouldTransitionToFatal() const {
|
||||
return this->transition_to_fatal;
|
||||
return m_transition_to_fatal;
|
||||
}
|
||||
|
||||
bool ShouldShowExtraInfo() const {
|
||||
return this->show_extra_info;
|
||||
return m_show_extra_info;
|
||||
}
|
||||
|
||||
bool IsQuest() const {
|
||||
return this->quest_flag;
|
||||
return m_quest_flag;
|
||||
}
|
||||
|
||||
bool IsFatalRebootEnabled() const {
|
||||
return this->fatal_auto_reboot_enabled;
|
||||
return m_fatal_auto_reboot_enabled;
|
||||
}
|
||||
|
||||
TimeSpan GetQuestRebootTimeoutInterval() const {
|
||||
return this->quest_reboot_interval;
|
||||
return m_quest_reboot_interval;
|
||||
}
|
||||
|
||||
TimeSpan GetFatalRebootTimeoutInterval() const {
|
||||
return this->fatal_auto_reboot_interval;
|
||||
return m_fatal_auto_reboot_interval;
|
||||
}
|
||||
|
||||
const char *GetErrorMessage() const {
|
||||
return this->error_msg;
|
||||
return m_error_msg;
|
||||
}
|
||||
|
||||
const char *GetErrorDescription() const {
|
||||
if (this->IsQuest()) {
|
||||
return this->quest_desc;
|
||||
return m_quest_desc;
|
||||
} else {
|
||||
return this->error_desc;
|
||||
return m_error_desc;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -18,26 +18,26 @@
|
||||
|
||||
namespace ams::fatal::srv {
|
||||
|
||||
FatalEventManager::FatalEventManager() : lock() {
|
||||
FatalEventManager::FatalEventManager() : m_lock() {
|
||||
/* Just create all the events. */
|
||||
for (size_t i = 0; i < FatalEventManager::NumFatalEvents; i++) {
|
||||
R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(this->events[i]), os::EventClearMode_AutoClear, true));
|
||||
R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(m_events[i]), os::EventClearMode_AutoClear, true));
|
||||
}
|
||||
}
|
||||
|
||||
Result FatalEventManager::GetEvent(const os::SystemEventType **out) {
|
||||
std::scoped_lock lk{this->lock};
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
/* Only allow GetEvent to succeed NumFatalEvents times. */
|
||||
R_UNLESS(this->num_events_gotten < FatalEventManager::NumFatalEvents, fatal::ResultTooManyEvents());
|
||||
R_UNLESS(m_num_events_gotten < FatalEventManager::NumFatalEvents, fatal::ResultTooManyEvents());
|
||||
|
||||
*out = std::addressof(this->events[this->num_events_gotten++]);
|
||||
*out = std::addressof(m_events[m_num_events_gotten++]);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void FatalEventManager::SignalEvents() {
|
||||
for (size_t i = 0; i < FatalEventManager::NumFatalEvents; i++) {
|
||||
os::SignalSystemEvent(std::addressof(this->events[i]));
|
||||
os::SignalSystemEvent(std::addressof(m_events[i]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ namespace ams::fatal::srv {
|
||||
public:
|
||||
static constexpr size_t NumFatalEvents = 3;
|
||||
private:
|
||||
os::SdkMutex lock;
|
||||
size_t num_events_gotten = 0;
|
||||
os::SystemEventType events[NumFatalEvents];
|
||||
os::SdkMutex m_lock;
|
||||
size_t m_num_events_gotten = 0;
|
||||
os::SystemEventType m_events[NumFatalEvents];
|
||||
public:
|
||||
FatalEventManager();
|
||||
Result GetEvent(const os::SystemEventType **out);
|
||||
|
||||
@@ -90,8 +90,8 @@ namespace ams::fatal::srv {
|
||||
}
|
||||
|
||||
/* Advance, if we write successfully. */
|
||||
if (R_SUCCEEDED(fs::WriteFile(this->file, this->offset, data, size, fs::WriteOption::Flush))) {
|
||||
this->offset += size;
|
||||
if (R_SUCCEEDED(fs::WriteFile(m_file, m_offset, data, size, fs::WriteOption::Flush))) {
|
||||
m_offset += size;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,24 +22,24 @@ namespace ams::fatal::srv {
|
||||
NON_COPYABLE(ScopedFile);
|
||||
NON_MOVEABLE(ScopedFile);
|
||||
private:
|
||||
fs::FileHandle file;
|
||||
s64 offset;
|
||||
bool opened;
|
||||
fs::FileHandle m_file;
|
||||
s64 m_offset;
|
||||
bool m_opened;
|
||||
public:
|
||||
ScopedFile(const char *path) : file(), offset(), opened(false) {
|
||||
ScopedFile(const char *path) : m_file(), m_offset(), m_opened(false) {
|
||||
if (R_SUCCEEDED(fs::CreateFile(path, 0))) {
|
||||
this->opened = R_SUCCEEDED(fs::OpenFile(std::addressof(this->file), path, fs::OpenMode_Write | fs::OpenMode_AllowAppend));
|
||||
m_opened = R_SUCCEEDED(fs::OpenFile(std::addressof(m_file), path, fs::OpenMode_Write | fs::OpenMode_AllowAppend));
|
||||
}
|
||||
}
|
||||
|
||||
~ScopedFile() {
|
||||
if (this->opened) {
|
||||
fs::CloseFile(file);
|
||||
if (m_opened) {
|
||||
fs::CloseFile(m_file);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsOpen() const {
|
||||
return this->opened;
|
||||
return m_opened;
|
||||
}
|
||||
|
||||
void WriteString(const char *str);
|
||||
|
||||
@@ -28,27 +28,27 @@ namespace ams::fatal::srv {
|
||||
/* Service Context. */
|
||||
class ServiceContext {
|
||||
private:
|
||||
os::Event erpt_event;
|
||||
os::Event battery_event;
|
||||
ThrowContext context;
|
||||
FatalEventManager event_manager;
|
||||
bool has_thrown;
|
||||
os::Event m_erpt_event;
|
||||
os::Event m_battery_event;
|
||||
ThrowContext m_context;
|
||||
FatalEventManager m_event_manager;
|
||||
bool m_has_thrown;
|
||||
private:
|
||||
Result TrySetHasThrown() {
|
||||
R_UNLESS(!this->has_thrown, fatal::ResultAlreadyThrown());
|
||||
this->has_thrown = true;
|
||||
R_UNLESS(!m_has_thrown, fatal::ResultAlreadyThrown());
|
||||
m_has_thrown = true;
|
||||
return ResultSuccess();
|
||||
}
|
||||
public:
|
||||
ServiceContext()
|
||||
: erpt_event(os::EventClearMode_ManualClear), battery_event(os::EventClearMode_ManualClear),
|
||||
context(std::addressof(erpt_event), std::addressof(battery_event)), has_thrown(false)
|
||||
: m_erpt_event(os::EventClearMode_ManualClear), m_battery_event(os::EventClearMode_ManualClear),
|
||||
m_context(std::addressof(m_erpt_event), std::addressof(m_battery_event)), m_has_thrown(false)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
Result GetEvent(const os::SystemEventType **out) {
|
||||
return this->event_manager.GetEvent(out);
|
||||
return m_event_manager.GetEvent(out);
|
||||
}
|
||||
|
||||
Result ThrowFatal(Result result, os::ProcessId process_id) {
|
||||
@@ -73,51 +73,51 @@ namespace ams::fatal::srv {
|
||||
/* Note that we've thrown fatal. */
|
||||
R_TRY(this->TrySetHasThrown());
|
||||
|
||||
/* At this point we have exclusive access to this->context. */
|
||||
this->context.result = result;
|
||||
this->context.cpu_ctx = cpu_ctx;
|
||||
/* At this point we have exclusive access to m_context. */
|
||||
m_context.result = result;
|
||||
m_context.cpu_ctx = cpu_ctx;
|
||||
|
||||
/* Cap the stack trace to a sane limit. */
|
||||
if (cpu_ctx.architecture == CpuContext::Architecture_Aarch64) {
|
||||
this->context.cpu_ctx.aarch64_ctx.stack_trace_size = std::max(size_t(this->context.cpu_ctx.aarch64_ctx.stack_trace_size), aarch64::CpuContext::MaxStackTraceDepth);
|
||||
m_context.cpu_ctx.aarch64_ctx.stack_trace_size = std::max(size_t(m_context.cpu_ctx.aarch64_ctx.stack_trace_size), aarch64::CpuContext::MaxStackTraceDepth);
|
||||
} else {
|
||||
this->context.cpu_ctx.aarch32_ctx.stack_trace_size = std::max(size_t(this->context.cpu_ctx.aarch32_ctx.stack_trace_size), aarch32::CpuContext::MaxStackTraceDepth);
|
||||
m_context.cpu_ctx.aarch32_ctx.stack_trace_size = std::max(size_t(m_context.cpu_ctx.aarch32_ctx.stack_trace_size), aarch32::CpuContext::MaxStackTraceDepth);
|
||||
}
|
||||
|
||||
/* Get program id. */
|
||||
pm::info::GetProgramId(std::addressof(this->context.program_id), process_id);
|
||||
this->context.is_creport = (this->context.program_id == ncm::SystemProgramId::Creport);
|
||||
pm::info::GetProgramId(std::addressof(m_context.program_id), process_id);
|
||||
m_context.is_creport = (m_context.program_id == ncm::SystemProgramId::Creport);
|
||||
|
||||
if (!this->context.is_creport) {
|
||||
if (!m_context.is_creport) {
|
||||
/* On firmware version 2.0.0, use debugging SVCs to collect information. */
|
||||
if (hos::GetVersion() >= hos::Version_2_0_0) {
|
||||
fatal::srv::TryCollectDebugInformation(std::addressof(this->context), process_id);
|
||||
fatal::srv::TryCollectDebugInformation(std::addressof(m_context), process_id);
|
||||
}
|
||||
} else {
|
||||
/* We received info from creport. Parse program id from afsr0. */
|
||||
if (cpu_ctx.architecture == CpuContext::Architecture_Aarch64) {
|
||||
this->context.program_id = cpu_ctx.aarch64_ctx.GetProgramIdForAtmosphere();
|
||||
m_context.program_id = cpu_ctx.aarch64_ctx.GetProgramIdForAtmosphere();
|
||||
} else {
|
||||
this->context.program_id = cpu_ctx.aarch32_ctx.GetProgramIdForAtmosphere();
|
||||
m_context.program_id = cpu_ctx.aarch32_ctx.GetProgramIdForAtmosphere();
|
||||
}
|
||||
}
|
||||
|
||||
/* Decide whether to generate a report. */
|
||||
this->context.generate_error_report = (policy == FatalPolicy_ErrorReportAndErrorScreen);
|
||||
m_context.generate_error_report = (policy == FatalPolicy_ErrorReportAndErrorScreen);
|
||||
|
||||
/* Adjust error code (ResultSuccess()/2000-0000 -> err::ResultSystemProgramAbort()/2162-0002). */
|
||||
if (R_SUCCEEDED(this->context.result)) {
|
||||
this->context.result = err::ResultSystemProgramAbort();
|
||||
if (R_SUCCEEDED(m_context.result)) {
|
||||
m_context.result = err::ResultSystemProgramAbort();
|
||||
}
|
||||
|
||||
switch (policy) {
|
||||
case FatalPolicy_ErrorReportAndErrorScreen:
|
||||
case FatalPolicy_ErrorScreen:
|
||||
/* Signal that we're throwing. */
|
||||
this->event_manager.SignalEvents();
|
||||
m_event_manager.SignalEvents();
|
||||
|
||||
if (GetFatalConfig().ShouldTransitionToFatal()) {
|
||||
RunTasks(std::addressof(this->context));
|
||||
RunTasks(std::addressof(m_context));
|
||||
}
|
||||
break;
|
||||
/* N aborts here. Should we just return an error code? */
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace ams::fatal::srv {
|
||||
class TaskThread {
|
||||
NON_COPYABLE(TaskThread);
|
||||
private:
|
||||
os::ThreadType thread;
|
||||
os::ThreadType m_thread;
|
||||
private:
|
||||
static void RunTaskImpl(void *arg) {
|
||||
ITask *task = reinterpret_cast<ITask *>(arg);
|
||||
@@ -41,9 +41,9 @@ namespace ams::fatal::srv {
|
||||
public:
|
||||
TaskThread() { /* ... */ }
|
||||
void StartTask(ITask *task) {
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(this->thread), RunTaskImpl, task, task->GetStack(), task->GetStackSize(), AMS_GET_SYSTEM_THREAD_PRIORITY(fatalsrv, FatalTaskThread), 3));
|
||||
os::SetThreadNamePointer(std::addressof(this->thread), AMS_GET_SYSTEM_THREAD_NAME(fatalsrv, FatalTaskThread));
|
||||
os::StartThread(std::addressof(this->thread));
|
||||
R_ABORT_UNLESS(os::CreateThread(std::addressof(m_thread), RunTaskImpl, task, task->GetStack(), task->GetStackSize(), AMS_GET_SYSTEM_THREAD_PRIORITY(fatalsrv, FatalTaskThread), 3));
|
||||
os::SetThreadNamePointer(std::addressof(m_thread), AMS_GET_SYSTEM_THREAD_NAME(fatalsrv, FatalTaskThread));
|
||||
os::StartThread(std::addressof(m_thread));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -52,13 +52,13 @@ namespace ams::fatal::srv {
|
||||
private:
|
||||
static constexpr size_t MaxTasks = 8;
|
||||
private:
|
||||
TaskThread task_threads[MaxTasks];
|
||||
size_t task_count = 0;
|
||||
TaskThread m_task_threads[MaxTasks];
|
||||
size_t m_task_count = 0;
|
||||
public:
|
||||
TaskManager() { /* ... */ }
|
||||
void StartTask(ITask *task) {
|
||||
AMS_ABORT_UNLESS(this->task_count < MaxTasks);
|
||||
this->task_threads[this->task_count++].StartTask(task);
|
||||
AMS_ABORT_UNLESS(m_task_count < MaxTasks);
|
||||
m_task_threads[m_task_count++].StartTask(task);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -20,10 +20,10 @@ namespace ams::fatal::srv {
|
||||
|
||||
class ITask {
|
||||
protected:
|
||||
const ThrowContext *context = nullptr;
|
||||
const ThrowContext *m_context = nullptr;
|
||||
public:
|
||||
void Initialize(const ThrowContext *context) {
|
||||
this->context = context;
|
||||
m_context = context;
|
||||
}
|
||||
|
||||
virtual Result Run() = 0;
|
||||
@@ -38,10 +38,10 @@ namespace ams::fatal::srv {
|
||||
static constexpr size_t StackSize = _StackSize;
|
||||
static_assert(util::IsAligned(StackSize, os::MemoryPageSize), "StackSize alignment");
|
||||
protected:
|
||||
alignas(os::MemoryPageSize) u8 stack_mem[StackSize] = {};
|
||||
alignas(os::MemoryPageSize) u8 m_stack_mem[StackSize] = {};
|
||||
public:
|
||||
virtual u8 *GetStack() override final {
|
||||
return this->stack_mem;
|
||||
return m_stack_mem;
|
||||
}
|
||||
|
||||
virtual size_t GetStackSize() const override final {
|
||||
|
||||
@@ -79,61 +79,61 @@ namespace ams::fatal::srv {
|
||||
|
||||
/* Open report file. */
|
||||
{
|
||||
util::SNPrintf(file_path, sizeof(file_path) - 1, "sdmc:/atmosphere/fatal_reports/%011lu_%016lx.log", timestamp, static_cast<u64>(this->context->program_id));
|
||||
util::SNPrintf(file_path, sizeof(file_path) - 1, "sdmc:/atmosphere/fatal_reports/%011lu_%016lx.log", timestamp, static_cast<u64>(m_context->program_id));
|
||||
ScopedFile file(file_path);
|
||||
if (file.IsOpen()) {
|
||||
file.WriteFormat("Atmosphère Fatal Report (v1.1):\n");
|
||||
file.WriteFormat("Result: 0x%X (2%03d-%04d)\n\n", this->context->result.GetValue(), this->context->result.GetModule(), this->context->result.GetDescription());
|
||||
file.WriteFormat("Program ID: %016lx\n", static_cast<u64>(this->context->program_id));
|
||||
if (strlen(this->context->proc_name)) {
|
||||
file.WriteFormat("Process Name: %s\n", this->context->proc_name);
|
||||
file.WriteFormat("Result: 0x%X (2%03d-%04d)\n\n", m_context->result.GetValue(), m_context->result.GetModule(), m_context->result.GetDescription());
|
||||
file.WriteFormat("Program ID: %016lx\n", static_cast<u64>(m_context->program_id));
|
||||
if (strlen(m_context->proc_name)) {
|
||||
file.WriteFormat("Process Name: %s\n", m_context->proc_name);
|
||||
}
|
||||
file.WriteFormat("Firmware: %s (Atmosphère %u.%u.%u-%s)\n", GetFatalConfig().GetFirmwareVersion().display_version, ATMOSPHERE_RELEASE_VERSION, ams::GetGitRevision());
|
||||
|
||||
if (this->context->cpu_ctx.architecture == CpuContext::Architecture_Aarch32) {
|
||||
if (m_context->cpu_ctx.architecture == CpuContext::Architecture_Aarch32) {
|
||||
file.WriteFormat("General Purpose Registers:\n");
|
||||
for (size_t i = 0; i <= aarch32::RegisterName_PC; i++) {
|
||||
if (this->context->cpu_ctx.aarch32_ctx.HasRegisterValue(static_cast<aarch32::RegisterName>(i))) {
|
||||
file.WriteFormat( " %3s: %08x\n", aarch32::CpuContext::RegisterNameStrings[i], this->context->cpu_ctx.aarch32_ctx.r[i]);
|
||||
if (m_context->cpu_ctx.aarch32_ctx.HasRegisterValue(static_cast<aarch32::RegisterName>(i))) {
|
||||
file.WriteFormat( " %3s: %08x\n", aarch32::CpuContext::RegisterNameStrings[i], m_context->cpu_ctx.aarch32_ctx.r[i]);
|
||||
}
|
||||
}
|
||||
file.WriteFormat("Start Address: %08x\n", this->context->cpu_ctx.aarch32_ctx.base_address);
|
||||
file.WriteFormat("Start Address: %08x\n", m_context->cpu_ctx.aarch32_ctx.base_address);
|
||||
file.WriteFormat("Stack Trace:\n");
|
||||
for (unsigned int i = 0; i < this->context->cpu_ctx.aarch32_ctx.stack_trace_size; i++) {
|
||||
file.WriteFormat(" ReturnAddress[%02u]: %08x\n", i, this->context->cpu_ctx.aarch32_ctx.stack_trace[i]);
|
||||
for (unsigned int i = 0; i < m_context->cpu_ctx.aarch32_ctx.stack_trace_size; i++) {
|
||||
file.WriteFormat(" ReturnAddress[%02u]: %08x\n", i, m_context->cpu_ctx.aarch32_ctx.stack_trace[i]);
|
||||
}
|
||||
} else {
|
||||
file.WriteFormat("General Purpose Registers:\n");
|
||||
for (size_t i = 0; i <= aarch64::RegisterName_PC; i++) {
|
||||
if (this->context->cpu_ctx.aarch64_ctx.HasRegisterValue(static_cast<aarch64::RegisterName>(i))) {
|
||||
file.WriteFormat( " %3s: %016lx\n", aarch64::CpuContext::RegisterNameStrings[i], this->context->cpu_ctx.aarch64_ctx.x[i]);
|
||||
if (m_context->cpu_ctx.aarch64_ctx.HasRegisterValue(static_cast<aarch64::RegisterName>(i))) {
|
||||
file.WriteFormat( " %3s: %016lx\n", aarch64::CpuContext::RegisterNameStrings[i], m_context->cpu_ctx.aarch64_ctx.x[i]);
|
||||
}
|
||||
}
|
||||
file.WriteFormat("Start Address: %016lx\n", this->context->cpu_ctx.aarch64_ctx.base_address);
|
||||
file.WriteFormat("Start Address: %016lx\n", m_context->cpu_ctx.aarch64_ctx.base_address);
|
||||
file.WriteFormat("Stack Trace:\n");
|
||||
for (unsigned int i = 0; i < this->context->cpu_ctx.aarch64_ctx.stack_trace_size; i++) {
|
||||
file.WriteFormat(" ReturnAddress[%02u]: %016lx\n", i, this->context->cpu_ctx.aarch64_ctx.stack_trace[i]);
|
||||
for (unsigned int i = 0; i < m_context->cpu_ctx.aarch64_ctx.stack_trace_size; i++) {
|
||||
file.WriteFormat(" ReturnAddress[%02u]: %016lx\n", i, m_context->cpu_ctx.aarch64_ctx.stack_trace[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (this->context->stack_dump_size != 0) {
|
||||
if (m_context->stack_dump_size != 0) {
|
||||
file.WriteFormat("Stack Dump: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
|
||||
for (size_t i = 0; i < 0x10; i++) {
|
||||
const size_t ofs = i * 0x10;
|
||||
file.WriteFormat(" %012lx %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
this->context->stack_dump_base + ofs, this->context->stack_dump[ofs + 0], this->context->stack_dump[ofs + 1], this->context->stack_dump[ofs + 2], this->context->stack_dump[ofs + 3], this->context->stack_dump[ofs + 4], this->context->stack_dump[ofs + 5], this->context->stack_dump[ofs + 6], this->context->stack_dump[ofs + 7],
|
||||
this->context->stack_dump[ofs + 8], this->context->stack_dump[ofs + 9], this->context->stack_dump[ofs + 10], this->context->stack_dump[ofs + 11], this->context->stack_dump[ofs + 12], this->context->stack_dump[ofs + 13], this->context->stack_dump[ofs + 14], this->context->stack_dump[ofs + 15]);
|
||||
m_context->stack_dump_base + ofs, m_context->stack_dump[ofs + 0], m_context->stack_dump[ofs + 1], m_context->stack_dump[ofs + 2], m_context->stack_dump[ofs + 3], m_context->stack_dump[ofs + 4], m_context->stack_dump[ofs + 5], m_context->stack_dump[ofs + 6], m_context->stack_dump[ofs + 7],
|
||||
m_context->stack_dump[ofs + 8], m_context->stack_dump[ofs + 9], m_context->stack_dump[ofs + 10], m_context->stack_dump[ofs + 11], m_context->stack_dump[ofs + 12], m_context->stack_dump[ofs + 13], m_context->stack_dump[ofs + 14], m_context->stack_dump[ofs + 15]);
|
||||
}
|
||||
}
|
||||
|
||||
if (this->context->tls_address != 0) {
|
||||
file.WriteFormat("TLS Address: %016lx\n", this->context->tls_address);
|
||||
if (m_context->tls_address != 0) {
|
||||
file.WriteFormat("TLS Address: %016lx\n", m_context->tls_address);
|
||||
file.WriteFormat("TLS Dump: 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
|
||||
for (size_t i = 0; i < 0x10; i++) {
|
||||
const size_t ofs = i * 0x10;
|
||||
file.WriteFormat(" %012lx %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
this->context->tls_address + ofs, this->context->tls_dump[ofs + 0], this->context->tls_dump[ofs + 1], this->context->tls_dump[ofs + 2], this->context->tls_dump[ofs + 3], this->context->tls_dump[ofs + 4], this->context->tls_dump[ofs + 5], this->context->tls_dump[ofs + 6], this->context->tls_dump[ofs + 7],
|
||||
this->context->tls_dump[ofs + 8], this->context->tls_dump[ofs + 9], this->context->tls_dump[ofs + 10], this->context->tls_dump[ofs + 11], this->context->tls_dump[ofs + 12], this->context->tls_dump[ofs + 13], this->context->tls_dump[ofs + 14], this->context->tls_dump[ofs + 15]);
|
||||
m_context->tls_address + ofs, m_context->tls_dump[ofs + 0], m_context->tls_dump[ofs + 1], m_context->tls_dump[ofs + 2], m_context->tls_dump[ofs + 3], m_context->tls_dump[ofs + 4], m_context->tls_dump[ofs + 5], m_context->tls_dump[ofs + 6], m_context->tls_dump[ofs + 7],
|
||||
m_context->tls_dump[ofs + 8], m_context->tls_dump[ofs + 9], m_context->tls_dump[ofs + 10], m_context->tls_dump[ofs + 11], m_context->tls_dump[ofs + 12], m_context->tls_dump[ofs + 13], m_context->tls_dump[ofs + 14], m_context->tls_dump[ofs + 15]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,29 +141,29 @@ namespace ams::fatal::srv {
|
||||
|
||||
/* Dump data to file. */
|
||||
{
|
||||
util::SNPrintf(file_path, sizeof(file_path) - 1, "sdmc:/atmosphere/fatal_reports/dumps/%011lu_%016lx.bin", timestamp, static_cast<u64>(this->context->program_id));
|
||||
util::SNPrintf(file_path, sizeof(file_path) - 1, "sdmc:/atmosphere/fatal_reports/dumps/%011lu_%016lx.bin", timestamp, static_cast<u64>(m_context->program_id));
|
||||
ScopedFile file(file_path);
|
||||
if (file.IsOpen()) {
|
||||
file.Write(this->context->tls_dump, sizeof(this->context->tls_dump));
|
||||
if (this->context->stack_dump_size) {
|
||||
file.Write(this->context->stack_dump, this->context->stack_dump_size);
|
||||
file.Write(m_context->tls_dump, sizeof(m_context->tls_dump));
|
||||
if (m_context->stack_dump_size) {
|
||||
file.Write(m_context->stack_dump, m_context->stack_dump_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Result ErrorReportTask::Run() {
|
||||
if (this->context->generate_error_report) {
|
||||
if (m_context->generate_error_report) {
|
||||
/* Here, Nintendo creates an error report with erpt. AMS will not do that. */
|
||||
}
|
||||
|
||||
/* Save report to SD card. */
|
||||
if (!this->context->is_creport) {
|
||||
if (!m_context->is_creport) {
|
||||
this->SaveReportToSdCard();
|
||||
}
|
||||
|
||||
/* Signal we're done with our job. */
|
||||
this->context->erpt_event->Signal();
|
||||
m_context->erpt_event->Signal();
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
@@ -53,17 +53,17 @@ namespace ams::fatal::srv {
|
||||
|
||||
class RebootTimingObserver {
|
||||
private:
|
||||
os::Tick start_tick;
|
||||
TimeSpan interval;
|
||||
bool flag;
|
||||
os::Tick m_start_tick;
|
||||
TimeSpan m_interval;
|
||||
bool m_flag;
|
||||
public:
|
||||
RebootTimingObserver(bool flag, TimeSpan iv) : start_tick(os::GetSystemTick()), interval(iv), flag(flag) {
|
||||
RebootTimingObserver(bool flag, TimeSpan iv) : m_start_tick(os::GetSystemTick()), m_interval(iv), m_flag(flag) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
bool IsRebootTiming() const {
|
||||
auto current_tick = os::GetSystemTick();
|
||||
return this->flag && (current_tick - this->start_tick).ToTimeSpan() >= this->interval;
|
||||
return m_flag && (current_tick - m_start_tick).ToTimeSpan() >= m_interval;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -114,13 +114,13 @@ namespace ams::fatal::srv {
|
||||
/* Check the battery state, and shutdown on low voltage. */
|
||||
if (R_FAILED(psmGetBatteryVoltageState(std::addressof(bv_state))) || bv_state == PsmBatteryVoltageState_NeedsShutdown) {
|
||||
/* Wait a second for the error report task to finish. */
|
||||
this->context->erpt_event->TimedWait(TimeSpan::FromSeconds(1));
|
||||
m_context->erpt_event->TimedWait(TimeSpan::FromSeconds(1));
|
||||
this->TryShutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Signal we've checked the battery at least once. */
|
||||
this->context->battery_event->Signal();
|
||||
m_context->battery_event->Signal();
|
||||
|
||||
/* Loop querying voltage state every 5 seconds. */
|
||||
while (true) {
|
||||
@@ -148,7 +148,7 @@ namespace ams::fatal::srv {
|
||||
|
||||
void PowerButtonObserveTask::WaitForPowerButton() {
|
||||
/* Wait up to a second for error report generation to finish. */
|
||||
this->context->erpt_event->TimedWait(TimeSpan::FromSeconds(1));
|
||||
m_context->erpt_event->TimedWait(TimeSpan::FromSeconds(1));
|
||||
|
||||
/* Force a reboot after some time if kiosk unit. */
|
||||
const auto &config = GetFatalConfig();
|
||||
|
||||
@@ -70,10 +70,10 @@ namespace ams::fatal::srv {
|
||||
/* Task definitions. */
|
||||
class ShowFatalTask : public ITaskWithStack<0x8000> {
|
||||
private:
|
||||
ViDisplay display;
|
||||
ViLayer layer;
|
||||
NWindow win;
|
||||
NvMap map;
|
||||
ViDisplay m_display;
|
||||
ViLayer m_layer;
|
||||
NWindow m_win;
|
||||
NvMap m_map;
|
||||
private:
|
||||
Result SetupDisplayInternal();
|
||||
Result SetupDisplayExternal();
|
||||
@@ -156,19 +156,19 @@ namespace ams::fatal::srv {
|
||||
R_TRY(SetupDisplayExternal());
|
||||
|
||||
/* Open the default display. */
|
||||
R_TRY(viOpenDefaultDisplay(std::addressof(this->display)));
|
||||
R_TRY(viOpenDefaultDisplay(std::addressof(m_display)));
|
||||
|
||||
/* Reset the display magnification to its default value. */
|
||||
s32 display_width, display_height;
|
||||
R_TRY(viGetDisplayLogicalResolution(std::addressof(this->display), std::addressof(display_width), std::addressof(display_height)));
|
||||
R_TRY(viGetDisplayLogicalResolution(std::addressof(m_display), std::addressof(display_width), std::addressof(display_height)));
|
||||
|
||||
/* viSetDisplayMagnification was added in 3.0.0. */
|
||||
if (hos::GetVersion() >= hos::Version_3_0_0) {
|
||||
R_TRY(viSetDisplayMagnification(std::addressof(this->display), 0, 0, display_width, display_height));
|
||||
R_TRY(viSetDisplayMagnification(std::addressof(m_display), 0, 0, display_width, display_height));
|
||||
}
|
||||
|
||||
/* Create layer to draw to. */
|
||||
R_TRY(viCreateLayer(std::addressof(this->display), std::addressof(this->layer)));
|
||||
R_TRY(viCreateLayer(std::addressof(m_display), std::addressof(m_layer)));
|
||||
|
||||
/* Setup the layer. */
|
||||
{
|
||||
@@ -183,16 +183,16 @@ namespace ams::fatal::srv {
|
||||
const float layer_x = static_cast<float>((display_width - LayerWidth) / 2);
|
||||
const float layer_y = static_cast<float>((display_height - LayerHeight) / 2);
|
||||
|
||||
R_TRY(viSetLayerSize(std::addressof(this->layer), LayerWidth, LayerHeight));
|
||||
R_TRY(viSetLayerSize(std::addressof(m_layer), LayerWidth, LayerHeight));
|
||||
|
||||
/* Set the layer's Z at display maximum, to be above everything else .*/
|
||||
R_TRY(viSetLayerZ(std::addressof(this->layer), FatalLayerZ));
|
||||
R_TRY(viSetLayerZ(std::addressof(m_layer), FatalLayerZ));
|
||||
|
||||
/* Center the layer in the screen. */
|
||||
R_TRY(viSetLayerPosition(std::addressof(this->layer), layer_x, layer_y));
|
||||
R_TRY(viSetLayerPosition(std::addressof(m_layer), layer_x, layer_y));
|
||||
|
||||
/* Create framebuffer. */
|
||||
R_TRY(nwindowCreateFromLayer(std::addressof(this->win), std::addressof(this->layer)));
|
||||
R_TRY(nwindowCreateFromLayer(std::addressof(m_win), std::addressof(m_layer)));
|
||||
R_TRY(this->InitializeNativeWindow());
|
||||
}
|
||||
|
||||
@@ -229,14 +229,14 @@ namespace ams::fatal::srv {
|
||||
/* Draw error message and firmware. */
|
||||
font::SetPosition(start_x, start_y);
|
||||
font::SetFontSize(16.0f);
|
||||
font::PrintFormat(config.GetErrorMessage(), this->context->result.GetModule(), this->context->result.GetDescription(), this->context->result.GetValue());
|
||||
font::PrintFormat(config.GetErrorMessage(), m_context->result.GetModule(), m_context->result.GetDescription(), m_context->result.GetValue());
|
||||
font::AddSpacingLines(0.5f);
|
||||
font::PrintFormatLine( "Program: %016lX", static_cast<u64>(this->context->program_id));
|
||||
font::PrintFormatLine( "Program: %016lX", static_cast<u64>(m_context->program_id));
|
||||
font::AddSpacingLines(0.5f);
|
||||
|
||||
font::PrintFormatLine("Firmware: %s (Atmosphère %u.%u.%u-%s)", config.GetFirmwareVersion().display_version, ATMOSPHERE_RELEASE_VERSION, ams::GetGitRevision());
|
||||
font::AddSpacingLines(1.5f);
|
||||
if (!exosphere::ResultVersionMismatch::Includes(this->context->result)) {
|
||||
if (!exosphere::ResultVersionMismatch::Includes(m_context->result)) {
|
||||
font::Print(config.GetErrorDescription());
|
||||
} else {
|
||||
/* Print a special message for atmosphere version mismatch. */
|
||||
@@ -260,7 +260,7 @@ namespace ams::fatal::srv {
|
||||
u32 pc_x = 0;
|
||||
|
||||
/* Note architecutre. */
|
||||
const bool is_aarch32 = this->context->cpu_ctx.architecture == CpuContext::Architecture_Aarch32;
|
||||
const bool is_aarch32 = m_context->cpu_ctx.architecture == CpuContext::Architecture_Aarch32;
|
||||
|
||||
/* Print GPRs. */
|
||||
font::SetFontSize(14.0f);
|
||||
@@ -273,8 +273,8 @@ namespace ams::fatal::srv {
|
||||
u32 x = font::GetX();
|
||||
font::PrintFormat("%s:", aarch32::CpuContext::RegisterNameStrings[i]);
|
||||
font::SetPosition(x + 47, font::GetY());
|
||||
if (this->context->cpu_ctx.aarch32_ctx.HasRegisterValue(static_cast<aarch32::RegisterName>(i))) {
|
||||
font::PrintMonospaceU32(this->context->cpu_ctx.aarch32_ctx.r[i]);
|
||||
if (m_context->cpu_ctx.aarch32_ctx.HasRegisterValue(static_cast<aarch32::RegisterName>(i))) {
|
||||
font::PrintMonospaceU32(m_context->cpu_ctx.aarch32_ctx.r[i]);
|
||||
font::PrintMonospaceBlank(8);
|
||||
} else {
|
||||
font::PrintMonospaceBlank(16);
|
||||
@@ -283,8 +283,8 @@ namespace ams::fatal::srv {
|
||||
pc_x = font::GetX();
|
||||
font::PrintFormat("%s:", aarch32::CpuContext::RegisterNameStrings[i + (aarch32::RegisterName_GeneralPurposeCount / 2)]);
|
||||
font::SetPosition(pc_x + 47, font::GetY());
|
||||
if (this->context->cpu_ctx.aarch32_ctx.HasRegisterValue(static_cast<aarch32::RegisterName>(i + (aarch32::RegisterName_GeneralPurposeCount / 2)))) {
|
||||
font::PrintMonospaceU32(this->context->cpu_ctx.aarch32_ctx.r[i + (aarch32::RegisterName_GeneralPurposeCount / 2)]);
|
||||
if (m_context->cpu_ctx.aarch32_ctx.HasRegisterValue(static_cast<aarch32::RegisterName>(i + (aarch32::RegisterName_GeneralPurposeCount / 2)))) {
|
||||
font::PrintMonospaceU32(m_context->cpu_ctx.aarch32_ctx.r[i + (aarch32::RegisterName_GeneralPurposeCount / 2)]);
|
||||
font::PrintMonospaceBlank(8);
|
||||
} else {
|
||||
font::PrintMonospaceBlank(16);
|
||||
@@ -303,8 +303,8 @@ namespace ams::fatal::srv {
|
||||
u32 x = font::GetX();
|
||||
font::PrintFormat("%s:", aarch64::CpuContext::RegisterNameStrings[i]);
|
||||
font::SetPosition(x + 47, font::GetY());
|
||||
if (this->context->cpu_ctx.aarch64_ctx.HasRegisterValue(static_cast<aarch64::RegisterName>(i))) {
|
||||
font::PrintMonospaceU64(this->context->cpu_ctx.aarch64_ctx.x[i]);
|
||||
if (m_context->cpu_ctx.aarch64_ctx.HasRegisterValue(static_cast<aarch64::RegisterName>(i))) {
|
||||
font::PrintMonospaceU64(m_context->cpu_ctx.aarch64_ctx.x[i]);
|
||||
} else {
|
||||
font::PrintMonospaceBlank(16);
|
||||
}
|
||||
@@ -312,8 +312,8 @@ namespace ams::fatal::srv {
|
||||
pc_x = font::GetX();
|
||||
font::PrintFormat("%s:", aarch64::CpuContext::RegisterNameStrings[i + (aarch64::RegisterName_GeneralPurposeCount / 2)]);
|
||||
font::SetPosition(pc_x + 47, font::GetY());
|
||||
if (this->context->cpu_ctx.aarch64_ctx.HasRegisterValue(static_cast<aarch64::RegisterName>(i + (aarch64::RegisterName_GeneralPurposeCount / 2)))) {
|
||||
font::PrintMonospaceU64(this->context->cpu_ctx.aarch64_ctx.x[i + (aarch64::RegisterName_GeneralPurposeCount / 2)]);
|
||||
if (m_context->cpu_ctx.aarch64_ctx.HasRegisterValue(static_cast<aarch64::RegisterName>(i + (aarch64::RegisterName_GeneralPurposeCount / 2)))) {
|
||||
font::PrintMonospaceU64(m_context->cpu_ctx.aarch64_ctx.x[i + (aarch64::RegisterName_GeneralPurposeCount / 2)]);
|
||||
} else {
|
||||
font::PrintMonospaceBlank(16);
|
||||
}
|
||||
@@ -336,17 +336,17 @@ namespace ams::fatal::srv {
|
||||
font::SetPosition(x + 47, font::GetY());
|
||||
}
|
||||
if (is_aarch32) {
|
||||
font::PrintMonospaceU32(this->context->cpu_ctx.aarch32_ctx.pc);
|
||||
font::PrintMonospaceU32(m_context->cpu_ctx.aarch32_ctx.pc);
|
||||
} else {
|
||||
font::PrintMonospaceU64(this->context->cpu_ctx.aarch64_ctx.pc);
|
||||
font::PrintMonospaceU64(m_context->cpu_ctx.aarch64_ctx.pc);
|
||||
}
|
||||
|
||||
/* Print Backtrace. */
|
||||
u32 bt_size;
|
||||
if (is_aarch32) {
|
||||
bt_size = this->context->cpu_ctx.aarch32_ctx.stack_trace_size;
|
||||
bt_size = m_context->cpu_ctx.aarch32_ctx.stack_trace_size;
|
||||
} else {
|
||||
bt_size = this->context->cpu_ctx.aarch64_ctx.stack_trace_size;
|
||||
bt_size = m_context->cpu_ctx.aarch64_ctx.stack_trace_size;
|
||||
}
|
||||
|
||||
|
||||
@@ -354,29 +354,29 @@ namespace ams::fatal::srv {
|
||||
if (bt_size == 0) {
|
||||
if (is_aarch32) {
|
||||
font::Print("Start Address: ");
|
||||
font::PrintMonospaceU32(this->context->cpu_ctx.aarch32_ctx.base_address);
|
||||
font::PrintMonospaceU32(m_context->cpu_ctx.aarch32_ctx.base_address);
|
||||
font::PrintLine("");
|
||||
} else {
|
||||
font::Print("Start Address: ");
|
||||
font::PrintMonospaceU64(this->context->cpu_ctx.aarch64_ctx.base_address);
|
||||
font::PrintMonospaceU64(m_context->cpu_ctx.aarch64_ctx.base_address);
|
||||
font::PrintLine("");
|
||||
}
|
||||
} else {
|
||||
if (is_aarch32) {
|
||||
font::Print("Backtrace - Start Address: ");
|
||||
font::PrintMonospaceU32(this->context->cpu_ctx.aarch32_ctx.base_address);
|
||||
font::PrintMonospaceU32(m_context->cpu_ctx.aarch32_ctx.base_address);
|
||||
font::PrintLine("");
|
||||
font::AddSpacingLines(0.5f);
|
||||
for (u32 i = 0; i < aarch32::CpuContext::MaxStackTraceDepth / 2; i++) {
|
||||
u32 bt_cur = 0, bt_next = 0;
|
||||
if (i < this->context->cpu_ctx.aarch32_ctx.stack_trace_size) {
|
||||
bt_cur = this->context->cpu_ctx.aarch32_ctx.stack_trace[i];
|
||||
if (i < m_context->cpu_ctx.aarch32_ctx.stack_trace_size) {
|
||||
bt_cur = m_context->cpu_ctx.aarch32_ctx.stack_trace[i];
|
||||
}
|
||||
if (i + aarch32::CpuContext::MaxStackTraceDepth / 2 < this->context->cpu_ctx.aarch32_ctx.stack_trace_size) {
|
||||
bt_next = this->context->cpu_ctx.aarch32_ctx.stack_trace[i + aarch32::CpuContext::MaxStackTraceDepth / 2];
|
||||
if (i + aarch32::CpuContext::MaxStackTraceDepth / 2 < m_context->cpu_ctx.aarch32_ctx.stack_trace_size) {
|
||||
bt_next = m_context->cpu_ctx.aarch32_ctx.stack_trace[i + aarch32::CpuContext::MaxStackTraceDepth / 2];
|
||||
}
|
||||
|
||||
if (i < this->context->cpu_ctx.aarch32_ctx.stack_trace_size) {
|
||||
if (i < m_context->cpu_ctx.aarch32_ctx.stack_trace_size) {
|
||||
u32 x = font::GetX();
|
||||
font::PrintFormat("BT[%02d]: ", i);
|
||||
font::SetPosition(x + 72, font::GetY());
|
||||
@@ -385,7 +385,7 @@ namespace ams::fatal::srv {
|
||||
font::Print(" ");
|
||||
}
|
||||
|
||||
if (i + aarch32::CpuContext::MaxStackTraceDepth / 2 < this->context->cpu_ctx.aarch32_ctx.stack_trace_size) {
|
||||
if (i + aarch32::CpuContext::MaxStackTraceDepth / 2 < m_context->cpu_ctx.aarch32_ctx.stack_trace_size) {
|
||||
u32 x = font::GetX();
|
||||
font::PrintFormat("BT[%02d]: ", i + aarch32::CpuContext::MaxStackTraceDepth / 2);
|
||||
font::SetPosition(x + 72, font::GetY());
|
||||
@@ -398,19 +398,19 @@ namespace ams::fatal::srv {
|
||||
}
|
||||
} else {
|
||||
font::Print("Backtrace - Start Address: ");
|
||||
font::PrintMonospaceU64(this->context->cpu_ctx.aarch64_ctx.base_address);
|
||||
font::PrintMonospaceU64(m_context->cpu_ctx.aarch64_ctx.base_address);
|
||||
font::PrintLine("");
|
||||
font::AddSpacingLines(0.5f);
|
||||
for (u32 i = 0; i < aarch64::CpuContext::MaxStackTraceDepth / 2; i++) {
|
||||
u64 bt_cur = 0, bt_next = 0;
|
||||
if (i < this->context->cpu_ctx.aarch64_ctx.stack_trace_size) {
|
||||
bt_cur = this->context->cpu_ctx.aarch64_ctx.stack_trace[i];
|
||||
if (i < m_context->cpu_ctx.aarch64_ctx.stack_trace_size) {
|
||||
bt_cur = m_context->cpu_ctx.aarch64_ctx.stack_trace[i];
|
||||
}
|
||||
if (i + aarch64::CpuContext::MaxStackTraceDepth / 2 < this->context->cpu_ctx.aarch64_ctx.stack_trace_size) {
|
||||
bt_next = this->context->cpu_ctx.aarch64_ctx.stack_trace[i + aarch64::CpuContext::MaxStackTraceDepth / 2];
|
||||
if (i + aarch64::CpuContext::MaxStackTraceDepth / 2 < m_context->cpu_ctx.aarch64_ctx.stack_trace_size) {
|
||||
bt_next = m_context->cpu_ctx.aarch64_ctx.stack_trace[i + aarch64::CpuContext::MaxStackTraceDepth / 2];
|
||||
}
|
||||
|
||||
if (i < this->context->cpu_ctx.aarch64_ctx.stack_trace_size) {
|
||||
if (i < m_context->cpu_ctx.aarch64_ctx.stack_trace_size) {
|
||||
u32 x = font::GetX();
|
||||
font::PrintFormat("BT[%02d]: ", i);
|
||||
font::SetPosition(x + 72, font::GetY());
|
||||
@@ -418,7 +418,7 @@ namespace ams::fatal::srv {
|
||||
font::Print(" ");
|
||||
}
|
||||
|
||||
if (i + aarch64::CpuContext::MaxStackTraceDepth / 2 < this->context->cpu_ctx.aarch64_ctx.stack_trace_size) {
|
||||
if (i + aarch64::CpuContext::MaxStackTraceDepth / 2 < m_context->cpu_ctx.aarch64_ctx.stack_trace_size) {
|
||||
u32 x = font::GetX();
|
||||
font::PrintFormat("BT[%02d]: ", i + aarch64::CpuContext::MaxStackTraceDepth / 2);
|
||||
font::SetPosition(x + 72, font::GetY());
|
||||
@@ -439,7 +439,7 @@ namespace ams::fatal::srv {
|
||||
R_TRY(nvFenceInit());
|
||||
|
||||
/* Create nvmap. */
|
||||
R_TRY(nvMapCreate(std::addressof(this->map), g_framebuffer_memory, sizeof(g_framebuffer_memory), 0x20000, NvKind_Pitch, true));
|
||||
R_TRY(nvMapCreate(std::addressof(m_map), g_framebuffer_memory, sizeof(g_framebuffer_memory), 0x20000, NvKind_Pitch, true));
|
||||
|
||||
/* Setup graphics buffer. */
|
||||
{
|
||||
@@ -458,14 +458,14 @@ namespace ams::fatal::srv {
|
||||
grbuf.planes[0].layout = NvLayout_BlockLinear;
|
||||
grbuf.planes[0].kind = NvKind_Generic_16BX2;
|
||||
grbuf.planes[0].block_height_log2 = 4;
|
||||
grbuf.nvmap_id = nvMapGetId(std::addressof(this->map));
|
||||
grbuf.nvmap_id = nvMapGetId(std::addressof(m_map));
|
||||
grbuf.stride = FatalScreenWidthAligned;
|
||||
grbuf.total_size = sizeof(g_framebuffer_memory);
|
||||
grbuf.planes[0].pitch = FatalScreenWidthAlignedBytes;
|
||||
grbuf.planes[0].size = sizeof(g_framebuffer_memory);
|
||||
grbuf.planes[0].offset = 0;
|
||||
|
||||
R_TRY(nwindowConfigureBuffer(std::addressof(this->win), 0, std::addressof(grbuf)));
|
||||
R_TRY(nwindowConfigureBuffer(std::addressof(m_win), 0, std::addressof(grbuf)));
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
@@ -473,9 +473,9 @@ namespace ams::fatal::srv {
|
||||
|
||||
void ShowFatalTask::DisplayPreRenderedFrame() {
|
||||
s32 slot;
|
||||
R_ABORT_UNLESS(nwindowDequeueBuffer(std::addressof(this->win), std::addressof(slot), nullptr));
|
||||
R_ABORT_UNLESS(nwindowDequeueBuffer(std::addressof(m_win), std::addressof(slot), nullptr));
|
||||
dd::FlushDataCache(g_framebuffer_memory, sizeof(g_framebuffer_memory));
|
||||
R_ABORT_UNLESS(nwindowQueueBuffer(std::addressof(this->win), this->win.cur_slot, NULL));
|
||||
R_ABORT_UNLESS(nwindowQueueBuffer(std::addressof(m_win), m_win.cur_slot, NULL));
|
||||
}
|
||||
|
||||
Result ShowFatalTask::ShowFatal() {
|
||||
@@ -493,7 +493,7 @@ namespace ams::fatal::srv {
|
||||
|
||||
Result ShowFatalTask::Run() {
|
||||
/* Don't show the fatal error screen until we've verified the battery is okay. */
|
||||
this->context->battery_event->Wait();
|
||||
m_context->battery_event->Wait();
|
||||
|
||||
return ShowFatal();
|
||||
}
|
||||
|
||||
@@ -59,15 +59,15 @@ namespace ams::ldr::caps {
|
||||
using IdBits = CapabilityField<0, static_cast<size_t>(Id) + 1>; \
|
||||
static constexpr u32 IdBitsValue = (static_cast<u32>(1) << static_cast<size_t>(Id)) - 1; \
|
||||
private: \
|
||||
util::BitPack32 value; \
|
||||
util::BitPack32 m_value; \
|
||||
private: \
|
||||
template<typename FieldType> \
|
||||
constexpr ALWAYS_INLINE typename FieldType::Type Get() const { return this->value.Get<FieldType>(); } \
|
||||
constexpr ALWAYS_INLINE typename FieldType::Type Get() const { return m_value.Get<FieldType>(); } \
|
||||
template<typename FieldType> \
|
||||
constexpr ALWAYS_INLINE void Set(typename FieldType::Type fv) { this->value.Set<FieldType>(fv); } \
|
||||
constexpr ALWAYS_INLINE u32 GetValue() const { return this->value.value; } \
|
||||
constexpr ALWAYS_INLINE void Set(typename FieldType::Type fv) { m_value.Set<FieldType>(fv); } \
|
||||
constexpr ALWAYS_INLINE u32 GetValue() const { return m_value.value; } \
|
||||
public: \
|
||||
constexpr ALWAYS_INLINE CAPABILITY_CLASS_NAME(id)(util::BitPack32 v) : value{v} { /* ... */ } \
|
||||
constexpr ALWAYS_INLINE CAPABILITY_CLASS_NAME(id)(util::BitPack32 v) : m_value{v} { /* ... */ } \
|
||||
\
|
||||
static constexpr CAPABILITY_CLASS_NAME(id) Decode(util::BitPack32 v) { return CAPABILITY_CLASS_NAME(id)(v); } \
|
||||
\
|
||||
|
||||
@@ -25,23 +25,23 @@ namespace ams::ldr {
|
||||
}
|
||||
|
||||
/* ScopedCodeMount functionality. */
|
||||
ScopedCodeMount::ScopedCodeMount(const ncm::ProgramLocation &loc) : lk(g_scoped_code_mount_lock), has_status(false), mounted_ams(false), mounted_sd_or_code(false), mounted_code(false) {
|
||||
this->result = this->Initialize(loc);
|
||||
ScopedCodeMount::ScopedCodeMount(const ncm::ProgramLocation &loc) : m_lk(g_scoped_code_mount_lock), m_has_status(false), m_mounted_ams(false), m_mounted_sd_or_code(false), m_mounted_code(false) {
|
||||
m_result = this->Initialize(loc);
|
||||
}
|
||||
|
||||
ScopedCodeMount::ScopedCodeMount(const ncm::ProgramLocation &loc, const cfg::OverrideStatus &o) : lk(g_scoped_code_mount_lock), override_status(o), has_status(true), mounted_ams(false), mounted_sd_or_code(false), mounted_code(false) {
|
||||
this->result = this->Initialize(loc);
|
||||
ScopedCodeMount::ScopedCodeMount(const ncm::ProgramLocation &loc, const cfg::OverrideStatus &o) : m_lk(g_scoped_code_mount_lock), m_override_status(o), m_has_status(true), m_mounted_ams(false), m_mounted_sd_or_code(false), m_mounted_code(false) {
|
||||
m_result = this->Initialize(loc);
|
||||
}
|
||||
|
||||
ScopedCodeMount::~ScopedCodeMount() {
|
||||
/* Unmount filesystems. */
|
||||
if (this->mounted_ams) {
|
||||
if (m_mounted_ams) {
|
||||
fs::Unmount(AtmosphereCodeMountName);
|
||||
}
|
||||
if (this->mounted_sd_or_code) {
|
||||
if (m_mounted_sd_or_code) {
|
||||
fs::Unmount(SdOrCodeMountName);
|
||||
}
|
||||
if (this->mounted_code) {
|
||||
if (m_mounted_code) {
|
||||
fs::Unmount(CodeMountName);
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,7 @@ namespace ams::ldr {
|
||||
Result ScopedCodeMount::Initialize(const ncm::ProgramLocation &loc) {
|
||||
/* Capture override status, if necessary. */
|
||||
this->EnsureOverrideStatus(loc);
|
||||
AMS_ABORT_UNLESS(this->has_status);
|
||||
AMS_ABORT_UNLESS(m_has_status);
|
||||
|
||||
/* Get the content path. */
|
||||
char content_path[fs::EntryNameLengthMax + 1] = "/";
|
||||
@@ -58,27 +58,27 @@ namespace ams::ldr {
|
||||
}
|
||||
|
||||
/* Mount the atmosphere code file system. */
|
||||
R_TRY(fs::MountCodeForAtmosphereWithRedirection(std::addressof(this->ams_code_verification_data), AtmosphereCodeMountName, content_path, loc.program_id, this->override_status.IsHbl(), this->override_status.IsProgramSpecific()));
|
||||
this->mounted_ams = true;
|
||||
R_TRY(fs::MountCodeForAtmosphereWithRedirection(std::addressof(m_ams_code_verification_data), AtmosphereCodeMountName, content_path, loc.program_id, m_override_status.IsHbl(), m_override_status.IsProgramSpecific()));
|
||||
m_mounted_ams = true;
|
||||
|
||||
/* Mount the sd or base code file system. */
|
||||
R_TRY(fs::MountCodeForAtmosphere(std::addressof(this->sd_or_base_code_verification_data), SdOrCodeMountName, content_path, loc.program_id));
|
||||
this->mounted_sd_or_code = true;
|
||||
R_TRY(fs::MountCodeForAtmosphere(std::addressof(m_sd_or_base_code_verification_data), SdOrCodeMountName, content_path, loc.program_id));
|
||||
m_mounted_sd_or_code = true;
|
||||
|
||||
/* Mount the base code file system. */
|
||||
if (R_SUCCEEDED(fs::MountCode(std::addressof(this->base_code_verification_data), CodeMountName, content_path, loc.program_id))) {
|
||||
this->mounted_code = true;
|
||||
if (R_SUCCEEDED(fs::MountCode(std::addressof(m_base_code_verification_data), CodeMountName, content_path, loc.program_id))) {
|
||||
m_mounted_code = true;
|
||||
}
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void ScopedCodeMount::EnsureOverrideStatus(const ncm::ProgramLocation &loc) {
|
||||
if (this->has_status) {
|
||||
if (m_has_status) {
|
||||
return;
|
||||
}
|
||||
this->override_status = cfg::CaptureOverrideStatus(loc.program_id);
|
||||
this->has_status = true;
|
||||
m_override_status = cfg::CaptureOverrideStatus(loc.program_id);
|
||||
m_has_status = true;
|
||||
}
|
||||
|
||||
/* Redirection API. */
|
||||
|
||||
@@ -23,40 +23,40 @@ namespace ams::ldr {
|
||||
NON_COPYABLE(ScopedCodeMount);
|
||||
NON_MOVEABLE(ScopedCodeMount);
|
||||
private:
|
||||
std::scoped_lock<os::SdkMutex> lk;
|
||||
cfg::OverrideStatus override_status;
|
||||
fs::CodeVerificationData ams_code_verification_data;
|
||||
fs::CodeVerificationData sd_or_base_code_verification_data;
|
||||
fs::CodeVerificationData base_code_verification_data;
|
||||
Result result;
|
||||
bool has_status;
|
||||
bool mounted_ams;
|
||||
bool mounted_sd_or_code;
|
||||
bool mounted_code;
|
||||
std::scoped_lock<os::SdkMutex> m_lk;
|
||||
cfg::OverrideStatus m_override_status;
|
||||
fs::CodeVerificationData m_ams_code_verification_data;
|
||||
fs::CodeVerificationData m_sd_or_base_code_verification_data;
|
||||
fs::CodeVerificationData m_base_code_verification_data;
|
||||
Result m_result;
|
||||
bool m_has_status;
|
||||
bool m_mounted_ams;
|
||||
bool m_mounted_sd_or_code;
|
||||
bool m_mounted_code;
|
||||
public:
|
||||
ScopedCodeMount(const ncm::ProgramLocation &loc);
|
||||
ScopedCodeMount(const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status);
|
||||
~ScopedCodeMount();
|
||||
|
||||
Result GetResult() const {
|
||||
return this->result;
|
||||
return m_result;
|
||||
}
|
||||
|
||||
const cfg::OverrideStatus &GetOverrideStatus() const {
|
||||
AMS_ABORT_UNLESS(this->has_status);
|
||||
return this->override_status;
|
||||
AMS_ABORT_UNLESS(m_has_status);
|
||||
return m_override_status;
|
||||
}
|
||||
|
||||
const fs::CodeVerificationData &GetAtmosphereCodeVerificationData() const {
|
||||
return this->ams_code_verification_data;
|
||||
return m_ams_code_verification_data;
|
||||
}
|
||||
|
||||
const fs::CodeVerificationData &GetSdOrBaseCodeVerificationData() const {
|
||||
return this->sd_or_base_code_verification_data;
|
||||
return m_sd_or_base_code_verification_data;
|
||||
}
|
||||
|
||||
const fs::CodeVerificationData &GetCodeVerificationData() const {
|
||||
return this->base_code_verification_data;
|
||||
return m_base_code_verification_data;
|
||||
}
|
||||
private:
|
||||
Result Initialize(const ncm::ProgramLocation &loc);
|
||||
|
||||
@@ -18,9 +18,9 @@
|
||||
|
||||
namespace ams::pm::impl {
|
||||
|
||||
ProcessInfo::ProcessInfo(os::NativeHandle h, os::ProcessId pid, ldr::PinId pin, const ncm::ProgramLocation &l, const cfg::OverrideStatus &s) : process_id(pid), pin_id(pin), loc(l), status(s), handle(h), state(svc::ProcessState_Created), flags(0) {
|
||||
os::InitializeMultiWaitHolder(std::addressof(this->multi_wait_holder), this->handle);
|
||||
os::SetMultiWaitHolderUserData(std::addressof(this->multi_wait_holder), reinterpret_cast<uintptr_t>(this));
|
||||
ProcessInfo::ProcessInfo(os::NativeHandle h, os::ProcessId pid, ldr::PinId pin, const ncm::ProgramLocation &l, const cfg::OverrideStatus &s) : m_process_id(pid), m_pin_id(pin), m_loc(l), m_status(s), m_handle(h), m_state(svc::ProcessState_Created), m_flags(0) {
|
||||
os::InitializeMultiWaitHolder(std::addressof(m_multi_wait_holder), m_handle);
|
||||
os::SetMultiWaitHolderUserData(std::addressof(m_multi_wait_holder), reinterpret_cast<uintptr_t>(this));
|
||||
}
|
||||
|
||||
ProcessInfo::~ProcessInfo() {
|
||||
@@ -28,18 +28,18 @@ namespace ams::pm::impl {
|
||||
}
|
||||
|
||||
void ProcessInfo::Cleanup() {
|
||||
if (this->handle != os::InvalidNativeHandle) {
|
||||
if (m_handle != os::InvalidNativeHandle) {
|
||||
/* Unregister the process. */
|
||||
fsprUnregisterProgram(this->process_id.value);
|
||||
sm::manager::UnregisterProcess(this->process_id);
|
||||
ldr::pm::UnpinProgram(this->pin_id);
|
||||
fsprUnregisterProgram(m_process_id.value);
|
||||
sm::manager::UnregisterProcess(m_process_id);
|
||||
ldr::pm::UnpinProgram(m_pin_id);
|
||||
|
||||
/* Close the process's handle. */
|
||||
os::CloseNativeHandle(this->handle);
|
||||
this->handle = os::InvalidNativeHandle;
|
||||
os::CloseNativeHandle(m_handle);
|
||||
m_handle = os::InvalidNativeHandle;
|
||||
|
||||
/* Unlink the process from its multi wait. */
|
||||
os::UnlinkMultiWaitHolder(std::addressof(this->multi_wait_holder));
|
||||
os::UnlinkMultiWaitHolder(std::addressof(m_multi_wait_holder));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,26 +38,26 @@ namespace ams::pm::impl {
|
||||
Flag_UnhandledException = (1 << 9),
|
||||
};
|
||||
private:
|
||||
util::IntrusiveListNode list_node;
|
||||
const os::ProcessId process_id;
|
||||
const ldr::PinId pin_id;
|
||||
const ncm::ProgramLocation loc;
|
||||
const cfg::OverrideStatus status;
|
||||
os::NativeHandle handle;
|
||||
svc::ProcessState state;
|
||||
u32 flags;
|
||||
os::MultiWaitHolderType multi_wait_holder;
|
||||
util::IntrusiveListNode m_list_node;
|
||||
const os::ProcessId m_process_id;
|
||||
const ldr::PinId m_pin_id;
|
||||
const ncm::ProgramLocation m_loc;
|
||||
const cfg::OverrideStatus m_status;
|
||||
os::NativeHandle m_handle;
|
||||
svc::ProcessState m_state;
|
||||
u32 m_flags;
|
||||
os::MultiWaitHolderType m_multi_wait_holder;
|
||||
private:
|
||||
void SetFlag(Flag flag) {
|
||||
this->flags |= flag;
|
||||
m_flags |= flag;
|
||||
}
|
||||
|
||||
void ClearFlag(Flag flag) {
|
||||
this->flags &= ~flag;
|
||||
m_flags &= ~flag;
|
||||
}
|
||||
|
||||
bool HasFlag(Flag flag) const {
|
||||
return (this->flags & flag);
|
||||
return (m_flags & flag);
|
||||
}
|
||||
public:
|
||||
ProcessInfo(os::NativeHandle h, os::ProcessId pid, ldr::PinId pin, const ncm::ProgramLocation &l, const cfg::OverrideStatus &s);
|
||||
@@ -65,43 +65,43 @@ namespace ams::pm::impl {
|
||||
void Cleanup();
|
||||
|
||||
void LinkToMultiWait(os::MultiWaitType &multi_wait) {
|
||||
os::LinkMultiWaitHolder(std::addressof(multi_wait), std::addressof(this->multi_wait_holder));
|
||||
os::LinkMultiWaitHolder(std::addressof(multi_wait), std::addressof(m_multi_wait_holder));
|
||||
}
|
||||
|
||||
os::NativeHandle GetHandle() const {
|
||||
return this->handle;
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
os::ProcessId GetProcessId() const {
|
||||
return this->process_id;
|
||||
return m_process_id;
|
||||
}
|
||||
|
||||
ldr::PinId GetPinId() const {
|
||||
return this->pin_id;
|
||||
return m_pin_id;
|
||||
}
|
||||
|
||||
const ncm::ProgramLocation &GetProgramLocation() const {
|
||||
return this->loc;
|
||||
return m_loc;
|
||||
}
|
||||
|
||||
const cfg::OverrideStatus &GetOverrideStatus() const {
|
||||
return this->status;
|
||||
return m_status;
|
||||
}
|
||||
|
||||
svc::ProcessState GetState() const {
|
||||
return this->state;
|
||||
return m_state;
|
||||
}
|
||||
|
||||
void SetState(svc::ProcessState state) {
|
||||
this->state = state;
|
||||
m_state = state;
|
||||
}
|
||||
|
||||
bool HasStarted() const {
|
||||
return this->state != svc::ProcessState_Created && this->state != svc::ProcessState_CreatedAttached;
|
||||
return m_state != svc::ProcessState_Created && m_state != svc::ProcessState_CreatedAttached;
|
||||
}
|
||||
|
||||
bool HasTerminated() const {
|
||||
return this->state == svc::ProcessState_Terminated;
|
||||
return m_state == svc::ProcessState_Terminated;
|
||||
}
|
||||
|
||||
#define DEFINE_FLAG_SET(flag) \
|
||||
@@ -165,18 +165,18 @@ namespace ams::pm::impl {
|
||||
#undef DEFINE_FLAG_CLEAR
|
||||
};
|
||||
|
||||
class ProcessList final : public util::IntrusiveListMemberTraits<&ProcessInfo::list_node>::ListType {
|
||||
class ProcessList final : public util::IntrusiveListMemberTraits<&ProcessInfo::m_list_node>::ListType {
|
||||
private:
|
||||
os::SdkMutex lock;
|
||||
os::SdkMutex m_lock;
|
||||
public:
|
||||
constexpr ProcessList() : lock() { /* ... */ }
|
||||
constexpr ProcessList() : m_lock() { /* ... */ }
|
||||
|
||||
void Lock() {
|
||||
this->lock.Lock();
|
||||
m_lock.Lock();
|
||||
}
|
||||
|
||||
void Unlock() {
|
||||
this->lock.Unlock();
|
||||
m_lock.Unlock();
|
||||
}
|
||||
|
||||
void Remove(ProcessInfo *process_info) {
|
||||
@@ -184,18 +184,18 @@ namespace ams::pm::impl {
|
||||
}
|
||||
|
||||
ProcessInfo *Find(os::ProcessId process_id) {
|
||||
for (auto it = this->begin(); it != this->end(); it++) {
|
||||
if ((*it).GetProcessId() == process_id) {
|
||||
return std::addressof(*it);
|
||||
for (auto &info : *this) {
|
||||
if (info.GetProcessId() == process_id) {
|
||||
return std::addressof(info);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ProcessInfo *Find(ncm::ProgramId program_id) {
|
||||
for (auto it = this->begin(); it != this->end(); it++) {
|
||||
if ((*it).GetProgramLocation().program_id == program_id) {
|
||||
return std::addressof(*it);
|
||||
for (auto &info : *this) {
|
||||
if (info.GetProgramLocation().program_id == program_id) {
|
||||
return std::addressof(info);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@@ -205,30 +205,30 @@ namespace ams::pm::impl {
|
||||
|
||||
class ProcessListAccessor final {
|
||||
private:
|
||||
ProcessList &list;
|
||||
ProcessList &m_list;
|
||||
public:
|
||||
explicit ProcessListAccessor(ProcessList &l) : list(l) {
|
||||
this->list.Lock();
|
||||
explicit ProcessListAccessor(ProcessList &l) : m_list(l) {
|
||||
m_list.Lock();
|
||||
}
|
||||
|
||||
~ProcessListAccessor() {
|
||||
this->list.Unlock();
|
||||
m_list.Unlock();
|
||||
}
|
||||
|
||||
ProcessList *operator->() {
|
||||
return std::addressof(this->list);
|
||||
return std::addressof(m_list);
|
||||
}
|
||||
|
||||
const ProcessList *operator->() const {
|
||||
return std::addressof(this->list);
|
||||
return std::addressof(m_list);
|
||||
}
|
||||
|
||||
ProcessList &operator*() {
|
||||
return this->list;
|
||||
return m_list;
|
||||
}
|
||||
|
||||
const ProcessList &operator*() const {
|
||||
return this->list;
|
||||
return m_list;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -78,27 +78,27 @@ namespace ams::pm::impl {
|
||||
NON_MOVEABLE(ProcessInfoAllocator);
|
||||
static_assert(MaxProcessInfos >= 0x40, "MaxProcessInfos is too small.");
|
||||
private:
|
||||
util::TypedStorage<ProcessInfo> process_info_storages[MaxProcessInfos]{};
|
||||
bool process_info_allocated[MaxProcessInfos]{};
|
||||
os::SdkMutex lock{};
|
||||
util::TypedStorage<ProcessInfo> m_process_info_storages[MaxProcessInfos]{};
|
||||
bool m_process_info_allocated[MaxProcessInfos]{};
|
||||
os::SdkMutex m_lock{};
|
||||
private:
|
||||
constexpr inline size_t GetProcessInfoIndex(ProcessInfo *process_info) const {
|
||||
return process_info - GetPointer(this->process_info_storages[0]);
|
||||
return process_info - GetPointer(m_process_info_storages[0]);
|
||||
}
|
||||
public:
|
||||
constexpr ProcessInfoAllocator() = default;
|
||||
|
||||
template<typename... Args>
|
||||
ProcessInfo *AllocateProcessInfo(Args &&... args) {
|
||||
std::scoped_lock lk(this->lock);
|
||||
std::scoped_lock lk(m_lock);
|
||||
|
||||
for (size_t i = 0; i < MaxProcessInfos; i++) {
|
||||
if (!this->process_info_allocated[i]) {
|
||||
this->process_info_allocated[i] = true;
|
||||
if (!m_process_info_allocated[i]) {
|
||||
m_process_info_allocated[i] = true;
|
||||
|
||||
std::memset(this->process_info_storages + i, 0, sizeof(this->process_info_storages[i]));
|
||||
std::memset(m_process_info_storages + i, 0, sizeof(m_process_info_storages[i]));
|
||||
|
||||
return util::ConstructAt(this->process_info_storages[i], std::forward<Args>(args)...);
|
||||
return util::ConstructAt(m_process_info_storages[i], std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,14 +106,14 @@ namespace ams::pm::impl {
|
||||
}
|
||||
|
||||
void FreeProcessInfo(ProcessInfo *process_info) {
|
||||
std::scoped_lock lk(this->lock);
|
||||
std::scoped_lock lk(m_lock);
|
||||
|
||||
const size_t index = this->GetProcessInfoIndex(process_info);
|
||||
AMS_ABORT_UNLESS(index < MaxProcessInfos);
|
||||
AMS_ABORT_UNLESS(this->process_info_allocated[index]);
|
||||
AMS_ABORT_UNLESS(m_process_info_allocated[index]);
|
||||
|
||||
util::DestroyAt(this->process_info_storages[index]);
|
||||
this->process_info_allocated[index] = false;
|
||||
util::DestroyAt(m_process_info_storages[index]);
|
||||
m_process_info_allocated[index] = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -74,206 +74,277 @@ namespace ams::ro::impl {
|
||||
};
|
||||
|
||||
struct ProcessContext {
|
||||
bool nro_in_use[MaxNroInfos];
|
||||
bool nrr_in_use[MaxNrrInfos];
|
||||
NroInfo nro_infos[MaxNroInfos];
|
||||
NrrInfo nrr_infos[MaxNrrInfos];
|
||||
os::NativeHandle process_handle;
|
||||
os::ProcessId process_id;
|
||||
bool in_use;
|
||||
private:
|
||||
bool m_nro_in_use[MaxNroInfos]{};
|
||||
bool m_nrr_in_use[MaxNrrInfos]{};
|
||||
NroInfo m_nro_infos[MaxNroInfos]{};
|
||||
NrrInfo m_nrr_infos[MaxNrrInfos]{};
|
||||
os::NativeHandle m_process_handle = os::InvalidNativeHandle;
|
||||
os::ProcessId m_process_id = os::InvalidProcessId;
|
||||
bool m_in_use{};
|
||||
public:
|
||||
constexpr ProcessContext() = default;
|
||||
|
||||
ncm::ProgramId GetProgramId(os::NativeHandle other_process_h) const {
|
||||
/* Automatically select a handle, allowing for override. */
|
||||
if (other_process_h != os::InvalidNativeHandle) {
|
||||
return os::GetProgramId(other_process_h);
|
||||
} else {
|
||||
return os::GetProgramId(this->process_handle);
|
||||
void Initialize(os::NativeHandle process_handle, os::ProcessId process_id) {
|
||||
AMS_ABORT_UNLESS(!m_in_use);
|
||||
|
||||
std::memset(m_nro_in_use, 0, sizeof(m_nro_in_use));
|
||||
std::memset(m_nrr_in_use, 0, sizeof(m_nrr_in_use));
|
||||
std::memset(m_nro_infos, 0, sizeof(m_nro_infos));
|
||||
std::memset(m_nrr_infos, 0, sizeof(m_nrr_infos));
|
||||
|
||||
m_process_handle = process_handle;
|
||||
m_process_id = process_id;
|
||||
m_in_use = true;
|
||||
}
|
||||
}
|
||||
|
||||
Result GetNrrInfoByAddress(NrrInfo **out, u64 nrr_heap_address) {
|
||||
for (size_t i = 0; i < MaxNrrInfos; i++) {
|
||||
if (this->nrr_in_use[i] && this->nrr_infos[i].nrr_heap_address == nrr_heap_address) {
|
||||
if (out != nullptr) {
|
||||
*out = this->nrr_infos + i;
|
||||
void Finalize() {
|
||||
AMS_ABORT_UNLESS(m_in_use);
|
||||
|
||||
if (m_process_handle != os::InvalidNativeHandle) {
|
||||
for (size_t i = 0; i < MaxNrrInfos; i++) {
|
||||
if (m_nrr_in_use[i]) {
|
||||
UnmapNrr(m_process_handle, m_nrr_infos[i].mapped_header, m_nrr_infos[i].nrr_heap_address, m_nrr_infos[i].nrr_heap_size, m_nrr_infos[i].mapped_code_address);
|
||||
}
|
||||
}
|
||||
os::CloseNativeHandle(m_process_handle);
|
||||
}
|
||||
|
||||
std::memset(m_nro_in_use, 0, sizeof(m_nro_in_use));
|
||||
std::memset(m_nrr_in_use, 0, sizeof(m_nrr_in_use));
|
||||
std::memset(m_nro_infos, 0, sizeof(m_nro_infos));
|
||||
std::memset(m_nrr_infos, 0, sizeof(m_nrr_infos));
|
||||
|
||||
m_process_handle = os::InvalidNativeHandle;
|
||||
m_process_id = os::InvalidProcessId;
|
||||
|
||||
m_in_use = false;
|
||||
}
|
||||
|
||||
os::NativeHandle GetProcessHandle() const {
|
||||
return m_process_handle;
|
||||
}
|
||||
|
||||
os::ProcessId GetProcessId() const {
|
||||
return m_process_id;
|
||||
}
|
||||
|
||||
bool IsFree() const {
|
||||
return !m_in_use;
|
||||
}
|
||||
|
||||
ncm::ProgramId GetProgramId(os::NativeHandle other_process_h) const {
|
||||
/* Automatically select a handle, allowing for override. */
|
||||
if (other_process_h != os::InvalidNativeHandle) {
|
||||
return os::GetProgramId(other_process_h);
|
||||
} else {
|
||||
return os::GetProgramId(m_process_handle);
|
||||
}
|
||||
}
|
||||
|
||||
Result GetNrrInfoByAddress(NrrInfo **out, u64 nrr_heap_address) {
|
||||
for (size_t i = 0; i < MaxNrrInfos; i++) {
|
||||
if (m_nrr_in_use[i] && m_nrr_infos[i].nrr_heap_address == nrr_heap_address) {
|
||||
if (out != nullptr) {
|
||||
*out = m_nrr_infos + i;
|
||||
}
|
||||
return ResultSuccess();
|
||||
}
|
||||
}
|
||||
return ro::ResultNotRegistered();
|
||||
}
|
||||
|
||||
Result GetFreeNrrInfo(NrrInfo **out) {
|
||||
for (size_t i = 0; i < MaxNrrInfos; i++) {
|
||||
if (!m_nrr_in_use[i]) {
|
||||
if (out != nullptr) {
|
||||
*out = m_nrr_infos + i;
|
||||
}
|
||||
return ResultSuccess();
|
||||
}
|
||||
}
|
||||
return ro::ResultTooManyNrr();
|
||||
}
|
||||
|
||||
Result GetNroInfoByAddress(NroInfo **out, u64 nro_address) {
|
||||
for (size_t i = 0; i < MaxNroInfos; i++) {
|
||||
if (m_nro_in_use[i] && m_nro_infos[i].base_address == nro_address) {
|
||||
if (out != nullptr) {
|
||||
*out = m_nro_infos + i;
|
||||
}
|
||||
return ResultSuccess();
|
||||
}
|
||||
}
|
||||
return ro::ResultNotLoaded();
|
||||
}
|
||||
|
||||
Result GetNroInfoByModuleId(NroInfo **out, const ModuleId *module_id) {
|
||||
for (size_t i = 0; i < MaxNroInfos; i++) {
|
||||
if (m_nro_in_use[i] && std::memcmp(std::addressof(m_nro_infos[i].module_id), module_id, sizeof(*module_id)) == 0) {
|
||||
if (out != nullptr) {
|
||||
*out = m_nro_infos + i;
|
||||
}
|
||||
return ResultSuccess();
|
||||
}
|
||||
}
|
||||
return ro::ResultNotLoaded();
|
||||
}
|
||||
|
||||
Result GetFreeNroInfo(NroInfo **out) {
|
||||
for (size_t i = 0; i < MaxNroInfos; i++) {
|
||||
if (!m_nro_in_use[i]) {
|
||||
if (out != nullptr) {
|
||||
*out = m_nro_infos + i;
|
||||
}
|
||||
return ResultSuccess();
|
||||
}
|
||||
}
|
||||
return ro::ResultTooManyNro();
|
||||
}
|
||||
|
||||
Result ValidateHasNroHash(const NroHeader *nro_header) const {
|
||||
/* Calculate hash. */
|
||||
Sha256Hash hash;
|
||||
crypto::GenerateSha256Hash(std::addressof(hash), sizeof(hash), nro_header, nro_header->GetSize());
|
||||
|
||||
for (size_t i = 0; i < MaxNrrInfos; i++) {
|
||||
/* Ensure we only check NRRs that are used. */
|
||||
if (!m_nrr_in_use[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get the mapped header, ensure that it has hashes. */
|
||||
const NrrHeader *mapped_nrr_header = m_nrr_infos[i].mapped_header;
|
||||
const size_t mapped_num_hashes = mapped_nrr_header->GetNumHashes();
|
||||
if (mapped_num_hashes == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Locate the hash within the mapped array. */
|
||||
const Sha256Hash *mapped_nro_hashes_start = reinterpret_cast<const Sha256Hash *>(mapped_nrr_header->GetHashes());
|
||||
const Sha256Hash *mapped_nro_hashes_end = mapped_nro_hashes_start + mapped_nrr_header->GetNumHashes();
|
||||
|
||||
const Sha256Hash *mapped_lower_bound = std::lower_bound(mapped_nro_hashes_start, mapped_nro_hashes_end, hash);
|
||||
if (mapped_lower_bound == mapped_nro_hashes_end || (*mapped_lower_bound != hash)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check that the hash entry is valid, since our heuristic passed. */
|
||||
const void *nrr_hash = std::addressof(m_nrr_infos[i].signed_area_hash);
|
||||
const void *signed_area = m_nrr_infos[i].cached_signed_area;
|
||||
const size_t signed_area_size = m_nrr_infos[i].cached_signed_area_size;
|
||||
const size_t hashes_offset = m_nrr_infos[i].cached_hashes_offset;
|
||||
const size_t num_hashes = m_nrr_infos[i].cached_num_hashes;
|
||||
const u8 *hash_table = reinterpret_cast<const u8 *>(mapped_nro_hashes_start);
|
||||
if (!ValidateNrrHashTableEntry(signed_area, signed_area_size, hashes_offset, num_hashes, nrr_hash, hash_table, std::addressof(hash))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* The hash is valid! */
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
return ro::ResultNotAuthorized();
|
||||
}
|
||||
return ro::ResultNotRegistered();
|
||||
}
|
||||
|
||||
Result GetFreeNrrInfo(NrrInfo **out) {
|
||||
for (size_t i = 0; i < MaxNrrInfos; i++) {
|
||||
if (!this->nrr_in_use[i]) {
|
||||
if (out != nullptr) {
|
||||
*out = this->nrr_infos + i;
|
||||
}
|
||||
return ResultSuccess();
|
||||
}
|
||||
}
|
||||
return ro::ResultTooManyNrr();
|
||||
}
|
||||
Result ValidateNro(ModuleId *out_module_id, u64 *out_rx_size, u64 *out_ro_size, u64 *out_rw_size, u64 base_address, u64 expected_nro_size, u64 expected_bss_size) {
|
||||
/* Find space to map the NRO. */
|
||||
uintptr_t map_address;
|
||||
R_UNLESS(R_SUCCEEDED(SearchFreeRegion(std::addressof(map_address), expected_nro_size)), ro::ResultOutOfAddressSpace());
|
||||
|
||||
Result GetNroInfoByAddress(NroInfo **out, u64 nro_address) {
|
||||
for (size_t i = 0; i < MaxNroInfos; i++) {
|
||||
if (this->nro_in_use[i] && this->nro_infos[i].base_address == nro_address) {
|
||||
if (out != nullptr) {
|
||||
*out = this->nro_infos + i;
|
||||
}
|
||||
return ResultSuccess();
|
||||
}
|
||||
}
|
||||
return ro::ResultNotLoaded();
|
||||
}
|
||||
/* Actually map the NRO. */
|
||||
AutoCloseMap nro_map(map_address, m_process_handle, base_address, expected_nro_size);
|
||||
R_TRY(nro_map.GetResult());
|
||||
|
||||
Result GetNroInfoByModuleId(NroInfo **out, const ModuleId *module_id) {
|
||||
for (size_t i = 0; i < MaxNroInfos; i++) {
|
||||
if (this->nro_in_use[i] && std::memcmp(std::addressof(this->nro_infos[i].module_id), module_id, sizeof(*module_id)) == 0) {
|
||||
if (out != nullptr) {
|
||||
*out = this->nro_infos + i;
|
||||
}
|
||||
return ResultSuccess();
|
||||
}
|
||||
}
|
||||
return ro::ResultNotLoaded();
|
||||
}
|
||||
/* Validate header. */
|
||||
const NroHeader *header = reinterpret_cast<const NroHeader *>(map_address);
|
||||
R_UNLESS(header->IsMagicValid(), ro::ResultInvalidNro());
|
||||
|
||||
Result GetFreeNroInfo(NroInfo **out) {
|
||||
for (size_t i = 0; i < MaxNroInfos; i++) {
|
||||
if (!this->nro_in_use[i]) {
|
||||
if (out != nullptr) {
|
||||
*out = this->nro_infos + i;
|
||||
}
|
||||
return ResultSuccess();
|
||||
}
|
||||
}
|
||||
return ro::ResultTooManyNro();
|
||||
}
|
||||
/* Read sizes from header. */
|
||||
const u64 nro_size = header->GetSize();
|
||||
const u64 text_ofs = header->GetTextOffset();
|
||||
const u64 text_size = header->GetTextSize();
|
||||
const u64 ro_ofs = header->GetRoOffset();
|
||||
const u64 ro_size = header->GetRoSize();
|
||||
const u64 rw_ofs = header->GetRwOffset();
|
||||
const u64 rw_size = header->GetRwSize();
|
||||
const u64 bss_size = header->GetBssSize();
|
||||
|
||||
Result ValidateHasNroHash(const NroHeader *nro_header) const {
|
||||
/* Calculate hash. */
|
||||
Sha256Hash hash;
|
||||
crypto::GenerateSha256Hash(std::addressof(hash), sizeof(hash), nro_header, nro_header->GetSize());
|
||||
/* Validate sizes meet expected. */
|
||||
R_UNLESS(nro_size == expected_nro_size, ro::ResultInvalidNro());
|
||||
R_UNLESS(bss_size == expected_bss_size, ro::ResultInvalidNro());
|
||||
|
||||
for (size_t i = 0; i < MaxNrrInfos; i++) {
|
||||
/* Ensure we only check NRRs that are used. */
|
||||
if (!this->nrr_in_use[i]) {
|
||||
continue;
|
||||
}
|
||||
/* Validate all sizes are aligned. */
|
||||
R_UNLESS(util::IsAligned(text_size, os::MemoryPageSize), ro::ResultInvalidNro());
|
||||
R_UNLESS(util::IsAligned(ro_size, os::MemoryPageSize), ro::ResultInvalidNro());
|
||||
R_UNLESS(util::IsAligned(rw_size, os::MemoryPageSize), ro::ResultInvalidNro());
|
||||
R_UNLESS(util::IsAligned(bss_size, os::MemoryPageSize), ro::ResultInvalidNro());
|
||||
|
||||
/* Get the mapped header, ensure that it has hashes. */
|
||||
const NrrHeader *mapped_nrr_header = this->nrr_infos[i].mapped_header;
|
||||
const size_t mapped_num_hashes = mapped_nrr_header->GetNumHashes();
|
||||
if (mapped_num_hashes == 0) {
|
||||
continue;
|
||||
}
|
||||
/* Validate sections are in order. */
|
||||
R_UNLESS(text_ofs <= ro_ofs, ro::ResultInvalidNro());
|
||||
R_UNLESS(ro_ofs <= rw_ofs, ro::ResultInvalidNro());
|
||||
|
||||
/* Locate the hash within the mapped array. */
|
||||
const Sha256Hash *mapped_nro_hashes_start = reinterpret_cast<const Sha256Hash *>(mapped_nrr_header->GetHashes());
|
||||
const Sha256Hash *mapped_nro_hashes_end = mapped_nro_hashes_start + mapped_nrr_header->GetNumHashes();
|
||||
/* Validate sections are sequential and contiguous. */
|
||||
R_UNLESS(text_ofs == 0, ro::ResultInvalidNro());
|
||||
R_UNLESS(text_ofs + text_size == ro_ofs, ro::ResultInvalidNro());
|
||||
R_UNLESS(ro_ofs + ro_size == rw_ofs, ro::ResultInvalidNro());
|
||||
R_UNLESS(rw_ofs + rw_size == nro_size, ro::ResultInvalidNro());
|
||||
|
||||
const Sha256Hash *mapped_lower_bound = std::lower_bound(mapped_nro_hashes_start, mapped_nro_hashes_end, hash);
|
||||
if (mapped_lower_bound == mapped_nro_hashes_end || (*mapped_lower_bound != hash)) {
|
||||
continue;
|
||||
}
|
||||
/* Verify NRO hash. */
|
||||
R_TRY(this->ValidateHasNroHash(header));
|
||||
|
||||
/* Check that the hash entry is valid, since our heuristic passed. */
|
||||
const void *nrr_hash = std::addressof(this->nrr_infos[i].signed_area_hash);
|
||||
const void *signed_area = this->nrr_infos[i].cached_signed_area;
|
||||
const size_t signed_area_size = this->nrr_infos[i].cached_signed_area_size;
|
||||
const size_t hashes_offset = this->nrr_infos[i].cached_hashes_offset;
|
||||
const size_t num_hashes = this->nrr_infos[i].cached_num_hashes;
|
||||
const u8 *hash_table = reinterpret_cast<const u8 *>(mapped_nro_hashes_start);
|
||||
if (!ValidateNrrHashTableEntry(signed_area, signed_area_size, hashes_offset, num_hashes, nrr_hash, hash_table, std::addressof(hash))) {
|
||||
continue;
|
||||
}
|
||||
/* Check if NRO has already been loaded. */
|
||||
const ModuleId *module_id = header->GetModuleId();
|
||||
R_UNLESS(R_FAILED(this->GetNroInfoByModuleId(nullptr, module_id)), ro::ResultAlreadyLoaded());
|
||||
|
||||
/* The hash is valid! */
|
||||
/* Apply patches to NRO. */
|
||||
LocateAndApplyIpsPatchesToModule(module_id, reinterpret_cast<u8 *>(map_address), nro_size);
|
||||
|
||||
/* Copy to output. */
|
||||
*out_module_id = *module_id;
|
||||
*out_rx_size = text_size;
|
||||
*out_ro_size = ro_size;
|
||||
*out_rw_size = rw_size;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
return ro::ResultNotAuthorized();
|
||||
}
|
||||
void SetNrrInfoInUse(const NrrInfo *info, bool in_use) {
|
||||
AMS_ASSERT(std::addressof(m_nrr_infos[0]) <= info && info <= std::addressof(m_nrr_infos[MaxNrrInfos - 1]));
|
||||
const size_t index = info - std::addressof(m_nrr_infos[0]);
|
||||
m_nrr_in_use[index] = in_use;
|
||||
}
|
||||
|
||||
Result ValidateNro(ModuleId *out_module_id, u64 *out_rx_size, u64 *out_ro_size, u64 *out_rw_size, u64 base_address, u64 expected_nro_size, u64 expected_bss_size) {
|
||||
/* Find space to map the NRO. */
|
||||
uintptr_t map_address;
|
||||
R_UNLESS(R_SUCCEEDED(SearchFreeRegion(std::addressof(map_address), expected_nro_size)), ro::ResultOutOfAddressSpace());
|
||||
void SetNroInfoInUse(const NroInfo *info, bool in_use) {
|
||||
AMS_ASSERT(std::addressof(m_nro_infos[0]) <= info && info <= std::addressof(m_nro_infos[MaxNroInfos - 1]));
|
||||
const size_t index = info - std::addressof(m_nro_infos[0]);
|
||||
m_nro_in_use[index] = in_use;
|
||||
}
|
||||
|
||||
/* Actually map the NRO. */
|
||||
AutoCloseMap nro_map(map_address, this->process_handle, base_address, expected_nro_size);
|
||||
R_TRY(nro_map.GetResult());
|
||||
void GetProcessModuleInfo(u32 *out_count, LoaderModuleInfo *out_infos, size_t max_out_count) const {
|
||||
size_t count = 0;
|
||||
|
||||
/* Validate header. */
|
||||
const NroHeader *header = reinterpret_cast<const NroHeader *>(map_address);
|
||||
R_UNLESS(header->IsMagicValid(), ro::ResultInvalidNro());
|
||||
for (size_t i = 0; i < MaxNroInfos && count < max_out_count; i++) {
|
||||
if (!m_nro_in_use[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Read sizes from header. */
|
||||
const u64 nro_size = header->GetSize();
|
||||
const u64 text_ofs = header->GetTextOffset();
|
||||
const u64 text_size = header->GetTextSize();
|
||||
const u64 ro_ofs = header->GetRoOffset();
|
||||
const u64 ro_size = header->GetRoSize();
|
||||
const u64 rw_ofs = header->GetRwOffset();
|
||||
const u64 rw_size = header->GetRwSize();
|
||||
const u64 bss_size = header->GetBssSize();
|
||||
const NroInfo *nro_info = m_nro_infos + i;
|
||||
|
||||
/* Validate sizes meet expected. */
|
||||
R_UNLESS(nro_size == expected_nro_size, ro::ResultInvalidNro());
|
||||
R_UNLESS(bss_size == expected_bss_size, ro::ResultInvalidNro());
|
||||
/* Just copy out the info. */
|
||||
LoaderModuleInfo *out_info = std::addressof(out_infos[count++]);
|
||||
memcpy(out_info->build_id, std::addressof(nro_info->module_id), sizeof(nro_info->module_id));
|
||||
out_info->base_address = nro_info->base_address;
|
||||
out_info->size = nro_info->nro_heap_size + nro_info->bss_heap_size;
|
||||
}
|
||||
|
||||
/* Validate all sizes are aligned. */
|
||||
R_UNLESS(util::IsAligned(text_size, os::MemoryPageSize), ro::ResultInvalidNro());
|
||||
R_UNLESS(util::IsAligned(ro_size, os::MemoryPageSize), ro::ResultInvalidNro());
|
||||
R_UNLESS(util::IsAligned(rw_size, os::MemoryPageSize), ro::ResultInvalidNro());
|
||||
R_UNLESS(util::IsAligned(bss_size, os::MemoryPageSize), ro::ResultInvalidNro());
|
||||
|
||||
/* Validate sections are in order. */
|
||||
R_UNLESS(text_ofs <= ro_ofs, ro::ResultInvalidNro());
|
||||
R_UNLESS(ro_ofs <= rw_ofs, ro::ResultInvalidNro());
|
||||
|
||||
/* Validate sections are sequential and contiguous. */
|
||||
R_UNLESS(text_ofs == 0, ro::ResultInvalidNro());
|
||||
R_UNLESS(text_ofs + text_size == ro_ofs, ro::ResultInvalidNro());
|
||||
R_UNLESS(ro_ofs + ro_size == rw_ofs, ro::ResultInvalidNro());
|
||||
R_UNLESS(rw_ofs + rw_size == nro_size, ro::ResultInvalidNro());
|
||||
|
||||
/* Verify NRO hash. */
|
||||
R_TRY(this->ValidateHasNroHash(header));
|
||||
|
||||
/* Check if NRO has already been loaded. */
|
||||
const ModuleId *module_id = header->GetModuleId();
|
||||
R_UNLESS(R_FAILED(this->GetNroInfoByModuleId(nullptr, module_id)), ro::ResultAlreadyLoaded());
|
||||
|
||||
/* Apply patches to NRO. */
|
||||
LocateAndApplyIpsPatchesToModule(module_id, reinterpret_cast<u8 *>(map_address), nro_size);
|
||||
|
||||
/* Copy to output. */
|
||||
*out_module_id = *module_id;
|
||||
*out_rx_size = text_size;
|
||||
*out_ro_size = ro_size;
|
||||
*out_rw_size = rw_size;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
void SetNrrInfoInUse(const NrrInfo *info, bool in_use) {
|
||||
AMS_ASSERT(std::addressof(this->nrr_infos[0]) <= info && info <= std::addressof(this->nrr_infos[MaxNrrInfos - 1]));
|
||||
const size_t index = info - std::addressof(this->nrr_infos[0]);
|
||||
this->nrr_in_use[index] = in_use;
|
||||
}
|
||||
|
||||
void SetNroInfoInUse(const NroInfo *info, bool in_use) {
|
||||
AMS_ASSERT(std::addressof(this->nro_infos[0]) <= info && info <= std::addressof(this->nro_infos[MaxNroInfos - 1]));
|
||||
const size_t index = info - std::addressof(this->nro_infos[0]);
|
||||
this->nro_in_use[index] = in_use;
|
||||
}
|
||||
*out_count = static_cast<u32>(count);
|
||||
}
|
||||
};
|
||||
|
||||
/* Globals. */
|
||||
ProcessContext g_process_contexts[MaxSessions] = {};
|
||||
bool g_is_development_hardware = false;
|
||||
bool g_is_development_function_enabled = false;
|
||||
constinit ProcessContext g_process_contexts[MaxSessions] = {};
|
||||
constinit bool g_is_development_hardware = false;
|
||||
constinit bool g_is_development_function_enabled = false;
|
||||
|
||||
/* Context Helpers. */
|
||||
ProcessContext *GetContextById(size_t context_id) {
|
||||
@@ -287,7 +358,7 @@ namespace ams::ro::impl {
|
||||
|
||||
ProcessContext *GetContextByProcessId(os::ProcessId process_id) {
|
||||
for (size_t i = 0; i < MaxSessions; i++) {
|
||||
if (g_process_contexts[i].process_id == process_id) {
|
||||
if (g_process_contexts[i].GetProcessId() == process_id) {
|
||||
return g_process_contexts + i;
|
||||
}
|
||||
}
|
||||
@@ -299,11 +370,8 @@ namespace ams::ro::impl {
|
||||
for (size_t i = 0; i < MaxSessions; i++) {
|
||||
ProcessContext *context = g_process_contexts + i;
|
||||
|
||||
if (!context->in_use) {
|
||||
std::memset(context, 0, sizeof(*context));
|
||||
context->process_id = process_id;
|
||||
context->process_handle = process_handle;
|
||||
context->in_use = true;
|
||||
if (context->IsFree()) {
|
||||
context->Initialize(process_handle, process_id);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -312,18 +380,8 @@ namespace ams::ro::impl {
|
||||
}
|
||||
|
||||
void FreeContext(size_t context_id) {
|
||||
ProcessContext *context = GetContextById(context_id);
|
||||
if (context != nullptr) {
|
||||
if (context->process_handle != os::InvalidNativeHandle) {
|
||||
for (size_t i = 0; i < MaxNrrInfos; i++) {
|
||||
if (context->nrr_in_use[i]) {
|
||||
UnmapNrr(context->process_handle, context->nrr_infos[i].mapped_header, context->nrr_infos[i].nrr_heap_address, context->nrr_infos[i].nrr_heap_size, context->nrr_infos[i].mapped_code_address);
|
||||
}
|
||||
}
|
||||
os::CloseNativeHandle(context->process_handle);
|
||||
}
|
||||
std::memset(context, 0, sizeof(*context));
|
||||
context->in_use = false;
|
||||
if (ProcessContext *context = GetContextById(context_id); context != nullptr) {
|
||||
context->Finalize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,8 +455,8 @@ namespace ams::ro::impl {
|
||||
|
||||
Result ValidateProcess(size_t context_id, os::ProcessId process_id) {
|
||||
const ProcessContext *ctx = GetContextById(context_id);
|
||||
R_UNLESS(ctx != nullptr, ro::ResultInvalidProcess());
|
||||
R_UNLESS(ctx->process_id == process_id, ro::ResultInvalidProcess());
|
||||
R_UNLESS(ctx != nullptr, ro::ResultInvalidProcess());
|
||||
R_UNLESS(ctx->GetProcessId() == process_id, ro::ResultInvalidProcess());
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
@@ -429,7 +487,7 @@ namespace ams::ro::impl {
|
||||
/* Map. */
|
||||
NrrHeader *header = nullptr;
|
||||
u64 mapped_code_address = 0;
|
||||
R_TRY(MapAndValidateNrr(std::addressof(header), std::addressof(mapped_code_address), std::addressof(signed_area_hash), sizeof(signed_area_hash), context->process_handle, program_id, nrr_address, nrr_size, nrr_kind, enforce_nrr_kind));
|
||||
R_TRY(MapAndValidateNrr(std::addressof(header), std::addressof(mapped_code_address), std::addressof(signed_area_hash), sizeof(signed_area_hash), context->GetProcessHandle(), program_id, nrr_address, nrr_size, nrr_kind, enforce_nrr_kind));
|
||||
|
||||
/* Set NRR info. */
|
||||
context->SetNrrInfoInUse(nrr_info, true);
|
||||
@@ -467,7 +525,7 @@ namespace ams::ro::impl {
|
||||
context->SetNrrInfoInUse(nrr_info, false);
|
||||
std::memset(nrr_info, 0, sizeof(*nrr_info));
|
||||
}
|
||||
return UnmapNrr(context->process_handle, nrr_backup.mapped_header, nrr_backup.nrr_heap_address, nrr_backup.nrr_heap_size, nrr_backup.mapped_code_address);
|
||||
return UnmapNrr(context->GetProcessHandle(), nrr_backup.mapped_header, nrr_backup.nrr_heap_address, nrr_backup.nrr_heap_size, nrr_backup.mapped_code_address);
|
||||
}
|
||||
|
||||
Result MapManualLoadModuleMemory(u64 *out_address, size_t context_id, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) {
|
||||
@@ -492,20 +550,20 @@ namespace ams::ro::impl {
|
||||
nro_info->bss_heap_size = bss_size;
|
||||
|
||||
/* Map the NRO. */
|
||||
R_TRY(MapNro(std::addressof(nro_info->base_address), context->process_handle, nro_address, nro_size, bss_address, bss_size));
|
||||
R_TRY(MapNro(std::addressof(nro_info->base_address), context->GetProcessHandle(), nro_address, nro_size, bss_address, bss_size));
|
||||
|
||||
/* Validate the NRO (parsing region extents). */
|
||||
u64 rx_size = 0, ro_size = 0, rw_size = 0;
|
||||
{
|
||||
auto unmap_guard = SCOPE_GUARD { UnmapNro(context->process_handle, nro_info->base_address, nro_address, bss_address, bss_size, nro_size, 0); };
|
||||
auto unmap_guard = SCOPE_GUARD { UnmapNro(context->GetProcessHandle(), nro_info->base_address, nro_address, bss_address, bss_size, nro_size, 0); };
|
||||
R_TRY(context->ValidateNro(std::addressof(nro_info->module_id), std::addressof(rx_size), std::addressof(ro_size), std::addressof(rw_size), nro_info->base_address, nro_size, bss_size));
|
||||
unmap_guard.Cancel();
|
||||
}
|
||||
|
||||
/* Set NRO perms. */
|
||||
{
|
||||
auto unmap_guard = SCOPE_GUARD { UnmapNro(context->process_handle, nro_info->base_address, nro_address, bss_address, bss_size, rx_size + ro_size, rw_size); };
|
||||
R_TRY(SetNroPerms(context->process_handle, nro_info->base_address, rx_size, ro_size, rw_size + bss_size));
|
||||
auto unmap_guard = SCOPE_GUARD { UnmapNro(context->GetProcessHandle(), nro_info->base_address, nro_address, bss_address, bss_size, rx_size + ro_size, rw_size); };
|
||||
R_TRY(SetNroPerms(context->GetProcessHandle(), nro_info->base_address, rx_size, ro_size, rw_size + bss_size));
|
||||
unmap_guard.Cancel();
|
||||
}
|
||||
|
||||
@@ -535,30 +593,15 @@ namespace ams::ro::impl {
|
||||
context->SetNroInfoInUse(nro_info, false);
|
||||
std::memset(nro_info, 0, sizeof(*nro_info));
|
||||
}
|
||||
return UnmapNro(context->process_handle, nro_backup.base_address, nro_backup.nro_heap_address, nro_backup.bss_heap_address, nro_backup.bss_heap_size, nro_backup.code_size, nro_backup.rw_size);
|
||||
return UnmapNro(context->GetProcessHandle(), nro_backup.base_address, nro_backup.nro_heap_address, nro_backup.bss_heap_address, nro_backup.bss_heap_size, nro_backup.code_size, nro_backup.rw_size);
|
||||
}
|
||||
|
||||
/* Debug service implementations. */
|
||||
Result GetProcessModuleInfo(u32 *out_count, LoaderModuleInfo *out_infos, size_t max_out_count, os::ProcessId process_id) {
|
||||
size_t count = 0;
|
||||
const ProcessContext *context = GetContextByProcessId(process_id);
|
||||
if (context != nullptr) {
|
||||
for (size_t i = 0; i < MaxNroInfos && count < max_out_count; i++) {
|
||||
if (!context->nro_in_use[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const NroInfo *nro_info = context->nro_infos + i;
|
||||
|
||||
/* Just copy out the info. */
|
||||
LoaderModuleInfo *out_info = std::addressof(out_infos[count++]);
|
||||
memcpy(out_info->build_id, std::addressof(nro_info->module_id), sizeof(nro_info->module_id));
|
||||
out_info->base_address = nro_info->base_address;
|
||||
out_info->size = nro_info->nro_heap_size + nro_info->bss_heap_size;
|
||||
}
|
||||
if (const ProcessContext *context = GetContextByProcessId(process_id); context != nullptr) {
|
||||
context->GetProcessModuleInfo(out_count, out_infos, max_out_count);
|
||||
}
|
||||
|
||||
*out_count = static_cast<u32>(count);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
|
||||
@@ -27,45 +27,45 @@ namespace ams::ro {
|
||||
impl::SetDevelopmentFunctionEnabled(is_development_function_enabled);
|
||||
}
|
||||
|
||||
RoService::RoService(NrrKind k) : context_id(impl::InvalidContextId), nrr_kind(k) {
|
||||
RoService::RoService(NrrKind k) : m_context_id(impl::InvalidContextId), m_nrr_kind(k) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
RoService::~RoService() {
|
||||
impl::UnregisterProcess(this->context_id);
|
||||
impl::UnregisterProcess(m_context_id);
|
||||
}
|
||||
|
||||
Result RoService::MapManualLoadModuleMemory(sf::Out<u64> load_address, const sf::ClientProcessId &client_pid, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) {
|
||||
R_TRY(impl::ValidateProcess(this->context_id, client_pid.GetValue()));
|
||||
return impl::MapManualLoadModuleMemory(load_address.GetPointer(), this->context_id, nro_address, nro_size, bss_address, bss_size);
|
||||
R_TRY(impl::ValidateProcess(m_context_id, client_pid.GetValue()));
|
||||
return impl::MapManualLoadModuleMemory(load_address.GetPointer(), m_context_id, nro_address, nro_size, bss_address, bss_size);
|
||||
}
|
||||
|
||||
Result RoService::UnmapManualLoadModuleMemory(const sf::ClientProcessId &client_pid, u64 nro_address) {
|
||||
R_TRY(impl::ValidateProcess(this->context_id, client_pid.GetValue()));
|
||||
return impl::UnmapManualLoadModuleMemory(this->context_id, nro_address);
|
||||
R_TRY(impl::ValidateProcess(m_context_id, client_pid.GetValue()));
|
||||
return impl::UnmapManualLoadModuleMemory(m_context_id, nro_address);
|
||||
}
|
||||
|
||||
Result RoService::RegisterModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size) {
|
||||
R_TRY(impl::ValidateProcess(this->context_id, client_pid.GetValue()));
|
||||
return impl::RegisterModuleInfo(this->context_id, os::InvalidNativeHandle, nrr_address, nrr_size, NrrKind_User, true);
|
||||
R_TRY(impl::ValidateProcess(m_context_id, client_pid.GetValue()));
|
||||
return impl::RegisterModuleInfo(m_context_id, os::InvalidNativeHandle, nrr_address, nrr_size, NrrKind_User, true);
|
||||
}
|
||||
|
||||
Result RoService::UnregisterModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address) {
|
||||
R_TRY(impl::ValidateProcess(this->context_id, client_pid.GetValue()));
|
||||
return impl::UnregisterModuleInfo(this->context_id, nrr_address);
|
||||
R_TRY(impl::ValidateProcess(m_context_id, client_pid.GetValue()));
|
||||
return impl::UnregisterModuleInfo(m_context_id, nrr_address);
|
||||
}
|
||||
|
||||
Result RoService::RegisterProcessHandle(const sf::ClientProcessId &client_pid, sf::CopyHandle &&process_h) {
|
||||
/* Register the process. */
|
||||
return impl::RegisterProcess(std::addressof(this->context_id), std::move(process_h), client_pid.GetValue());
|
||||
return impl::RegisterProcess(std::addressof(m_context_id), std::move(process_h), client_pid.GetValue());
|
||||
}
|
||||
|
||||
Result RoService::RegisterProcessModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle &&process_h) {
|
||||
/* Validate the process. */
|
||||
R_TRY(impl::ValidateProcess(this->context_id, client_pid.GetValue()));
|
||||
R_TRY(impl::ValidateProcess(m_context_id, client_pid.GetValue()));
|
||||
|
||||
/* Register the module. */
|
||||
return impl::RegisterModuleInfo(this->context_id, process_h.GetOsHandle(), nrr_address, nrr_size, this->nrr_kind, this->nrr_kind == NrrKind_JitPlugin);
|
||||
return impl::RegisterModuleInfo(m_context_id, process_h.GetOsHandle(), nrr_address, nrr_size, m_nrr_kind, m_nrr_kind == NrrKind_JitPlugin);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,8 +25,8 @@ namespace ams::ro {
|
||||
|
||||
class RoService {
|
||||
private:
|
||||
size_t context_id;
|
||||
NrrKind nrr_kind;
|
||||
size_t m_context_id;
|
||||
NrrKind m_nrr_kind;
|
||||
protected:
|
||||
explicit RoService(NrrKind k);
|
||||
public:
|
||||
|
||||
@@ -122,20 +122,20 @@ namespace ams::sm::impl {
|
||||
|
||||
class InitialProcessIdLimits {
|
||||
private:
|
||||
os::ProcessId min;
|
||||
os::ProcessId max;
|
||||
os::ProcessId m_min;
|
||||
os::ProcessId m_max;
|
||||
public:
|
||||
InitialProcessIdLimits() {
|
||||
/* Retrieve process limits. */
|
||||
cfg::GetInitialProcessRange(std::addressof(this->min), std::addressof(this->max));
|
||||
cfg::GetInitialProcessRange(std::addressof(m_min), std::addressof(m_max));
|
||||
|
||||
/* Ensure range is sane. */
|
||||
AMS_ABORT_UNLESS(this->min <= this->max);
|
||||
AMS_ABORT_UNLESS(m_min <= m_max);
|
||||
}
|
||||
|
||||
bool IsInitialProcess(os::ProcessId process_id) const {
|
||||
AMS_ABORT_UNLESS(process_id != os::InvalidProcessId);
|
||||
return this->min <= process_id && process_id <= this->max;
|
||||
return m_min <= process_id && process_id <= m_max;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -186,25 +186,25 @@ namespace ams::spl::impl {
|
||||
/* Type definitions. */
|
||||
class ScopedAesKeySlot {
|
||||
private:
|
||||
s32 slot;
|
||||
bool has_slot;
|
||||
s32 m_slot;
|
||||
bool m_has_slot;
|
||||
public:
|
||||
ScopedAesKeySlot() : slot(-1), has_slot(false) {
|
||||
ScopedAesKeySlot() : m_slot(-1), m_has_slot(false) {
|
||||
/* ... */
|
||||
}
|
||||
~ScopedAesKeySlot() {
|
||||
if (this->has_slot) {
|
||||
DeallocateAesKeySlot(slot, this);
|
||||
if (m_has_slot) {
|
||||
DeallocateAesKeySlot(m_slot, this);
|
||||
}
|
||||
}
|
||||
|
||||
u32 GetKeySlot() const {
|
||||
return this->slot;
|
||||
return m_slot;
|
||||
}
|
||||
|
||||
Result Allocate() {
|
||||
R_TRY(AllocateAesKeySlot(std::addressof(this->slot), this));
|
||||
this->has_slot = true;
|
||||
R_TRY(AllocateAesKeySlot(std::addressof(m_slot), this));
|
||||
m_has_slot = true;
|
||||
return ResultSuccess();
|
||||
}
|
||||
};
|
||||
@@ -222,17 +222,17 @@ namespace ams::spl::impl {
|
||||
|
||||
class DeviceAddressSpaceMapHelper {
|
||||
private:
|
||||
os::NativeHandle das_hnd;
|
||||
u64 dst_addr;
|
||||
u64 src_addr;
|
||||
size_t size;
|
||||
svc::MemoryPermission perm;
|
||||
os::NativeHandle m_handle;
|
||||
u64 m_dst_addr;
|
||||
u64 m_src_addr;
|
||||
size_t m_size;
|
||||
svc::MemoryPermission m_perm;
|
||||
public:
|
||||
DeviceAddressSpaceMapHelper(os::NativeHandle h, u64 dst, u64 src, size_t sz, svc::MemoryPermission p) : das_hnd(h), dst_addr(dst), src_addr(src), size(sz), perm(p) {
|
||||
R_ABORT_UNLESS(svc::MapDeviceAddressSpaceAligned(this->das_hnd, dd::GetCurrentProcessHandle(), this->src_addr, this->size, this->dst_addr, this->perm));
|
||||
DeviceAddressSpaceMapHelper(os::NativeHandle h, u64 dst, u64 src, size_t sz, svc::MemoryPermission p) : m_handle(h), m_dst_addr(dst), m_src_addr(src), m_size(sz), m_perm(p) {
|
||||
R_ABORT_UNLESS(svc::MapDeviceAddressSpaceAligned(m_handle, dd::GetCurrentProcessHandle(), m_src_addr, m_size, m_dst_addr, m_perm));
|
||||
}
|
||||
~DeviceAddressSpaceMapHelper() {
|
||||
R_ABORT_UNLESS(svc::UnmapDeviceAddressSpace(this->das_hnd, dd::GetCurrentProcessHandle(), this->src_addr, this->size, this->dst_addr));
|
||||
R_ABORT_UNLESS(svc::UnmapDeviceAddressSpace(m_handle, dd::GetCurrentProcessHandle(), m_src_addr, m_size, m_dst_addr));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -19,30 +19,30 @@
|
||||
namespace ams::spl {
|
||||
|
||||
void CtrDrbg::Update(const void *data) {
|
||||
aes128ContextCreate(std::addressof(this->aes_ctx), this->key, true);
|
||||
for (size_t offset = 0; offset < sizeof(this->work[1]); offset += BlockSize) {
|
||||
IncrementCounter(this->counter);
|
||||
aes128EncryptBlock(std::addressof(this->aes_ctx), std::addressof(this->work[1][offset]), this->counter);
|
||||
aes128ContextCreate(std::addressof(m_aes_ctx), m_key, true);
|
||||
for (size_t offset = 0; offset < sizeof(m_work[1]); offset += BlockSize) {
|
||||
IncrementCounter(m_counter);
|
||||
aes128EncryptBlock(std::addressof(m_aes_ctx), std::addressof(m_work[1][offset]), m_counter);
|
||||
}
|
||||
|
||||
Xor(this->work[1], data, sizeof(this->work[1]));
|
||||
Xor(m_work[1], data, sizeof(m_work[1]));
|
||||
|
||||
std::memcpy(this->key, std::addressof(this->work[1][0]), sizeof(this->key));
|
||||
std::memcpy(this->counter, std::addressof(this->work[1][BlockSize]), sizeof(this->key));
|
||||
std::memcpy(m_key, std::addressof(m_work[1][0]), sizeof(m_key));
|
||||
std::memcpy(m_counter, std::addressof(m_work[1][BlockSize]), sizeof(m_key));
|
||||
}
|
||||
|
||||
void CtrDrbg::Initialize(const void *seed) {
|
||||
std::memcpy(this->work[0], seed, sizeof(this->work[0]));
|
||||
std::memset(this->key, 0, sizeof(this->key));
|
||||
std::memset(this->counter, 0, sizeof(this->counter));
|
||||
this->Update(this->work[0]);
|
||||
this->reseed_counter = 1;
|
||||
std::memcpy(m_work[0], seed, sizeof(m_work[0]));
|
||||
std::memset(m_key, 0, sizeof(m_key));
|
||||
std::memset(m_counter, 0, sizeof(m_counter));
|
||||
this->Update(m_work[0]);
|
||||
m_reseed_counter = 1;
|
||||
}
|
||||
|
||||
void CtrDrbg::Reseed(const void *seed) {
|
||||
std::memcpy(this->work[0], seed, sizeof(this->work[0]));
|
||||
this->Update(this->work[0]);
|
||||
this->reseed_counter = 1;
|
||||
std::memcpy(m_work[0], seed, sizeof(m_work[0]));
|
||||
this->Update(m_work[0]);
|
||||
m_reseed_counter = 1;
|
||||
}
|
||||
|
||||
bool CtrDrbg::GenerateRandomBytes(void *out, size_t size) {
|
||||
@@ -50,30 +50,30 @@ namespace ams::spl {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->reseed_counter > ReseedInterval) {
|
||||
if (m_reseed_counter > ReseedInterval) {
|
||||
return false;
|
||||
}
|
||||
|
||||
aes128ContextCreate(std::addressof(this->aes_ctx), this->key, true);
|
||||
aes128ContextCreate(std::addressof(m_aes_ctx), m_key, true);
|
||||
u8 *cur_dst = reinterpret_cast<u8 *>(out);
|
||||
|
||||
size_t aligned_size = (size & ~(BlockSize - 1));
|
||||
for (size_t offset = 0; offset < aligned_size; offset += BlockSize) {
|
||||
IncrementCounter(this->counter);
|
||||
aes128EncryptBlock(std::addressof(this->aes_ctx), cur_dst, this->counter);
|
||||
IncrementCounter(m_counter);
|
||||
aes128EncryptBlock(std::addressof(m_aes_ctx), cur_dst, m_counter);
|
||||
cur_dst += BlockSize;
|
||||
}
|
||||
|
||||
if (size > aligned_size) {
|
||||
IncrementCounter(this->counter);
|
||||
aes128EncryptBlock(std::addressof(this->aes_ctx), this->work[1], this->counter);
|
||||
std::memcpy(cur_dst, this->work[1], size - aligned_size);
|
||||
IncrementCounter(m_counter);
|
||||
aes128EncryptBlock(std::addressof(m_aes_ctx), m_work[1], m_counter);
|
||||
std::memcpy(cur_dst, m_work[1], size - aligned_size);
|
||||
}
|
||||
|
||||
std::memset(this->work[0], 0, sizeof(this->work[0]));
|
||||
this->Update(this->work[0]);
|
||||
std::memset(m_work[0], 0, sizeof(m_work[0]));
|
||||
this->Update(m_work[0]);
|
||||
|
||||
this->reseed_counter++;
|
||||
m_reseed_counter++;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@@ -26,11 +26,11 @@ namespace ams::spl {
|
||||
static constexpr size_t BlockSize = AES_BLOCK_SIZE;
|
||||
static constexpr size_t SeedSize = 2 * AES_BLOCK_SIZE;
|
||||
private:
|
||||
Aes128Context aes_ctx;
|
||||
u8 counter[BlockSize];
|
||||
u8 key[BlockSize];
|
||||
u8 work[2][SeedSize];
|
||||
u32 reseed_counter;
|
||||
Aes128Context m_aes_ctx;
|
||||
u8 m_counter[BlockSize];
|
||||
u8 m_key[BlockSize];
|
||||
u8 m_work[2][SeedSize];
|
||||
u32 m_reseed_counter;
|
||||
private:
|
||||
static void Xor(void *dst, const void *src, size_t size) {
|
||||
const u8 *src_u8 = reinterpret_cast<const u8 *>(src);
|
||||
|
||||
@@ -26,25 +26,25 @@ namespace ams::spl {
|
||||
public:
|
||||
static constexpr size_t KeySize = crypto::AesDecryptor128::KeySize;
|
||||
private:
|
||||
const s32 slot_index;
|
||||
s32 virtual_slot;
|
||||
const s32 m_slot_index;
|
||||
s32 m_virtual_slot;
|
||||
public:
|
||||
explicit KeySlotCacheEntry(s32 idx) : slot_index(idx), virtual_slot(-1) { /* ... */ }
|
||||
explicit KeySlotCacheEntry(s32 idx) : m_slot_index(idx), m_virtual_slot(-1) { /* ... */ }
|
||||
|
||||
bool Contains(s32 virtual_slot) const {
|
||||
return virtual_slot == this->virtual_slot;
|
||||
return virtual_slot == m_virtual_slot;
|
||||
}
|
||||
|
||||
s32 GetPhysicalKeySlotIndex() const { return this->slot_index; }
|
||||
s32 GetPhysicalKeySlotIndex() const { return m_slot_index; }
|
||||
|
||||
s32 GetVirtualKeySlotIndex() const { return this->virtual_slot; }
|
||||
s32 GetVirtualKeySlotIndex() const { return m_virtual_slot; }
|
||||
|
||||
void SetVirtualSlot(s32 virtual_slot) {
|
||||
this->virtual_slot = virtual_slot;
|
||||
m_virtual_slot = virtual_slot;
|
||||
}
|
||||
|
||||
void ClearVirtualSlot() {
|
||||
this->virtual_slot = -1;
|
||||
m_virtual_slot = -1;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -54,16 +54,16 @@ namespace ams::spl {
|
||||
private:
|
||||
using KeySlotCacheEntryList = util::IntrusiveListBaseTraits<KeySlotCacheEntry>::ListType;
|
||||
private:
|
||||
KeySlotCacheEntryList mru_list;
|
||||
KeySlotCacheEntryList m_mru_list;
|
||||
public:
|
||||
constexpr KeySlotCache() : mru_list() { /* ... */ }
|
||||
constexpr KeySlotCache() : m_mru_list() { /* ... */ }
|
||||
|
||||
s32 Allocate(s32 virtual_slot) {
|
||||
return this->AllocateFromLru(virtual_slot);
|
||||
}
|
||||
|
||||
bool Find(s32 *out, s32 virtual_slot) {
|
||||
for (auto it = this->mru_list.begin(); it != this->mru_list.end(); ++it) {
|
||||
for (auto it = m_mru_list.begin(); it != m_mru_list.end(); ++it) {
|
||||
if (it->Contains(virtual_slot)) {
|
||||
*out = it->GetPhysicalKeySlotIndex();
|
||||
|
||||
@@ -76,7 +76,7 @@ namespace ams::spl {
|
||||
}
|
||||
|
||||
bool Release(s32 *out, s32 virtual_slot) {
|
||||
for (auto it = this->mru_list.begin(); it != this->mru_list.end(); ++it) {
|
||||
for (auto it = m_mru_list.begin(); it != m_mru_list.end(); ++it) {
|
||||
if (it->Contains(virtual_slot)) {
|
||||
*out = it->GetPhysicalKeySlotIndex();
|
||||
it->ClearVirtualSlot();
|
||||
@@ -90,7 +90,7 @@ namespace ams::spl {
|
||||
}
|
||||
|
||||
bool FindPhysical(s32 physical_slot) {
|
||||
for (auto it = this->mru_list.begin(); it != this->mru_list.end(); ++it) {
|
||||
for (auto it = m_mru_list.begin(); it != m_mru_list.end(); ++it) {
|
||||
if (it->GetPhysicalKeySlotIndex() == physical_slot) {
|
||||
this->UpdateMru(it);
|
||||
|
||||
@@ -106,32 +106,32 @@ namespace ams::spl {
|
||||
}
|
||||
|
||||
void AddEntry(KeySlotCacheEntry *entry) {
|
||||
this->mru_list.push_front(*entry);
|
||||
m_mru_list.push_front(*entry);
|
||||
}
|
||||
private:
|
||||
s32 AllocateFromLru(s32 virtual_slot) {
|
||||
AMS_ASSERT(!this->mru_list.empty());
|
||||
AMS_ASSERT(!m_mru_list.empty());
|
||||
|
||||
auto it = this->mru_list.rbegin();
|
||||
auto it = m_mru_list.rbegin();
|
||||
it->SetVirtualSlot(virtual_slot);
|
||||
|
||||
auto *entry = std::addressof(*it);
|
||||
this->mru_list.pop_back();
|
||||
this->mru_list.push_front(*entry);
|
||||
m_mru_list.pop_back();
|
||||
m_mru_list.push_front(*entry);
|
||||
|
||||
return entry->GetPhysicalKeySlotIndex();
|
||||
}
|
||||
|
||||
void UpdateMru(KeySlotCacheEntryList::iterator it) {
|
||||
auto *entry = std::addressof(*it);
|
||||
this->mru_list.erase(it);
|
||||
this->mru_list.push_front(*entry);
|
||||
m_mru_list.erase(it);
|
||||
m_mru_list.push_front(*entry);
|
||||
}
|
||||
|
||||
void UpdateLru(KeySlotCacheEntryList::iterator it) {
|
||||
auto *entry = std::addressof(*it);
|
||||
this->mru_list.erase(it);
|
||||
this->mru_list.push_back(*entry);
|
||||
m_mru_list.erase(it);
|
||||
m_mru_list.push_back(*entry);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user