diff --git a/nx/include/switch/kernel/virtmem.h b/nx/include/switch/kernel/virtmem.h index 92d2f205..c4f80404 100644 --- a/nx/include/switch/kernel/virtmem.h +++ b/nx/include/switch/kernel/virtmem.h @@ -44,3 +44,12 @@ void* virtmemFindAslr(size_t size, size_t guard_size); * @note The virtual memory manager mutex must be held during the find-and-map process (see \ref virtmemLock and \ref virtmemUnlock). */ void* virtmemFindStack(size_t size, size_t guard_size); + +/** + * @brief Finds a random slice of free code memory address space. + * @param size Desired size of the slice (rounded up to page alignment). + * @param guard_size Desired size of the unmapped guard areas surrounding the slice (rounded up to page alignment). + * @return Pointer to the slice of address space, or NULL on failure. + * @note The virtual memory manager mutex must be held during the find-and-map process (see \ref virtmemLock and \ref virtmemUnlock). + */ +void* virtmemFindCodeMemory(size_t size, size_t guard_size); diff --git a/nx/source/kernel/virtmem.c b/nx/source/kernel/virtmem.c index 74a48275..1258da6a 100644 --- a/nx/source/kernel/virtmem.c +++ b/nx/source/kernel/virtmem.c @@ -22,6 +22,7 @@ static MemRegion g_AslrRegion; static MemRegion g_StackRegion; static uintptr_t g_SequentialAddr; +static bool g_IsLegacyKernel; static Result _memregionInitWithInfo(MemRegion* r, InfoType id0_addr, InfoType id0_sz) { u64 base; @@ -141,6 +142,7 @@ void virtmemSetup(void) { else { // [1.0.0] doesn't expose aslr/stack region information so we have to do this dirty hack to detect it. // Forgive me. + g_IsLegacyKernel = true; rc = svcUnmapMemory((void*)0xFFFFFFFFFFFFE000UL, (void*)0xFFFFFE000UL, 0x1000); if (rc == KERNELRESULT(InvalidMemoryState)) { // Invalid src-address error means that a valid 36-bit address was rejected. @@ -228,3 +230,9 @@ void* virtmemFindStack(size_t size, size_t guard_size) { if (!mutexIsLockedByCurrentThread(&g_VirtmemMutex)) return NULL; return _memregionFindRandom(&g_StackRegion, size, guard_size); } + +void* virtmemFindCodeMemory(size_t size, size_t guard_size) { + if (!mutexIsLockedByCurrentThread(&g_VirtmemMutex)) return NULL; + // [1.0.0] requires CodeMemory to be mapped within the stack region. + return _memregionFindRandom(g_IsLegacyKernel ? &g_StackRegion : &g_AslrRegion, size, guard_size); +}