]> Chaos Git - corbenik/ctrulib.git/commitdiff
Add fs:REG implementation based on @yifanlu's in loader
authorchaoskagami <chaos.kagami@gmail.com>
Fri, 14 Oct 2016 04:59:09 +0000 (00:59 -0400)
committerchaoskagami <chaos.kagami@gmail.com>
Fri, 14 Oct 2016 05:00:04 +0000 (01:00 -0400)
libctru/include/3ds.h
libctru/include/3ds/exheader.h [new file with mode: 0644]
libctru/include/3ds/services/fsreg.h [new file with mode: 0644]
libctru/source/services/fsreg.c [new file with mode: 0644]

index 7b8ed5729cd1d259d7d908907d759d9d3db3dd5c..09268b5afb992c1004b8e99f40a7343f153ca0c1 100644 (file)
@@ -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 (file)
index 0000000..07f2f72
--- /dev/null
@@ -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 (file)
index 0000000..614f0fd
--- /dev/null
@@ -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 (file)
index 0000000..5390213
--- /dev/null
@@ -0,0 +1,126 @@
+#include <3ds.h>
+#include <string.h>
+// #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];
+}