From: chaoskagami Date: Fri, 14 Oct 2016 04:59:09 +0000 (-0400) Subject: Add fs:REG implementation based on @yifanlu's in loader X-Git-Url: https://chaos.moe/g/?a=commitdiff_plain;h=adbdf3584bde6ac7cfaa19eba1a362a800365a97;p=corbenik%2Fctrulib.git Add fs:REG implementation based on @yifanlu's in loader --- diff --git a/libctru/include/3ds.h b/libctru/include/3ds.h index 7b8ed57..09268b5 100644 --- a/libctru/include/3ds.h +++ b/libctru/include/3ds.h @@ -37,6 +37,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/gspgpu.h> #include <3ds/services/gsplcd.h> #include <3ds/services/hid.h> diff --git a/libctru/include/3ds/exheader.h b/libctru/include/3ds/exheader.h new file mode 100644 index 0000000..07f2f72 --- /dev/null +++ b/libctru/include/3ds/exheader.h @@ -0,0 +1,115 @@ +/** + * @file exheader.h + * @brief Structures describing extended headers as in use by the system + */ +#pragma once + +#include <3ds/types.h> + +typedef struct +{ + u32 text_addr; + u32 text_size; + u32 ro_addr; + u32 ro_size; + u32 data_addr; + u32 data_size; + u32 total_size; +} PACKED EXHEADER_prog_addrs; + +typedef struct +{ + u8 reserved[5]; + u8 flag; // Maybe a feature - Bits 2-7 are unused. We could allow uh, custom flags here. Like zlib compression on code rather than lzss. + u8 remasterversion[2]; +} PACKED EXHEADER_systeminfoflags; + +typedef struct +{ + u32 address; + u32 nummaxpages; + u32 codesize; +} PACKED EXHEADER_codesegmentinfo; + +typedef struct +{ + u8 name[8]; + EXHEADER_systeminfoflags flags; + EXHEADER_codesegmentinfo text; + u8 stacksize[4]; + EXHEADER_codesegmentinfo ro; + u8 reserved[4]; + EXHEADER_codesegmentinfo data; + u32 bsssize; +} PACKED EXHEADER_codesetinfo; + +typedef struct +{ + u64 programid[0x30]; +} PACKED EXHEADER_dependencylist; + +typedef struct +{ + u8 savedatasize[4]; + u8 reserved[4]; + u8 jumpid[8]; + u8 reserved2[0x30]; +} PACKED EXHEADER_systeminfo; + +typedef struct +{ + u8 extsavedataid[8]; + u8 systemsavedataid[8]; + u8 reserved[8]; + u8 accessinfo[7]; + u8 otherattributes; +} PACKED EXHEADER_storageinfo; + +// New3DS speed is flags[1]:1 + +typedef struct +{ + u64 programid; + u8 coreVersion[4]; // Kernel version required for this. + u8 flag2; + u8 flag1; + u8 flag0; // CPU speed settings. + u8 priority; + u16 resourcelimitdescriptor[0x10]; + EXHEADER_storageinfo storageinfo; + u64 serviceaccesscontrol[0x20]; + u8 reserved[0x1f]; + u8 resourcelimitcategory; +} PACKED EXHEADER_arm11systemlocalcaps; + +typedef struct +{ + u32 descriptors[28]; + u8 reserved[0x10]; +} PACKED EXHEADER_arm11kernelcapabilities; + +typedef struct +{ + u8 descriptors[15]; + u8 descversion; +} PACKED EXHEADER_arm9accesscontrol; + +typedef struct +{ + u8 signature[0x100]; + u8 ncchpubkeymodulus[0x100]; + EXHEADER_arm11systemlocalcaps arm11systemlocalcaps; + EXHEADER_arm11kernelcapabilities arm11kernelcaps; + EXHEADER_arm9accesscontrol arm9accesscontrol; +} PACKED EXHEADER_accessdesc; + +typedef struct +{ + EXHEADER_codesetinfo codesetinfo; + EXHEADER_dependencylist deplist; + EXHEADER_systeminfo systeminfo; + EXHEADER_arm11systemlocalcaps arm11systemlocalcaps; + EXHEADER_arm11kernelcapabilities arm11kernelcaps; + EXHEADER_arm9accesscontrol arm9accesscontrol; + EXHEADER_accessdesc accessdesc; +} PACKED EXHEADER_header; diff --git a/libctru/include/3ds/services/fsreg.h b/libctru/include/3ds/services/fsreg.h new file mode 100644 index 0000000..614f0fd --- /dev/null +++ b/libctru/include/3ds/services/fsreg.h @@ -0,0 +1,57 @@ +/** + * @file fsreg.h + * @brief Program Registry Service + */ +#pragma once + +#include <3ds/types.h> +#include <3ds/services/fs.h> +#include <3ds/exheader.h> + +/// Initialize the fs:REG service. Bear in mind a limited number of handles exist for this. +Result fsregInit(void); + +/// Close and deinitialize fs:REG +void fsregExit(void); + +/** + * @brief Checks if a program handle is valid? + * @param prog_handle Program handle to check validity of + */ +Result FSREG_CheckHostLoadId(u64 prog_handle); + +/** + * @brief Registers a loading program. + * @param prog_handle Program handle + * @param title Program information + */ +Result FSREG_LoadProgram(u64 *prog_handle, FS_ProgramInfo *title); + +/** + * @brief Retrieves the SystemControlInfo and AccessControlInfo for a program. + * @param exheader Exheader struct to place output in + * @param entry_count How many entries to get info for (?) + * @param prog_handle Program handle to get info for + */ +Result FSREG_GetProgramInfo(EXHEADER_header *exheader, u32 entry_count, u64 prog_handle); + +/** + * @brief Unregisters a currently registered program. + * @param prog_handle Handle of program to unregister. + */ +Result FSREG_UnloadProgram(u64 prog_handle); + +/** + * @brief Unregister a program previously registered. + * @param pid Process ID to unregister. + */ +Result FSREG_Unregister(u32 pid); + +/** + * @brief Register a program. + * @param pid Process ID to register. + * @param prog_handle Handle of program to register + * @param info Program info + * @param storageinfo Storage access flags + */ +Result FSREG_Register(u32 pid, u64 prog_handle, FS_ProgramInfo *info, void *storageinfo); diff --git a/libctru/source/services/fsreg.c b/libctru/source/services/fsreg.c new file mode 100644 index 0000000..5390213 --- /dev/null +++ b/libctru/source/services/fsreg.c @@ -0,0 +1,126 @@ +#include <3ds.h> +#include +// #include "srvsys.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); +} + +Result FSREG_CheckHostLoadId(u64 prog_handle) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x406, 2, 0); // 0x4060080 + cmdbuf[1] = (u32)(prog_handle); + cmdbuf[2] = (u32)(prog_handle >> 32); + + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(fsregHandle))) + return ret; + + return cmdbuf[1]; +} + +Result FSREG_LoadProgram(u64 *prog_handle, FS_ProgramInfo *title) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x404, 4, 0); // 0x4040100 + memcpy(&cmdbuf[1], &title->programId, sizeof(u64)); + *(u8 *)&cmdbuf[3] = title->mediaType; + memcpy(((u8 *)&cmdbuf[3]) + 1, &title->padding, 7); + + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(fsregHandle))) + return ret; + *prog_handle = *(u64 *)&cmdbuf[2]; + + return cmdbuf[1]; +} + +Result FSREG_GetProgramInfo(EXHEADER_header *exheader, u32 entry_count, u64 prog_handle) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x403, 3, 0); // 0x40300C0 + cmdbuf[1] = entry_count; + *(u64 *)&cmdbuf[2] = prog_handle; + cmdbuf[64] = ((entry_count << 10) << 14) | 2; + cmdbuf[65] = (u32)exheader; + + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(fsregHandle))) + return ret; + + return cmdbuf[1]; +} + +Result FSREG_UnloadProgram(u64 prog_handle) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x405, 2, 0); // 0x4050080 + cmdbuf[1] = (u32)(prog_handle); + cmdbuf[2] = (u32)(prog_handle >> 32); + + 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_Register(u32 pid, u64 prog_handle, FS_ProgramInfo *info, void *storageinfo) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x401, 0xf, 0); // 0x40103C0 + cmdbuf[1] = pid; + *(u64 *)&cmdbuf[2] = prog_handle; + memcpy(&cmdbuf[4], &info->programId, sizeof(u64)); + *(u8 *)&cmdbuf[6] = info->mediaType; + memcpy(((u8 *)&cmdbuf[6]) + 1, &info->padding, 7); + memcpy((u8 *)&cmdbuf[8], storageinfo, 32); + + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(fsregHandle))) + return ret; + + return cmdbuf[1]; +}