libnx/nx/source/kernel/detect.c
fincs 61cc738730 Introduce hosversion.h - HOS version detection utilities
- Simplify kernel/detect.h logic; introduce detectKernelVersion()
- Use set:sys (if available) during __appInit in order to initialize
  the current HOS version
2019-02-18 21:48:41 +01:00

106 lines
2.9 KiB
C

// Copyright 2017 plutoo
#include "types.h"
#include "result.h"
#include "kernel/detect.h"
#include "kernel/mutex.h"
#include "kernel/svc.h"
#include <malloc.h>
static bool g_VersionCached;
static Mutex g_VersionMutex;
static int g_Version;
static bool g_JitKernelPatchCached;
static Mutex g_JitKernelPatchMutex;
static bool g_JitKernelPatchDetected;
static void _CacheVersion(void)
{
if (__atomic_load_n(&g_VersionCached, __ATOMIC_SEQ_CST))
return;
mutexLock(&g_VersionMutex);
if (g_VersionCached) {
mutexUnlock(&g_VersionMutex);
return;
}
u64 tmp;
g_Version = 1;
if (R_VALUE(svcGetInfo(&tmp, 12, INVALID_HANDLE, 0)) != KERNELRESULT(InvalidEnumValue))
g_Version = 2;
if (R_VALUE(svcGetInfo(&tmp, 18, INVALID_HANDLE, 0)) != KERNELRESULT(InvalidEnumValue))
g_Version = 3;
if (R_VALUE(svcGetInfo(&tmp, 19, INVALID_HANDLE, 0)) != KERNELRESULT(InvalidEnumValue))
g_Version = 4;
if (R_VALUE(svcGetInfo(&tmp, 20, INVALID_HANDLE, 0)) != KERNELRESULT(InvalidEnumValue))
g_Version = 5;
if (R_VALUE(svcGetInfo(&tmp, 21, INVALID_HANDLE, 0)) != KERNELRESULT(InvalidEnumValue))
g_Version = 6;
__atomic_store_n(&g_VersionCached, true, __ATOMIC_SEQ_CST);
mutexUnlock(&g_VersionMutex);
}
static void _CacheJitKernelPatch(void)
{
if (__atomic_load_n(&g_JitKernelPatchCached, __ATOMIC_SEQ_CST))
return;
mutexLock(&g_JitKernelPatchMutex);
if (g_JitKernelPatchCached) {
mutexUnlock(&g_JitKernelPatchMutex);
return;
}
void* heap = memalign(0x1000, 0x1000);
if (heap != NULL) {
Handle code;
Result rc;
rc = svcCreateCodeMemory(&code, heap, 0x1000);
if (R_SUCCEEDED(rc)) {
// On an unpatched kernel on 5.0.0 and above, this would return InvalidMemoryState (0xD401).
// It is not allowed for the creator-process of a CodeMemory object to use svcControlCodeMemory on it.
// If the patch is present, the function should return InvalidEnumValue (0xF001), because -1 is not a valid enum CodeOperation.
rc = svcControlCodeMemory(code, -1, 0, 0x1000, 0);
g_JitKernelPatchDetected = R_VALUE(rc) == KERNELRESULT(InvalidEnumValue);
__atomic_store_n(&g_JitKernelPatchCached, true, __ATOMIC_SEQ_CST);
svcCloseHandle(code);
}
free(heap);
}
mutexUnlock(&g_JitKernelPatchMutex);
}
int detectKernelVersion(void) {
_CacheVersion();
return g_Version;
}
bool detectDebugger(void) {
u64 tmp;
svcGetInfo(&tmp, 8, 0, 0);
return !!tmp;
}
bool detectJitKernelPatch(void) {
_CacheJitKernelPatch();
return g_JitKernelPatchDetected;
}
void detectIgnoreJitKernelPatch(void) {
mutexLock(&g_JitKernelPatchMutex);
g_JitKernelPatchDetected = false;
__atomic_store_n(&g_JitKernelPatchCached, true, __ATOMIC_SEQ_CST);
mutexUnlock(&g_JitKernelPatchMutex);
}