Merge pull request #219 from Steveice10/launcher
Reference count srv, cleanup launcher code.
This commit is contained in:
commit
6e3b2a4cd7
@ -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
72
libctru/include/3ds/env.h
Normal 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;
|
||||
}
|
@ -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.
|
||||
*
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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
67
libctru/source/env.c
Normal 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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
}
|
@ -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();
|
||||
|
@ -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 ++)
|
||||
{
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user