Merge pull request #219 from Steveice10/launcher

Reference count srv, cleanup launcher code.
This commit is contained in:
fincs 2015-11-15 23:18:52 +01:00
commit 6e3b2a4cd7
17 changed files with 211 additions and 134 deletions

View File

@ -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>

72
libctru/include/3ds/env.h Normal file
View File

@ -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;
}

View File

@ -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.
*

View File

@ -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.
*/

View File

@ -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);

67
libctru/source/env.c Normal file
View File

@ -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; i<num; i++) {
if(__name_cmp(service_list->services[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; i<num; i++)
svcCloseHandle(service_list->services[i].handle);
service_list->num = 0;
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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; i<num; i++) {
if(__name_cmp(__service_ptr->services[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; i<num; i++)
svcCloseHandle(__service_ptr->services[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);

View File

@ -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);
svcControlMemory(&__ctru_linear_heap, 0x0, 0x0, __ctru_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;
fake_heap_start = (char*)__ctru_heap;
fake_heap_end = fake_heap_start + __ctru_heap_size;
}

View File

@ -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();

View File

@ -1,11 +1,11 @@
#include <3ds/types.h>
#include <3ds/env.h>
#include <string.h>
// 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 ++)
{

View File

@ -1,15 +1,13 @@
#include <sys/iosupport.h>
#include <sys/time.h>
#include <string.h>
#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();