// Copyright 2018 plutoo #include static bool g_isNso = false; static Handle g_mainThreadHandle = INVALID_HANDLE; 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]; typedef struct { u32 Key; u32 Flags; u64 Value[2]; } ConfigEntry; 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) { 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)); return; } ConfigEntry* ent = ctx; while (ent->Key != EntryType_EndOfList) { switch (ent->Key) { case EntryType_MainThreadHandle: g_mainThreadHandle = ent->Value[0]; break; case EntryType_LoaderReturnAddr: g_loaderRetAddr = (void*) ent->Value[0]; break; case EntryType_OverrideHeap: g_overrideHeapAddr = (void*) ent->Value[0]; g_overrideHeapSize = ent->Value[1]; break; case EntryType_OverrideService: smAddOverrideHandle(ent->Value[0], ent->Value[1]); break; case EntryType_Argv: g_overrideArgc = ent->Value[0]; 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); } break; } case EntryType_AppletType: // TODO break; default: if (ent->Flags & IsMandatory) { // Encountered unknown but mandatory key, bail back to loader. g_loaderRetAddr(346 | ((100 + ent->Key) << 9)); } break; } ent++; } } Handle envGetMainThreadHandle(void) { if (g_mainThreadHandle != INVALID_HANDLE) { return g_mainThreadHandle; } fatalSimple(MAKERESULT(MODULE_LIBNX, LIBNX_HANDLETOOEARLY)); } bool envIsNso(void) { return g_isNso; } bool envHasHeapOverride(void) { return g_overrideHeapAddr != NULL; } void* envGetHeapOverrideAddr(void) { return g_overrideHeapAddr; } u64 envGetHeapOverrideSize(void) { return g_overrideHeapSize; } bool envHasArgv(void) { return g_overrideArgv != NULL; } u64 envGetArgc(void) { return g_overrideArgc; } void* envGetArgv(void) { return g_overrideArgv; } bool envIsSyscallHinted(u8 svc) { return !!(g_syscallHints[svc/64] & (1llu << (svc%64))); }