diff --git a/stratosphere/dmnt/source/dmnt_debug_monitor.cpp b/stratosphere/dmnt/source/dmnt_debug_monitor.cpp deleted file mode 100644 index 2e287e6..0000000 --- a/stratosphere/dmnt/source/dmnt_debug_monitor.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2018 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 . - */ - -#include -#include "dmnt_debug_monitor.hpp" - -Result DebugMonitorService::BreakDebugProcess(Handle debug_hnd) { - /* Nintendo discards the output of this command, but we will return it. */ - return svcBreakDebugProcess(debug_hnd); -} - -Result DebugMonitorService::TerminateDebugProcess(Handle debug_hnd) { - /* Nintendo discards the output of this command, but we will return it. */ - return svcTerminateDebugProcess(debug_hnd); -} - -Result DebugMonitorService::CloseHandle(Handle debug_hnd) { - /* Nintendo discards the output of this command, but we will return it. */ - /* This command is, entertainingly, also pretty unsafe in general... */ - return svcCloseHandle(debug_hnd); -} - -Result DebugMonitorService::GetProcessId(Out out_pid, Handle hnd) { - /* Nintendo discards the output of this command, but we will return it. */ - return svcGetProcessId(out_pid.GetPointer(), hnd); -} - -Result DebugMonitorService::GetProcessHandle(Out out_hnd, u64 pid) { - Result rc = svcDebugActiveProcess(out_hnd.GetPointer(), pid); - if (rc == 0xF401) { - rc = 0x4B7; - } - return rc; -} - -Result DebugMonitorService::WaitSynchronization(Handle hnd, u64 ns) { - /* Nintendo discards the output of this command, but we will return it. */ - return svcWaitSynchronizationSingle(hnd, ns); -} diff --git a/stratosphere/dmnt/source/dmnt_debug_monitor.hpp b/stratosphere/dmnt/source/dmnt_debug_monitor.hpp deleted file mode 100644 index bd73d4a..0000000 --- a/stratosphere/dmnt/source/dmnt_debug_monitor.hpp +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (c) 2018 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 . - */ - -#pragma once -#include -#include - -enum DmntCmd { - DebugMonitor_Cmd_BreakDebugProcess = 0, - DebugMonitor_Cmd_TerminateDebugProcess = 1, - DebugMonitor_Cmd_CloseHandle = 2, - DebugMonitor_Cmd_LoadImage = 3, - DebugMonitor_Cmd_GetProcessId = 4, - DebugMonitor_Cmd_GetProcessHandle = 5, - DebugMonitor_Cmd_WaitSynchronization = 6, - DebugMonitor_Cmd_GetDebugEvent = 7, - DebugMonitor_Cmd_GetProcessModuleInfo = 8, - DebugMonitor_Cmd_GetProcessList = 9, - DebugMonitor_Cmd_GetThreadList = 10, - DebugMonitor_Cmd_GetDebugThreadContext = 11, - DebugMonitor_Cmd_ContinueDebugEvent = 12, - DebugMonitor_Cmd_ReadDebugProcessMemory = 13, - DebugMonitor_Cmd_WriteDebugProcessMemory = 14, - DebugMonitor_Cmd_SetDebugThreadContext = 15, - DebugMonitor_Cmd_GetDebugThreadParam = 16, - DebugMonitor_Cmd_InitializeThreadInfo = 17, - DebugMonitor_Cmd_SetHardwareBreakPoint = 18, - DebugMonitor_Cmd_QueryDebugProcessMemory = 19, - DebugMonitor_Cmd_GetProcessMemoryDetails = 20, - DebugMonitor_Cmd_AttachByProgramId = 21, - DebugMonitor_Cmd_AttachOnLaunch = 22, - DebugMonitor_Cmd_GetDebugMonitorProcessId = 23, - DebugMonitor_Cmd_GetJitDebugProcessList = 25, - DebugMonitor_Cmd_CreateCoreDump = 26, - DebugMonitor_Cmd_GetAllDebugThreadInfo = 27, - DebugMonitor_Cmd_TargetIO_FileOpen = 29, - DebugMonitor_Cmd_TargetIO_FileClose = 30, - DebugMonitor_Cmd_TargetIO_FileRead = 31, - DebugMonitor_Cmd_TargetIO_FileWrite = 32, - DebugMonitor_Cmd_TargetIO_FileSetAttributes = 33, - DebugMonitor_Cmd_TargetIO_FileGetInformation = 34, - DebugMonitor_Cmd_TargetIO_FileSetTime = 35, - DebugMonitor_Cmd_TargetIO_FileSetSize = 36, - DebugMonitor_Cmd_TargetIO_FileDelete = 37, - DebugMonitor_Cmd_TargetIO_FileMove = 38, - DebugMonitor_Cmd_TargetIO_DirectoryCreate = 39, - DebugMonitor_Cmd_TargetIO_DirectoryDelete = 40, - DebugMonitor_Cmd_TargetIO_DirectoryRename = 41, - DebugMonitor_Cmd_TargetIO_DirectoryGetCount = 42, - DebugMonitor_Cmd_TargetIO_DirectoryOpen = 43, - DebugMonitor_Cmd_TargetIO_DirectoryGetNext = 44, - DebugMonitor_Cmd_TargetIO_DirectoryClose = 45, - DebugMonitor_Cmd_TargetIO_GetFreeSpace = 46, - DebugMonitor_Cmd_TargetIO_GetVolumeInformation = 47, - DebugMonitor_Cmd_InitiateCoreDump = 48, - DebugMonitor_Cmd_ContinueCoreDump = 49, - DebugMonitor_Cmd_AddTTYToCoreDump = 50, - DebugMonitor_Cmd_AddImageToCoreDump = 51, - DebugMonitor_Cmd_CloseCoreDump = 52, - DebugMonitor_Cmd_CancelAttach = 53, -}; - -class DebugMonitorService final : public IServiceObject { - private: - Result BreakDebugProcess(Handle debug_hnd); - Result TerminateDebugProcess(Handle debug_hnd); - Result CloseHandle(Handle debug_hnd); - Result GetProcessId(Out out_pid, Handle hnd); - Result GetProcessHandle(Out out_hnd, u64 pid); - Result WaitSynchronization(Handle hnd, u64 ns); - public: - DEFINE_SERVICE_DISPATCH_TABLE { - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - MakeServiceCommandMeta(), - //MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - // MakeServiceCommandMeta(), - }; -}; diff --git a/stratosphere/dmnt/source/dmnt_main.cpp b/stratosphere/dmnt/source/dmnt_main.cpp index dbf9366..fc4917f 100644 --- a/stratosphere/dmnt/source/dmnt_main.cpp +++ b/stratosphere/dmnt/source/dmnt_main.cpp @@ -23,7 +23,7 @@ #include #include -#include "dmnt_debug_monitor.hpp" +#include "dmnt_service.hpp" extern "C" { extern u32 __start__; diff --git a/stratosphere/dmnt/source/dmnt_service.hpp b/stratosphere/dmnt/source/dmnt_service.hpp new file mode 100644 index 0000000..4959657 --- /dev/null +++ b/stratosphere/dmnt/source/dmnt_service.hpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2018 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 . + */ + +#pragma once +#include +#include + +enum DmntCmd { + DebugMonitor_Cmd_BreakDebugProcess = 0, + DebugMonitor_Cmd_TerminateDebugProcess = 1, + DebugMonitor_Cmd_CloseHandle = 2, + DebugMonitor_Cmd_LoadImage = 3, + DebugMonitor_Cmd_GetProcessId = 4, + DebugMonitor_Cmd_GetProcessHandle = 5, + DebugMonitor_Cmd_WaitSynchronization = 6, + DebugMonitor_Cmd_GetDebugEvent = 7, + DebugMonitor_Cmd_GetProcessModuleInfo = 8, + DebugMonitor_Cmd_GetProcessList = 9, + DebugMonitor_Cmd_GetThreadList = 10, + DebugMonitor_Cmd_GetDebugThreadContext = 11, + DebugMonitor_Cmd_ContinueDebugEvent = 12, + DebugMonitor_Cmd_ReadDebugProcessMemory = 13, + DebugMonitor_Cmd_WriteDebugProcessMemory = 14, + DebugMonitor_Cmd_SetDebugThreadContext = 15, + DebugMonitor_Cmd_GetDebugThreadParam = 16, + DebugMonitor_Cmd_InitializeThreadInfo = 17, + DebugMonitor_Cmd_SetHardwareBreakPoint = 18, + DebugMonitor_Cmd_QueryDebugProcessMemory = 19, + DebugMonitor_Cmd_GetProcessMemoryDetails = 20, + DebugMonitor_Cmd_AttachByProgramId = 21, + DebugMonitor_Cmd_AttachOnLaunch = 22, + DebugMonitor_Cmd_GetDebugMonitorProcessId = 23, + DebugMonitor_Cmd_GetJitDebugProcessList = 25, + DebugMonitor_Cmd_CreateCoreDump = 26, + DebugMonitor_Cmd_GetAllDebugThreadInfo = 27, + DebugMonitor_Cmd_TargetIO_FileOpen = 29, + DebugMonitor_Cmd_TargetIO_FileClose = 30, + DebugMonitor_Cmd_TargetIO_FileRead = 31, + DebugMonitor_Cmd_TargetIO_FileWrite = 32, + DebugMonitor_Cmd_TargetIO_FileSetAttributes = 33, + DebugMonitor_Cmd_TargetIO_FileGetInformation = 34, + DebugMonitor_Cmd_TargetIO_FileSetTime = 35, + DebugMonitor_Cmd_TargetIO_FileSetSize = 36, + DebugMonitor_Cmd_TargetIO_FileDelete = 37, + DebugMonitor_Cmd_TargetIO_FileMove = 38, + DebugMonitor_Cmd_TargetIO_DirectoryCreate = 39, + DebugMonitor_Cmd_TargetIO_DirectoryDelete = 40, + DebugMonitor_Cmd_TargetIO_DirectoryRename = 41, + DebugMonitor_Cmd_TargetIO_DirectoryGetCount = 42, + DebugMonitor_Cmd_TargetIO_DirectoryOpen = 43, + DebugMonitor_Cmd_TargetIO_DirectoryGetNext = 44, + DebugMonitor_Cmd_TargetIO_DirectoryClose = 45, + DebugMonitor_Cmd_TargetIO_GetFreeSpace = 46, + DebugMonitor_Cmd_TargetIO_GetVolumeInformation = 47, + DebugMonitor_Cmd_InitiateCoreDump = 48, + DebugMonitor_Cmd_ContinueCoreDump = 49, + DebugMonitor_Cmd_AddTTYToCoreDump = 50, + DebugMonitor_Cmd_AddImageToCoreDump = 51, + DebugMonitor_Cmd_CloseCoreDump = 52, + DebugMonitor_Cmd_CancelAttach = 53, +}; + +class DebugMonitorService final : public IServiceObject { + private: + Result BreakDebugProcess(Handle debug_hnd); + Result TerminateDebugProcess(Handle debug_hnd); + Result CloseHandle(Handle debug_hnd); + Result GetProcessId(Out out_pid, Handle hnd); + Result GetProcessHandle(Out out_hnd, u64 pid); + Result WaitSynchronization(Handle hnd, u64 ns); + + Result TargetIO_FileOpen(OutBuffer out_hnd, InBuffer path, int open_mode, u32 create_mode); + Result TargetIO_FileClose(InBuffer hnd); + Result TargetIO_FileRead(InBuffer hnd, OutBuffer out_data, Out out_read, u64 offset); + Result TargetIO_FileWrite(InBuffer hnd, InBuffer data, Out out_written, u64 offset); + public: + DEFINE_SERVICE_DISPATCH_TABLE { + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + //MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + // MakeServiceCommandMeta(), + }; +}; diff --git a/stratosphere/dmnt/source/dmnt_service_debug.cpp b/stratosphere/dmnt/source/dmnt_service_debug.cpp new file mode 100644 index 0000000..2c384a9 --- /dev/null +++ b/stratosphere/dmnt/source/dmnt_service_debug.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018 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 . + */ + +#include +#include "dmnt_service.hpp" + +Result DebugMonitorService::BreakDebugProcess(Handle debug_hnd) { + /* Nintendo discards the output of this command, but we will return it. */ + return svcBreakDebugProcess(debug_hnd); +} + +Result DebugMonitorService::TerminateDebugProcess(Handle debug_hnd) { + /* Nintendo discards the output of this command, but we will return it. */ + return svcTerminateDebugProcess(debug_hnd); +} + +Result DebugMonitorService::CloseHandle(Handle debug_hnd) { + /* Nintendo discards the output of this command, but we will return it. */ + /* This command is, entertainingly, also pretty unsafe in general... */ + return svcCloseHandle(debug_hnd); +} + +Result DebugMonitorService::GetProcessId(Out out_pid, Handle hnd) { + /* Nintendo discards the output of this command, but we will return it. */ + return svcGetProcessId(out_pid.GetPointer(), hnd); +} + +Result DebugMonitorService::GetProcessHandle(Out out_hnd, u64 pid) { + Result rc = svcDebugActiveProcess(out_hnd.GetPointer(), pid); + if (rc == 0xF401) { + rc = 0x4B7; + } + return rc; +} + +Result DebugMonitorService::WaitSynchronization(Handle hnd, u64 ns) { + /* Nintendo discards the output of this command, but we will return it. */ + return svcWaitSynchronizationSingle(hnd, ns); +} diff --git a/stratosphere/dmnt/source/dmnt_service_target_io.cpp b/stratosphere/dmnt/source/dmnt_service_target_io.cpp new file mode 100644 index 0000000..15f8e08 --- /dev/null +++ b/stratosphere/dmnt/source/dmnt_service_target_io.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2018 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 . + */ + +#include +#include +#include "dmnt_service.hpp" + +enum TIOCreateOption : u32 { + TIOCreateOption_CreateNew = 1, + TIOCreateOption_CreateAlways = 2, + TIOCreateOption_OpenExisting = 3, + TIOCreateOption_OpenAlways = 4, + TIOCreateOption_ResetSize = 5, +}; + +/* Nintendo uses actual pointers as file handles. We'll add a layer of indirection... */ +static bool g_sd_initialized = false; +static HosMutex g_sd_lock; +static FsFileSystem g_sd_fs; + +static HosMutex g_file_handle_lock; +static u64 g_cur_fd = 0; +static std::unordered_map g_file_handles; + +static Result EnsureSdInitialized() { + std::scoped_lock lk(g_sd_lock); + if (g_sd_initialized) { + return 0; + } + + Result rc = fsMountSdcard(&g_sd_fs); + if (R_SUCCEEDED(rc)) { + g_sd_initialized = true; + } + return rc; +} + +static u64 GetFileHandle(FsFile f) { + std::scoped_lock lk(g_file_handle_lock); + + u64 fd = g_cur_fd++; + g_file_handles[fd] = f; + return fd; +} + +static Result GetFileByHandle(FsFile *out, u64 handle) { + std::scoped_lock lk(g_file_handle_lock); + if (g_file_handles.find(handle) != g_file_handles.end()) { + *out = g_file_handles[handle]; + return 0; + } + return 0x2EE202; +} + +static Result CloseFileByHandle(u64 handle) { + std::scoped_lock lk(g_file_handle_lock); + if (g_file_handles.find(handle) != g_file_handles.end()) { + fsFileClose(&g_file_handles[handle]); + g_file_handles.erase(handle); + return 0; + } + return 0x2EE202; +} + +static void FixPath(char *dst, size_t dst_size, InBuffer &path) { + dst[dst_size - 1] = 0; + strncpy(dst, "/", dst_size - 1); + + const char *src = path.buffer; + size_t src_idx = 0; + size_t dst_idx = 1; + while (src_idx < path.num_elements && (src[src_idx] == '/' || src[src_idx] == '\\')) { + src_idx++; + } + + while (src_idx < path.num_elements && dst_idx < dst_size - 1 && src[src_idx] != 0) { + if (src[src_idx] == '\\') { + dst[dst_idx] = '/'; + } else { + dst[dst_idx] = src[src_idx]; + } + + src_idx++; + dst_idx++; + } + + if (dst_idx < dst_size) { + dst[dst_idx] = 0; + } +} + +Result DebugMonitorService::TargetIO_FileOpen(OutBuffer out_hnd, InBuffer path, int open_mode, u32 create_mode) { + if (out_hnd.num_elements != 1) { + return 0xF601; + } + + Result rc = EnsureSdInitialized(); + if (R_FAILED(rc)) { + return rc; + } + + char fs_path[FS_MAX_PATH]; + + FixPath(fs_path, sizeof(fs_path), path); + + if (create_mode == TIOCreateOption_CreateAlways) { + fsFsDeleteFile(&g_sd_fs, fs_path); + rc = fsFsCreateFile(&g_sd_fs, fs_path, 0, 0); + } else if (create_mode == TIOCreateOption_CreateNew) { + rc = fsFsCreateFile(&g_sd_fs, fs_path, 0, 0); + } + + if (R_FAILED(rc)) { + return rc; + } + + FsFile f; + rc = fsFsOpenFile(&g_sd_fs, fs_path, open_mode, &f); + if (R_FAILED(rc)) { + if (create_mode == TIOCreateOption_OpenAlways) { + fsFsCreateFile(&g_sd_fs, fs_path, 0, 0); + rc = fsFsOpenFile(&g_sd_fs, fs_path, open_mode, &f); + } + } + + if (R_SUCCEEDED(rc)) { + if (create_mode == TIOCreateOption_ResetSize) { + rc = fsFileSetSize(&f, 0); + } + if (R_SUCCEEDED(rc)) { + out_hnd[0] = GetFileHandle(f); + } else { + fsFileClose(&f); + } + } + + return rc; +} + +Result DebugMonitorService::TargetIO_FileClose(InBuffer hnd) { + if (hnd.num_elements != 1) { + return 0xF601; + } + + return CloseFileByHandle(hnd[0]); +} + +Result DebugMonitorService::TargetIO_FileRead(InBuffer hnd, OutBuffer out_data, Out out_read, u64 offset) { + if (hnd.num_elements != 1) { + return 0xF601; + } + + FsFile f; + Result rc = GetFileByHandle(&f, hnd[0]); + if (R_FAILED(rc)) { + return rc; + } + + size_t read = 0; + rc = fsFileRead(&f, offset, out_data.buffer, out_data.num_elements, &read); + out_read.SetValue(static_cast(read)); + return rc; +} + +Result DebugMonitorService::TargetIO_FileWrite(InBuffer hnd, InBuffer data, Out out_written, u64 offset) { + if (hnd.num_elements != 1) { + return 0xF601; + } + + FsFile f; + Result rc = GetFileByHandle(&f, hnd[0]); + if (R_FAILED(rc)) { + return rc; + } + + rc = fsFileWrite(&f, offset, data.buffer, data.num_elements); + if (R_SUCCEEDED(rc)) { + out_written.SetValue(data.num_elements); + } + + return rc; +}