Merge upstream Atmosphere-NX/Atmosphere master

This commit is contained in:
Niklas080208
2026-09-29 21:44:46 +02:00
223 changed files with 2769 additions and 1401 deletions

View File

@@ -679,7 +679,7 @@ namespace ams::tio {
/* NOTE: Nintendo does not check the output of this call. */
s64 read_count = 0;
fs::ReadDirectory(std::addressof(read_count), reinterpret_cast<fs::DirectoryEntry *>(body), handle, cur);
R_DISCARD(fs::ReadDirectory(std::addressof(read_count), reinterpret_cast<fs::DirectoryEntry *>(body), handle, cur));
/* Send the current entries. */
const ssize_t cur_size = read_count * sizeof(fs::DirectoryEntry);

View File

@@ -89,7 +89,7 @@ namespace ams::mitm {
void CreateAutomaticBackups() {
/* Create a backup directory, if one doesn't exist. */
mitm::fs::CreateAtmosphereSdDirectory("/automatic_backups");
R_DISCARD(mitm::fs::CreateAtmosphereSdDirectory("/automatic_backups"));
/* Initialize PRODINFO and get a reference for the device. */
char device_reference[0x40] = {};
@@ -127,7 +127,7 @@ namespace ams::mitm {
char bis_keys_backup_name[ams::fs::EntryNameLengthMax + 1];
GetBackupFileName(bis_keys_backup_name, sizeof(bis_keys_backup_name), device_reference, "BISKEYS.bin");
mitm::fs::CreateAtmosphereSdFile(bis_keys_backup_name, sizeof(bis_keys), ams::fs::CreateOption_None);
R_DISCARD(mitm::fs::CreateAtmosphereSdFile(bis_keys_backup_name, sizeof(bis_keys), ams::fs::CreateOption_None));
R_ABORT_UNLESS(mitm::fs::OpenAtmosphereSdFile(std::addressof(g_bis_key_file), bis_keys_backup_name, ams::fs::OpenMode_ReadWrite));
R_ABORT_UNLESS(fsFileSetSize(std::addressof(g_bis_key_file), sizeof(bis_keys)));
R_ABORT_UNLESS(fsFileWrite(std::addressof(g_bis_key_file), 0, bis_keys, sizeof(bis_keys), FsWriteOption_Flush));
@@ -153,11 +153,11 @@ namespace ams::mitm {
mitm::fs::OpenGlobalSdCardFileSystem();
/* Mount the sd card at a convenient mountpoint. */
ams::fs::MountSdCard(ams::fs::impl::SdCardFileSystemMountName);
R_DISCARD(ams::fs::MountSdCard(ams::fs::impl::SdCardFileSystemMountName));
/* Initialize the reboot manager (load a payload off the SD). */
/* Discard result, since it doesn't need to succeed. */
mitm::bpc::LoadRebootPayload();
R_DISCARD(mitm::bpc::LoadRebootPayload());
/* Backup Calibration Binary and BIS keys. */
CreateAutomaticBackups();
@@ -167,7 +167,7 @@ namespace ams::mitm {
if (const char *emummc_file_path = emummc::GetFilePath(); emummc_file_path != nullptr) {
char emummc_path[ams::fs::EntryNameLengthMax + 1];
util::SNPrintf(emummc_path, sizeof(emummc_path), "%s/eMMC", emummc_file_path);
mitm::fs::OpenSdFile(std::addressof(g_emummc_file), emummc_path, ams::fs::OpenMode_Read);
R_DISCARD(mitm::fs::OpenSdFile(std::addressof(g_emummc_file), emummc_path, ams::fs::OpenMode_Read));
}
/* NOTE: due to an Atmosphere bug, NS accesses to the Nintendo dir accessed /Nintendo/Nintendo */
@@ -185,7 +185,7 @@ namespace ams::mitm {
/* Ensure Contents directory exists for normal emummc. */
/* NOTE: Allowed to fail on already-exists. */
util::SNPrintf(emummc_path, sizeof(emummc_path), "%s:/%s/Contents", ams::fs::impl::SdCardFileSystemMountName, emummc::GetNintendoDirPath());
ams::fs::CreateDirectory(emummc_path);
R_DISCARD(ams::fs::CreateDirectory(emummc_path));
/* Fix Contents/private */
util::SNPrintf(emummc_path, sizeof(emummc_path), "%s:/%s/Contents/private", ams::fs::impl::SdCardFileSystemMountName, emummc::GetNintendoDirPath());

View File

@@ -436,7 +436,7 @@ namespace ams::mitm {
GetBackupFileName(backup_fn, sizeof(backup_fn), info);
/* Create the file, in case it does not exist. */
mitm::fs::CreateAtmosphereSdFile(backup_fn, sizeof(CalibrationInfo), ams::fs::CreateOption_None);
R_DISCARD(mitm::fs::CreateAtmosphereSdFile(backup_fn, sizeof(CalibrationInfo), ams::fs::CreateOption_None));
/* Open the file. */
FsFile libnx_file;

View File

@@ -40,10 +40,10 @@ namespace ams::mitm::socket::resolver {
if (g_log_enabled) {
/* Create the logs directory. */
mitm::fs::CreateAtmosphereSdDirectory("/logs");
R_DISCARD(mitm::fs::CreateAtmosphereSdDirectory("/logs"));
/* Create the log file. */
mitm::fs::CreateAtmosphereSdFile("/logs/dns_mitm_debug.log", 0, ams::fs::CreateOption_None);
R_DISCARD(mitm::fs::CreateAtmosphereSdFile("/logs/dns_mitm_debug.log", 0, ams::fs::CreateOption_None));
/* Open the log file. */
R_ABORT_UNLESS(mitm::fs::OpenAtmosphereSdFile(std::addressof(g_log_file), "/logs/dns_mitm_debug.log", ams::fs::OpenMode_ReadWrite | ams::fs::OpenMode_AllowAppend));

View File

@@ -313,8 +313,8 @@ namespace ams::mitm::socket::resolver {
/* Open log file. */
::FsFile log_file;
mitm::fs::DeleteAtmosphereSdFile("/logs/dns_mitm_startup.log");
mitm::fs::CreateAtmosphereSdDirectory("/logs");
R_DISCARD(mitm::fs::DeleteAtmosphereSdFile("/logs/dns_mitm_startup.log"));
R_DISCARD(mitm::fs::CreateAtmosphereSdDirectory("/logs"));
R_ABORT_UNLESS(mitm::fs::CreateAtmosphereSdFile("/logs/dns_mitm_startup.log", 0, ams::fs::CreateOption_None));
R_ABORT_UNLESS(mitm::fs::OpenAtmosphereSdFile(std::addressof(log_file), "/logs/dns_mitm_startup.log", ams::fs::OpenMode_ReadWrite | ams::fs::OpenMode_AllowAppend));
ON_SCOPE_EXIT { ::fsFileClose(std::addressof(log_file)); };
@@ -325,7 +325,7 @@ namespace ams::mitm::socket::resolver {
if (!mitm::fs::HasAtmosphereSdFile("/hosts/default.txt")) {
Log(log_file, "Creating /hosts/default.txt because it does not exist.\n");
mitm::fs::CreateAtmosphereSdDirectory("/hosts");
R_DISCARD(mitm::fs::CreateAtmosphereSdDirectory("/hosts"));
R_ABORT_UNLESS(mitm::fs::CreateAtmosphereSdFile("/hosts/default.txt", sizeof(DefaultHostsFile) - 1, ams::fs::CreateOption_None));
::FsFile default_file;

View File

@@ -131,7 +131,7 @@ namespace ams::mitm::socket::resolver {
}
/* Initialize the socket allocator. */
ams::socket::InitializeAllocatorForInternal(g_resolver_allocator_buffer, sizeof(g_resolver_allocator_buffer));
R_DISCARD(ams::socket::InitializeAllocatorForInternal(g_resolver_allocator_buffer, sizeof(g_resolver_allocator_buffer)));
/* Initialize debug. */
resolver::InitializeDebug(ShouldEnableDebugLog());

View File

@@ -262,7 +262,7 @@ namespace ams::mitm::fs {
constexpr const fs::Path root_path = fs::MakeConstantPath("/");
u8 savedata_copy_buffer[2_KB];
fssystem::CopyDirectoryRecursively(dirsave_ifs.get(), save_ifs.get(), root_path, root_path, std::addressof(work_entry), savedata_copy_buffer, sizeof(savedata_copy_buffer));
R_DISCARD(fssystem::CopyDirectoryRecursively(dirsave_ifs.get(), save_ifs.get(), root_path, root_path, std::addressof(work_entry), savedata_copy_buffer, sizeof(savedata_copy_buffer)));
}
/* Set output. */

View File

@@ -36,6 +36,11 @@ namespace ams::mitm::fs {
};
constexpr const ApplicationWithDynamicHeapInfo ApplicationsWithDynamicHeap[] = {
/* Danganronpa V3: Killing Harmony Anniversary Edition. */
/* Requirement ? MB. 16 MB stolen heap fixes a crash, though. */
/* Unknown heap sensitivity. */
{ 0x010063F014176000, 16_MB, 0_MB },
/* Until Then. */
/* Requirement ~34 MB. */
/* No particular heap sensitivity. */

View File

@@ -90,7 +90,7 @@ namespace ams::mitm::settings {
}
Result SetMitmService::GetLanguageCode(sf::Out<settings::LanguageCode> out) {
this->EnsureLocale();
R_DISCARD(this->EnsureLocale());
/* If there's no override locale, just use the actual one. */
if (AMS_UNLIKELY(!m_is_valid_language)) {
@@ -109,7 +109,7 @@ namespace ams::mitm::settings {
}
Result SetMitmService::GetRegionCode(sf::Out<settings::RegionCode> out) {
this->EnsureLocale();
R_DISCARD(this->EnsureLocale());
/* If there's no override locale, just use the actual one. */
if (AMS_UNLIKELY(!m_is_valid_region)) {

View File

@@ -466,12 +466,21 @@ namespace ams::boot {
boot::ShutdownSystem();
}
}
/* On 18.0.0+ i2c shutdown is unconditionally disabled here. */
if (hos::GetVersion() >= hos::Version_18_0_0) {
if (R_FAILED(battery_driver.SetI2cShutdownEnabled(false))) {
boot::ShutdownSystem();
}
}
/* Get the boot reason. */
const auto boot_reason = boot::GetBootReason();
/* Initialize the charger driver. */
if (R_FAILED(charger_driver.Initialize(boot_reason != spl::BootReason_RtcAlarm2)))
if (R_FAILED(charger_driver.Initialize(boot_reason != spl::BootReason_RtcAlarm2))) {
boot::ShutdownSystem();
}
/* Check that the charger input limit is greater than 150 milli-amps. */
{
@@ -481,7 +490,7 @@ namespace ams::boot {
}
if (input_current_limit_ma <= 150) {
charger_driver.SetChargerConfiguration(powctl::ChargerConfiguration_ChargeDisable);
R_DISCARD(charger_driver.SetChargerConfiguration(powctl::ChargerConfiguration_ChargeDisable));
boot::ShutdownSystem();
}
}

View File

@@ -262,10 +262,10 @@ namespace ams::boot {
R_ABORT_UNLESS(i2c::driver::OpenSession(std::addressof(i2c_session), i2c::DeviceCode_Max77620Pmic));
if (g_soc_type == spl::SocType_Mariko) {
WriteI2cRegister(i2c_session, 0x18, 0x3A);
WriteI2cRegister(i2c_session, 0x1F, 0x71);
R_DISCARD(WriteI2cRegister(i2c_session, 0x18, 0x3A));
R_DISCARD(WriteI2cRegister(i2c_session, 0x1F, 0x71));
}
WriteI2cRegister(i2c_session, 0x23, 0xD0);
R_DISCARD(WriteI2cRegister(i2c_session, 0x23, 0xD0));
i2c::driver::CloseSession(i2c_session);
}

View File

@@ -74,11 +74,14 @@ namespace ams::boot {
u8 on_off_1_val = 0;
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. */
if (spl::GetHardwareType() != spl::HardwareType::Calcio) {
BatteryDriver battery_driver;
this->FinalizeBattery(battery_driver);
/* 23.0.0+ no longer finalizes the battery on any hardware type. */
if (hos::GetVersion() < hos::Version_23_0_0) {
/* Finalize the battery on non-Calcio. */
if (spl::GetHardwareType() != spl::HardwareType::Calcio) {
BatteryDriver battery_driver;
this->FinalizeBattery(battery_driver);
}
}
/* Actually write the value to trigger shutdown/reset. */
@@ -116,7 +119,7 @@ namespace ams::boot {
desired_shutdown_enabled &= use_desired_shutdown;
if (shutdown_enabled != desired_shutdown_enabled) {
battery_driver.SetI2cShutdownEnabled(desired_shutdown_enabled);
R_DISCARD(battery_driver.SetI2cShutdownEnabled(desired_shutdown_enabled));
}
}

View File

@@ -53,8 +53,8 @@ namespace ams::creport {
}
void TryCreateReportDirectories() {
fs::EnsureDirectory("sdmc:/atmosphere/crash_reports/dumps");
fs::EnsureDirectory("sdmc:/atmosphere/fatal_reports/dumps");
R_DISCARD(fs::EnsureDirectory("sdmc:/atmosphere/crash_reports/dumps"));
R_DISCARD(fs::EnsureDirectory("sdmc:/atmosphere/fatal_reports/dumps"));
}
constexpr const char *GetDebugExceptionString(const svc::DebugException type) {
@@ -244,7 +244,7 @@ namespace ams::creport {
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(m_result)), m_debug_handle, d.info.exception.specific.user_break.address, sizeof(m_result));
R_DISCARD(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:
@@ -289,7 +289,7 @@ namespace ams::creport {
}
/* Read the dying message. */
svc::ReadDebugProcessMemory(reinterpret_cast<uintptr_t>(m_dying_message), m_debug_handle, m_dying_message_address, m_dying_message_size);
R_DISCARD(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) {

View File

@@ -67,11 +67,11 @@ namespace ams::creport {
}
bool IsApplication() const {
return (m_process_info.flags & svc::CreateProcessFlag_IsApplication) != 0;
return (m_process_info.flags & svc::CreateProcessParameterFlag_IsApplication) != 0;
}
bool Is64Bit() const {
return (m_process_info.flags & svc::CreateProcessFlag_Is64Bit) != 0;
return (m_process_info.flags & svc::CreateProcessParameterFlag_64Bit) != 0;
}
bool IsUserBreak() const {

View File

@@ -123,7 +123,7 @@ namespace ams {
if (R_SUCCEEDED(pgl::Initialize())) {
ON_SCOPE_EXIT { pgl::Finalize(); };
pgl::TerminateProcess(crashed_pid);
R_DISCARD(pgl::TerminateProcess(crashed_pid));
}
} else {
/* Use ns to terminate. */

View File

@@ -38,9 +38,9 @@ namespace ams::creport {
~ScopedFile() {
if (m_opened) {
if (m_cache != nullptr) {
this->TryWriteCache();
R_DISCARD(this->TryWriteCache());
}
fs::FlushFile(m_file);
R_DISCARD(fs::FlushFile(m_file));
fs::CloseFile(m_file);
}
}

View File

@@ -29,7 +29,7 @@ namespace ams::dmnt {
for (size_t i = 0; (bp = static_cast<BreakPoint *>(this->GetBreakPoint(i))) != nullptr; ++i) {
if (bp->m_in_use && bp->m_is_step) {
AMS_DMNT2_GDB_LOG_DEBUG("BreakPointManager::ClearStep %p 0x%lx (idx=%zu)\n", bp, bp->m_address, i);
bp->Clear(m_debug_process);
R_DISCARD(bp->Clear(m_debug_process));
}
}
}

View File

@@ -28,7 +28,7 @@ namespace ams::dmnt {
BreakPointBase *bp = nullptr;
for (size_t i = 0; (bp = static_cast<BreakPointBase *>(this->GetBreakPoint(i))) != nullptr; ++i) {
if (bp->m_in_use) {
bp->Clear(m_debug_process);
R_DISCARD(bp->Clear(m_debug_process));
}
}
}

View File

@@ -44,7 +44,7 @@ namespace ams::dmnt {
/* Get our process id. */
u64 pid_value = 0;
svc::GetProcessId(std::addressof(pid_value), m_debug_handle);
R_DISCARD(svc::GetProcessId(std::addressof(pid_value), m_debug_handle));
m_process_id = { pid_value };
@@ -88,8 +88,8 @@ namespace ams::dmnt {
m_create_process_info = d.info.create_process;
/* Cache our bools. */
m_is_64_bit = (m_create_process_info.flags & svc::CreateProcessFlag_Is64Bit);
m_is_64_bit_address_space = (m_create_process_info.flags & svc::CreateProcessFlag_AddressSpaceMask) == svc::CreateProcessFlag_AddressSpace64Bit;
m_is_64_bit = (m_create_process_info.flags & svc::CreateProcessParameterFlag_64Bit);
m_is_64_bit_address_space = (m_create_process_info.flags & svc::CreateProcessParameterFlag_AddressSpaceMask) == svc::CreateProcessParameterFlag_AddressSpace64Bit39;
}
break;
case svc::DebugEvent_CreateThread:
@@ -413,7 +413,7 @@ namespace ams::dmnt {
/* Get the instruction where we were. */
u32 insn = 0;
this->ReadMemory(std::addressof(insn), pc, sizeof(insn));
R_DISCARD(this->ReadMemory(std::addressof(insn), pc, sizeof(insn)));
/* Handle by architecture. */
bool is_call = false;
@@ -471,7 +471,7 @@ namespace ams::dmnt {
}
Result DebugProcess::ClearBreakPoint(uintptr_t address, size_t size) {
m_software_breakpoints.ClearBreakPoint(address, size);
R_DISCARD(m_software_breakpoints.ClearBreakPoint(address, size));
R_SUCCEED();
}
@@ -480,7 +480,7 @@ namespace ams::dmnt {
}
Result DebugProcess::ClearHardwareBreakPoint(uintptr_t address, size_t size) {
m_hardware_breakpoints.ClearBreakPoint(address, size);
R_DISCARD(m_hardware_breakpoints.ClearBreakPoint(address, size));
R_SUCCEED();
}
@@ -522,8 +522,8 @@ namespace ams::dmnt {
m_create_process_info = out->info.create_process;
/* Cache our bools. */
m_is_64_bit = (m_create_process_info.flags & svc::CreateProcessFlag_Is64Bit);
m_is_64_bit_address_space = (m_create_process_info.flags & svc::CreateProcessFlag_AddressSpaceMask) == svc::CreateProcessFlag_AddressSpace64Bit;
m_is_64_bit = (m_create_process_info.flags & svc::CreateProcessParameterFlag_64Bit);
m_is_64_bit_address_space = (m_create_process_info.flags & svc::CreateProcessParameterFlag_AddressSpaceMask) == svc::CreateProcessParameterFlag_AddressSpace64Bit39;
}
break;
case svc::DebugEvent_CreateThread:

View File

@@ -1030,7 +1030,7 @@ namespace ams::dmnt {
const auto reason = info.break_reason & ~svc::BreakReason_NotificationOnlyFlag;
if (reason == svc::BreakReason_PostLoadDll || reason == svc::BreakReason_PostUnloadDll) {
/* Re-collect the process's modules. */
m_debug_process.CollectModules();
R_DISCARD(m_debug_process.CollectModules());
}
if (m_debug_process.GetOverrideStatus().IsHbl() && reason == svc::BreakReason_PostLoadDll) {
@@ -1049,7 +1049,7 @@ namespace ams::dmnt {
}
/* This was just a notification, so we should continue. */
m_debug_process.Continue();
R_DISCARD(m_debug_process.Continue());
continue;
}
@@ -1064,7 +1064,7 @@ namespace ams::dmnt {
if (!is_svc_break) {
AMS_DMNT2_GDB_LOG_ERROR("UserBreak from non-SvcBreak (%08x)\n", insn);
m_debug_process.Continue();
R_DISCARD(m_debug_process.Continue());
continue;
}
}
@@ -1194,7 +1194,7 @@ namespace ams::dmnt {
AMS_DMNT2_GDB_LOG_DEBUG("CreateThread %lx\n", thread_id);
if (m_debug_process.IsValid()) {
m_debug_process.Continue();
R_DISCARD(m_debug_process.Continue());
} else {
AppendReplyFormat(reply_cur, reply_end, "W00");
}
@@ -1205,7 +1205,7 @@ namespace ams::dmnt {
AMS_DMNT2_GDB_LOG_DEBUG("ExitThread %lx\n", thread_id);
if (m_debug_process.IsValid()) {
m_debug_process.Continue();
R_DISCARD(m_debug_process.Continue());
} else {
AppendReplyFormat(reply_cur, reply_end, "W00");
}
@@ -1227,7 +1227,7 @@ namespace ams::dmnt {
break;
default:
AMS_DMNT2_GDB_LOG_DEBUG("Unhandled ProcessEvent %u %lx\n", static_cast<u32>(d.type), thread_id);
m_debug_process.Continue();
R_DISCARD(m_debug_process.Continue());
break;
}
@@ -1235,7 +1235,7 @@ namespace ams::dmnt {
bool do_break;
this->SendPacket(std::addressof(do_break), send_buffer);
if (do_break) {
m_debug_process.Break();
R_DISCARD(m_debug_process.Break());
}
}
}
@@ -1250,7 +1250,7 @@ namespace ams::dmnt {
/* Get the thread context. */
svc::ThreadContext thread_context = {};
m_debug_process.GetThreadContext(std::addressof(thread_context), thread_id, svc::ThreadContextFlag_General | svc::ThreadContextFlag_Control);
R_DISCARD(m_debug_process.GetThreadContext(std::addressof(thread_context), thread_id, svc::ThreadContextFlag_General | svc::ThreadContextFlag_Control));
/* Add important registers. */
/* TODO: aarch32 */
@@ -1280,7 +1280,7 @@ namespace ams::dmnt {
/* Add the thread core. */
{
u32 core = 0;
m_debug_process.GetThreadCurrentCore(std::addressof(core), thread_id);
R_DISCARD(m_debug_process.GetThreadCurrentCore(std::addressof(core), thread_id));
AppendReplyFormat(m_reply_cur, m_reply_end, ";core:%u;", core);
}
@@ -1305,7 +1305,7 @@ namespace ams::dmnt {
/* If we should, break the process. */
if (do_break) {
m_debug_process.Break();
R_DISCARD(m_debug_process.Break());
}
}
}
@@ -1721,7 +1721,7 @@ namespace ams::dmnt {
}
void GdbServerImpl::k() {
m_debug_process.Terminate();
R_DISCARD(m_debug_process.Terminate());
m_killed = true;
}
@@ -2369,7 +2369,7 @@ namespace ams::dmnt {
/* Get the thread core. */
u32 core = 0;
m_debug_process.GetThreadCurrentCore(std::addressof(core), thread_ids[i]);
R_DISCARD(m_debug_process.GetThreadCurrentCore(std::addressof(core), thread_ids[i]));
/* Get the thread name. */
char name[os::ThreadNameLengthMax + 1];

View File

@@ -197,7 +197,7 @@ namespace ams::dmnt {
g_last_bp_ctx_register = g_last_bp_register;
for (int i = g_last_bp_ctx_register; i >= static_cast<int>(svc::HardwareBreakPointRegisterName_I0); --i) {
const Result result = svc::SetHardwareBreakPoint(static_cast<svc::HardwareBreakPointRegisterName>(i), dbgbcr, svc::PseudoHandle::CurrentProcess);
svc::SetHardwareBreakPoint(static_cast<svc::HardwareBreakPointRegisterName>(i), 0, 0);
R_DISCARD(svc::SetHardwareBreakPoint(static_cast<svc::HardwareBreakPointRegisterName>(i), 0, 0));
if (R_FAILED(result)) {
if (!svc::ResultInvalidHandle::Includes(result)) {

View File

@@ -346,7 +346,7 @@ namespace ams::dmnt::cheat::impl {
Result ResumeCheatProcessUnsafe() {
m_broken_unsafe = false;
m_unsafe_break_event.Signal();
dmnt::cheat::impl::ContinueCheatProcess(this->GetCheatProcessHandle());
R_DISCARD(dmnt::cheat::impl::ContinueCheatProcess(this->GetCheatProcessHandle()));
R_SUCCEED();
}
@@ -682,7 +682,7 @@ namespace ams::dmnt::cheat::impl {
while (true) {
eventLoadRemote(std::addressof(hook), manager->HookToCreateApplicationProcess(), true);
if (R_SUCCEEDED(eventWait(std::addressof(hook), std::numeric_limits<u64>::max()))) {
manager->AttachToApplicationProcess(true);
R_DISCARD(manager->AttachToApplicationProcess(true));
}
eventClose(std::addressof(hook));
}
@@ -760,7 +760,7 @@ namespace ams::dmnt::cheat::impl {
const auto &value = entry.GetValue();
/* Use Write SVC directly, to avoid the usual frozen address update logic. */
svc::WriteDebugProcessMemory(manager->GetCheatProcessHandle(), reinterpret_cast<uintptr_t>(std::addressof(value.value)), address, value.width);
R_DISCARD(svc::WriteDebugProcessMemory(manager->GetCheatProcessHandle(), reinterpret_cast<uintptr_t>(std::addressof(value.value)), address, value.width));
}
}
}
@@ -1146,8 +1146,8 @@ namespace ams::dmnt::cheat::impl {
{
char path[fs::EntryNameLengthMax + 1];
util::SNPrintf(path, sizeof(path), "sdmc:/atmosphere/contents/%016lx/cheats/toggles.txt", program_id.value);
fs::DeleteFile(path);
fs::CreateFile(path, 0);
R_DISCARD(fs::DeleteFile(path));
R_DISCARD(fs::CreateFile(path, 0));
if (R_FAILED(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Write | fs::OpenMode_AllowAppend))) {
return;
}

View File

@@ -21,7 +21,7 @@ namespace ams::dmnt::cheat::impl {
void CheatVirtualMachine::DebugLog(u32 log_id, u64 value) {
/* Just unconditionally try to create the log folder. */
fs::EnsureDirectory("sdmc:/atmosphere/cheat_vm_logs");
R_DISCARD(fs::EnsureDirectory("sdmc:/atmosphere/cheat_vm_logs"));
fs::FileHandle log_file;
{
@@ -40,7 +40,7 @@ namespace ams::dmnt::cheat::impl {
char log_value[18];
util::SNPrintf(log_value, sizeof(log_value), "%016lx\n", value);
fs::WriteFile(log_file, log_offset, log_value, std::strlen(log_value), fs::WriteOption::Flush);
R_DISCARD(fs::WriteFile(log_file, log_offset, log_value, std::strlen(log_value), fs::WriteOption::Flush));
}
void CheatVirtualMachine::OpenDebugLogFile() {
@@ -796,7 +796,7 @@ namespace ams::dmnt::cheat::impl {
u64 kHeld = 0;
/* Get Keys held. */
hid::GetKeysHeld(std::addressof(kHeld));
R_DISCARD(hid::GetKeysHeld(std::addressof(kHeld)));
this->OpenDebugLogFile();
ON_SCOPE_EXIT { this->CloseDebugLogFile(); };
@@ -838,7 +838,7 @@ namespace ams::dmnt::cheat::impl {
case 2:
case 4:
case 8:
dmnt::cheat::impl::WriteCheatProcessMemoryUnsafe(dst_address, std::addressof(dst_value), cur_opcode.store_static.bit_width);
R_DISCARD(dmnt::cheat::impl::WriteCheatProcessMemoryUnsafe(dst_address, std::addressof(dst_value), cur_opcode.store_static.bit_width));
break;
}
}
@@ -853,7 +853,7 @@ namespace ams::dmnt::cheat::impl {
case 2:
case 4:
case 8:
dmnt::cheat::impl::ReadCheatProcessMemoryUnsafe(src_address, std::addressof(src_value), cur_opcode.begin_cond.bit_width);
R_DISCARD(dmnt::cheat::impl::ReadCheatProcessMemoryUnsafe(src_address, std::addressof(src_value), cur_opcode.begin_cond.bit_width));
break;
}
/* Check against condition. */
@@ -933,7 +933,7 @@ namespace ams::dmnt::cheat::impl {
case 2:
case 4:
case 8:
dmnt::cheat::impl::ReadCheatProcessMemoryUnsafe(src_address, std::addressof(m_registers[cur_opcode.ldr_memory.reg_index]), cur_opcode.ldr_memory.bit_width);
R_DISCARD(dmnt::cheat::impl::ReadCheatProcessMemoryUnsafe(src_address, std::addressof(m_registers[cur_opcode.ldr_memory.reg_index]), cur_opcode.ldr_memory.bit_width));
break;
}
}
@@ -952,7 +952,7 @@ namespace ams::dmnt::cheat::impl {
case 2:
case 4:
case 8:
dmnt::cheat::impl::WriteCheatProcessMemoryUnsafe(dst_address, std::addressof(dst_value), cur_opcode.str_static.bit_width);
R_DISCARD(dmnt::cheat::impl::WriteCheatProcessMemoryUnsafe(dst_address, std::addressof(dst_value), cur_opcode.str_static.bit_width));
break;
}
/* Increment register if relevant. */
@@ -1143,7 +1143,7 @@ namespace ams::dmnt::cheat::impl {
case 2:
case 4:
case 8:
dmnt::cheat::impl::WriteCheatProcessMemoryUnsafe(dst_address, std::addressof(dst_value), cur_opcode.str_register.bit_width);
R_DISCARD(dmnt::cheat::impl::WriteCheatProcessMemoryUnsafe(dst_address, std::addressof(dst_value), cur_opcode.str_register.bit_width));
break;
}
@@ -1214,7 +1214,7 @@ namespace ams::dmnt::cheat::impl {
case 2:
case 4:
case 8:
dmnt::cheat::impl::ReadCheatProcessMemoryUnsafe(cond_address, std::addressof(cond_value), cur_opcode.begin_reg_cond.bit_width);
R_DISCARD(dmnt::cheat::impl::ReadCheatProcessMemoryUnsafe(cond_address, std::addressof(cond_value), cur_opcode.begin_reg_cond.bit_width));
break;
}
}
@@ -1309,10 +1309,10 @@ namespace ams::dmnt::cheat::impl {
}
break;
case CheatVmOpcodeType_PauseProcess:
dmnt::cheat::impl::PauseCheatProcessUnsafe();
R_DISCARD(dmnt::cheat::impl::PauseCheatProcessUnsafe());
break;
case CheatVmOpcodeType_ResumeProcess:
dmnt::cheat::impl::ResumeCheatProcessUnsafe();
R_DISCARD(dmnt::cheat::impl::ResumeCheatProcessUnsafe());
break;
case CheatVmOpcodeType_DebugLog:
{
@@ -1356,7 +1356,7 @@ namespace ams::dmnt::cheat::impl {
case 2:
case 4:
case 8:
dmnt::cheat::impl::ReadCheatProcessMemoryUnsafe(val_address, std::addressof(log_value), cur_opcode.debug_log.bit_width);
R_DISCARD(dmnt::cheat::impl::ReadCheatProcessMemoryUnsafe(val_address, std::addressof(log_value), cur_opcode.debug_log.bit_width));
break;
}
}

View File

@@ -62,9 +62,9 @@ namespace ams {
{
u8 disable_report_cleanup = 0;
if (settings::fwdbg::GetSettingsItemValue(std::addressof(disable_report_cleanup), sizeof(disable_report_cleanup), "erpt", "disable_automatic_report_cleanup") == sizeof(disable_report_cleanup)) {
erpt::srv::SetEnabledAutomaticReportCleanup(disable_report_cleanup == 0);
R_DISCARD(erpt::srv::SetEnabledAutomaticReportCleanup(disable_report_cleanup == 0));
} else {
erpt::srv::SetEnabledAutomaticReportCleanup(true);
R_DISCARD(erpt::srv::SetEnabledAutomaticReportCleanup(true));
}
}
@@ -72,7 +72,7 @@ namespace ams {
R_ABORT_UNLESS(erpt::srv::Initialize(erpt::g_memory_heap, erpt::MemoryHeapSize));
/* Atmosphere always wants to redirect new reports to the SD card, to prevent them from being logged. */
erpt::srv::SetRedirectNewReportsToSdCard(true);
R_DISCARD(erpt::srv::SetRedirectNewReportsToSdCard(true));
/* Configure the serial number, OS version, product model, and region. */
{

View File

@@ -105,11 +105,11 @@ namespace ams::fatal::srv {
void CheckRepairStatus() {
if (IsInRepairWithoutVolHeld()) {
ThrowFatalForSelf(ResultInRepairWithoutVolHeld());
R_DISCARD(ThrowFatalForSelf(ResultInRepairWithoutVolHeld()));
}
if (IsInRepairWithoutTimeReviserCartridge()) {
ThrowFatalForSelf(ResultInRepairWithoutTimeReviserCartridge());
R_DISCARD(ThrowFatalForSelf(ResultInRepairWithoutTimeReviserCartridge()));
}
}

View File

@@ -24,7 +24,7 @@ namespace ams::fatal::srv {
/* Helpers. */
void TryEnsureReportDirectories() {
fs::EnsureDirectory("sdmc:/atmosphere/fatal_reports/dumps");
R_DISCARD(fs::EnsureDirectory("sdmc:/atmosphere/fatal_reports/dumps"));
}
bool TryGetCurrentTimestamp(u64 *out) {

View File

@@ -177,7 +177,7 @@ namespace ams {
/* Create the htc misc ipc thread. */
os::ThreadType htc_ipc_thread;
os::CreateThread(std::addressof(htc_ipc_thread), htc::HtcIpcThreadFunction, nullptr, htc::g_htc_ipc_thread_stack, sizeof(htc::g_htc_ipc_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(htc, HtcIpc));
R_DISCARD(os::CreateThread(std::addressof(htc_ipc_thread), htc::HtcIpcThreadFunction, nullptr, htc::g_htc_ipc_thread_stack, sizeof(htc::g_htc_ipc_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(htc, HtcIpc)));
os::SetThreadNamePointer(std::addressof(htc_ipc_thread), AMS_GET_SYSTEM_THREAD_NAME(htc, HtcIpc));
/* Initialize the htcfs server. */
@@ -186,7 +186,7 @@ namespace ams {
/* Create the htcfs ipc thread. */
os::ThreadType htcfs_ipc_thread;
os::CreateThread(std::addressof(htcfs_ipc_thread), htc::HtcfsIpcThreadFunction, nullptr, htc::g_htcfs_ipc_thread_stack, sizeof(htc::g_htcfs_ipc_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(htc, HtcfsIpc));
R_DISCARD(os::CreateThread(std::addressof(htcfs_ipc_thread), htc::HtcfsIpcThreadFunction, nullptr, htc::g_htcfs_ipc_thread_stack, sizeof(htc::g_htcfs_ipc_thread_stack), AMS_GET_SYSTEM_THREAD_PRIORITY(htc, HtcfsIpc)));
os::SetThreadNamePointer(std::addressof(htcfs_ipc_thread), AMS_GET_SYSTEM_THREAD_NAME(htc, HtcfsIpc));
/* Initialize the htcs server. */
@@ -196,7 +196,7 @@ namespace ams {
/* Create the htcs ipc threads. */
os::ThreadType htcs_ipc_threads[htc::NumHtcsIpcThreads];
for (size_t i = 0; i < htc::NumHtcsIpcThreads; ++i) {
os::CreateThread(std::addressof(htcs_ipc_threads[i]), htc::HtcsIpcThreadFunction, nullptr, htc::g_htcs_ipc_thread_stack[i], sizeof(htc::g_htcs_ipc_thread_stack[i]), AMS_GET_SYSTEM_THREAD_PRIORITY(htc, HtcsIpc));
R_DISCARD(os::CreateThread(std::addressof(htcs_ipc_threads[i]), htc::HtcsIpcThreadFunction, nullptr, htc::g_htcs_ipc_thread_stack[i], sizeof(htc::g_htcs_ipc_thread_stack[i]), AMS_GET_SYSTEM_THREAD_PRIORITY(htc, HtcsIpc)));
os::SetThreadNamePointer(std::addressof(htcs_ipc_threads[i]), AMS_GET_SYSTEM_THREAD_NAME(htc, HtcsIpc));
}

View File

@@ -33,7 +33,7 @@ namespace ams::ldr {
Entry m_argument_map[ArgumentMapCount];
public:
constexpr ArgumentStore() : m_argument_map{} {
this->Flush();
R_DISCARD(this->Flush());
}
public:
const Entry *Get(ncm::ProgramId program_id);

View File

@@ -102,4 +102,5 @@ constexpr inline const EmbeddedPatch Usb30ForceEnablePatches[] = {
{ ParseModuleId("766D0C2277207B40AD9B8DE309396D50CCE94885"), util::size(Usb30ForceEnablePatches_21_0_0), Usb30ForceEnablePatches_21_0_0 }, /* 21.0.0 */
{ ParseModuleId("B734339F2280170AF0200573F9B943242CEF8C15"), util::size(Usb30ForceEnablePatches_22_0_0), Usb30ForceEnablePatches_22_0_0 }, /* 22.0.0 - 22.1.0 */
{ ParseModuleId("AD8D36F2029822A4C498F055ADBDAA789EB913C6"), util::size(Usb30ForceEnablePatches_22_0_0), Usb30ForceEnablePatches_22_0_0 }, /* 22.5.0 */
{ ParseModuleId("760E48C572F8192C9BC6DC8FEB3D6213F0551505"), util::size(Usb30ForceEnablePatches_22_0_0), Usb30ForceEnablePatches_22_0_0 }, /* 23.0.0 */
};

View File

@@ -0,0 +1,61 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Breakdown of each patch in order: */
/* #1 - Patch the 0xDEEF000 size check branch to NOP. */
/* #2 - Change the root heap "Reserved" region allocation size from 0x43E000 to 0. */
/* #3 - Change the root heap "Scene" size from 0x4580000 to 0x4040000. */
/* #4 - Change the scene heap "ReservedTbd" region allocation size from 0x540000 to 0. */
/* #5 - Patch the linking of "ReservedTbd" to the parent heap with a NOP. */
/* #6 - Patch the initial memory block allocation size from 0xB400000 to 0xAC00000. */
/* #7 - Patch the initial memory block initialization size from 0xB400000 to 0xAC00000. */
constexpr inline const EmbeddedPatchEntry SystemWebMemoryPatches_23_0_0[] = {
{ 0x861DD4, "\x1F\x20\x03\xD5", 4 },
{ 0x861E80, "\x02\x00\x80\x52", 4 },
{ 0x861E6C, "\x82\x80\xA0\x52", 4 },
{ 0x8C1718, "\x02\x00\x80\x52", 4 },
{ 0x8C172C, "\x1F\x20\x03\xD5", 4 },
{ 0x861D44, "\x01\x58\xA1\x52", 4 },
{ 0x861D5C, "\x03\x58\xA1\x52", 4 },
};
constexpr inline const EmbeddedPatchEntry OpenWebMemoryPatches_23_0_0[] = {
{ 0x828DBC, "\x1F\x20\x03\xD5", 4 },
{ 0x828E68, "\x02\x00\x80\x52", 4 },
{ 0x828E54, "\x82\x80\xA0\x52", 4 },
{ 0x74C564, "\x02\x00\x80\x52", 4 },
{ 0x74C578, "\x1F\x20\x03\xD5", 4 },
{ 0x828D2C, "\x01\x58\xA1\x52", 4 },
{ 0x828D44, "\x03\x58\xA1\x52", 4 },
};
constexpr inline const EmbeddedPatchEntry OfflineWebMemoryPatches_23_0_0[] = {
{ 0x130698, "\x1F\x20\x03\xD5", 4 },
{ 0x130744, "\x02\x00\x80\x52", 4 },
{ 0x130730, "\x82\x80\xA0\x52", 4 },
{ 0x4D728, "\x02\x00\x80\x52", 4 },
{ 0x4D738, "\x1F\x20\x03\xD5", 4 },
{ 0x130614, "\x01\x58\xA1\x52", 4 },
{ 0x130624, "\x02\x58\xA1\x52", 4 },
};
constexpr inline const EmbeddedPatch WebMemoryPatches[] = {
{ ParseModuleId("97BF9C2D43EB002FB5B3578E7714F428104ED596"), util::size(SystemWebMemoryPatches_23_0_0), SystemWebMemoryPatches_23_0_0 }, /* 23.0.0 */
{ ParseModuleId("1470453424A9CDE689BE6DA86457ED1C79F5F403"), util::size(OpenWebMemoryPatches_23_0_0), OpenWebMemoryPatches_23_0_0 }, /* 23.0.0 */
{ ParseModuleId("86DAFFA68DA38660317018ADC7AD415BCCDDC583"), util::size(OfflineWebMemoryPatches_23_0_0), OfflineWebMemoryPatches_23_0_0 }, /* 23.0.0 */
};

View File

@@ -88,8 +88,8 @@ namespace ams::ldr {
R_UNLESS(npdm->magic == Npdm::Magic, ldr::ResultInvalidMeta());
/* Validate flags. */
constexpr u32 InvalidMetaFlagMask = 0x80000000;
R_UNLESS(!(npdm->flags & InvalidMetaFlagMask), ldr::ResultInvalidMeta());
constexpr u32 InvalidMetaFlag0Mask = 0x80000000;
R_UNLESS(!(npdm->flags0 & InvalidMetaFlag0Mask), ldr::ResultInvalidMeta());
/* Validate Acid extents. */
R_TRY(ValidateSubregion(sizeof(Npdm), size, npdm->acid_offset, npdm->acid_size, sizeof(Acid)));
@@ -262,14 +262,15 @@ namespace ams::ldr {
/* Perform address space override. */
if (status.HasOverrideAddressSpace()) {
/* Clear the existing address space. */
meta->npdm->flags &= ~Npdm::MetaFlag_AddressSpaceTypeMask;
meta->npdm->flags0 &= ~Npdm::MetaFlag0_ProcessAddressSpaceMask;
/* Set the new address space flag. */
switch (status.GetOverrideAddressSpaceFlags()) {
case cfg::impl::OverrideStatusFlag_AddressSpace32Bit: meta->npdm->flags |= (Npdm::AddressSpaceType_32Bit) << Npdm::MetaFlag_AddressSpaceTypeShift; break;
case cfg::impl::OverrideStatusFlag_AddressSpace64BitDeprecated: meta->npdm->flags |= (Npdm::AddressSpaceType_64BitDeprecated) << Npdm::MetaFlag_AddressSpaceTypeShift; break;
case cfg::impl::OverrideStatusFlag_AddressSpace32BitWithoutAlias: meta->npdm->flags |= (Npdm::AddressSpaceType_32BitWithoutAlias) << Npdm::MetaFlag_AddressSpaceTypeShift; break;
case cfg::impl::OverrideStatusFlag_AddressSpace64Bit: meta->npdm->flags |= (Npdm::AddressSpaceType_64Bit) << Npdm::MetaFlag_AddressSpaceTypeShift; break;
case cfg::impl::OverrideStatusFlag_AddressSpace32Bit: meta->npdm->flags0 |= (Npdm::ProcessAddressSpace_32Bit) << Npdm::MetaFlag0_ProcessAddressSpaceShift; break;
case cfg::impl::OverrideStatusFlag_AddressSpace64Bit36: meta->npdm->flags0 |= (Npdm::ProcessAddressSpace_64Bit36) << Npdm::MetaFlag0_ProcessAddressSpaceShift; break;
case cfg::impl::OverrideStatusFlag_AddressSpace32BitNoReserved: meta->npdm->flags0 |= (Npdm::ProcessAddressSpace_32BitNoReserved) << Npdm::MetaFlag0_ProcessAddressSpaceShift; break;
case cfg::impl::OverrideStatusFlag_AddressSpace64Bit39: meta->npdm->flags0 |= (Npdm::ProcessAddressSpace_64Bit39) << Npdm::MetaFlag0_ProcessAddressSpaceShift; break;
case cfg::impl::OverrideStatusFlag_AddressSpace64Bit42: meta->npdm->flags0 |= (Npdm::ProcessAddressSpace_64Bit42) << Npdm::MetaFlag0_ProcessAddressSpaceShift; break;
AMS_UNREACHABLE_DEFAULT_CASE();
}
}

View File

@@ -109,6 +109,7 @@ namespace ams::ldr {
#include "ldr_embedded_usb_patches.inc"
#include "ldr_embedded_am_patches.inc"
#include "ldr_embedded_web_patches.inc"
}
@@ -153,6 +154,18 @@ namespace ams::ldr {
}
}
}
/* TODO: Remove this if/when a cleaner solution is figured out. */
for (const auto &patch : WebMemoryPatches) {
if (std::memcmp(std::addressof(patch.module_id), std::addressof(module_id), sizeof(module_id)) == 0) {
for (size_t i = 0; i < patch.num_entries; ++i) {
const auto &entry = patch.entries[i];
if (entry.offset + entry.size <= mapped_size) {
std::memcpy(reinterpret_cast<void *>(mapped_nso + entry.offset), entry.data, entry.size);
}
}
}
}
}
}

View File

@@ -175,8 +175,8 @@ namespace ams::ldr {
return (MakeProgramInfoFlag(static_cast<const util::BitPack32 *>(meta->aci_kac), meta->aci->kac_size / sizeof(util::BitPack32)) & ProgramInfoFlag_ApplicationTypeMask) == ProgramInfoFlag_Application;
}
Npdm::AddressSpaceType GetAddressSpaceType(const Meta *meta) {
return static_cast<Npdm::AddressSpaceType>((meta->npdm->flags & Npdm::MetaFlag_AddressSpaceTypeMask) >> Npdm::MetaFlag_AddressSpaceTypeShift);
Npdm::ProcessAddressSpace GetProcessAddressSpace(const Meta *meta) {
return static_cast<Npdm::ProcessAddressSpace>((meta->npdm->flags0 & Npdm::MetaFlag0_ProcessAddressSpaceMask) >> Npdm::MetaFlag0_ProcessAddressSpaceShift);
}
Acid::PoolPartition GetPoolPartition(const Meta *meta) {
@@ -399,52 +399,56 @@ namespace ams::ldr {
R_SUCCEED();
}
Result GetCreateProcessFlags(u32 *out, const Meta *meta, const u32 ldr_flags) {
const u8 meta_flags = meta->npdm->flags;
Result GetCreateProcessParameterFlags(u32 *out, const Meta *meta, const u32 ldr_flags) {
const u8 meta_flags0 = meta->npdm->flags0;
const u8 meta_flags1 = meta->npdm->flags1;
u32 flags = 0;
/* Set Is64Bit. */
if (meta_flags & Npdm::MetaFlag_Is64Bit) {
flags |= svc::CreateProcessFlag_Is64Bit;
if (meta_flags0 & Npdm::MetaFlag0_Is64BitInstruction) {
flags |= svc::CreateProcessParameterFlag_64Bit;
}
/* Set AddressSpaceType. */
switch (GetAddressSpaceType(meta)) {
case Npdm::AddressSpaceType_32Bit:
flags |= svc::CreateProcessFlag_AddressSpace32Bit;
/* Set ProcessAddressSpace. */
switch (GetProcessAddressSpace(meta)) {
case Npdm::ProcessAddressSpace_32Bit:
flags |= svc::CreateProcessParameterFlag_AddressSpace32Bit;
break;
case Npdm::AddressSpaceType_64BitDeprecated:
flags |= svc::CreateProcessFlag_AddressSpace64BitDeprecated;
case Npdm::ProcessAddressSpace_64Bit36:
flags |= svc::CreateProcessParameterFlag_AddressSpace64Bit36;
break;
case Npdm::AddressSpaceType_32BitWithoutAlias:
flags |= svc::CreateProcessFlag_AddressSpace32BitWithoutAlias;
case Npdm::ProcessAddressSpace_32BitNoReserved:
flags |= svc::CreateProcessParameterFlag_AddressSpace32BitNoReserved;
break;
case Npdm::AddressSpaceType_64Bit:
flags |= svc::CreateProcessFlag_AddressSpace64Bit;
case Npdm::ProcessAddressSpace_64Bit39:
flags |= svc::CreateProcessParameterFlag_AddressSpace64Bit39;
break;
case Npdm::ProcessAddressSpace_64Bit42:
flags |= svc::CreateProcessParameterFlag_AddressSpace64Bit42;
break;
default:
R_THROW(ldr::ResultInvalidMeta());
}
/* Set Enable Debug. */
if (ldr_flags & CreateProcessFlag_EnableDebug) {
flags |= svc::CreateProcessFlag_EnableDebug;
if (ldr_flags & CreateProcessParameterFlag_EnableJitDebug) {
flags |= svc::CreateProcessParameterFlag_EnableJitDebug;
}
/* Set Enable ASLR. */
if (!(ldr_flags & CreateProcessFlag_DisableAslr)) {
flags |= svc::CreateProcessFlag_EnableAslr;
if (!(ldr_flags & CreateProcessParameterFlag_DisableAslr)) {
flags |= svc::CreateProcessParameterFlag_EnableAslr;
}
/* Set Is Application. */
if (IsApplication(meta)) {
flags |= svc::CreateProcessFlag_IsApplication;
flags |= svc::CreateProcessParameterFlag_IsApplication;
/* 7.0.0+: Set OptimizeMemoryAllocation if relevant. */
if (hos::GetVersion() >= hos::Version_7_0_0) {
if (meta_flags & Npdm::MetaFlag_OptimizeMemoryAllocation) {
flags |= svc::CreateProcessFlag_OptimizeMemoryAllocation;
if (meta_flags0 & Npdm::MetaFlag0_OptimizeMemoryAllocation) {
flags |= svc::CreateProcessParameterFlag_OptimizeMemoryAllocation;
}
}
}
@@ -456,19 +460,19 @@ namespace ams::ldr {
switch (GetPoolPartition(meta)) {
case Acid::PoolPartition_Application:
if (IsApplet(meta)) {
flags |= svc::CreateProcessFlag_PoolPartitionApplet;
flags |= svc::CreateProcessParameterFlag_PoolPartitionApplet;
} else {
flags |= svc::CreateProcessFlag_PoolPartitionApplication;
flags |= svc::CreateProcessParameterFlag_PoolPartitionApplication;
}
break;
case Acid::PoolPartition_Applet:
flags |= svc::CreateProcessFlag_PoolPartitionApplet;
flags |= svc::CreateProcessParameterFlag_PoolPartitionApplet;
break;
case Acid::PoolPartition_System:
flags |= svc::CreateProcessFlag_PoolPartitionSystem;
flags |= svc::CreateProcessParameterFlag_PoolPartitionSystem;
break;
case Acid::PoolPartition_SystemNonSecure:
flags |= svc::CreateProcessFlag_PoolPartitionSystemNonSecure;
flags |= svc::CreateProcessParameterFlag_PoolPartitionSystemNonSecure;
break;
default:
R_THROW(ldr::ResultInvalidMeta());
@@ -476,18 +480,23 @@ namespace ams::ldr {
} else if (hos::GetVersion() >= hos::Version_4_0_0) {
/* On 4.0.0+, the corresponding bit was simply "UseSecureMemory". */
if (meta->acid->flags & Acid::AcidFlag_DeprecatedUseSecureMemory) {
flags |= svc::CreateProcessFlag_DeprecatedUseSecureMemory;
flags |= svc::CreateProcessParameterFlag_DeprecatedUseSecureMemory;
}
}
/* 11.0.0+/meso Set Disable DAS merge. */
if (meta_flags & Npdm::MetaFlag_DisableDeviceAddressSpaceMerge) {
flags |= svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge;
/* 11.0.0+/meso Set Disable DAS Merge. */
if (meta_flags0 & Npdm::MetaFlag0_DisableDeviceAddressSpaceMerge) {
flags |= svc::CreateProcessParameterFlag_DisableDeviceAddressSpaceMerge;
}
/* 18.0.0+/meso Set Alias region extra size. */
if (meta_flags & Npdm::MetaFlag_EnableAliasRegionExtraSize) {
flags |= svc::CreateProcessFlag_EnableAliasRegionExtraSize;
/* 18.0.0+/meso Set Enable Address Sanitizer . */
if (meta_flags0 & Npdm::MetaFlag0_EnableAddressSanitizer) {
flags |= svc::CreateProcessParameterFlag_EnableAddressSanitizer;
}
/* 23.0.0+/meso Set Enable Shadow Stack. */
if (meta_flags1 & Npdm::MetaFlag1_EnableShadowStack) {
flags |= svc::CreateProcessParameterFlag_EnableShadowStack;
}
*out = flags;
@@ -505,7 +514,7 @@ namespace ams::ldr {
out->reslimit = resource_limit;
/* Set flags. */
R_TRY(GetCreateProcessFlags(std::addressof(out->flags), meta, flags));
R_TRY(GetCreateProcessParameterFlags(std::addressof(out->flags), meta, flags));
/* 3.0.0+ System Resource Size. */
if (hos::GetVersion() >= hos::Version_3_0_0) {
@@ -515,7 +524,7 @@ namespace ams::ldr {
/* Validate system resource usage. */
if (meta->npdm->system_resource_size) {
/* Process must be 64-bit. */
R_UNLESS((out->flags & svc::CreateProcessFlag_AddressSpace64Bit), ldr::ResultInvalidMeta());
R_UNLESS((out->flags & svc::CreateProcessParameterFlag_AddressSpace64Bit39), ldr::ResultInvalidMeta());
/* Process must be application or applet. */
R_UNLESS(IsApplication(meta) || IsApplet(meta), ldr::ResultInvalidMeta());
@@ -583,25 +592,29 @@ namespace ams::ldr {
uintptr_t aslr_start = 0;
size_t aslr_size = 0;
if (hos::GetVersion() >= hos::Version_2_0_0) {
switch (out_param->flags & svc::CreateProcessFlag_AddressSpaceMask) {
case svc::CreateProcessFlag_AddressSpace32Bit:
case svc::CreateProcessFlag_AddressSpace32BitWithoutAlias:
switch (out_param->flags & svc::CreateProcessParameterFlag_AddressSpaceMask) {
case svc::CreateProcessParameterFlag_AddressSpace32Bit:
case svc::CreateProcessParameterFlag_AddressSpace32BitNoReserved:
aslr_start = svc::AddressSmallMap32Start;
aslr_size = svc::AddressSmallMap32Size;
break;
case svc::CreateProcessFlag_AddressSpace64BitDeprecated:
case svc::CreateProcessParameterFlag_AddressSpace64Bit36:
aslr_start = svc::AddressSmallMap36Start;
aslr_size = svc::AddressSmallMap36Size;
break;
case svc::CreateProcessFlag_AddressSpace64Bit:
case svc::CreateProcessParameterFlag_AddressSpace64Bit39:
aslr_start = svc::AddressMap39Start;
aslr_size = svc::AddressMap39Size;
break;
case svc::CreateProcessParameterFlag_AddressSpace64Bit42:
aslr_start = svc::AddressMap42Start;
aslr_size = svc::AddressMap42Size;
break;
AMS_UNREACHABLE_DEFAULT_CASE();
}
} else {
/* On 1.0.0, only 2 address space types existed. */
if (out_param->flags & svc::CreateProcessFlag_AddressSpace64BitDeprecated) {
if (out_param->flags & svc::CreateProcessParameterFlag_AddressSpace64Bit36) {
aslr_start = svc::AddressSmallMap36Start;
aslr_size = svc::AddressSmallMap36Size;
} else {
@@ -614,7 +627,7 @@ namespace ams::ldr {
/* Set Create Process output. */
uintptr_t aslr_slide = 0;
size_t free_size = (aslr_size - total_size);
if (out_param->flags & svc::CreateProcessFlag_EnableAslr) {
if (out_param->flags & svc::CreateProcessParameterFlag_EnableAslr) {
aslr_slide = GenerateSecureRandom(free_size / os::MemoryBlockUnitSize) * os::MemoryBlockUnitSize;
}
@@ -799,7 +812,7 @@ namespace ams::ldr {
/* Set the output handle, and ensure that if we fail after this point we clean it up. */
out->process_handle = process_handle;
out->code_address = param.code_address;
ON_RESULT_FAILURE { svc::CloseHandle(process_handle); };
ON_RESULT_FAILURE { R_DISCARD(svc::CloseHandle(process_handle)); };
/* Load all auto load modules. */
R_RETURN(LoadAutoLoadModules(out, ctx, argument));
@@ -857,8 +870,8 @@ namespace ams::ldr {
os::ProcessId process_id = os::GetProcessId(info.process_handle);
/* Register new process. */
const auto as_type = GetAddressSpaceType(std::addressof(meta));
RoManager::GetInstance().RegisterProcess(pin_id, process_id, meta.aci->program_id, as_type == Npdm::AddressSpaceType_64Bit || as_type == Npdm::AddressSpaceType_64BitDeprecated);
const auto as_type = GetProcessAddressSpace(std::addressof(meta));
RoManager::GetInstance().RegisterProcess(pin_id, process_id, meta.aci->program_id, as_type == Npdm::ProcessAddressSpace_64Bit39 || as_type == Npdm::ProcessAddressSpace_64Bit36);
/* Register all NSOs. */
for (int i = 0; i < ctx.nso_count; i++) {
@@ -869,7 +882,7 @@ namespace ams::ldr {
/* If we're overriding for HBL, perform HTML document redirection. */
if (override_status.IsHbl()) {
/* Don't validate result, failure is okay. */
RedirectHtmlDocumentPathForHbl(loc);
R_DISCARD(RedirectHtmlDocumentPathForHbl(loc));
}
/* Clear the external code for the program. */

View File

@@ -89,8 +89,8 @@ namespace ams::pm::impl {
if (m_handle != os::InvalidNativeHandle) {
/* Unregister the process. */
fsprUnregisterProgram(m_process_id.value);
sm::manager::UnregisterProcess(m_process_id);
ldr::pm::UnpinProgram(m_pin_id);
R_DISCARD(sm::manager::UnregisterProcess(m_process_id));
R_DISCARD(ldr::pm::UnpinProgram(m_pin_id));
/* Close the process's handle. */
os::CloseNativeHandle(m_handle);

View File

@@ -86,14 +86,14 @@ namespace ams::pm::impl {
R_ABORT_UNLESS(os::CreateSystemEvent(std::addressof(g_hook_to_create_application_process_event), os::EventClearMode_AutoClear, true));
}
inline u32 GetLoaderCreateProcessFlags(u32 launch_flags) {
inline u32 GetLoaderCreateProcessParameterFlags(u32 launch_flags) {
u32 ldr_flags = 0;
if (ShouldSignalOnException(launch_flags) || (hos::GetVersion() >= hos::Version_2_0_0 && !ShouldStartSuspended(launch_flags))) {
ldr_flags |= ldr::CreateProcessFlag_EnableDebug;
ldr_flags |= ldr::CreateProcessParameterFlag_EnableJitDebug;
}
if (ShouldDisableAslr(launch_flags)) {
ldr_flags |= ldr::CreateProcessFlag_DisableAslr;
ldr_flags |= ldr::CreateProcessParameterFlag_DisableAslr;
}
return ldr_flags;
@@ -142,7 +142,7 @@ namespace ams::pm::impl {
R_TRY(ldr::pm::AtmospherePinProgram(std::addressof(pin_id), fixed_location, override_status));
/* If we fail after now, unpin. */
ON_RESULT_FAILURE { ldr::pm::UnpinProgram(pin_id); };
ON_RESULT_FAILURE { R_DISCARD(ldr::pm::UnpinProgram(pin_id)); };
/* Ensure we can talk to mitm services. */
{
@@ -166,7 +166,7 @@ namespace ams::pm::impl {
WaitResourceAvailable(std::addressof(program_info));
/* Actually create the process. */
R_TRY(ldr::pm::CreateProcess(std::addressof(process_handle), pin_id, GetLoaderCreateProcessFlags(flags), GetResourceLimitHandle(std::addressof(program_info)), attrs.program_attrs));
R_TRY(ldr::pm::CreateProcess(std::addressof(process_handle), pin_id, GetLoaderCreateProcessParameterFlags(flags), GetResourceLimitHandle(std::addressof(program_info)), attrs.program_attrs));
}
/* Get the process id. */
@@ -480,13 +480,16 @@ namespace ams::pm::impl {
Result NotifyBootFinished() {
AMS_FUNCTION_LOCAL_STATIC_CONSTINIT(bool, s_has_boot_finished, false);
if (!s_has_boot_finished) {
/* Set program verification disabled, if we should. */
/* NOTE: Nintendo does not check the result of this. */
if (spl::IsDisabledProgramVerification()) {
if (hos::GetVersion() >= hos::Version_10_0_0) {
ldr::pm::SetEnabledProgramVerification(false);
} else {
fsprSetEnabledProgramVerification(false);
/* 23.0.0+ removed this and all usage of spl from the pm sysmodule, both in normal and safe mode FIRM. */
if (hos::GetVersion() < hos::Version_23_0_0) {
/* Set program verification disabled, if we should. */
/* NOTE: Nintendo does not check the result of this. */
if (spl::IsDisabledProgramVerification()) {
if (hos::GetVersion() >= hos::Version_10_0_0) {
R_DISCARD(ldr::pm::SetEnabledProgramVerification(false));
} else {
fsprSetEnabledProgramVerification(false);
}
}
}

View File

@@ -94,7 +94,7 @@ namespace ams::pm::impl {
auto list = GetProcessList();
/* Reset the process's signal. */
svc::ResetSignal(process_info->GetHandle());
R_DISCARD(svc::ResetSignal(process_info->GetHandle()));
/* Update the process's state. */
const svc::ProcessState old_state = process_info->GetState();

View File

@@ -54,8 +54,8 @@ namespace ams {
void RegisterPrivilegedProcess(os::ProcessId process_id, ncm::ProgramId program_id) {
fsprUnregisterProgram(process_id.value);
fsprRegisterProgram(process_id.value, process_id.value, NcmStorageId_BuiltInSystem, PrivilegedFileAccessHeader, sizeof(PrivilegedFileAccessHeader), PrivilegedFileAccessControl, sizeof(PrivilegedFileAccessControl), 0);
sm::manager::UnregisterProcess(process_id);
sm::manager::RegisterProcess(process_id, program_id, cfg::OverrideStatus{}, PrivilegedServiceAccessControl, sizeof(PrivilegedServiceAccessControl), PrivilegedServiceAccessControl, sizeof(PrivilegedServiceAccessControl));
R_DISCARD(sm::manager::UnregisterProcess(process_id));
R_DISCARD(sm::manager::RegisterProcess(process_id, program_id, cfg::OverrideStatus{}, PrivilegedServiceAccessControl, sizeof(PrivilegedServiceAccessControl), PrivilegedServiceAccessControl, sizeof(PrivilegedServiceAccessControl)));
}
void RegisterPrivilegedProcesses() {

View File

@@ -47,7 +47,7 @@ namespace ams::ro::impl {
}
};
static_assert(sizeof(Sha256Hash) == sizeof(Sha256Hash::hash));
struct NroInfo {
u64 base_address;
u64 nro_heap_address;
@@ -55,8 +55,10 @@ namespace ams::ro::impl {
u64 bss_heap_address;
u64 bss_heap_size;
u64 code_size;
u64 ro_size; /* 23.0.0+ */
u64 rw_size;
ModuleId module_id;
bool is_compress; /* 23.0.0+ */
};
struct NrrInfo {
@@ -72,7 +74,17 @@ namespace ams::ro::impl {
u8 cached_signed_area[sizeof(NrrHeader) - NrrHeader::GetSignedAreaOffset()];
Sha256Hash signed_area_hash;
};
struct AdditionalNroHeaderInfo {
u32 signature;
u8 reserved_04[0xC];
u32 compressed_size;
u32 reserved_14;
u32 hash_size;
u32 hash_offset;
u8 reserved_20[0x40];
};
struct ProcessContext {
private:
bool m_nro_in_use[MaxNroInfos]{};
@@ -82,6 +94,8 @@ namespace ams::ro::impl {
os::NativeHandle m_process_handle = os::InvalidNativeHandle;
os::ProcessId m_process_id = os::InvalidProcessId;
bool m_in_use{};
u8 m_decompression_src_work_buffer[0x10000]{};
u8 m_decompression_dst_work_buffer[0x10000]{};
public:
constexpr ProcessContext() = default;
@@ -96,6 +110,9 @@ namespace ams::ro::impl {
m_process_handle = process_handle;
m_process_id = process_id;
m_in_use = true;
std::memset(m_decompression_src_work_buffer, 0, sizeof(m_decompression_src_work_buffer));
std::memset(m_decompression_dst_work_buffer, 0, sizeof(m_decompression_dst_work_buffer));
}
void Finalize() {
@@ -104,7 +121,7 @@ namespace ams::ro::impl {
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);
R_DISCARD(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);
@@ -117,8 +134,11 @@ namespace ams::ro::impl {
m_process_handle = os::InvalidNativeHandle;
m_process_id = os::InvalidProcessId;
m_in_use = false;
std::memset(m_decompression_src_work_buffer, 0, sizeof(m_decompression_src_work_buffer));
std::memset(m_decompression_dst_work_buffer, 0, sizeof(m_decompression_dst_work_buffer));
}
os::NativeHandle GetProcessHandle() const {
@@ -246,21 +266,12 @@ namespace ams::ro::impl {
R_THROW(ro::ResultNotAuthorized());
}
Result ValidateNro(ModuleId *out_module_id, u64 *out_rx_size, u64 *out_ro_size, u64 *out_rw_size, bool *out_aligned_header, u64 base_address, u64 expected_nro_size, u64 expected_bss_size) {
/* Map the NRO. */
void *mapped_memory = nullptr;
R_TRY_CATCH(os::MapProcessMemory(std::addressof(mapped_memory), m_process_handle, base_address, expected_nro_size, ro::impl::GenerateSecureRandom)) {
R_CONVERT(os::ResultOutOfAddressSpace, ro::ResultOutOfAddressSpace())
} R_END_TRY_CATCH;
/* When we're done, unmap the memory. */
ON_SCOPE_EXIT { os::UnmapProcessMemory(mapped_memory, m_process_handle, base_address, expected_nro_size); };
Result ValidateNro(NroHeader **out_header, AdditionalNroHeaderInfo *out_additional_header_info, void *out_additional_header_hash, u8 *mapped_memory, u64 expected_nro_size, u64 expected_bss_size) {
/* Validate header. */
const NroHeader *header = static_cast<const NroHeader *>(mapped_memory);
NroHeader *header = reinterpret_cast<NroHeader *>(mapped_memory);
R_UNLESS(header->IsMagicValid(), ro::ResultInvalidNro());
/* Read sizes from header. */
const u64 nro_size = header->GetSize();
const u64 text_ofs = header->GetTextOffset();
@@ -270,17 +281,28 @@ namespace ams::ro::impl {
const u64 rw_ofs = header->GetRwOffset();
const u64 rw_size = header->GetRwSize();
const u64 bss_size = header->GetBssSize();
/* Validate sizes meet expected. */
R_UNLESS(nro_size == expected_nro_size, ro::ResultInvalidNro());
R_UNLESS(bss_size == expected_bss_size, ro::ResultInvalidNro());
/* 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 sizes meet expected. */
R_UNLESS(nro_size == expected_nro_size, ro::ResultInvalidNro());
/* Account for compression when checking bss size. */
if (header->IsCompress()) {
R_UNLESS((bss_size - expected_nro_size + (rw_ofs + rw_size)) == expected_bss_size, ro::ResultInvalidBssSize());
} else {
/* 23.0.0+ uses the new error code here too. */
if (hos::GetVersion() >= hos::Version_23_0_0) {
R_UNLESS(bss_size == expected_bss_size, ro::ResultInvalidBssSize());
} else {
R_UNLESS(bss_size == expected_bss_size, ro::ResultInvalidNro());
}
}
/* Validate sections are in order. */
R_UNLESS(text_ofs <= ro_ofs, ro::ResultInvalidNro());
R_UNLESS(ro_ofs <= rw_ofs, ro::ResultInvalidNro());
@@ -289,24 +311,160 @@ namespace ams::ro::impl {
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());
/* Only check data section if not using compression. */
if (!header->IsCompress()) {
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());
/* Validate compression related fields. */
if (header->IsCompress()) {
const u64 additional_header_offset = header->GetAdditionalHeaderOffset();
/* Compression must have aligned header as well. */
R_UNLESS(header->IsAlignedHeader(), ro::ResultInvalidNro());
/* Validate additional header offset. */
R_UNLESS(additional_header_offset == 0x80, ro::ResultInvalidNro());
/* Validate additional header. */
AdditionalNroHeader *additional_header = reinterpret_cast<AdditionalNroHeader *>(mapped_memory + additional_header_offset);
R_UNLESS(additional_header->IsMagicValid(), ro::ResultInvalidNro());
/* Read sizes from header. */
const u64 hash_size = additional_header->GetHashSize();
const u64 hash_offset = additional_header->GetHashOffset();
const u64 compressed_size = additional_header->GetCompressedSize();
/* Validate additional header hash size and offset. */
R_UNLESS(hash_size == 0x20, ro::ResultInvalidNro());
R_UNLESS(hash_offset == 0xE0, ro::ResultInvalidNro());
/* Copy the additional header hash to output. */
std::memcpy(out_additional_header_hash, additional_header->GetHash(), hash_size);
/* Validate compressed size. */
R_UNLESS(rw_ofs + rw_size > nro_size, ro::ResultInvalidNro());
R_UNLESS(compressed_size >= 0x1000, ro::ResultInvalidNro());
R_UNLESS(util::AlignUp(compressed_size, os::MemoryPageSize) == expected_nro_size, ro::ResultInvalidNro());
/* Copy the additional header info to output. This is AdditionalNroHeader minus the hash. */
std::memcpy(reinterpret_cast<void*>(out_additional_header_info), additional_header, sizeof(AdditionalNroHeader) - hash_size);
} else {
/* Explicitly clear additional header hash and info. */
std::memset(out_additional_header_hash, 0, crypto::Sha256Generator::HashSize);
std::memset(reinterpret_cast<void*>(out_additional_header_info), 0, sizeof(AdditionalNroHeaderInfo));
}
/* Copy the header to output. */
*out_header = header;
R_SUCCEED();
}
Result DecompressNro(u8 *mapped_nro, u64 total_size, const NroHeader *nro_header, u32 compressed_size) {
/* Read sizes from header. */
const u64 rw_ofs = nro_header->GetRwOffset();
const u64 rw_size = nro_header->GetRwSize();
const u64 bss_size = nro_header->GetBssSize();
/* Divide the mapped NRO into regions devised for the decompression. */
u8 *nro_aligned_start = static_cast<u8 *>(mapped_nro + 0x1000);
const u8 *nro_expected_end = static_cast<const u8 *>(mapped_nro + total_size);
const u64 nro_src_buffer_size = compressed_size - 0x1000;
u8 *nro_src_buffer = static_cast<u8 *>(mapped_nro + total_size - nro_src_buffer_size);
const u64 nro_dst_buffer_size = total_size - 0xC00;
u8 *nro_dst_buffer = static_cast<u8 *>(mapped_nro + 0xC00);
/* Copy to source buffer. */
std::memmove(nro_src_buffer, nro_aligned_start, nro_src_buffer_size);
/* Decompress. */
u64 decompressed_size = 0;
R_UNLESS(util::DecompressLZ4Frame(std::addressof(decompressed_size), nro_dst_buffer, nro_dst_buffer_size, nro_src_buffer, nro_src_buffer_size, m_decompression_src_work_buffer, sizeof(m_decompression_src_work_buffer), m_decompression_dst_work_buffer, sizeof(m_decompression_dst_work_buffer)) == 0, ro::ResultInvalidNro());
/* Find the BSS. */
u8 *nro_expected_bss_start = static_cast<u8 *>(mapped_nro + rw_ofs + rw_size);
const u8 *nro_expected_bss_end = static_cast<const u8 *>(nro_expected_bss_start + bss_size);
const u8 *nro_bss_start = static_cast<const u8 *>(nro_expected_bss_start - 0x400);
const u8 *nro_decompressed_end = static_cast<const u8 *>(nro_dst_buffer + decompressed_size);
/* The decompressed data must end at the expected BSS start. */
if (nro_decompressed_end == nro_bss_start) {
/* Copy the decompressed data back to the mapped NRO memory. */
std::memmove(nro_aligned_start, nro_dst_buffer, decompressed_size);
std::memset(nro_dst_buffer, 0, 0x400);
/* Check the BSS ends where it's supposed, initialize it and then succeed. */
if (nro_expected_bss_end == nro_expected_end) {
std::memset(nro_expected_bss_start, 0, bss_size);
R_SUCCEED();
}
}
/* Clear the decompressed data buffer in case of error. */
std::memset(nro_dst_buffer, 0, nro_dst_buffer_size);
R_THROW(ro::ResultInvalidNro());
}
Result CheckAdditionalHeaderHash(const u8 *mapped_nro, const void *additional_nro_header_hash, size_t additional_nro_header_hash_size, u64 rw_ofs, u64 rw_size) {
/* Calculate hash. */
Sha256Hash nro_rw_hash;
crypto::GenerateSha256(std::addressof(nro_rw_hash), additional_nro_header_hash_size, mapped_nro + 0x1000, (rw_ofs + rw_size) - 0x1000);
/* Compare the hashes. */
const Sha256Hash *expected_hash = reinterpret_cast<const Sha256Hash *>(additional_nro_header_hash);
if (*expected_hash != nro_rw_hash) {
R_THROW(ro::ResultInvalidNro());
}
R_SUCCEED();
}
Result ParseNro(ModuleId *out_module_id, u64 *out_rx_size, u64 *out_ro_size, u64 *out_rw_size, u64 *out_bss_size, bool *out_aligned_header, bool *out_is_compress, u64 base_address, u64 total_size, u64 expected_nro_size, u64 expected_bss_size) {
/* Map the NRO. */
void *mapped_memory = nullptr;
R_TRY_CATCH(os::MapProcessMemory(std::addressof(mapped_memory), m_process_handle, base_address, total_size, ro::impl::GenerateSecureRandom)) {
R_CONVERT(os::ResultOutOfAddressSpace, ro::ResultOutOfAddressSpace())
} R_END_TRY_CATCH;
/* When we're done, unmap the memory. */
ON_SCOPE_EXIT { os::UnmapProcessMemory(mapped_memory, m_process_handle, base_address, total_size); };
/* ValidateNro */
NroHeader *nro_header = nullptr;
AdditionalNroHeaderInfo additional_nro_header_info;
u8 additional_nro_header_hash[crypto::Sha256Generator::HashSize];
R_TRY(this->ValidateNro(std::addressof(nro_header), std::addressof(additional_nro_header_info), std::addressof(additional_nro_header_hash), static_cast<u8 *>(mapped_memory), expected_nro_size, expected_bss_size));
/* DecompressNro */
if (nro_header->IsCompress()) {
R_TRY(this->DecompressNro(static_cast<u8 *>(mapped_memory), total_size, nro_header, additional_nro_header_info.compressed_size));
/* CheckAdditionalHeaderHash */
if (nro_header->GetAdditionalHeaderOffset() != 0) {
R_TRY(this->CheckAdditionalHeaderHash(static_cast<u8 *>(mapped_memory), std::addressof(additional_nro_header_hash), sizeof(additional_nro_header_hash), nro_header->GetRwOffset(), nro_header->GetRwSize()));
ON_RESULT_FAILURE { std::memset(static_cast<u8 *>(mapped_memory) + 0x1000, 0, total_size - 0x1000); };
}
}
/* Apply patches to NRO. */
LocateAndApplyIpsPatchesToModule(module_id, static_cast<u8 *>(mapped_memory), nro_size);
const ModuleId *module_id = nro_header->GetModuleId();
LocateAndApplyIpsPatchesToModule(module_id, static_cast<u8 *>(mapped_memory), nro_header->GetSize());
/* Copy to output. */
*out_module_id = *module_id;
*out_rx_size = text_size;
*out_ro_size = ro_size;
*out_rw_size = rw_size;
*out_aligned_header = header->IsAlignedHeader();
*out_rx_size = nro_header->GetTextSize();
*out_ro_size = nro_header->GetRoSize();
*out_rw_size = nro_header->GetRwSize();
*out_bss_size = nro_header->GetBssSize();
*out_aligned_header = nro_header->IsAlignedHeader();
*out_is_compress = nro_header->IsCompress();
R_SUCCEED();
}
@@ -547,26 +705,35 @@ namespace ams::ro::impl {
/* Check we have space for a new NRO. */
NroInfo *nro_info = nullptr;
R_TRY(context->GetFreeNroInfo(std::addressof(nro_info)));
/* Map the NRO. */
R_TRY(MapNro(std::addressof(nro_info->base_address), context->GetProcessHandle(), nro_address, nro_size, bss_address, bss_size));
/* Parse the NRO. */
u64 nro_rx_size = 0, nro_ro_size = 0, nro_rw_size = 0, nro_bss_size = 0;
bool nro_aligned_header = false;
bool nro_is_compress = false;
R_TRY(context->ParseNro(std::addressof(nro_info->module_id), std::addressof(nro_rx_size), std::addressof(nro_ro_size), std::addressof(nro_rw_size), std::addressof(nro_bss_size), std::addressof(nro_aligned_header), std::addressof(nro_is_compress), nro_info->base_address, total_size, nro_size, bss_size));
ON_RESULT_FAILURE { R_DISCARD(UnmapNro(context->GetProcessHandle(), nro_info->base_address, nro_address, nro_size, bss_address, bss_size)); };
/* Set NRO perms. */
R_TRY(SetNroPerms(context->GetProcessHandle(), nro_info->base_address, nro_rx_size, nro_ro_size, nro_rw_size + nro_bss_size, nro_aligned_header));
ON_RESULT_FAILURE_2 { if (!nro_is_compress) { R_DISCARD(UnmapNro(context->GetProcessHandle(), nro_info->base_address, nro_address, nro_size, bss_address, bss_size)); } };
context->SetNroInfoInUse(nro_info, true);
nro_info->nro_heap_address = nro_address;
nro_info->nro_heap_size = nro_size;
nro_info->bss_heap_address = bss_address;
nro_info->bss_heap_size = bss_size;
/* Map the NRO. */
R_TRY(MapNro(std::addressof(nro_info->base_address), context->GetProcessHandle(), nro_address, nro_size, bss_address, bss_size));
ON_RESULT_FAILURE { UnmapNro(context->GetProcessHandle(), nro_info->base_address, nro_address, nro_size, bss_address, bss_size); };
/* Validate the NRO (parsing region extents). */
u64 rx_size = 0, ro_size = 0, rw_size = 0;
bool aligned_header = false;
R_TRY(context->ValidateNro(std::addressof(nro_info->module_id), std::addressof(rx_size), std::addressof(ro_size), std::addressof(rw_size), std::addressof(aligned_header), nro_info->base_address, nro_size, bss_size));
/* Set NRO perms. */
R_TRY(SetNroPerms(context->GetProcessHandle(), nro_info->base_address, rx_size, ro_size, rw_size + bss_size, aligned_header));
context->SetNroInfoInUse(nro_info, true);
nro_info->code_size = rx_size + ro_size;
nro_info->rw_size = rw_size;
if (hos::GetVersion() >= hos::Version_23_0_0) {
nro_info->code_size = nro_rx_size;
nro_info->ro_size = nro_ro_size;
} else {
nro_info->code_size = nro_rx_size + nro_ro_size;
nro_info->ro_size = 0;
}
nro_info->rw_size = nro_rw_size;
nro_info->is_compress = nro_is_compress;
*out_address = nro_info->base_address;
R_SUCCEED();
}
@@ -582,6 +749,25 @@ namespace ams::ro::impl {
/* Check the NRO is loaded. */
NroInfo *nro_info = nullptr;
R_TRY(context->GetNroInfoByAddress(std::addressof(nro_info), nro_address));
/* Handle compression related mappings. */
if (nro_info->is_compress) {
const u64 code_address = nro_info->base_address + 0x1000;
const u64 code_size = nro_info->code_size - 0x1000;
/* Remove code region permissions. */
R_TRY(os::SetProcessMemoryPermission(context->GetProcessHandle(), code_address, code_size, os::MemoryPermission_None));
/* Map the code region. */
void *mapped_memory = nullptr;
R_TRY(os::MapProcessMemory(std::addressof(mapped_memory), context->GetProcessHandle(), code_address, code_size, ro::impl::GenerateSecureRandom));
/* Clear the memory. */
std::memset(mapped_memory, 0, code_size);
/* Unmap the code region. */
os::UnmapProcessMemory(mapped_memory, context->GetProcessHandle(), code_address, code_size);
}
/* Unmap. */
const NroInfo nro_backup = *nro_info;
@@ -590,7 +776,11 @@ namespace ams::ro::impl {
context->SetNroInfoInUse(nro_info, false);
std::memset(nro_info, 0, sizeof(*nro_info));
}
R_RETURN(UnmapNro(context->GetProcessHandle(), nro_backup.base_address, nro_backup.nro_heap_address, nro_backup.code_size + nro_backup.rw_size, nro_backup.bss_heap_address, nro_backup.bss_heap_size));
if (hos::GetVersion() >= hos::Version_23_0_0) {
R_RETURN(UnmapNro(context->GetProcessHandle(), nro_backup.base_address, nro_backup.nro_heap_address, nro_backup.nro_heap_size, nro_backup.bss_heap_address, nro_backup.bss_heap_size));
} else {
R_RETURN(UnmapNro(context->GetProcessHandle(), nro_backup.base_address, nro_backup.nro_heap_address, nro_backup.code_size + nro_backup.rw_size, nro_backup.bss_heap_address, nro_backup.bss_heap_size));
}
}
/* Debug service implementations. */

View File

@@ -60,7 +60,7 @@ namespace ams::ro {
R_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) {
Result RoService::RegisterModuleInfoWithUserProcessHandle(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle &&process_h) {
/* Validate the process. */
R_TRY(impl::ValidateProcess(m_context_id, client_pid.GetValue()));

View File

@@ -38,7 +38,7 @@ namespace ams::ro {
Result RegisterModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size);
Result UnregisterModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address);
Result RegisterProcessHandle(const sf::ClientProcessId &client_pid, sf::CopyHandle &&process_h);
Result RegisterProcessModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle &&process_h);
Result RegisterModuleInfoWithUserProcessHandle(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle &&process_h);
};
static_assert(ro::impl::IsIRoInterface<RoService>);

View File

@@ -147,7 +147,7 @@ namespace ams {
R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_Ssl, SslServiceName, SslMaxSessions));
R_ABORT_UNLESS(g_server_manager.RegisterServer(PortIndex_Es, EsServiceName, EsMaxSessions));
if (fw_ver >= hos::Version_5_0_0) {
g_server_manager.RegisterServer(PortIndex_Manu, ManuServiceName, ManuMaxSessions);
R_DISCARD(g_server_manager.RegisterServer(PortIndex_Manu, ManuServiceName, ManuMaxSessions));
}
}

View File

@@ -164,7 +164,7 @@ namespace ams::spl {
for (auto i = 0; i < impl::AesKeySlotCount; ++i) {
if (m_aes_keyslot_owners[i] == owner) {
m_aes_keyslot_owners[i] = nullptr;
impl::DeallocateAesKeySlot(impl::AesKeySlotMin + i);
R_DISCARD(impl::DeallocateAesKeySlot(impl::AesKeySlotMin + i));
}
}
}