mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-30 11:40:32 +00:00
2633b3e310
This prevents graphical issues if the gfx is already initialized. Which should always be the case if called from a running core.
349 lines
8.3 KiB
C
349 lines
8.3 KiB
C
#include <3ds.h>
|
|
#include <sys/iosupport.h>
|
|
#include <3ds/services/apt.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include "ctr_debug.h"
|
|
|
|
#define CTR_APPMEMALLOC_PTR ((u32*)0x1FF80040)
|
|
|
|
/* Global variables */
|
|
u32 __stacksize__ = 0x00400000;
|
|
u32 __linear_heap_size = 0x01000000;
|
|
|
|
u32 __heap_size;
|
|
u32 __linear_heap;
|
|
u32 __heapBase;
|
|
|
|
u32 __stack_bottom;
|
|
u32 __stack_size_extra;
|
|
|
|
u32 __saved_stack;
|
|
|
|
extern u32 __linear_heap_size_hbl;
|
|
extern u32 __heap_size_hbl;
|
|
extern void* __service_ptr;
|
|
|
|
extern void (*__system_retAddr)(void);
|
|
|
|
/* Forward declarations */
|
|
void envDestroyHandles(void);
|
|
void __appExit(void);
|
|
void __libc_fini_array(void);
|
|
|
|
void __appInit(void);
|
|
void __libc_init_array(void);
|
|
void __system_initSyscalls(void);
|
|
void __system_initArgv(void);
|
|
|
|
void __ctru_exit(int rc);
|
|
int __libctru_gtod(struct _reent* ptr,
|
|
struct timeval* tp, struct timezone* tz);
|
|
void (*__system_retAddr)(void);
|
|
|
|
Result __sync_init(void) __attribute__((weak));
|
|
|
|
void __system_allocateHeaps(void)
|
|
{
|
|
extern char* fake_heap_end;
|
|
u32 tmp = 0;
|
|
|
|
MemInfo stack_memInfo;
|
|
PageInfo stack_pageInfo;
|
|
|
|
register u32 sp_val __asm__("sp");
|
|
|
|
svcQueryMemory(&stack_memInfo, &stack_pageInfo, sp_val);
|
|
|
|
__stacksize__ += 0xFFF;
|
|
__stacksize__ &= ~0xFFF;
|
|
__stack_size_extra = __stacksize__ > stack_memInfo.size ? __stacksize__ - stack_memInfo.size : 0;
|
|
__stack_bottom = stack_memInfo.base_addr - __stack_size_extra;
|
|
|
|
if (__stack_size_extra)
|
|
{
|
|
svcControlMemory(&tmp, __stack_bottom, 0x0, __stack_size_extra, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE);
|
|
memset((void*)__stack_bottom, 0xFC, __stack_size_extra);
|
|
}
|
|
|
|
/* setup the application heap */
|
|
__heapBase = 0x08000000;
|
|
__heap_size = 0;
|
|
|
|
/* Allocate the linear heap */
|
|
svcControlMemory(&__linear_heap, 0x0, 0x0, __linear_heap_size, MEMOP_ALLOC_LINEAR, MEMPERM_READ | MEMPERM_WRITE);
|
|
|
|
#ifdef USE_CTRULIB_2
|
|
/* Mappable allocator init */
|
|
mappableInit(OS_MAP_AREA_BEGIN, OS_MAP_AREA_END);
|
|
#endif
|
|
|
|
/* Set up newlib heap */
|
|
fake_heap_end = (char*)0x13F00000;
|
|
}
|
|
|
|
void __attribute__((weak)) __libctru_init(void (*retAddr)(void))
|
|
{
|
|
/* Store the return address */
|
|
__system_retAddr = NULL;
|
|
if (envIsHomebrew())
|
|
__system_retAddr = retAddr;
|
|
|
|
/* Initialize the synchronization subsystem */
|
|
__sync_init();
|
|
|
|
/* Initialize newlib support system calls */
|
|
__system_initSyscalls();
|
|
|
|
/* Allocate application and linear heaps */
|
|
__system_allocateHeaps();
|
|
}
|
|
|
|
Result __sync_fini(void) __attribute__((weak));
|
|
|
|
extern char** __system_argv;
|
|
|
|
void __attribute__((noreturn)) __libctru_exit(int rc)
|
|
{
|
|
u32 tmp = 0;
|
|
int size = 0;
|
|
|
|
if (__system_argv)
|
|
free(__system_argv);
|
|
|
|
/* Unmap the linear heap */
|
|
/* Do this 1MB at a time to avoid kernel panics, see https://github.com/LumaTeam/Luma3DS/issues/1504 */
|
|
while (__linear_heap_size > 0) {
|
|
size = __linear_heap_size < 0x100000 ? __linear_heap_size : 0x100000;
|
|
__linear_heap_size -= size;
|
|
svcControlMemory(&tmp, __linear_heap + __linear_heap_size, 0x0, size, MEMOP_FREE, 0x0);
|
|
}
|
|
|
|
/* Unmap the application heap */
|
|
/* Do this 1MB at a time to avoid kernel panics */
|
|
while (__heap_size > 0) {
|
|
size = __heap_size < 0x100000 ? __heap_size : 0x100000;
|
|
__heap_size -= size;
|
|
svcControlMemory(&tmp, __heapBase + __heap_size, 0x0, size, MEMOP_FREE, 0x0);
|
|
}
|
|
|
|
if (__stack_size_extra)
|
|
svcControlMemory(&tmp, __stack_bottom, 0x0, __stack_size_extra, MEMOP_FREE, 0x0);
|
|
|
|
/* Close some handles */
|
|
envDestroyHandles();
|
|
|
|
if (__sync_fini)
|
|
__sync_fini();
|
|
|
|
/* Jump to the loader if it provided a callback */
|
|
if (__system_retAddr)
|
|
__system_retAddr();
|
|
|
|
/* Since above did not jump, end this process */
|
|
svcExitProcess();
|
|
}
|
|
|
|
#include <3ds/types.h>
|
|
|
|
#include <string.h>
|
|
|
|
/* System globals we define here */
|
|
int __system_argc;
|
|
char** __system_argv;
|
|
extern const char* __system_arglist;
|
|
|
|
// sha-256 of "ARGV"
|
|
char __argv_hmac[0x20] = {0x1d, 0x78, 0xff, 0xb9, 0xc5, 0xbc, 0x78, 0xb7, 0xac, 0x29, 0x1d, 0x3e, 0x16, 0xd0, 0xcf, 0x53,
|
|
0xef, 0x12, 0x58, 0x83, 0xb6, 0x9e, 0x2f, 0x79, 0x47, 0xf9, 0x35, 0x61, 0xeb, 0x50, 0xd7, 0x67};
|
|
|
|
Result APT_ReceiveDeliverArg_(void* param, size_t param_size,
|
|
void* hmac, size_t hmac_size, u64* source_pid, bool* received)
|
|
{
|
|
u32 cmdbuf[16];
|
|
u32 saved_threadstorage[4];
|
|
u32 *staticbufs;
|
|
Result ret;
|
|
|
|
cmdbuf[0] = IPC_MakeHeader(0x35,2,0);
|
|
cmdbuf[1] = param_size;
|
|
cmdbuf[2] = hmac_size;
|
|
|
|
staticbufs = getThreadStaticBuffers();
|
|
saved_threadstorage[0] = staticbufs[0];
|
|
saved_threadstorage[1] = staticbufs[1];
|
|
saved_threadstorage[2] = staticbufs[2];
|
|
saved_threadstorage[3] = staticbufs[3];
|
|
staticbufs[0] = IPC_Desc_StaticBuffer(param_size, 0);
|
|
staticbufs[1] = (u32)param;
|
|
staticbufs[2] = IPC_Desc_StaticBuffer(hmac_size, 2);
|
|
staticbufs[3] = (u32)hmac;
|
|
|
|
ret = aptSendCommand(cmdbuf);
|
|
staticbufs[0] = saved_threadstorage[0];
|
|
staticbufs[1] = saved_threadstorage[1];
|
|
staticbufs[2] = saved_threadstorage[2];
|
|
staticbufs[3] = saved_threadstorage[3];
|
|
|
|
if(R_FAILED(ret))
|
|
return ret;
|
|
|
|
if(source_pid)
|
|
*source_pid = ((u64*)cmdbuf)[1];
|
|
if(received)
|
|
*received = ((bool*)cmdbuf)[16];
|
|
|
|
return cmdbuf[1];
|
|
}
|
|
|
|
void __system_initArgv(void)
|
|
{
|
|
int i;
|
|
|
|
struct
|
|
{
|
|
u32 argc;
|
|
char args[];
|
|
}*arg_struct = (void*)__system_arglist;
|
|
|
|
static u8 param[0x300];
|
|
u8 hmac[0x20];
|
|
bool received;
|
|
|
|
if(!__service_ptr
|
|
&& R_SUCCEEDED(APT_ReceiveDeliverArg_(¶m, sizeof(param), hmac, sizeof(hmac), NULL, &received))
|
|
&& received
|
|
&& !memcmp(hmac, __argv_hmac, sizeof(__argv_hmac)))
|
|
arg_struct = (void*)param;
|
|
|
|
__system_argc = 0;
|
|
|
|
if (arg_struct)
|
|
__system_argc = arg_struct->argc;
|
|
|
|
if (__system_argc)
|
|
{
|
|
__system_argv = (char**)malloc(
|
|
(__system_argc + 1) * sizeof(char**));
|
|
__system_argv[0] = arg_struct->args;
|
|
for (i = 1; i < __system_argc; i++)
|
|
__system_argv[i] = __system_argv[i - 1] + strlen(__system_argv[i - 1]) + 1;
|
|
|
|
i = __system_argc - 1;
|
|
__system_argc = 1;
|
|
|
|
while (i)
|
|
{
|
|
if(__system_argv[i] && isalnum(__system_argv[i][0])
|
|
&& strncmp(__system_argv[i], "3dslink:/", 9))
|
|
{
|
|
__system_argv[1] = __system_argv[i];
|
|
__system_argc = 2;
|
|
break;
|
|
}
|
|
i--;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
__system_argc = 1;
|
|
__system_argv = (char**) malloc(sizeof(char**) * 2);
|
|
__system_argv[0] = "sdmc:/retroarch/retroarch";
|
|
}
|
|
__system_argv[__system_argc] = NULL;
|
|
}
|
|
|
|
void initSystem(void (*retAddr)(void))
|
|
{
|
|
register u32 sp_val __asm__("sp");
|
|
__saved_stack = sp_val;
|
|
|
|
__libctru_init(retAddr);
|
|
__appInit();
|
|
__system_initArgv();
|
|
__libc_init_array();
|
|
}
|
|
|
|
void __attribute__((noreturn)) __ctru_exit(int rc)
|
|
{
|
|
__libc_fini_array();
|
|
__appExit();
|
|
asm ("mov sp, %[saved_stack] \n\t" : : [saved_stack] "r" (__saved_stack) : "sp");
|
|
__libctru_exit(rc);
|
|
}
|
|
|
|
typedef union
|
|
{
|
|
struct
|
|
{
|
|
unsigned description : 10;
|
|
unsigned module : 8;
|
|
unsigned : 3;
|
|
unsigned summary : 6;
|
|
unsigned level : 5;
|
|
};
|
|
Result val;
|
|
} ctr_result_value;
|
|
|
|
void dump_result_value(Result val)
|
|
{
|
|
ctr_result_value res;
|
|
res.val = val;
|
|
printf("result : 0x%08X\n", val);
|
|
printf("description : %u\n", res.description);
|
|
printf("module : %u\n", res.module);
|
|
printf("summary : %u\n", res.summary);
|
|
printf("level : %u\n", res.level);
|
|
}
|
|
|
|
void wait_for_input(void)
|
|
{
|
|
printf("\n\nPress Start.\n\n");
|
|
fflush(stdout);
|
|
|
|
while (aptMainLoop())
|
|
{
|
|
u32 kDown;
|
|
|
|
hidScanInput();
|
|
|
|
kDown = hidKeysDown();
|
|
|
|
if (kDown & KEY_START)
|
|
break;
|
|
|
|
if (kDown & KEY_SELECT)
|
|
exit(0);
|
|
|
|
svcSleepThread(1000000);
|
|
}
|
|
}
|
|
|
|
void error_and_quit(const char* errorStr)
|
|
{
|
|
errorConf error;
|
|
#ifdef IS_SALAMANDER
|
|
gfxInitDefault();
|
|
#endif
|
|
errorInit(&error, ERROR_TEXT, CFG_LANGUAGE_EN);
|
|
errorText(&error, errorStr);
|
|
errorDisp(&error);
|
|
|
|
gfxExit();
|
|
exit(0);
|
|
}
|
|
|
|
long sysconf(int name)
|
|
{
|
|
switch (name)
|
|
{
|
|
case _SC_NPROCESSORS_ONLN:
|
|
return 2;
|
|
}
|
|
|
|
return -1;
|
|
}
|