From 8ae150d110be2907f0fee88c974860f6e13707ea Mon Sep 17 00:00:00 2001 From: plutoo Date: Sat, 20 Jan 2018 00:10:34 +0100 Subject: [PATCH] NRO loading bringup --- crt0/switch_crt0.s | 16 ++++--- nx/include/switch/runtime/env.h | 31 ++++++++++++- nx/source/kernel/thread.c | 1 - nx/source/runtime/env.c | 78 ++++++++++++++++----------------- nx/source/runtime/init.c | 6 +-- 5 files changed, 79 insertions(+), 53 deletions(-) diff --git a/crt0/switch_crt0.s b/crt0/switch_crt0.s index 7a8fd932..4c49ff95 100644 --- a/crt0/switch_crt0.s +++ b/crt0/switch_crt0.s @@ -8,13 +8,16 @@ _start: .org _start+0x80 startup: + // save lr + mov x27, x30 + // get aslr base bl +4 - sub x28, x30, #0x84 + sub x28, x30, #0x88 - // save context ptr and main thread handle - mov x26, x0 - mov x27, x1 + // context ptr and main thread handle + mov x25, x0 + mov x26, x1 // clear .bss adrp x0, __bss_start__ @@ -37,8 +40,9 @@ bss_loop: bl __nx_dynamic // initialize system - mov x0, x26 - mov x1, x27 + mov x0, x25 + mov x1, x26 + mov x2, x27 bl __libnx_init // call entrypoint diff --git a/nx/include/switch/runtime/env.h b/nx/include/switch/runtime/env.h index 9a3487e6..742e1911 100644 --- a/nx/include/switch/runtime/env.h +++ b/nx/include/switch/runtime/env.h @@ -1,6 +1,33 @@ // Copyright 2018 plutoo -void envParse(void* ctx, Handle main_thread); +typedef struct { + u32 Key; + u32 Flags; + u64 Value[2]; +} ConfigEntry; + +enum { + EntryFlag_IsMandatory = BIT(0), +}; + +enum { + EntryType_EndOfList=0, + EntryType_MainThreadHandle=1, + EntryType_NextLoadPath=2, + EntryType_OverrideHeap=3, + EntryType_OverrideService=4, + EntryType_Argv=5, + EntryType_SyscallAvailableHint=6, + EntryType_AppletType=7, + EntryType_AppletWorkaround=8, + EntryType_StdioSockets=9, + EntryType_ProcessHandle=10, + EntryType_LastLoadResult=11 +}; + +typedef void NORETURN (*LoaderReturnFn)(int result_code); + +void envParse(void* ctx, Handle main_thread, LoaderReturnFn saved_lr); Handle envGetMainThreadHandle(void); bool envIsNso(void); @@ -15,4 +42,4 @@ void* envGetArgv(void); bool envIsSyscallHinted(u8 svc); -typedef void __attribute__((noreturn)) (*LoaderReturnFn)(int result_code); +LoaderReturnFn envGetExitFuncPtr(void); diff --git a/nx/source/kernel/thread.c b/nx/source/kernel/thread.c index 62efccc3..6e9dd72f 100644 --- a/nx/source/kernel/thread.c +++ b/nx/source/kernel/thread.c @@ -47,7 +47,6 @@ Result threadCreate( rc = MAKERESULT(MODULE_LIBNX, LIBNX_OUTOFMEM); } else { - // todo: svcMapMemory returns 0xDC01 void* stack_mirror = virtmemReserveMap(stack_sz); rc = svcMapMemory(stack_mirror, stack, stack_sz); diff --git a/nx/source/runtime/env.c b/nx/source/runtime/env.c index 7e8a408c..845b1c28 100644 --- a/nx/source/runtime/env.c +++ b/nx/source/runtime/env.c @@ -3,47 +3,40 @@ static bool g_isNso = false; static Handle g_mainThreadHandle = INVALID_HANDLE; -static LoaderReturnFn g_loaderRetAddr = NULL; +static LoaderReturnFn g_loaderRetAddr = NULL; static void* g_overrideHeapAddr = NULL; static u64 g_overrideHeapSize = 0; static u64 g_overrideArgc = 0; static void* g_overrideArgv = NULL; -static u64 g_syscallHints[0x80/8]; +static u64 g_syscallHints[2]; +static Handle g_processHandle = INVALID_HANDLE; -typedef struct { - u32 Key; - u32 Flags; - u64 Value[2]; -} ConfigEntry; +extern __attribute__((weak)) u32 __nx_applet_type; -enum { - IsMandatory = BIT(0), -}; - -enum { - EntryType_EndOfList=0, - EntryType_MainThreadHandle=1, - EntryType_LoaderReturnAddr=2, - EntryType_OverrideHeap=3, - EntryType_OverrideService=4, - EntryType_Argv=5, - EntryType_SyscallAvailableHint=6, - EntryType_AppletType=7 -}; - -void envParse(void* ctx, Handle main_thread) +void envParse(void* ctx, Handle main_thread, LoaderReturnFn saved_lr) { + // If we're running under NSO, we should just call svcExitProcess. + // Otherwise we should return to loader via LR. + if (saved_lr == NULL) { + g_loaderRetAddr = (LoaderReturnFn) &svcExitProcess; + } + else { + g_loaderRetAddr = saved_lr; + } + + // Detect NSO environment. if (main_thread != INVALID_HANDLE) { g_mainThreadHandle = main_thread; g_isNso = true; // For NSO we assume kernelhax thus access to all syscalls. - memset((void*) &g_syscallHints, 0xFF, sizeof(g_syscallHints)); + g_syscallHints[0] = g_syscallHints[1] = -1ull; return; } + // Parse NRO config entries. ConfigEntry* ent = ctx; while (ent->Key != EntryType_EndOfList) @@ -54,8 +47,8 @@ void envParse(void* ctx, Handle main_thread) g_mainThreadHandle = ent->Value[0]; break; - case EntryType_LoaderReturnAddr: - g_loaderRetAddr = (void*) ent->Value[0]; + case EntryType_NextLoadPath: + // TODO break; case EntryType_OverrideHeap: @@ -72,26 +65,21 @@ void envParse(void* ctx, Handle main_thread) g_overrideArgv = (void*) ent->Value[1]; break; - case EntryType_SyscallAvailableHint: { - int i, j; - - for (i=0; i<2; i++) for (j=0; j<8; j++) - { - u8 svc = ent->Value[i] >> (8*j); - - if (svc < 0x80) - g_syscallHints[svc/64] |= 1llu << (svc%64); - } - + case EntryType_SyscallAvailableHint: + g_syscallHints[0] = ent->Value[0]; + g_syscallHints[1] = ent->Value[1]; break; - } case EntryType_AppletType: - // TODO + __nx_applet_type = ent->Value[0]; + break; + + case EntryType_ProcessHandle: + g_processHandle = ent->Value[0]; break; default: - if (ent->Flags & IsMandatory) + if (ent->Flags & EntryFlag_IsMandatory) { // Encountered unknown but mandatory key, bail back to loader. g_loaderRetAddr(MAKERESULT(346, 100 + ent->Key)); @@ -142,5 +130,13 @@ void* envGetArgv(void) { } bool envIsSyscallHinted(u8 svc) { - return !!(g_syscallHints[svc/64] & (1llu << (svc%64))); + return !!(g_syscallHints[svc/64] & (1ull << (svc%64))); +} + +Handle envGetOwnProcessHandle(void) { + return g_processHandle; +} + +LoaderReturnFn envGetExitFuncPtr(void) { + return g_loaderRetAddr; } diff --git a/nx/source/runtime/init.c b/nx/source/runtime/init.c index 2ae61d58..5e89b6db 100644 --- a/nx/source/runtime/init.c +++ b/nx/source/runtime/init.c @@ -97,12 +97,12 @@ void __attribute__((weak)) __appExit(void) smExit(); } -void __attribute__((weak)) __libnx_init(void* ctx, Handle main_thread) +void __attribute__((weak)) __libnx_init(void* ctx, Handle main_thread, void* saved_lr) { // Called by crt0. // Libnx initialization goes here. - envParse(ctx, main_thread); + envParse(ctx, main_thread, saved_lr); newlibSetup(); virtmemSetup(); __libnx_initheap(); @@ -127,6 +127,6 @@ void __attribute__((weak)) NORETURN __libnx_exit(int rc) // Clean up services. __appExit(); - svcExitProcess(); + envGetExitFuncPtr()(0); while(1); }