diff --git a/libctru/include/3ds.h b/libctru/include/3ds.h index 44b91d2..a2c8e72 100644 --- a/libctru/include/3ds.h +++ b/libctru/include/3ds.h @@ -18,6 +18,7 @@ extern "C" { #include <3ds/synchronization.h> #include <3ds/gfx.h> #include <3ds/console.h> +#include <3ds/env.h> #include <3ds/util/utf.h> #include <3ds/allocator/linear.h> diff --git a/libctru/include/3ds/env.h b/libctru/include/3ds/env.h new file mode 100644 index 0000000..eaefb98 --- /dev/null +++ b/libctru/include/3ds/env.h @@ -0,0 +1,72 @@ +/** + * @file env.h + * @brief Homebrew environment information. + */ +#pragma once + +/// System run-flags. +enum { + RUNFLAG_APTWORKAROUND = BIT(0), ///< Use APT workaround. + RUNFLAG_APTREINIT = BIT(1), ///< Reinitialize APT. +}; + +/** + * @brief Gets whether the application was launched from a homebrew environment. + * @return Whether the application was launched from a homebrew environment. + */ +static inline bool envIsHomebrew(void) { + extern void* __service_ptr; + return __service_ptr != NULL; +} + +/** + * @brief Retrieves a handle from the environment handle list. + * @param name Name of the handle. + * @return The retrieved handle. + */ +Handle envGetHandle(const char* name); + +/** + * @brief Gets the environment-recommended app ID to use with APT. + * @return The APT app ID. + */ +static inline u32 envGetAptAppId(void) { + extern u32 __apt_appid; + return __apt_appid; +} + +/** + * @brief Gets the environment-recommended heap size. + * @return The heap size. + */ +static inline u32 envGetHeapSize(void) { + extern u32 __heap_size; + return __heap_size; +} + +/** + * @brief Gets the environment-recommended linear heap size. + * @return The linear heap size. + */ +static inline u32 envGetLinearHeapSize(void) { + extern u32 __linear_heap_size; + return __linear_heap_size; +} + +/** + * @brief Gets the environment argument list. + * @return The argument list. + */ +static inline const char* envGetSystemArgList(void) { + extern const char* __system_arglist; + return __system_arglist; +} + +/** + * @brief Gets the environment run flags. + * @return The run flags. + */ +static inline u32 envGetSystemRunFlags(void) { + extern u32 __system_runflags; + return __system_runflags; +} diff --git a/libctru/include/3ds/services/apt.h b/libctru/include/3ds/services/apt.h index afe860b..3b102bf 100644 --- a/libctru/include/3ds/services/apt.h +++ b/libctru/include/3ds/services/apt.h @@ -4,12 +4,6 @@ */ #pragma once -// TODO: find a better place to put this -/// APT workaround flag. -#define RUNFLAG_APTWORKAROUND (BIT(0)) -/// APT reinititalize flag. -#define RUNFLAG_APTREINIT (BIT(1)) - /** * @brief NS Application IDs. * diff --git a/libctru/include/3ds/srv.h b/libctru/include/3ds/srv.h index d61d640..d121cb1 100644 --- a/libctru/include/3ds/srv.h +++ b/libctru/include/3ds/srv.h @@ -8,7 +8,7 @@ Result srvInit(void); /// Exits the service API. -Result srvExit(void); +void srvExit(void); /** * @brief Gets the current service API session handle. @@ -17,7 +17,7 @@ Result srvExit(void); Handle *srvGetSessionHandle(void); /** - * @brief Retrieves a service handle, retrieving from the launcher handle list if possible. + * @brief Retrieves a service handle, retrieving from the environment handle list if possible. * @param out Pointer to write the handle to. * @param name Name of the service. */ diff --git a/libctru/source/allocator/linear.cpp b/libctru/source/allocator/linear.cpp index 1a1e1cb..05e86e0 100644 --- a/libctru/source/allocator/linear.cpp +++ b/libctru/source/allocator/linear.cpp @@ -8,13 +8,14 @@ extern "C" #include "mem_pool.h" #include "addrmap.h" -extern u32 __linear_heap, __linear_heap_size; +extern u32 __ctru_linear_heap; +extern u32 __ctru_linear_heap_size; static MemPool sLinearPool; static bool linearInit() { - auto blk = MemBlock::Create((u8*)__linear_heap, __linear_heap_size); + auto blk = MemBlock::Create((u8*)__ctru_linear_heap, __ctru_linear_heap_size); if (blk) { sLinearPool.AddBlock(blk); diff --git a/libctru/source/env.c b/libctru/source/env.c new file mode 100644 index 0000000..4eb24ba --- /dev/null +++ b/libctru/source/env.c @@ -0,0 +1,67 @@ +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/env.h> + +/* + The homebrew loader can choose to supply a list of service handles that have + been "stolen" from other processes that have been compromised. This allows us + to access services that are normally restricted from the current process. + + For every service requested by the application, we shall first check if the + list given to us contains the requested service and if so use it. If we don't + find the service in that list, we ask the service manager and hope for the + best. + */ + +typedef struct { + u32 num; + + struct { + char name[8]; + Handle handle; + } services[]; +} service_list_t; + +extern void* __service_ptr; + +static int __name_cmp(const char* a, const char* b) { + u32 i; + + for(i=0; i<8; i++) { + if(a[i] != b[i]) + return 1; + if(a[i] == '\0') + return 0; + } + + return 0; +} + +Handle envGetHandle(const char* name) { + if(__service_ptr == NULL) + return 0; + + service_list_t* service_list = (service_list_t*) __service_ptr; + u32 i, num = service_list->num; + + for(i=0; iservices[i].name, name) == 0) + return service_list->services[i].handle; + } + + return 0; +} + +void envDestroyHandles(void) { + if(__service_ptr == NULL) + return; + + service_list_t* service_list = (service_list_t*) __service_ptr; + u32 i, num = service_list->num; + + for(i=0; iservices[i].handle); + + service_list->num = 0; +} + diff --git a/libctru/source/gpu/gpu.c b/libctru/source/gpu/gpu.c index 90fd34b..9146c10 100644 --- a/libctru/source/gpu/gpu.c +++ b/libctru/source/gpu/gpu.c @@ -45,13 +45,13 @@ void GPUCMD_Run(void) GX_ProcessCommandList(gpuCmdBuf, gpuCmdBufOffset*4, GX_CMDLIST_FLUSH); } -extern u32 __linear_heap_size; -extern u32 __linear_heap; +extern u32 __ctru_linear_heap; +extern u32 __ctru_linear_heap_size; void GPUCMD_FlushAndRun(void) { //take advantage of GX_FlushCacheRegions to flush gsp heap - GX_FlushCacheRegions(gpuCmdBuf, gpuCmdBufOffset*4, (u32 *) __linear_heap, __linear_heap_size, NULL, 0); + GX_FlushCacheRegions(gpuCmdBuf, gpuCmdBufOffset*4, (u32 *) __ctru_linear_heap, __ctru_linear_heap_size, NULL, 0); GX_ProcessCommandList(gpuCmdBuf, gpuCmdBufOffset*4, 0x0); } diff --git a/libctru/source/ndsp/ndsp.c b/libctru/source/ndsp/ndsp.c index 11445ba..4c5a503 100644 --- a/libctru/source/ndsp/ndsp.c +++ b/libctru/source/ndsp/ndsp.c @@ -1,6 +1,7 @@ #include "ndsp-internal.h" #include <3ds/services/cfgu.h> #include <3ds/services/fs.h> +#include <3ds/env.h> #define NDSP_THREAD_STACK_SIZE 0x1000 @@ -388,7 +389,6 @@ void ndspUseComponent(const void* binary, u32 size, u16 progMask, u16 dataMask) static bool ndspFindAndLoadComponent(void) { - extern Handle __get_handle_from_list(const char* name); Result rc; Handle rsrc; void* bin; @@ -425,7 +425,7 @@ static bool ndspFindAndLoadComponent(void) } while (0); // Try loading the DSP component from hb:ndsp - rsrc = __get_handle_from_list("hb:ndsp"); + rsrc = envGetHandle("hb:ndsp"); if (rsrc) do { extern u32 fake_heap_end; diff --git a/libctru/source/romfs_dev.c b/libctru/source/romfs_dev.c index 1706b78..3b25602 100644 --- a/libctru/source/romfs_dev.c +++ b/libctru/source/romfs_dev.c @@ -14,6 +14,7 @@ #include <3ds/romfs.h> #include <3ds/services/fs.h> #include <3ds/util/utf.h> +#include <3ds/env.h> static bool romFS_active; static Handle romFS_file; @@ -24,7 +25,6 @@ static romfs_dir* romFS_cwd; static u32 *dirHashTable, *fileHashTable; static void *dirTable, *fileTable; -extern u32 __service_ptr; extern int __system_argc; extern char** __system_argv; @@ -117,7 +117,7 @@ static Result romfsInitCommon(void); Result romfsInit(void) { if (romFS_active) return 0; - if (__service_ptr) + if (envIsHomebrew()) { // RomFS appended to a 3DSX file if (__system_argc == 0 || !__system_argv[0]) return 1; diff --git a/libctru/source/services/apt.c b/libctru/source/services/apt.c index 98591cb..5bbbbe2 100644 --- a/libctru/source/services/apt.c +++ b/libctru/source/services/apt.c @@ -12,14 +12,10 @@ #include <3ds/services/apt.h> #include <3ds/services/gspgpu.h> #include <3ds/ipc.h> - +#include <3ds/env.h> #define APT_HANDLER_STACKSIZE (0x1000) -//TODO : better place to put this ? -extern u32 __apt_appid; -extern u32 __system_runflags; - NS_APPID currentAppId; static const char *__apt_servicestr; @@ -71,12 +67,12 @@ static void aptAppStarted(void); static bool aptIsReinit(void) { - return (__system_runflags & RUNFLAG_APTREINIT) != 0; + return (envGetSystemRunFlags() & RUNFLAG_APTREINIT) != 0; } static bool aptIsCrippled(void) { - return (__system_runflags & RUNFLAG_APTWORKAROUND) != 0 && !aptIsReinit(); + return (envGetSystemRunFlags() & RUNFLAG_APTWORKAROUND) != 0 && !aptIsReinit(); } static Result __apt_initservicehandle(void) @@ -464,7 +460,7 @@ Result aptInit(void) if(R_FAILED(ret=APT_GetLockHandle(0x0, &aptLockHandle))) goto _fail; svcCloseHandle(aptuHandle); - currentAppId = __apt_appid; + currentAppId = envGetAptAppId(); svcCreateEvent(&aptStatusEvent, 0); svcCreateEvent(&aptSleepSync, 0); diff --git a/libctru/source/services/fs.c b/libctru/source/services/fs.c index 8e18cbc..90738a6 100644 --- a/libctru/source/services/fs.c +++ b/libctru/source/services/fs.c @@ -6,13 +6,11 @@ #include <3ds/synchronization.h> #include <3ds/services/fs.h> #include <3ds/ipc.h> +#include <3ds/env.h> static Handle fsuHandle; static int fsuRefCount; -// used to determine whether or not we should do FSUSER_Initialize on fsuHandle -Handle __get_handle_from_list(char* name); - Result fsInit(void) { Result ret = 0; @@ -20,7 +18,7 @@ Result fsInit(void) if (AtomicPostIncrement(&fsuRefCount)) return 0; ret = srvGetServiceHandle(&fsuHandle, "fs:USER"); - if (R_SUCCEEDED(ret) && __get_handle_from_list("fs:USER") == 0) + if (R_SUCCEEDED(ret) && envGetHandle("fs:USER") == 0) { ret = FSUSER_Initialize(); if (R_FAILED(ret)) svcCloseHandle(fsuHandle); diff --git a/libctru/source/services/irrst.c b/libctru/source/services/irrst.c index 4337939..2f93fc1 100644 --- a/libctru/source/services/irrst.c +++ b/libctru/source/services/irrst.c @@ -11,9 +11,7 @@ #include <3ds/synchronization.h> #include <3ds/services/irrst.h> #include <3ds/ipc.h> - -// used to determine whether or not we should do IRRST_Initialize -Handle __get_handle_from_list(char* name); +#include <3ds/env.h> Handle irrstHandle; Handle irrstMemHandle; @@ -38,7 +36,7 @@ Result irrstInit(void) if(R_FAILED(ret=IRRST_GetHandles(&irrstMemHandle, &irrstEvent))) goto cleanup1; // Initialize ir:rst - if(__get_handle_from_list("ir:rst")==0)ret=IRRST_Initialize(10, 0); + if(envGetHandle("ir:rst") == 0) ret = IRRST_Initialize(10, 0); // Map ir:rst shared memory. irrstSharedMem=(vu32*)mappableAlloc(0x98); @@ -48,7 +46,7 @@ Result irrstInit(void) goto cleanup1; } - if(R_FAILED(ret=svcMapMemoryBlock(irrstMemHandle, (u32)irrstSharedMem, MEMPERM_READ, 0x10000000)))goto cleanup2; + if(R_FAILED(ret = svcMapMemoryBlock(irrstMemHandle, (u32)irrstSharedMem, MEMPERM_READ, 0x10000000))) goto cleanup2; // Reset internal state. kHeld = 0; @@ -75,7 +73,7 @@ void irrstExit(void) svcCloseHandle(irrstEvent); // Unmap ir:rst sharedmem and close handles. svcUnmapMemoryBlock(irrstMemHandle, (u32)irrstSharedMem); - if(__get_handle_from_list("ir:rst")==0) IRRST_Shutdown(); + if(envGetHandle("ir:rst") == 0) IRRST_Shutdown(); svcCloseHandle(irrstMemHandle); svcCloseHandle(irrstHandle); diff --git a/libctru/source/srv.c b/libctru/source/srv.c index e3daaa1..e5b6652 100644 --- a/libctru/source/srv.c +++ b/libctru/source/srv.c @@ -8,93 +8,33 @@ #include <3ds/srv.h> #include <3ds/svc.h> #include <3ds/ipc.h> - - -/* - The homebrew loader can choose to supply a list of service handles that have - been "stolen" from other processes that have been compromised. This allows us - to access services that are normally restricted from the current process. - - For every service requested by the application, we shall first check if the - list given to us contains the requested service and if so use it. If we don't - find the service in that list, we ask the service manager and hope for the - best. - */ - -typedef struct { - u32 num; - - struct { - char name[8]; - Handle handle; - } services[]; -} service_list_t; - -extern service_list_t* __service_ptr; - -static int __name_cmp(const char* a, const char* b) { - u32 i; - - for(i=0; i<8; i++) { - if(a[i] != b[i]) - return 1; - if(a[i] == '\0') - return 0; - } - - return 0; -} - -Handle __get_handle_from_list(const char* name) { - if((u32)__service_ptr == 0) - return 0; - - u32 i, num = __service_ptr->num; - - for(i=0; iservices[i].name, name) == 0) - return __service_ptr->services[i].handle; - } - - return 0; -} - -void __destroy_handle_list(void) { - if((u32)__service_ptr == 0) - return; - - u32 i, num = __service_ptr->num; - - for(i=0; iservices[i].handle); - - __service_ptr->num = 0; -} +#include <3ds/synchronization.h> +#include <3ds/env.h> static Handle srvHandle; +static int srvRefCount; Result srvInit(void) { Result rc = 0; - if(srvHandle != 0) return rc; + if (AtomicPostIncrement(&srvRefCount)) return 0; - if(R_FAILED(rc = svcConnectToPort(&srvHandle, "srv:"))) return rc; - - if(R_FAILED(rc = srvRegisterClient())) { - svcCloseHandle(srvHandle); - srvHandle = 0; - } + rc = svcConnectToPort(&srvHandle, "srv:"); + if (R_FAILED(rc)) goto end; + rc = srvRegisterClient(); +end: + if (R_FAILED(rc)) srvExit(); return rc; } -Result srvExit(void) +void srvExit(void) { - if(srvHandle != 0) svcCloseHandle(srvHandle); + if (AtomicDecrement(&srvRefCount)) return; + if (srvHandle != 0) svcCloseHandle(srvHandle); srvHandle = 0; - return 0; } Handle *srvGetSessionHandle(void) @@ -106,7 +46,7 @@ Result srvGetServiceHandle(Handle* out, const char* name) { /* Look in service-list given to us by loader. If we find find a match, we return it. */ - Handle h = __get_handle_from_list(name); + Handle h = envGetHandle(name); if(h != 0) { return svcDuplicateHandle(out, h); diff --git a/libctru/source/system/allocateHeaps.c b/libctru/source/system/allocateHeaps.c index 44bbe63..6bfcb62 100644 --- a/libctru/source/system/allocateHeaps.c +++ b/libctru/source/system/allocateHeaps.c @@ -1,24 +1,31 @@ #include <3ds/types.h> #include <3ds/svc.h> +#include <3ds/env.h> extern char* fake_heap_start; extern char* fake_heap_end; -u32 __linear_heap; -u32 __heapBase; -extern u32 __heap_size, __linear_heap_size; +u32 __ctru_heap; +u32 __ctru_heap_size; +u32 __ctru_linear_heap; +u32 __ctru_linear_heap_size; void __attribute__((weak)) __system_allocateHeaps() { u32 tmp=0; + // Retrieve heap sizes. + __ctru_heap_size = envGetHeapSize(); + __ctru_linear_heap_size = envGetLinearHeapSize(); + // Allocate the application heap - __heapBase = 0x08000000; - svcControlMemory(&tmp, __heapBase, 0x0, __heap_size, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE); + __ctru_heap = 0x08000000; + svcControlMemory(&tmp, __ctru_heap, 0x0, __ctru_heap_size, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE); // Allocate the linear heap - svcControlMemory(&__linear_heap, 0x0, 0x0, __linear_heap_size, MEMOP_ALLOC_LINEAR, MEMPERM_READ | MEMPERM_WRITE); - // Set up newlib heap - fake_heap_start = (char*)__heapBase; - fake_heap_end = fake_heap_start + __heap_size; + svcControlMemory(&__ctru_linear_heap, 0x0, 0x0, __ctru_linear_heap_size, MEMOP_ALLOC_LINEAR, MEMPERM_READ | MEMPERM_WRITE); -} \ No newline at end of file + // Set up newlib heap + fake_heap_start = (char*)__ctru_heap; + fake_heap_end = fake_heap_start + __ctru_heap_size; + +} diff --git a/libctru/source/system/ctru_exit.c b/libctru/source/system/ctru_exit.c index 41c5acd..e9ece2e 100644 --- a/libctru/source/system/ctru_exit.c +++ b/libctru/source/system/ctru_exit.c @@ -1,12 +1,16 @@ #include <3ds/types.h> #include <3ds/svc.h> +#include <3ds/env.h> + +extern u32 __ctru_heap; +extern u32 __ctru_heap_size; +extern u32 __ctru_linear_heap; +extern u32 __ctru_linear_heap_size; -extern u32 __linear_heap; -extern u32 __heapBase; -extern u32 __heap_size, __linear_heap_size; extern void (*__system_retAddr)(void); -void __destroy_handle_list(void); +void envDestroyHandles(void); + void __appExit(); void __libc_fini_array(void); @@ -18,13 +22,13 @@ void __attribute__((weak)) __attribute__((noreturn)) __libctru_exit(int rc) u32 tmp=0; // Unmap the linear heap - svcControlMemory(&tmp, __linear_heap, 0x0, __linear_heap_size, MEMOP_FREE, 0x0); + svcControlMemory(&tmp, __ctru_linear_heap, 0x0, __ctru_linear_heap_size, MEMOP_FREE, 0x0); // Unmap the application heap - svcControlMemory(&tmp, __heapBase, 0x0, __heap_size, MEMOP_FREE, 0x0); + svcControlMemory(&tmp, __ctru_heap, 0x0, __ctru_heap_size, MEMOP_FREE, 0x0); // Close some handles - __destroy_handle_list(); + envDestroyHandles(); if (__sync_fini) __sync_fini(); diff --git a/libctru/source/system/initArgv.c b/libctru/source/system/initArgv.c index 0fae5dd..d566b00 100644 --- a/libctru/source/system/initArgv.c +++ b/libctru/source/system/initArgv.c @@ -1,11 +1,11 @@ #include <3ds/types.h> +#include <3ds/env.h> #include // System globals we define here int __system_argc; char** __system_argv; -extern const char* __system_arglist; extern char* fake_heap_start; extern char* fake_heap_end; @@ -13,7 +13,8 @@ extern char* fake_heap_end; void __system_initArgv() { int i; - const char* temp = __system_arglist; + const char* arglist = envGetSystemArgList(); + const char* temp = arglist; // Check if the argument list is present if (!temp) @@ -31,14 +32,14 @@ void __system_initArgv() } // Reserve heap memory for argv data - u32 argSize = temp - __system_arglist - sizeof(u32); + u32 argSize = temp - arglist - sizeof(u32); __system_argv = (char**)fake_heap_start; fake_heap_start += sizeof(char**)*(__system_argc + 1); char* argCopy = fake_heap_start; fake_heap_start += argSize; // Fill argv array - memcpy(argCopy, &__system_arglist[4], argSize); + memcpy(argCopy, &arglist[4], argSize); temp = argCopy; for (i = 0; i < __system_argc; i ++) { diff --git a/libctru/source/system/initSystem.c b/libctru/source/system/initSystem.c index 98c5837..0d0ac97 100644 --- a/libctru/source/system/initSystem.c +++ b/libctru/source/system/initSystem.c @@ -1,15 +1,13 @@ #include #include - #include + #include <3ds/types.h> #include <3ds/svc.h> +#include <3ds/env.h> void (*__system_retAddr)(void); -// Data from _prm structure -extern void* __service_ptr; // used to detect if we're run from a homebrew launcher - void __system_allocateHeaps(); void __system_initArgv(); void __appInit(); @@ -27,7 +25,7 @@ void __attribute__((weak)) __libctru_init(void (*retAddr)(void)) __syscalls.exit = __ctru_exit; __syscalls.gettod_r = __libctru_gtod; - __system_retAddr = __service_ptr ? retAddr : NULL; + __system_retAddr = envIsHomebrew() ? retAddr : NULL; if (__sync_init) __sync_init();