From dacacfa40354aa76f3f1951ae664b1c47cdb80ff Mon Sep 17 00:00:00 2001 From: TuxSH Date: Sun, 10 Mar 2019 22:18:28 +0100 Subject: [PATCH] Implement fs:REG --- libctru/include/3ds.h | 1 + libctru/include/3ds/services/fsreg.h | 63 +++++++++++++ libctru/source/services/fsreg.c | 127 +++++++++++++++++++++++++++ 3 files changed, 191 insertions(+) create mode 100644 libctru/include/3ds/services/fsreg.h create mode 100644 libctru/source/services/fsreg.c diff --git a/libctru/include/3ds.h b/libctru/include/3ds.h index 86c92fe..571e3e4 100644 --- a/libctru/include/3ds.h +++ b/libctru/include/3ds.h @@ -40,6 +40,7 @@ extern "C" { #include <3ds/services/csnd.h> #include <3ds/services/dsp.h> #include <3ds/services/fs.h> +#include <3ds/services/fsreg.h> #include <3ds/services/frd.h> #include <3ds/services/gspgpu.h> #include <3ds/services/gsplcd.h> diff --git a/libctru/include/3ds/services/fsreg.h b/libctru/include/3ds/services/fsreg.h new file mode 100644 index 0000000..5e81d80 --- /dev/null +++ b/libctru/include/3ds/services/fsreg.h @@ -0,0 +1,63 @@ +/** + * @file fsReg.h + * @brief Filesystem registry service + */ + +#pragma once + +#include <3ds/exheader.h> +#include <3ds/services/fs.h> + +/// Initializes fs:REG. +Result fsRegInit(void); + +/// Exits fs:REG. +void fsRegExit(void); + +/** + * @brief Gets the current fs:REG session handle. + * @return The current fs:REG session handle. + */ +Handle *fsRegGetSessionHandle(void); + +/** + * @brief Registers a program's storage information. + * @param pid The Process ID of the program. + * @param programHandle The program handle. + * @param programInfo Information about the program. + * @param storageInfo Storage information to register. + */ +Result FSREG_Register(u32 pid, u64 programHandle, const FS_ProgramInfo *programInfo, const ExHeader_Arm11StorageInfo *storageInfo); + +/** + * @brief Unregisters a program's storage information. + * @param pid The Process ID of the program. + */ +Result FSREG_Unregister(u32 pid); + +/** + * @brief Retrives the exheader information set(s) (SCI+ACI) about a program. + * @param exheaderInfos[out] Pointer to the output exheader information set(s). + * @param maxNumEntries The maximum number of entries. + * @param programHandle The program handle. + */ +Result FSREG_GetProgramInfo(ExHeader_Info *exheaderInfos, u32 maxNumEntries, u64 programHandle); + +/** + * @brief Loads a program. + * @param programHandle[out] Pointer to the output the program handle to. + * @param programInfo Information about the program to load. + */ +Result FSREG_LoadProgram(u64 *programHandle, const FS_ProgramInfo *programInfo); + +/** + * @brief Unloads a program. + * @param programHandle The program handle. + */ +Result FSREG_UnloadProgram(u64 programHandle); + +/** + * @brief Checks if a program has been loaded by fs:REG. + * @param programHandle The program handle. + */ +Result FSREG_CheckHostLoadId(u64 programHandle); diff --git a/libctru/source/services/fsreg.c b/libctru/source/services/fsreg.c new file mode 100644 index 0000000..987a18c --- /dev/null +++ b/libctru/source/services/fsreg.c @@ -0,0 +1,127 @@ +#include +#include <3ds/result.h> +#include <3ds/synchronization.h> +#include <3ds/result.h> +#include <3ds/services/fsreg.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/ipc.h> + +static Handle fsRegHandle; +static int fsRegRefCount; + +Result fsRegInit(void) +{ + Result ret = 0; + + if (AtomicPostIncrement(&fsRegRefCount)) return 0; + + ret = srvGetServiceHandle(&fsRegHandle, "fs:REG"); + + if (R_FAILED(ret)) AtomicDecrement(&fsRegRefCount); + return ret; +} + +void fsRegExit(void) +{ + if (AtomicDecrement(&fsRegRefCount)) return; + svcCloseHandle(fsRegHandle); +} + +Handle *fsRegGetSessionHandle(void) +{ + return &fsRegHandle; +} + +Result FSREG_Register(u32 pid, u64 programHandle, const FS_ProgramInfo *programInfo, const ExHeader_Arm11StorageInfo *storageInfo) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x401, 0xF, 0); // 0x40103C0 + cmdbuf[1] = pid; + cmdbuf[2] = (u32)programHandle; + cmdbuf[3] = (u32)(programHandle >> 32); + memcpy(&cmdbuf[4], programInfo, sizeof(FS_ProgramInfo)); + memcpy(&cmdbuf[8], storageInfo, sizeof(ExHeader_Arm11StorageInfo)); + + Result ret = 0; + if(R_FAILED(ret = svcSendSyncRequest(fsRegHandle))) return ret; + + return cmdbuf[1]; +} + +Result FSREG_Unregister(u32 pid) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x402, 1, 0); // 0x4020040 + cmdbuf[1] = pid; + + Result ret = 0; + if(R_FAILED(ret = svcSendSyncRequest(fsRegHandle))) return ret; + + return cmdbuf[1]; +} + +Result FSREG_GetProgramInfo(ExHeader_Info *exheaderInfos, u32 maxNumEntries, u64 programHandle) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + u32 *staticbufs = getThreadStaticBuffers(); + + cmdbuf[0] = IPC_MakeHeader(0x403, 3, 0); // 0x40300C0 + cmdbuf[1] = maxNumEntries; + cmdbuf[2] = (u32)programHandle; + cmdbuf[3] = (u32)(programHandle >> 32); + + u32 staticbufscpy[2] = {staticbufs[0], staticbufs[1]}; + staticbufs[0] = IPC_Desc_StaticBuffer(maxNumEntries * sizeof(ExHeader_Info), 0); + staticbufs[1] = (u32)exheaderInfos; + + Result ret = svcSendSyncRequest(fsRegHandle); + + staticbufs[0] = staticbufscpy[0]; + staticbufs[1] = staticbufscpy[1]; + return R_FAILED(ret) ? ret : cmdbuf[1]; +} + +Result FSREG_LoadProgram(u64 *programHandle, const FS_ProgramInfo *programInfo) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x404, 4, 0); // 0x4040100 + memcpy(&cmdbuf[1], programInfo, sizeof(FS_ProgramInfo)); + + Result ret = 0; + if(R_FAILED(ret = svcSendSyncRequest(fsRegHandle))) return ret; + *programHandle = ((u64)cmdbuf[3] << 32) | cmdbuf[2]; + + return cmdbuf[1]; +} + +Result FSREG_UnloadProgram(u64 programHandle) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x405, 2, 0); // 0x4050080 + cmdbuf[1] = (u32)programHandle; + cmdbuf[2] = (u32)(programHandle >> 32); + + Result ret = 0; + if(R_FAILED(ret = svcSendSyncRequest(fsRegHandle))) return ret; + + return cmdbuf[1]; +} + +Result FSREG_CheckHostLoadId(u64 programHandle) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x406, 2, 0); // 0x4060080 + cmdbuf[1] = (u32)programHandle; + cmdbuf[2] = (u32)(programHandle >> 32); + + Result ret = 0; + if(R_FAILED(ret = svcSendSyncRequest(fsRegHandle))) return ret; + + return cmdbuf[1]; +}