mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
loader: refactor ro manager/improve accuracy
This commit is contained in:
parent
d8a36e39f2
commit
d9dc04318d
24 changed files with 328 additions and 218 deletions
|
@ -33,7 +33,7 @@ namespace ams::dmnt::cheat {
|
||||||
MemoryRegionExtents heap_extents;
|
MemoryRegionExtents heap_extents;
|
||||||
MemoryRegionExtents alias_extents;
|
MemoryRegionExtents alias_extents;
|
||||||
MemoryRegionExtents aslr_extents;
|
MemoryRegionExtents aslr_extents;
|
||||||
u8 main_nso_build_id[0x20];
|
u8 main_nso_module_id[0x20];
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(util::is_pod<CheatProcessMetadata>::value && sizeof(CheatProcessMetadata) == 0x70, "CheatProcessMetadata definition!");
|
static_assert(util::is_pod<CheatProcessMetadata>::value && sizeof(CheatProcessMetadata) == 0x70, "CheatProcessMetadata definition!");
|
||||||
|
|
|
@ -73,8 +73,12 @@ namespace ams::ldr {
|
||||||
}
|
}
|
||||||
static_assert(sizeof(PinId) == sizeof(u64) && util::is_pod<PinId>::value, "PinId definition!");
|
static_assert(sizeof(PinId) == sizeof(u64) && util::is_pod<PinId>::value, "PinId definition!");
|
||||||
|
|
||||||
/* Import ModuleInfo from libnx. */
|
struct ModuleInfo {
|
||||||
using ModuleInfo = ::LoaderModuleInfo;
|
u8 module_id[0x20];
|
||||||
|
u64 address;
|
||||||
|
u64 size;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ModuleInfo) == 0x30);
|
||||||
|
|
||||||
/* NSO types. */
|
/* NSO types. */
|
||||||
struct NsoHeader {
|
struct NsoHeader {
|
||||||
|
@ -123,7 +127,7 @@ namespace ams::ldr {
|
||||||
};
|
};
|
||||||
SegmentInfo segments[Segment_Count];
|
SegmentInfo segments[Segment_Count];
|
||||||
};
|
};
|
||||||
u8 build_id[sizeof(ModuleInfo::build_id)];
|
u8 module_id[sizeof(ModuleInfo::module_id)];
|
||||||
union {
|
union {
|
||||||
u32 compressed_sizes[Segment_Count];
|
u32 compressed_sizes[Segment_Count];
|
||||||
struct {
|
struct {
|
||||||
|
|
|
@ -17,9 +17,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <vapours.hpp>
|
#include <vapours.hpp>
|
||||||
#include <stratosphere/ro/ro_types.hpp>
|
#include <stratosphere/ro/ro_types.hpp>
|
||||||
|
#include <stratosphere/ldr/ldr_types.hpp>
|
||||||
#include <stratosphere/sf.hpp>
|
#include <stratosphere/sf.hpp>
|
||||||
|
|
||||||
#define AMS_RO_I_DEBUG_MONITOR_INTERFACE_INTERFACE_INFO(C, H) \
|
#define AMS_RO_I_DEBUG_MONITOR_INTERFACE_INTERFACE_INFO(C, H) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 0, Result, GetProcessModuleInfo, (sf::Out<u32> out_count, const sf::OutArray<LoaderModuleInfo> &out_infos, os::ProcessId process_id), (out_count, out_infos, process_id))
|
AMS_SF_METHOD_INFO(C, H, 0, Result, GetProcessModuleInfo, (sf::Out<u32> out_count, const sf::OutArray<ldr::ModuleInfo> &out_infos, os::ProcessId process_id), (out_count, out_infos, process_id))
|
||||||
|
|
||||||
AMS_SF_DEFINE_INTERFACE(ams::ro::impl, IDebugMonitorInterface, AMS_RO_I_DEBUG_MONITOR_INTERFACE_INTERFACE_INFO)
|
AMS_SF_DEFINE_INTERFACE(ams::ro::impl, IDebugMonitorInterface, AMS_RO_I_DEBUG_MONITOR_INTERFACE_INTERFACE_INFO)
|
||||||
|
|
|
@ -27,10 +27,11 @@ namespace ams::ro {
|
||||||
NrrKind_Count,
|
NrrKind_Count,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static constexpr size_t ModuleIdSize = 0x20;
|
||||||
struct ModuleId {
|
struct ModuleId {
|
||||||
u8 build_id[0x20];
|
u8 data[ModuleIdSize];
|
||||||
};
|
};
|
||||||
static_assert(sizeof(ModuleId) == sizeof(LoaderModuleInfo::build_id), "ModuleId definition!");
|
static_assert(sizeof(ModuleId) == ModuleIdSize);
|
||||||
|
|
||||||
struct NrrCertification {
|
struct NrrCertification {
|
||||||
static constexpr size_t RsaKeySize = 0x100;
|
static constexpr size_t RsaKeySize = 0x100;
|
||||||
|
|
|
@ -43,3 +43,16 @@
|
||||||
\
|
\
|
||||||
return ::ams::util::GetReference(s_singleton_storage); \
|
return ::ams::util::GetReference(s_singleton_storage); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define AMS_CONSTINIT_SINGLETON_TRAITS(_CLASSNAME_) \
|
||||||
|
private: \
|
||||||
|
NON_COPYABLE(_CLASSNAME_); \
|
||||||
|
NON_MOVEABLE(_CLASSNAME_); \
|
||||||
|
private: \
|
||||||
|
constexpr _CLASSNAME_ () = default; \
|
||||||
|
public: \
|
||||||
|
static _CLASSNAME_ &GetInstance() { \
|
||||||
|
/* Declare singleton instance variables. */ \
|
||||||
|
static constinit _CLASSNAME_ s_singleton_instance; \
|
||||||
|
return s_singleton_instance; \
|
||||||
|
}
|
|
@ -56,8 +56,8 @@ namespace ams::patcher {
|
||||||
/* Read module id from name. */
|
/* Read module id from name. */
|
||||||
std::memset(out_module_id, 0, sizeof(*out_module_id));
|
std::memset(out_module_id, 0, sizeof(*out_module_id));
|
||||||
for (unsigned int name_ofs = 0, id_ofs = 0; name_ofs < name_len - extension_len && id_ofs < sizeof(*out_module_id); id_ofs++) {
|
for (unsigned int name_ofs = 0, id_ofs = 0; name_ofs < name_len - extension_len && id_ofs < sizeof(*out_module_id); id_ofs++) {
|
||||||
out_module_id->build_id[id_ofs] |= ConvertHexNybble(name[name_ofs++]) << 4;
|
out_module_id->data[id_ofs] |= ConvertHexNybble(name[name_ofs++]) << 4;
|
||||||
out_module_id->build_id[id_ofs] |= ConvertHexNybble(name[name_ofs++]);
|
out_module_id->data[id_ofs] |= ConvertHexNybble(name[name_ofs++]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -76,7 +76,7 @@ namespace ams::patcher {
|
||||||
bool IsIpsFileForModule(const char *name, const ro::ModuleId *module_id) {
|
bool IsIpsFileForModule(const char *name, const ro::ModuleId *module_id) {
|
||||||
const size_t name_len = std::strlen(name);
|
const size_t name_len = std::strlen(name);
|
||||||
|
|
||||||
/* The path must be correct size for a build id (with trailing zeroes optionally trimmed) + ".ips". */
|
/* The path must be correct size for a module id (with trailing zeroes optionally trimmed) + ".ips". */
|
||||||
if (!(IpsFileExtensionLength < name_len && name_len <= ModuleIpsPatchLength)) {
|
if (!(IpsFileExtensionLength < name_len && name_len <= ModuleIpsPatchLength)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -330,7 +330,7 @@ namespace ams::scs {
|
||||||
Result PrepareToLaunchProgram(ncm::ProgramId program_id, const void *args, size_t args_size) {
|
Result PrepareToLaunchProgram(ncm::ProgramId program_id, const void *args, size_t args_size) {
|
||||||
/* Set the arguments. */
|
/* Set the arguments. */
|
||||||
R_TRY_CATCH(ldr::SetProgramArgument(program_id, args, args_size)) {
|
R_TRY_CATCH(ldr::SetProgramArgument(program_id, args, args_size)) {
|
||||||
R_CATCH(ldr::ResultTooManyArguments) {
|
R_CATCH(ldr::ResultArgumentCountOverflow) {
|
||||||
/* There are too many arguments already registered. Flush the arguments queue. */
|
/* There are too many arguments already registered. Flush the arguments queue. */
|
||||||
R_TRY(ldr::FlushArguments());
|
R_TRY(ldr::FlushArguments());
|
||||||
|
|
||||||
|
|
|
@ -21,29 +21,30 @@ namespace ams::ldr {
|
||||||
|
|
||||||
R_DEFINE_NAMESPACE_RESULT_MODULE(9);
|
R_DEFINE_NAMESPACE_RESULT_MODULE(9);
|
||||||
|
|
||||||
R_DEFINE_ERROR_RESULT(TooLongArgument, 1);
|
R_DEFINE_ERROR_RESULT(ArgumentOverflow, 1);
|
||||||
R_DEFINE_ERROR_RESULT(TooManyArguments, 2);
|
R_DEFINE_ERROR_RESULT(ArgumentCountOverflow, 2);
|
||||||
R_DEFINE_ERROR_RESULT(TooLargeMeta, 3);
|
R_DEFINE_ERROR_RESULT(MetaOverflow, 3);
|
||||||
R_DEFINE_ERROR_RESULT(InvalidMeta, 4);
|
R_DEFINE_ERROR_RESULT(InvalidMeta, 4);
|
||||||
R_DEFINE_ERROR_RESULT(InvalidNso, 5);
|
R_DEFINE_ERROR_RESULT(InvalidNso, 5);
|
||||||
R_DEFINE_ERROR_RESULT(InvalidPath, 6);
|
R_DEFINE_ERROR_RESULT(InvalidPath, 6);
|
||||||
R_DEFINE_ERROR_RESULT(TooManyProcesses, 7);
|
R_DEFINE_ERROR_RESULT(MaxProcess, 7);
|
||||||
R_DEFINE_ERROR_RESULT(NotPinned, 8);
|
R_DEFINE_ERROR_RESULT(NotPinned, 8);
|
||||||
R_DEFINE_ERROR_RESULT(InvalidProgramId, 9);
|
R_DEFINE_ERROR_RESULT(InvalidProgramId, 9);
|
||||||
R_DEFINE_ERROR_RESULT(InvalidVersion, 10);
|
R_DEFINE_ERROR_RESULT(InvalidVersion, 10);
|
||||||
R_DEFINE_ERROR_RESULT(InvalidAcidSignature, 11);
|
R_DEFINE_ERROR_RESULT(InvalidAcidSignature, 11);
|
||||||
R_DEFINE_ERROR_RESULT(InvalidNcaSignature, 12);
|
R_DEFINE_ERROR_RESULT(InvalidNcaSignature, 12);
|
||||||
|
|
||||||
R_DEFINE_ERROR_RESULT(InsufficientAddressSpace, 51);
|
R_DEFINE_ERROR_RESULT(OutOfAddressSpace, 51);
|
||||||
R_DEFINE_ERROR_RESULT(InvalidNro, 52);
|
R_DEFINE_ERROR_RESULT(InvalidNroImage, 52);
|
||||||
R_DEFINE_ERROR_RESULT(InvalidNrr, 53);
|
R_DEFINE_ERROR_RESULT(InvalidNrrImage, 53);
|
||||||
R_DEFINE_ERROR_RESULT(InvalidSignature, 54);
|
R_DEFINE_ERROR_RESULT(NotAuthorized, 54);
|
||||||
R_DEFINE_ERROR_RESULT(InsufficientNroRegistrations, 55);
|
R_DEFINE_ERROR_RESULT(MaxModule, 55);
|
||||||
R_DEFINE_ERROR_RESULT(InsufficientNrrRegistrations, 56);
|
R_DEFINE_ERROR_RESULT(MaxRegistration, 56);
|
||||||
R_DEFINE_ERROR_RESULT(NroAlreadyLoaded, 57);
|
R_DEFINE_ERROR_RESULT(NroAlreadyLoaded, 57);
|
||||||
|
|
||||||
R_DEFINE_ERROR_RESULT(InvalidAddress, 81);
|
R_DEFINE_ERROR_RESULT(InvalidAddress, 81);
|
||||||
R_DEFINE_ERROR_RESULT(InvalidSize, 82);
|
R_DEFINE_ERROR_RESULT(InvalidSize, 82);
|
||||||
|
R_DEFINE_ERROR_RESULT(InvalidCurrentMemory, 83);
|
||||||
R_DEFINE_ERROR_RESULT(NotLoaded, 84);
|
R_DEFINE_ERROR_RESULT(NotLoaded, 84);
|
||||||
R_DEFINE_ERROR_RESULT(NotRegistered, 85);
|
R_DEFINE_ERROR_RESULT(NotRegistered, 85);
|
||||||
R_DEFINE_ERROR_RESULT(InvalidSession, 86);
|
R_DEFINE_ERROR_RESULT(InvalidSession, 86);
|
||||||
|
|
|
@ -54,7 +54,7 @@ namespace ams::creport {
|
||||||
if (std::strcmp(m_modules[i].name, "") != 0) {
|
if (std::strcmp(m_modules[i].name, "") != 0) {
|
||||||
file.WriteFormat(" Name: %s\n", module.name);
|
file.WriteFormat(" Name: %s\n", module.name);
|
||||||
}
|
}
|
||||||
file.DumpMemory(" Build Id: ", module.build_id, sizeof(module.build_id));
|
file.DumpMemory(" Module Id: ", module.module_id, sizeof(module.module_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,10 +104,10 @@ namespace ams::creport {
|
||||||
module.start_address = mi.base_address;
|
module.start_address = mi.base_address;
|
||||||
module.end_address = mi.base_address + mi.size;
|
module.end_address = mi.base_address + mi.size;
|
||||||
GetModuleName(module.name, module.start_address, module.end_address);
|
GetModuleName(module.name, module.start_address, module.end_address);
|
||||||
GetModuleBuildId(module.build_id, module.end_address);
|
GetModuleId(module.module_id, module.end_address);
|
||||||
/* Some homebrew won't have a name. Add a fake one for readability. */
|
/* Some homebrew won't have a name. Add a fake one for readability. */
|
||||||
if (std::strcmp(module.name, "") == 0) {
|
if (std::strcmp(module.name, "") == 0) {
|
||||||
util::SNPrintf(module.name, sizeof(module.name), "[%02x%02x%02x%02x]", module.build_id[0], module.build_id[1], module.build_id[2], module.build_id[3]);
|
util::SNPrintf(module.name, sizeof(module.name), "[%02x%02x%02x%02x]", module.module_id[0], module.module_id[1], module.module_id[2], module.module_id[3]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,9 +221,9 @@ namespace ams::creport {
|
||||||
out_name[ModuleNameLengthMax - 1] = '\x00';
|
out_name[ModuleNameLengthMax - 1] = '\x00';
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModuleList::GetModuleBuildId(u8 *out_build_id, uintptr_t ro_start_address) {
|
void ModuleList::GetModuleId(u8 *out, uintptr_t ro_start_address) {
|
||||||
/* Clear output. */
|
/* Clear output. */
|
||||||
std::memset(out_build_id, 0, ModuleBuildIdLength);
|
std::memset(out, 0, ModuleIdSize);
|
||||||
|
|
||||||
/* Verify .rodata is read-only. */
|
/* Verify .rodata is read-only. */
|
||||||
svc::MemoryInfo mi;
|
svc::MemoryInfo mi;
|
||||||
|
@ -238,10 +238,10 @@ namespace ams::creport {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find GNU\x00 to locate start of build id. */
|
/* Find GNU\x00 to locate start of module id (GNU build id). */
|
||||||
for (int ofs = read_size - sizeof(GnuSignature) - ModuleBuildIdLength; ofs >= 0; ofs--) {
|
for (int ofs = read_size - sizeof(GnuSignature) - ModuleIdSize; ofs >= 0; ofs--) {
|
||||||
if (std::memcmp(g_last_rodata_pages + ofs, GnuSignature, sizeof(GnuSignature)) == 0) {
|
if (std::memcmp(g_last_rodata_pages + ofs, GnuSignature, sizeof(GnuSignature)) == 0) {
|
||||||
std::memcpy(out_build_id, g_last_rodata_pages + ofs + sizeof(GnuSignature), ModuleBuildIdLength);
|
std::memcpy(out, g_last_rodata_pages + ofs + sizeof(GnuSignature), ModuleIdSize);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,11 +23,11 @@ namespace ams::creport {
|
||||||
private:
|
private:
|
||||||
static constexpr size_t ModuleCountMax = 0x60;
|
static constexpr size_t ModuleCountMax = 0x60;
|
||||||
static constexpr size_t ModuleNameLengthMax = 0x20;
|
static constexpr size_t ModuleNameLengthMax = 0x20;
|
||||||
static constexpr size_t ModuleBuildIdLength = 0x20;
|
static constexpr size_t ModuleIdSize = 0x20;
|
||||||
|
|
||||||
struct ModuleInfo {
|
struct ModuleInfo {
|
||||||
char name[ModuleNameLengthMax];
|
char name[ModuleNameLengthMax];
|
||||||
u8 build_id[ModuleBuildIdLength];
|
u8 module_id[ModuleIdSize];
|
||||||
u64 start_address;
|
u64 start_address;
|
||||||
u64 end_address;
|
u64 end_address;
|
||||||
};
|
};
|
||||||
|
@ -58,7 +58,7 @@ namespace ams::creport {
|
||||||
bool TryFindModule(uintptr_t *out_address, uintptr_t guess);
|
bool TryFindModule(uintptr_t *out_address, uintptr_t guess);
|
||||||
void TryAddModule(uintptr_t guess);
|
void TryAddModule(uintptr_t guess);
|
||||||
void GetModuleName(char *out_name, uintptr_t text_start, uintptr_t ro_start);
|
void GetModuleName(char *out_name, uintptr_t text_start, uintptr_t ro_start);
|
||||||
void GetModuleBuildId(u8 *out_build_id, uintptr_t ro_start);
|
void GetModuleId(u8 *out, uintptr_t ro_start);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ namespace ams::dmnt::cheat::impl {
|
||||||
Result AttachToApplicationProcess(bool on_process_launch);
|
Result AttachToApplicationProcess(bool on_process_launch);
|
||||||
|
|
||||||
bool ParseCheats(const char *s, size_t len);
|
bool ParseCheats(const char *s, size_t len);
|
||||||
bool LoadCheats(const ncm::ProgramId program_id, const u8 *build_id);
|
bool LoadCheats(const ncm::ProgramId program_id, const u8 *module_id);
|
||||||
bool ParseCheatToggles(const char *s, size_t len);
|
bool ParseCheatToggles(const char *s, size_t len);
|
||||||
bool LoadCheatToggles(const ncm::ProgramId program_id);
|
bool LoadCheatToggles(const ncm::ProgramId program_id);
|
||||||
void SaveCheatToggles(const ncm::ProgramId program_id);
|
void SaveCheatToggles(const ncm::ProgramId program_id);
|
||||||
|
@ -826,16 +826,16 @@ namespace ams::dmnt::cheat::impl {
|
||||||
|
|
||||||
/* Get module information from loader. */
|
/* Get module information from loader. */
|
||||||
{
|
{
|
||||||
LoaderModuleInfo proc_modules[2];
|
ldr::ModuleInfo proc_modules[2];
|
||||||
s32 num_modules;
|
s32 num_modules;
|
||||||
|
|
||||||
/* TODO: ldr::dmnt:: */
|
/* TODO: ldr::dmnt:: */
|
||||||
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)));
|
R_ABORT_UNLESS_IF_NEW_PROCESS(ldrDmntGetProcessModuleInfo(static_cast<u64>(m_cheat_process_metadata.process_id), reinterpret_cast<LoaderModuleInfo *>(proc_modules), util::size(proc_modules), std::addressof(num_modules)));
|
||||||
|
|
||||||
/* All applications must have two modules. */
|
/* All applications must have two modules. */
|
||||||
/* Only accept one (which means we're attaching to HBL) */
|
/* Only accept one (which means we're attaching to HBL) */
|
||||||
/* if we aren't auto-attaching. */
|
/* if we aren't auto-attaching. */
|
||||||
const LoaderModuleInfo *proc_module = nullptr;
|
const ldr::ModuleInfo *proc_module = nullptr;
|
||||||
if (num_modules == 2) {
|
if (num_modules == 2) {
|
||||||
proc_module = std::addressof(proc_modules[1]);
|
proc_module = std::addressof(proc_modules[1]);
|
||||||
} else if (num_modules == 1 && !on_process_launch) {
|
} else if (num_modules == 1 && !on_process_launch) {
|
||||||
|
@ -844,13 +844,13 @@ namespace ams::dmnt::cheat::impl {
|
||||||
return dmnt::cheat::ResultCheatNotAttached();
|
return dmnt::cheat::ResultCheatNotAttached();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_cheat_process_metadata.main_nso_extents.base = proc_module->base_address;
|
m_cheat_process_metadata.main_nso_extents.base = proc_module->address;
|
||||||
m_cheat_process_metadata.main_nso_extents.size = proc_module->size;
|
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));
|
std::memcpy(m_cheat_process_metadata.main_nso_module_id, proc_module->module_id, sizeof(m_cheat_process_metadata.main_nso_module_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read cheats off the SD. */
|
/* Read cheats off the SD. */
|
||||||
if (!this->LoadCheats(m_cheat_process_metadata.program_id, m_cheat_process_metadata.main_nso_build_id) ||
|
if (!this->LoadCheats(m_cheat_process_metadata.program_id, m_cheat_process_metadata.main_nso_module_id) ||
|
||||||
!this->LoadCheatToggles(m_cheat_process_metadata.program_id)) {
|
!this->LoadCheatToggles(m_cheat_process_metadata.program_id)) {
|
||||||
/* If new process launch, require success. */
|
/* If new process launch, require success. */
|
||||||
R_UNLESS(!on_process_launch, dmnt::cheat::ResultCheatNotAttached());
|
R_UNLESS(!on_process_launch, dmnt::cheat::ResultCheatNotAttached());
|
||||||
|
@ -1059,16 +1059,16 @@ namespace ams::dmnt::cheat::impl {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheatProcessManager::LoadCheats(const ncm::ProgramId program_id, const u8 *build_id) {
|
bool CheatProcessManager::LoadCheats(const ncm::ProgramId program_id, const u8 *module_id) {
|
||||||
/* Reset existing entries. */
|
/* Reset existing entries. */
|
||||||
this->ResetAllCheatEntries();
|
this->ResetAllCheatEntries();
|
||||||
|
|
||||||
/* Open the file for program/build_id. */
|
/* Open the file for program/module_id. */
|
||||||
fs::FileHandle file;
|
fs::FileHandle file;
|
||||||
{
|
{
|
||||||
char path[fs::EntryNameLengthMax + 1];
|
char path[fs::EntryNameLengthMax + 1];
|
||||||
util::SNPrintf(path, sizeof(path), "sdmc:/atmosphere/contents/%016lx/cheats/%02x%02x%02x%02x%02x%02x%02x%02x.txt", program_id.value,
|
util::SNPrintf(path, sizeof(path), "sdmc:/atmosphere/contents/%016lx/cheats/%02x%02x%02x%02x%02x%02x%02x%02x.txt", program_id.value,
|
||||||
build_id[0], build_id[1], build_id[2], build_id[3], build_id[4], build_id[5], build_id[6], build_id[7]);
|
module_id[0], module_id[1], module_id[2], module_id[3], module_id[4], module_id[5], module_id[6], module_id[7]);
|
||||||
if (R_FAILED(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Read))) {
|
if (R_FAILED(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Read))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,13 +48,13 @@ namespace ams::ldr::args {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Set(ncm::ProgramId program_id, const void *args, size_t args_size) {
|
Result Set(ncm::ProgramId program_id, const void *args, size_t args_size) {
|
||||||
R_UNLESS(args_size < ArgumentSizeMax, ldr::ResultTooLongArgument());
|
R_UNLESS(args_size < ArgumentSizeMax, ldr::ResultArgumentOverflow());
|
||||||
|
|
||||||
ArgumentInfo *arg_info = FindArgumentInfo(program_id);
|
ArgumentInfo *arg_info = FindArgumentInfo(program_id);
|
||||||
if (arg_info == nullptr) {
|
if (arg_info == nullptr) {
|
||||||
arg_info = FindFreeArgumentInfo();
|
arg_info = FindFreeArgumentInfo();
|
||||||
}
|
}
|
||||||
R_UNLESS(arg_info != nullptr, ldr::ResultTooManyArguments());
|
R_UNLESS(arg_info != nullptr, ldr::ResultArgumentCountOverflow());
|
||||||
|
|
||||||
arg_info->program_id = program_id;
|
arg_info->program_id = program_id;
|
||||||
arg_info->args_size = args_size;
|
arg_info->args_size = args_size;
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include "ldr_process_creation.hpp"
|
#include "ldr_process_creation.hpp"
|
||||||
#include "ldr_launch_record.hpp"
|
#include "ldr_launch_record.hpp"
|
||||||
#include "ldr_loader_service.hpp"
|
#include "ldr_loader_service.hpp"
|
||||||
#include "ldr_ro_manager.hpp"
|
|
||||||
|
|
||||||
namespace ams::ldr {
|
namespace ams::ldr {
|
||||||
|
|
||||||
|
@ -64,7 +63,7 @@ namespace ams::ldr {
|
||||||
char path[fs::EntryNameLengthMax];
|
char path[fs::EntryNameLengthMax];
|
||||||
|
|
||||||
/* Get location and override status. */
|
/* Get location and override status. */
|
||||||
R_TRY(ldr::ro::GetProgramLocationAndStatus(std::addressof(loc), std::addressof(override_status), id));
|
R_TRY(ldr::GetProgramLocationAndOverrideStatusFromPinId(std::addressof(loc), std::addressof(override_status), id));
|
||||||
|
|
||||||
if (loc.storage_id != static_cast<u8>(ncm::StorageId::None)) {
|
if (loc.storage_id != static_cast<u8>(ncm::StorageId::None)) {
|
||||||
R_TRY(ResolveContentPath(path, loc));
|
R_TRY(ResolveContentPath(path, loc));
|
||||||
|
@ -87,11 +86,11 @@ namespace ams::ldr {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result LoaderService::PinProgram(sf::Out<PinId> out_id, const ncm::ProgramLocation &loc) {
|
Result LoaderService::PinProgram(sf::Out<PinId> out_id, const ncm::ProgramLocation &loc) {
|
||||||
return ldr::ro::PinProgram(out_id.GetPointer(), loc, cfg::OverrideStatus{});
|
return ldr::PinProgram(out_id.GetPointer(), loc, cfg::OverrideStatus{});
|
||||||
}
|
}
|
||||||
|
|
||||||
Result LoaderService::UnpinProgram(PinId id) {
|
Result LoaderService::UnpinProgram(PinId id) {
|
||||||
return ldr::ro::UnpinProgram(id);
|
return ldr::UnpinProgram(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result LoaderService::SetProgramArgumentsDeprecated(ncm::ProgramId program_id, const sf::InPointerBuffer &args, u32 args_size) {
|
Result LoaderService::SetProgramArgumentsDeprecated(ncm::ProgramId program_id, const sf::InPointerBuffer &args, u32 args_size) {
|
||||||
|
@ -107,8 +106,9 @@ namespace ams::ldr {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result LoaderService::GetProcessModuleInfo(sf::Out<u32> count, const sf::OutPointerArray<ModuleInfo> &out, os::ProcessId process_id) {
|
Result LoaderService::GetProcessModuleInfo(sf::Out<u32> count, const sf::OutPointerArray<ModuleInfo> &out, os::ProcessId process_id) {
|
||||||
R_UNLESS(out.GetSize() <= std::numeric_limits<s32>::max(), ldr::ResultInvalidSize());
|
*count = 0;
|
||||||
return ldr::ro::GetProcessModuleInfo(count.GetPointer(), out.GetPointer(), out.GetSize(), process_id);
|
std::memset(out.GetPointer(), 0, out.GetSize() * sizeof(ldr::ModuleInfo));
|
||||||
|
return ldr::GetProcessModuleInfo(count.GetPointer(), out.GetPointer(), out.GetSize(), process_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result LoaderService::SetEnabledProgramVerification(bool enabled) {
|
Result LoaderService::SetEnabledProgramVerification(bool enabled) {
|
||||||
|
@ -138,7 +138,7 @@ namespace ams::ldr {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result LoaderService::AtmospherePinProgram(sf::Out<PinId> out_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status) {
|
Result LoaderService::AtmospherePinProgram(sf::Out<PinId> out_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status) {
|
||||||
return ldr::ro::PinProgram(out_id.GetPointer(), loc, override_status);
|
return ldr::PinProgram(out_id.GetPointer(), loc, override_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,7 +147,7 @@ namespace ams::ldr {
|
||||||
R_TRY(fs::GetFileSize(std::addressof(npdm_size), file));
|
R_TRY(fs::GetFileSize(std::addressof(npdm_size), file));
|
||||||
|
|
||||||
/* Read data into cache buffer. */
|
/* Read data into cache buffer. */
|
||||||
R_UNLESS(npdm_size <= static_cast<s64>(MetaCacheBufferSize), ldr::ResultTooLargeMeta());
|
R_UNLESS(npdm_size <= static_cast<s64>(MetaCacheBufferSize), ldr::ResultMetaOverflow());
|
||||||
R_TRY(fs::ReadFile(file, 0, cache->buffer, npdm_size));
|
R_TRY(fs::ReadFile(file, 0, cache->buffer, npdm_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ namespace ams::ldr {
|
||||||
AMS_ASSUME(ofs < sizeof(module_id));
|
AMS_ASSUME(ofs < sizeof(module_id));
|
||||||
AMS_ASSUME(str[1] != 0);
|
AMS_ASSUME(str[1] != 0);
|
||||||
|
|
||||||
module_id.build_id[ofs] = (ParseNybble(str[0]) << 4) | (ParseNybble(str[1]) << 0);
|
module_id.data[ofs] = (ParseNybble(str[0]) << 4) | (ParseNybble(str[1]) << 0);
|
||||||
|
|
||||||
str += 2;
|
str += 2;
|
||||||
ofs++;
|
ofs++;
|
||||||
|
@ -112,21 +112,21 @@ namespace ams::ldr {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apply IPS patches. */
|
/* Apply IPS patches. */
|
||||||
void LocateAndApplyIpsPatchesToModule(const u8 *build_id, uintptr_t mapped_nso, size_t mapped_size) {
|
void LocateAndApplyIpsPatchesToModule(const u8 *module_id_data, uintptr_t mapped_nso, size_t mapped_size) {
|
||||||
if (!EnsureSdCardMounted()) {
|
if (!EnsureSdCardMounted()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ro::ModuleId module_id;
|
ro::ModuleId module_id;
|
||||||
std::memcpy(std::addressof(module_id.build_id), build_id, sizeof(module_id.build_id));
|
std::memcpy(std::addressof(module_id.data), module_id_data, sizeof(module_id.data));
|
||||||
ams::patcher::LocateAndApplyIpsPatchesToModule(LoaderSdMountName, NsoPatchesDirectory, NsoPatchesProtectedSize, NsoPatchesProtectedOffset, std::addressof(module_id), reinterpret_cast<u8 *>(mapped_nso), mapped_size);
|
ams::patcher::LocateAndApplyIpsPatchesToModule(LoaderSdMountName, NsoPatchesDirectory, NsoPatchesProtectedSize, NsoPatchesProtectedOffset, std::addressof(module_id), reinterpret_cast<u8 *>(mapped_nso), mapped_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apply embedded patches. */
|
/* Apply embedded patches. */
|
||||||
void ApplyEmbeddedPatchesToModule(const u8 *build_id, uintptr_t mapped_nso, size_t mapped_size) {
|
void ApplyEmbeddedPatchesToModule(const u8 *module_id_data, uintptr_t mapped_nso, size_t mapped_size) {
|
||||||
/* Make module id. */
|
/* Make module id. */
|
||||||
ro::ModuleId module_id;
|
ro::ModuleId module_id;
|
||||||
std::memcpy(std::addressof(module_id.build_id), build_id, sizeof(module_id.build_id));
|
std::memcpy(std::addressof(module_id.data), module_id_data, sizeof(module_id.data));
|
||||||
|
|
||||||
if (IsUsb30ForceEnabled()) {
|
if (IsUsb30ForceEnabled()) {
|
||||||
for (const auto &patch : Usb30ForceEnablePatches) {
|
for (const auto &patch : Usb30ForceEnablePatches) {
|
||||||
|
|
|
@ -19,9 +19,9 @@
|
||||||
namespace ams::ldr {
|
namespace ams::ldr {
|
||||||
|
|
||||||
/* Apply IPS patches. */
|
/* Apply IPS patches. */
|
||||||
void LocateAndApplyIpsPatchesToModule(const u8 *build_id, uintptr_t mapped_nso, size_t mapped_size);
|
void LocateAndApplyIpsPatchesToModule(const u8 *module_id_data, uintptr_t mapped_nso, size_t mapped_size);
|
||||||
|
|
||||||
/* Apply embedded patches. */
|
/* Apply embedded patches. */
|
||||||
void ApplyEmbeddedPatchesToModule(const u8 *build_id, uintptr_t mapped_nso, size_t mapped_size);
|
void ApplyEmbeddedPatchesToModule(const u8 *module_id_data, uintptr_t mapped_nso, size_t mapped_size);
|
||||||
|
|
||||||
}
|
}
|
|
@ -591,10 +591,10 @@ namespace ams::ldr {
|
||||||
std::memset(reinterpret_cast<void *>(map_address + rw_end), 0, nso_header->bss_size);
|
std::memset(reinterpret_cast<void *>(map_address + rw_end), 0, nso_header->bss_size);
|
||||||
|
|
||||||
/* Apply embedded patches. */
|
/* Apply embedded patches. */
|
||||||
ApplyEmbeddedPatchesToModule(nso_header->build_id, map_address, nso_size);
|
ApplyEmbeddedPatchesToModule(nso_header->module_id, map_address, nso_size);
|
||||||
|
|
||||||
/* Apply IPS patches. */
|
/* Apply IPS patches. */
|
||||||
LocateAndApplyIpsPatchesToModule(nso_header->build_id, map_address, nso_size);
|
LocateAndApplyIpsPatchesToModule(nso_header->module_id, map_address, nso_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set permissions. */
|
/* Set permissions. */
|
||||||
|
@ -683,24 +683,32 @@ namespace ams::ldr {
|
||||||
ProcessInfo info;
|
ProcessInfo info;
|
||||||
R_TRY(CreateProcessImpl(std::addressof(info), std::addressof(meta), nso_headers, has_nso, arg_info, flags, reslimit_h));
|
R_TRY(CreateProcessImpl(std::addressof(info), std::addressof(meta), nso_headers, has_nso, arg_info, flags, reslimit_h));
|
||||||
|
|
||||||
/* Ensure we close the process handle, if we fail. */
|
|
||||||
ON_SCOPE_EXIT { os::CloseNativeHandle(info.process_handle); };
|
|
||||||
|
|
||||||
/* Load NSOs into process memory. */
|
/* Load NSOs into process memory. */
|
||||||
|
{
|
||||||
|
/* Ensure we close the process handle, if we fail. */
|
||||||
|
auto process_guard = SCOPE_GUARD { os::CloseNativeHandle(info.process_handle); };
|
||||||
|
|
||||||
|
/* Load all NSOs. */
|
||||||
R_TRY(LoadNsosIntoProcessMemory(std::addressof(info), nso_headers, has_nso, arg_info));
|
R_TRY(LoadNsosIntoProcessMemory(std::addressof(info), nso_headers, has_nso, arg_info));
|
||||||
|
|
||||||
/* Register NSOs with ro manager. */
|
/* We don't need to close the process handle, since we succeeded. */
|
||||||
|
process_guard.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register NSOs with the RoManager. */
|
||||||
{
|
{
|
||||||
/* Nintendo doesn't validate this get, but we do. */
|
/* Nintendo doesn't validate this get, but we do. */
|
||||||
os::ProcessId process_id = os::GetProcessId(info.process_handle);
|
os::ProcessId process_id = os::GetProcessId(info.process_handle);
|
||||||
|
|
||||||
/* Register new process. */
|
/* Register new process. */
|
||||||
ldr::ro::RegisterProcess(pin_id, process_id, loc.program_id);
|
/* NOTE: Nintendo uses meta->aci->program_id, not loc.program_id. Should we? */
|
||||||
|
const auto as_type = GetAddressSpaceType(std::addressof(meta));
|
||||||
|
RoManager::GetInstance().RegisterProcess(pin_id, process_id, loc.program_id, as_type == Npdm::AddressSpaceType_64Bit || as_type == Npdm::AddressSpaceType_64BitDeprecated);
|
||||||
|
|
||||||
/* Register all NSOs. */
|
/* Register all NSOs. */
|
||||||
for (size_t i = 0; i < Nso_Count; i++) {
|
for (size_t i = 0; i < Nso_Count; i++) {
|
||||||
if (has_nso[i]) {
|
if (has_nso[i]) {
|
||||||
ldr::ro::RegisterModule(pin_id, nso_headers[i].build_id, info.nso_address[i], info.nso_size[i]);
|
RoManager::GetInstance().AddNso(pin_id, nso_headers[i].module_id, info.nso_address[i], info.nso_size[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -719,7 +727,6 @@ namespace ams::ldr {
|
||||||
|
|
||||||
/* Move the process handle to output. */
|
/* Move the process handle to output. */
|
||||||
*out = info.process_handle;
|
*out = info.process_handle;
|
||||||
info.process_handle = os::InvalidNativeHandle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
|
@ -741,4 +748,24 @@ namespace ams::ldr {
|
||||||
return GetProgramInfoFromMeta(out, std::addressof(meta));
|
return GetProgramInfoFromMeta(out, std::addressof(meta));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result PinProgram(PinId *out_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status) {
|
||||||
|
R_UNLESS(RoManager::GetInstance().Allocate(out_id, loc, override_status), ldr::ResultMaxProcess());
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result UnpinProgram(PinId id) {
|
||||||
|
R_UNLESS(RoManager::GetInstance().Free(id), ldr::ResultNotPinned());
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetProcessModuleInfo(u32 *out_count, ldr::ModuleInfo *out, size_t max_out_count, os::ProcessId process_id) {
|
||||||
|
R_UNLESS(RoManager::GetInstance().GetProcessModuleInfo(out_count, out, max_out_count, process_id), ldr::ResultNotPinned());
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetProgramLocationAndOverrideStatusFromPinId(ncm::ProgramLocation *out, cfg::OverrideStatus *out_status, PinId pin_id) {
|
||||||
|
R_UNLESS(RoManager::GetInstance().GetProgramLocationAndStatus(out, out_status, pin_id), ldr::ResultNotPinned());
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,4 +22,11 @@ namespace ams::ldr {
|
||||||
Result CreateProcess(os::NativeHandle *out, PinId pin_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status, const char *path, u32 flags, os::NativeHandle reslimit_h);
|
Result CreateProcess(os::NativeHandle *out, PinId pin_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status, const char *path, u32 flags, os::NativeHandle reslimit_h);
|
||||||
Result GetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc);
|
Result GetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc);
|
||||||
|
|
||||||
|
Result PinProgram(PinId *out_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status);
|
||||||
|
Result UnpinProgram(PinId id);
|
||||||
|
|
||||||
|
Result GetProcessModuleInfo(u32 *out_count, ldr::ModuleInfo *out, size_t max_out_count, os::ProcessId process_id);
|
||||||
|
|
||||||
|
Result GetProgramLocationAndOverrideStatusFromPinId(ncm::ProgramLocation *out, cfg::OverrideStatus *out_status, PinId pin_id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,147 +16,166 @@
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "ldr_ro_manager.hpp"
|
#include "ldr_ro_manager.hpp"
|
||||||
|
|
||||||
namespace ams::ldr::ro {
|
namespace ams::ldr {
|
||||||
|
|
||||||
namespace {
|
bool RoManager::Allocate(PinId *out, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status) {
|
||||||
|
/* Ensure that output pin id is set. */
|
||||||
/* Convenience definitions. */
|
|
||||||
constexpr PinId InvalidPinId = {};
|
|
||||||
constexpr size_t ProcessCountMax = 0x40;
|
|
||||||
constexpr size_t ModuleCountMax = 0x20;
|
|
||||||
|
|
||||||
/* Types. */
|
|
||||||
struct ModuleInfo {
|
|
||||||
ldr::ModuleInfo info;
|
|
||||||
bool in_use;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ProcessInfo {
|
|
||||||
PinId pin_id;
|
|
||||||
os::ProcessId process_id;
|
|
||||||
ncm::ProgramId program_id;
|
|
||||||
cfg::OverrideStatus override_status;
|
|
||||||
ncm::ProgramLocation loc;
|
|
||||||
ModuleInfo modules[ModuleCountMax];
|
|
||||||
bool in_use;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Globals. */
|
|
||||||
ProcessInfo g_process_infos[ProcessCountMax];
|
|
||||||
u64 g_cur_pin_id = 1;
|
|
||||||
|
|
||||||
/* Helpers. */
|
|
||||||
ProcessInfo *GetProcessInfo(PinId pin_id) {
|
|
||||||
for (size_t i = 0; i < ProcessCountMax; i++) {
|
|
||||||
ProcessInfo *info = g_process_infos + i;
|
|
||||||
if (info->in_use && info->pin_id == pin_id) {
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessInfo *GetProcessInfo(os::ProcessId process_id) {
|
|
||||||
for (size_t i = 0; i < ProcessCountMax; i++) {
|
|
||||||
ProcessInfo *info = g_process_infos + i;
|
|
||||||
if (info->in_use && info->process_id == process_id) {
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessInfo *GetFreeProcessInfo() {
|
|
||||||
for (size_t i = 0; i < ProcessCountMax; i++) {
|
|
||||||
ProcessInfo *info = g_process_infos + i;
|
|
||||||
if (!info->in_use) {
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* RO Manager API. */
|
|
||||||
Result PinProgram(PinId *out, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status) {
|
|
||||||
*out = InvalidPinId;
|
*out = InvalidPinId;
|
||||||
ProcessInfo *info = GetFreeProcessInfo();
|
|
||||||
R_UNLESS(info != nullptr, ldr::ResultTooManyProcesses());
|
|
||||||
|
|
||||||
std::memset(info, 0, sizeof(*info));
|
/* Allocate a process info. */
|
||||||
info->pin_id = { g_cur_pin_id++ };
|
auto *found = this->AllocateProcessInfo();
|
||||||
info->loc = loc;
|
if (found == nullptr) {
|
||||||
info->override_status = status;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup the process info. */
|
||||||
|
std::memset(found, 0, sizeof(*found));
|
||||||
|
found->pin_id = { ++m_pin_id };
|
||||||
|
found->program_location = loc;
|
||||||
|
found->override_status = status;
|
||||||
|
found->in_use = true;
|
||||||
|
|
||||||
|
/* Set the output pin id. */
|
||||||
|
*out = found->pin_id;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RoManager::Free(PinId pin_id) {
|
||||||
|
/* Find the process. */
|
||||||
|
auto *found = this->FindProcessInfo(pin_id);
|
||||||
|
if (found == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the process as not in use. */
|
||||||
|
found->in_use = false;
|
||||||
|
|
||||||
|
/* Set all the process's nsos as not in use. */
|
||||||
|
for (auto i = 0; i < NsoCount; ++i) {
|
||||||
|
found->nso_infos[i].in_use = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RoManager::RegisterProcess(PinId pin_id, os::ProcessId process_id, ncm::ProgramId program_id, bool is_64_bit_address_space) {
|
||||||
|
/* Find the process. */
|
||||||
|
auto *found = this->FindProcessInfo(pin_id);
|
||||||
|
if (found == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the process id and program id. */
|
||||||
|
found->process_id = process_id;
|
||||||
|
found->program_id = program_id;
|
||||||
|
AMS_UNUSED(is_64_bit_address_space);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RoManager::GetProgramLocationAndStatus(ncm::ProgramLocation *out, cfg::OverrideStatus *out_status, PinId pin_id) {
|
||||||
|
/* Find the process. */
|
||||||
|
auto *found = this->FindProcessInfo(pin_id);
|
||||||
|
if (found == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the output location/status. */
|
||||||
|
*out = found->program_location;
|
||||||
|
*out_status = found->override_status;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RoManager::AddNso(PinId pin_id, const u8 *module_id, u64 address, u64 size) {
|
||||||
|
/* Find the process. */
|
||||||
|
auto *found = this->FindProcessInfo(pin_id);
|
||||||
|
if (found == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate an nso. */
|
||||||
|
auto *info = this->AllocateNsoInfo(found);
|
||||||
|
if (info == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the information into the nso info. */
|
||||||
|
std::memcpy(info->module_info.module_id, module_id, sizeof(info->module_info.module_id));
|
||||||
|
info->module_info.address = address;
|
||||||
|
info->module_info.size = size;
|
||||||
info->in_use = true;
|
info->in_use = true;
|
||||||
*out = info->pin_id;
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result UnpinProgram(PinId id) {
|
bool RoManager::GetProcessModuleInfo(u32 *out_count, ModuleInfo *out, size_t max_out_count, os::ProcessId process_id) {
|
||||||
ProcessInfo *info = GetProcessInfo(id);
|
/* Find the process. */
|
||||||
R_UNLESS(info != nullptr, ldr::ResultNotPinned());
|
auto *found = this->FindProcessInfo(process_id);
|
||||||
|
if (found == nullptr) {
|
||||||
info->in_use = false;
|
return false;
|
||||||
return ResultSuccess();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Copy allocated nso module infos. */
|
||||||
Result GetProgramLocationAndStatus(ncm::ProgramLocation *out, cfg::OverrideStatus *out_status, PinId id) {
|
|
||||||
ProcessInfo *info = GetProcessInfo(id);
|
|
||||||
R_UNLESS(info != nullptr, ldr::ResultNotPinned());
|
|
||||||
|
|
||||||
*out = info->loc;
|
|
||||||
*out_status = info->override_status;
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result RegisterProcess(PinId id, os::ProcessId process_id, ncm::ProgramId program_id) {
|
|
||||||
ProcessInfo *info = GetProcessInfo(id);
|
|
||||||
R_UNLESS(info != nullptr, ldr::ResultNotPinned());
|
|
||||||
|
|
||||||
info->program_id = program_id;
|
|
||||||
info->process_id = process_id;
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result RegisterModule(PinId id, const u8 *build_id, uintptr_t address, size_t size) {
|
|
||||||
ProcessInfo *info = GetProcessInfo(id);
|
|
||||||
R_UNLESS(info != nullptr, ldr::ResultNotPinned());
|
|
||||||
|
|
||||||
/* Nintendo doesn't actually care about successful allocation. */
|
|
||||||
for (size_t i = 0; i < ModuleCountMax; i++) {
|
|
||||||
ModuleInfo *module = info->modules + i;
|
|
||||||
if (module->in_use) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::memcpy(module->info.build_id, build_id, sizeof(module->info.build_id));
|
|
||||||
module->info.base_address = address;
|
|
||||||
module->info.size = size;
|
|
||||||
module->in_use = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result GetProcessModuleInfo(u32 *out_count, ldr::ModuleInfo *out, size_t max_out_count, os::ProcessId process_id) {
|
|
||||||
const ProcessInfo *info = GetProcessInfo(process_id);
|
|
||||||
R_UNLESS(info != nullptr, ldr::ResultNotPinned());
|
|
||||||
|
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
for (size_t i = 0; i < ModuleCountMax && count < max_out_count; i++) {
|
for (auto i = 0; i < NsoCount && count < max_out_count; ++i) {
|
||||||
const ModuleInfo *module = info->modules + i;
|
/* Skip unallocated nsos. */
|
||||||
if (!module->in_use) {
|
if (!found->nso_infos[i].in_use) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
out[count++] = module->info;
|
/* Copy out the module info. */
|
||||||
|
out[count++] = found->nso_infos[i].module_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_count = static_cast<u32>(count);
|
/* Set the output count. */
|
||||||
return ResultSuccess();
|
*out_count = count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RoManager::ProcessInfo *RoManager::AllocateProcessInfo() {
|
||||||
|
for (auto i = 0; i < ProcessCount; ++i) {
|
||||||
|
if (!m_processes[i].in_use) {
|
||||||
|
return m_processes + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
RoManager::ProcessInfo *RoManager::FindProcessInfo(PinId pin_id) {
|
||||||
|
for (auto i = 0; i < ProcessCount; ++i) {
|
||||||
|
if (m_processes[i].in_use && m_processes[i].pin_id == pin_id) {
|
||||||
|
return m_processes + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
RoManager::ProcessInfo *RoManager::FindProcessInfo(os::ProcessId process_id) {
|
||||||
|
for (auto i = 0; i < ProcessCount; ++i) {
|
||||||
|
if (m_processes[i].in_use && m_processes[i].process_id == process_id) {
|
||||||
|
return m_processes + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
RoManager::ProcessInfo *RoManager::FindProcessInfo(ncm::ProgramId program_id) {
|
||||||
|
for (auto i = 0; i < ProcessCount; ++i) {
|
||||||
|
if (m_processes[i].in_use && m_processes[i].program_id == program_id) {
|
||||||
|
return m_processes + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
RoManager::NsoInfo *RoManager::AllocateNsoInfo(ProcessInfo *info) {
|
||||||
|
for (auto i = 0; i < NsoCount; ++i) {
|
||||||
|
if (!info->nso_infos[i].in_use) {
|
||||||
|
return info->nso_infos + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,14 +16,50 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
|
|
||||||
namespace ams::ldr::ro {
|
namespace ams::ldr {
|
||||||
|
|
||||||
/* RO Manager API. */
|
class RoManager {
|
||||||
Result PinProgram(PinId *out, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status);
|
AMS_CONSTINIT_SINGLETON_TRAITS(RoManager);
|
||||||
Result UnpinProgram(PinId id);
|
public:
|
||||||
Result GetProgramLocationAndStatus(ncm::ProgramLocation *out, cfg::OverrideStatus *out_status, PinId id);
|
static constexpr PinId InvalidPinId = {};
|
||||||
Result RegisterProcess(PinId id, os::ProcessId process_id, ncm::ProgramId program_id);
|
static constexpr int ProcessCount = 0x40;
|
||||||
Result RegisterModule(PinId id, const u8 *build_id, uintptr_t address, size_t size);
|
static constexpr int NsoCount = 0x20;
|
||||||
Result GetProcessModuleInfo(u32 *out_count, ModuleInfo *out, size_t max_out_count, os::ProcessId process_id);
|
private:
|
||||||
|
struct NsoInfo {
|
||||||
|
bool in_use;
|
||||||
|
ldr::ModuleInfo module_info;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ProcessInfo {
|
||||||
|
bool in_use;
|
||||||
|
PinId pin_id;
|
||||||
|
os::ProcessId process_id;
|
||||||
|
ncm::ProgramId program_id;
|
||||||
|
cfg::OverrideStatus override_status;
|
||||||
|
ncm::ProgramLocation program_location;
|
||||||
|
NsoInfo nso_infos[NsoCount];
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
ProcessInfo m_processes[ProcessCount];
|
||||||
|
u64 m_pin_id;
|
||||||
|
public:
|
||||||
|
bool Allocate(PinId *out, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status);
|
||||||
|
bool Free(PinId pin_id);
|
||||||
|
|
||||||
|
void RegisterProcess(PinId pin_id, os::ProcessId process_id, ncm::ProgramId program_id, bool is_64_bit_address_space);
|
||||||
|
|
||||||
|
bool GetProgramLocationAndStatus(ncm::ProgramLocation *out, cfg::OverrideStatus *out_status, PinId pin_id);
|
||||||
|
|
||||||
|
void AddNso(PinId pin_id, const u8 *module_id, u64 address, u64 size);
|
||||||
|
|
||||||
|
bool GetProcessModuleInfo(u32 *out_count, ModuleInfo *out, size_t max_out_count, os::ProcessId process_id);
|
||||||
|
private:
|
||||||
|
ProcessInfo *AllocateProcessInfo();
|
||||||
|
ProcessInfo *FindProcessInfo(PinId pin_id);
|
||||||
|
ProcessInfo *FindProcessInfo(os::ProcessId process_id);
|
||||||
|
ProcessInfo *FindProcessInfo(ncm::ProgramId program_id);
|
||||||
|
|
||||||
|
NsoInfo *AllocateNsoInfo(ProcessInfo *info);
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,7 +320,7 @@ namespace ams::ro::impl {
|
||||||
m_nro_in_use[index] = in_use;
|
m_nro_in_use[index] = in_use;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetProcessModuleInfo(u32 *out_count, LoaderModuleInfo *out_infos, size_t max_out_count) const {
|
void GetProcessModuleInfo(u32 *out_count, ldr::ModuleInfo *out_infos, size_t max_out_count) const {
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
|
|
||||||
for (size_t i = 0; i < MaxNroInfos && count < max_out_count; i++) {
|
for (size_t i = 0; i < MaxNroInfos && count < max_out_count; i++) {
|
||||||
|
@ -331,10 +331,11 @@ namespace ams::ro::impl {
|
||||||
const NroInfo *nro_info = m_nro_infos + i;
|
const NroInfo *nro_info = m_nro_infos + i;
|
||||||
|
|
||||||
/* Just copy out the info. */
|
/* Just copy out the info. */
|
||||||
LoaderModuleInfo *out_info = std::addressof(out_infos[count++]);
|
auto &out_info = 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;
|
std::memcpy(out_info.module_id, nro_info->module_id.data, sizeof(out_info.module_id));
|
||||||
out_info->size = nro_info->nro_heap_size + nro_info->bss_heap_size;
|
out_info.address = nro_info->base_address;
|
||||||
|
out_info.size = nro_info->nro_heap_size + nro_info->bss_heap_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
*out_count = static_cast<u32>(count);
|
*out_count = static_cast<u32>(count);
|
||||||
|
@ -597,7 +598,7 @@ namespace ams::ro::impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Debug service implementations. */
|
/* Debug service implementations. */
|
||||||
Result GetProcessModuleInfo(u32 *out_count, LoaderModuleInfo *out_infos, size_t max_out_count, os::ProcessId process_id) {
|
Result GetProcessModuleInfo(u32 *out_count, ldr::ModuleInfo *out_infos, size_t max_out_count, os::ProcessId process_id) {
|
||||||
if (const ProcessContext *context = GetContextByProcessId(process_id); context != nullptr) {
|
if (const ProcessContext *context = GetContextByProcessId(process_id); context != nullptr) {
|
||||||
context->GetProcessModuleInfo(out_count, out_infos, max_out_count);
|
context->GetProcessModuleInfo(out_count, out_infos, max_out_count);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,6 @@ namespace ams::ro::impl {
|
||||||
Result UnmapManualLoadModuleMemory(size_t context_id, u64 nro_address);
|
Result UnmapManualLoadModuleMemory(size_t context_id, u64 nro_address);
|
||||||
|
|
||||||
/* Debug service implementations. */
|
/* Debug service implementations. */
|
||||||
Result GetProcessModuleInfo(u32 *out_count, LoaderModuleInfo *out_infos, size_t max_out_count, os::ProcessId process_id);
|
Result GetProcessModuleInfo(u32 *out_count, ldr::ModuleInfo *out_infos, size_t max_out_count, os::ProcessId process_id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
namespace ams::ro {
|
namespace ams::ro {
|
||||||
|
|
||||||
Result DebugMonitorService::GetProcessModuleInfo(sf::Out<u32> out_count, const sf::OutArray<LoaderModuleInfo> &out_infos, os::ProcessId process_id) {
|
Result DebugMonitorService::GetProcessModuleInfo(sf::Out<u32> out_count, const sf::OutArray<ldr::ModuleInfo> &out_infos, os::ProcessId process_id) {
|
||||||
R_UNLESS(out_infos.GetSize() <= std::numeric_limits<s32>::max(), ro::ResultInvalidSize());
|
R_UNLESS(out_infos.GetSize() <= std::numeric_limits<s32>::max(), ro::ResultInvalidSize());
|
||||||
return impl::GetProcessModuleInfo(out_count.GetPointer(), out_infos.GetPointer(), out_infos.GetSize(), process_id);
|
return impl::GetProcessModuleInfo(out_count.GetPointer(), out_infos.GetPointer(), out_infos.GetSize(), process_id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace ams::ro {
|
||||||
|
|
||||||
class DebugMonitorService {
|
class DebugMonitorService {
|
||||||
public:
|
public:
|
||||||
Result GetProcessModuleInfo(sf::Out<u32> out_count, const sf::OutArray<LoaderModuleInfo> &out_infos, os::ProcessId process_id);
|
Result GetProcessModuleInfo(sf::Out<u32> out_count, const sf::OutArray<ldr::ModuleInfo> &out_infos, os::ProcessId process_id);
|
||||||
};
|
};
|
||||||
static_assert(ro::impl::IsIDebugMonitorInterface<DebugMonitorService>);
|
static_assert(ro::impl::IsIDebugMonitorInterface<DebugMonitorService>);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue