mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 12:32:40 +02:00
232 lines
5.8 KiB
C
232 lines
5.8 KiB
C
// Copyright 2018 plutoo
|
|
#include <string.h>
|
|
#include "runtime/env.h"
|
|
#include "runtime/hosversion.h"
|
|
#include "services/sm.h"
|
|
#include "services/applet.h"
|
|
#include "services/acc.h"
|
|
#include "runtime/diag.h"
|
|
|
|
void NORETURN __nx_exit(Result rc, LoaderReturnFn retaddr);
|
|
|
|
static bool g_isNso = false;
|
|
static const char* g_loaderInfo = NULL;
|
|
static u64 g_loaderInfoSize = 0;
|
|
static Handle g_mainThreadHandle = INVALID_HANDLE;
|
|
static LoaderReturnFn g_loaderRetAddr = NULL;
|
|
static void* g_overrideHeapAddr = NULL;
|
|
static u64 g_overrideHeapSize = 0;
|
|
static void* g_overrideArgv = NULL;
|
|
static u64 g_syscallHints[3];
|
|
static Handle g_processHandle = INVALID_HANDLE;
|
|
static char* g_nextLoadPath = NULL;
|
|
static char* g_nextLoadArgv = NULL;
|
|
static Result g_lastLoadResult = 0;
|
|
static bool g_hasRandomSeed = false;
|
|
static u64 g_randomSeed[2] = { 0, 0 };
|
|
static AccountUid* g_userIdStorage = NULL;
|
|
|
|
extern __attribute__((weak)) u32 __nx_applet_type;
|
|
|
|
void envSetup(void* ctx, Handle main_thread, LoaderReturnFn saved_lr)
|
|
{
|
|
// Detect and set up NSO environment.
|
|
if (ctx == NULL)
|
|
{
|
|
// Under NSO, we use svcExitProcess as the return address and hint all syscalls as available.
|
|
g_isNso = true;
|
|
g_mainThreadHandle = main_thread;
|
|
g_loaderRetAddr = (LoaderReturnFn) &svcExitProcess;
|
|
g_syscallHints[0] = g_syscallHints[1] = g_syscallHints[2] = UINT64_MAX;
|
|
return;
|
|
}
|
|
|
|
// Save the loader return address.
|
|
g_loaderRetAddr = saved_lr;
|
|
|
|
// Parse homebrew ABI config entries.
|
|
ConfigEntry* ent = ctx;
|
|
|
|
while (ent->Key != EntryType_EndOfList)
|
|
{
|
|
switch (ent->Key)
|
|
{
|
|
case EntryType_MainThreadHandle:
|
|
g_mainThreadHandle = ent->Value[0];
|
|
break;
|
|
|
|
case EntryType_NextLoadPath:
|
|
g_nextLoadPath = (char*) ent->Value[0];
|
|
g_nextLoadArgv = (char*) ent->Value[1];
|
|
break;
|
|
|
|
case EntryType_OverrideHeap:
|
|
g_overrideHeapAddr = (void*) ent->Value[0];
|
|
g_overrideHeapSize = ent->Value[1];
|
|
break;
|
|
|
|
case EntryType_OverrideService:
|
|
smAddOverrideHandle(smServiceNameFromU64(ent->Value[0]), ent->Value[1]);
|
|
break;
|
|
|
|
case EntryType_Argv:
|
|
g_overrideArgv = (void*) ent->Value[1];
|
|
break;
|
|
|
|
case EntryType_SyscallAvailableHint:
|
|
g_syscallHints[0] = ent->Value[0];
|
|
g_syscallHints[1] = ent->Value[1];
|
|
break;
|
|
|
|
case EntryType_AppletType:
|
|
__nx_applet_type = ent->Value[0];
|
|
if ((ent->Value[1] & EnvAppletFlags_ApplicationOverride) && __nx_applet_type == AppletType_SystemApplication) __nx_applet_type = AppletType_Application;
|
|
break;
|
|
|
|
case EntryType_ProcessHandle:
|
|
g_processHandle = ent->Value[0];
|
|
break;
|
|
|
|
case EntryType_LastLoadResult:
|
|
g_lastLoadResult = ent->Value[0];
|
|
break;
|
|
|
|
case EntryType_RandomSeed:
|
|
g_hasRandomSeed = true;
|
|
g_randomSeed[0] = ent->Value[0];
|
|
g_randomSeed[1] = ent->Value[1];
|
|
break;
|
|
|
|
case EntryType_UserIdStorage:
|
|
g_userIdStorage = (AccountUid*)(uintptr_t)ent->Value[0];
|
|
break;
|
|
|
|
case EntryType_HosVersion: {
|
|
u32 version = ent->Value[0];
|
|
if (ent->Value[1] == 0x41544d4f53504852UL) { // 'ATMOSPHR'
|
|
version |= BIT(31);
|
|
}
|
|
hosversionSet(version);
|
|
break;
|
|
}
|
|
|
|
case EntryType_SyscallAvailableHint2:
|
|
g_syscallHints[2] = ent->Value[0];
|
|
break;
|
|
|
|
default:
|
|
if (ent->Flags & EntryFlag_IsMandatory)
|
|
{
|
|
// Encountered unknown but mandatory key, bail back to loader.
|
|
__nx_exit(MAKERESULT(Module_HomebrewAbi, 100 + ent->Key), g_loaderRetAddr);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
ent++;
|
|
}
|
|
|
|
g_loaderInfoSize = ent->Value[1];
|
|
if (g_loaderInfoSize) {
|
|
g_loaderInfo = (const char*)(uintptr_t)ent->Value[0];
|
|
}
|
|
|
|
}
|
|
|
|
const char* envGetLoaderInfo(void) {
|
|
return g_loaderInfo;
|
|
}
|
|
|
|
u64 envGetLoaderInfoSize(void) {
|
|
return g_loaderInfoSize;
|
|
}
|
|
|
|
Handle envGetMainThreadHandle(void) {
|
|
if (g_mainThreadHandle != INVALID_HANDLE) {
|
|
return g_mainThreadHandle;
|
|
}
|
|
|
|
diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_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;
|
|
}
|
|
|
|
void* envGetArgv(void) {
|
|
return g_overrideArgv;
|
|
}
|
|
|
|
bool envIsSyscallHinted(unsigned svc) {
|
|
if (svc >= 0xC0) return false;
|
|
return !!(g_syscallHints[svc/64] & (1ull << (svc%64)));
|
|
}
|
|
|
|
Handle envGetOwnProcessHandle(void) {
|
|
return g_processHandle;
|
|
}
|
|
|
|
LoaderReturnFn envGetExitFuncPtr(void) {
|
|
return g_loaderRetAddr;
|
|
}
|
|
|
|
void envSetExitFuncPtr(LoaderReturnFn addr) {
|
|
g_loaderRetAddr = addr;
|
|
}
|
|
|
|
Result envSetNextLoad(const char* path, const char* argv)
|
|
{
|
|
if (g_nextLoadPath == NULL)
|
|
return MAKERESULT(Module_Libnx, LibnxError_NotInitialized);
|
|
|
|
strcpy(g_nextLoadPath, path);
|
|
|
|
if (g_nextLoadArgv != NULL)
|
|
{
|
|
if (argv == NULL)
|
|
g_nextLoadArgv[0] = '\0';
|
|
else
|
|
strcpy(g_nextLoadArgv, argv);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool envHasNextLoad(void) {
|
|
return g_nextLoadPath != NULL;
|
|
}
|
|
|
|
Result envGetLastLoadResult(void) {
|
|
return g_lastLoadResult;
|
|
}
|
|
|
|
bool envHasRandomSeed(void) {
|
|
return g_hasRandomSeed;
|
|
}
|
|
|
|
void envGetRandomSeed(u64 out[2]) {
|
|
out[0] = g_randomSeed[0];
|
|
out[1] = g_randomSeed[1];
|
|
}
|
|
|
|
AccountUid* envGetUserIdStorage(void) {
|
|
return g_userIdStorage;
|
|
}
|