From b34b9ba0e4df1cfbf979c68cb28734a539fef9ee Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 26 Apr 2018 18:04:30 -0600 Subject: [PATCH] Loader: Greatly simplify mapping logic, add CodeMemory mapper. --- stratosphere/loader/source/ldr_map.cpp | 241 ++++++++++++++----------- stratosphere/loader/source/ldr_map.hpp | 19 ++ 2 files changed, 150 insertions(+), 110 deletions(-) diff --git a/stratosphere/loader/source/ldr_map.cpp b/stratosphere/loader/source/ldr_map.cpp index 9913c39f8..7ac554e16 100644 --- a/stratosphere/loader/source/ldr_map.cpp +++ b/stratosphere/loader/source/ldr_map.cpp @@ -1,6 +1,7 @@ #include #include "ldr_map.hpp" +#include "ldr_random.hpp" Result MapUtils::LocateSpaceForMap(u64 *out, u64 out_size) { if (kernelAbove200()) { @@ -11,38 +12,26 @@ Result MapUtils::LocateSpaceForMap(u64 *out, u64 out_size) { } +Result MapUtils::MapCodeMemoryForProcess(Handle process_h, bool is_64_bit_address_space, u64 base_address, u64 size, u64 *out_code_memory_address) { + if (kernelAbove200()) { + return MapCodeMemoryForProcessModern(process_h, base_address, size, out_code_memory_address); + } else { + return MapCodeMemoryForProcessDeprecated(process_h, is_64_bit_address_space, base_address, size, out_code_memory_address); + } +} + Result MapUtils::LocateSpaceForMapModern(u64 *out, u64 out_size) { MemoryInfo mem_info = {0}; + AddressSpaceInfo address_space = {0}; u32 page_info = 0; - u64 heap_base = 0, heap_size = 0, heap_end = 0; - u64 map_base = 0, map_size = 0, map_end = 0; - u64 addspace_base = 0, addspace_size = 0, addspace_end = 0; u64 cur_base = 0, cur_end = 0; Result rc; - if (R_FAILED((rc = svcGetInfo(&heap_base, 4, CUR_PROCESS_HANDLE, 0)))) { + if (R_FAILED((rc = GetAddressSpaceInfo(&address_space, CUR_PROCESS_HANDLE)))) { return rc; } - if (R_FAILED((rc = svcGetInfo(&heap_size, 5, CUR_PROCESS_HANDLE, 0)))) { - return rc; - } - if (R_FAILED((rc = svcGetInfo(&map_base, 2, CUR_PROCESS_HANDLE, 0)))) { - return rc; - } - if (R_FAILED((rc = svcGetInfo(&map_size, 3, CUR_PROCESS_HANDLE, 0)))) { - return rc; - } - if (R_FAILED((rc = svcGetInfo(&addspace_base, 12, CUR_PROCESS_HANDLE, 0)))) { - return rc; - } - if (R_FAILED((rc = svcGetInfo(&addspace_size, 13, CUR_PROCESS_HANDLE, 0)))) { - return rc; - } - heap_end = heap_base + heap_size; - map_end = map_base + map_size; - addspace_end = addspace_base + addspace_size; - cur_base = addspace_base; + cur_base = address_space.addspace_base; rc = 0xD001; cur_end = cur_base + out_size; @@ -50,98 +39,40 @@ Result MapUtils::LocateSpaceForMapModern(u64 *out, u64 out_size) { return rc; } - if (heap_size) { - if (map_size) { - while (true) { - if (cur_end - 1 < heap_base || heap_end - 1 < cur_base) { - if (cur_end - 1 < map_base || map_end - 1 < cur_base) { - if (R_FAILED(svcQueryMemory(&mem_info, &page_info, cur_base))) { - /* TODO: panic. */ - } - if (mem_info.type == 0 && mem_info.addr - cur_base + mem_info.size >= out_size) { - *out = cur_base; - return 0x0; - } - if (mem_info.addr + mem_info.size <= cur_base) { - return rc; - } - cur_base = mem_info.addr + mem_info.size; - if (cur_base >= addspace_end) { - return rc; - } - } else { - if (map_end == cur_base) { - return rc; - } - cur_base = map_end; - } - } else { - if (heap_end == cur_base) { - return rc; - } - cur_base = heap_end; - } - cur_end = cur_base + out_size; - if (cur_base + out_size <= cur_base) { - return rc; - } + while (true) { + if (address_space.heap_size && (address_space.heap_base <= cur_end - 1 && cur_base <= address_space.heap_end - 1)) { + /* If we overlap the heap region, go to the end of the heap region. */ + if (cur_base == address_space.heap_end) { + return rc; } + cur_base = address_space.heap_end; + } else if (address_space.map_size && (address_space.map_base <= cur_end - 1 && cur_base <= address_space.map_end - 1)) { + /* If we overlap the map region, go to the end of the map region. */ + if (cur_base == address_space.map_end) { + return rc; + } + cur_base = address_space.map_end; } else { - while (true) { - if (cur_end - 1 < heap_base || heap_end - 1 < cur_base) { - if (R_FAILED(svcQueryMemory(&mem_info, &page_info, cur_base))) { - /* TODO: panic. */ - } - if (mem_info.type == 0 && mem_info.addr - cur_base + mem_info.size >= out_size) { - *out = cur_base; - return 0x0; - } - if (mem_info.addr + mem_info.size <= cur_base) { - return rc; - } - cur_base = mem_info.addr + mem_info.size; - if (cur_base >= addspace_end) { - return rc; - } - } else { - if (heap_end == cur_base) { - return rc; - } - cur_base = heap_end; - } - cur_end = cur_base + out_size; - if (cur_base + out_size <= cur_base) { - return rc; - } + if (R_FAILED(svcQueryMemory(&mem_info, &page_info, cur_base))) { + /* TODO: panic. */ + } + if (mem_info.type == 0 && mem_info.addr - cur_base + mem_info.size >= out_size) { + *out = cur_base; + return 0x0; + } + if (mem_info.addr + mem_info.size <= cur_base) { + return rc; + } + cur_base = mem_info.addr + mem_info.size; + if (cur_base >= address_space.addspace_end) { + return rc; } } - } else { - while (cur_end > cur_base) { - if (map_size && cur_end - 1 >= map_base && map_end - 1 >= cur_base) { - if (cur_base == map_end) { - return rc; - } - cur_base = map_end; - } else { - if (R_FAILED(svcQueryMemory(&mem_info, &page_info, cur_base))) { - /* TODO: panic. */ - } - if (mem_info.type == 0 && mem_info.addr - cur_base + mem_info.size >= out_size) { - *out = cur_base; - return 0x0; - } - if (mem_info.addr + mem_info.size <= cur_base) { - return rc; - } - cur_base = mem_info.addr + mem_info.size; - if (cur_base >= addspace_end) { - return rc; - } - } - cur_end = cur_base + out_size; + cur_end = cur_base + out_size; + if (cur_base + out_size <= cur_base) { + return rc; } - } - return rc; + } } @@ -177,4 +108,94 @@ Result MapUtils::LocateSpaceForMapDeprecated(u64 *out, u64 out_size) { } } return rc; +} + +Result MapUtils::MapCodeMemoryForProcessModern(Handle process_h, u64 base_address, u64 size, u64 *out_code_memory_address) { + AddressSpaceInfo address_space = {0}; + Result rc; + + if (R_FAILED((rc = GetAddressSpaceInfo(&address_space, CUR_PROCESS_HANDLE)))) { + return rc; + } + + if (size > address_space.addspace_size) { + return 0x6609; + } + + u64 try_address; + for (unsigned int i = 0; i < 0x200; i++) { + while (true) { + try_address = address_space.addspace_base + (RandomUtils::GetRandomU64((u64)(address_space.addspace_size - size) >> 12) << 12); + if (address_space.heap_size && (address_space.heap_base <= try_address + size - 1 && try_address <= address_space.heap_end - 1)) { + continue; + } + if (address_space.map_size && (address_space.map_base <= try_address + size - 1 && try_address <= address_space.map_end - 1)) { + continue; + } + break; + } + rc = svcMapProcessCodeMemory(process_h, try_address, base_address, size); + if (rc != 0xD401) { + break; + } + } + if (R_SUCCEEDED(rc)) { + *out_code_memory_address = try_address; + } + return rc; +} + +Result MapUtils::MapCodeMemoryForProcessDeprecated(Handle process_h, bool is_64_bit_address_space, u64 base_address, u64 size, u64 *out_code_memory_address) { + Result rc; + u64 addspace_base, addspace_size; + if (is_64_bit_address_space) { + addspace_base = 0x8000000ULL; + addspace_size = 0x78000000ULL; + } else { + addspace_base = 0x200000ULL; + addspace_size = 0x3FE0000ULL; + } + + if (size > addspace_size) { + return 0x6609; + } + + u64 try_address; + for (unsigned int i = 0; i < 0x200; i++) { + try_address = addspace_base + (RandomUtils::GetRandomU64((u64)(addspace_size - size) >> 12) << 12); + rc = svcMapProcessCodeMemory(process_h, try_address, base_address, size); + if (rc != 0xD401) { + break; + } + } + if (R_SUCCEEDED(rc)) { + *out_code_memory_address = try_address; + } + return rc; +} + +Result MapUtils::GetAddressSpaceInfo(AddressSpaceInfo *out, Handle process_h) { + Result rc; + if (R_FAILED((rc = svcGetInfo(&out->heap_base, 4, CUR_PROCESS_HANDLE, 0)))) { + return rc; + } + if (R_FAILED((rc = svcGetInfo(&out->heap_size, 5, CUR_PROCESS_HANDLE, 0)))) { + return rc; + } + if (R_FAILED((rc = svcGetInfo(&out->map_base, 2, CUR_PROCESS_HANDLE, 0)))) { + return rc; + } + if (R_FAILED((rc = svcGetInfo(&out->map_size, 3, CUR_PROCESS_HANDLE, 0)))) { + return rc; + } + if (R_FAILED((rc = svcGetInfo(&out->addspace_base, 12, CUR_PROCESS_HANDLE, 0)))) { + return rc; + } + if (R_FAILED((rc = svcGetInfo(&out->addspace_size, 13, CUR_PROCESS_HANDLE, 0)))) { + return rc; + } + out->heap_end = out->heap_base + out->heap_size; + out->map_end = out->map_base + out->map_size; + out->addspace_end = out->addspace_base + out->addspace_size; + return 0; } \ No newline at end of file diff --git a/stratosphere/loader/source/ldr_map.hpp b/stratosphere/loader/source/ldr_map.hpp index bca18a47d..301b8f4ac 100644 --- a/stratosphere/loader/source/ldr_map.hpp +++ b/stratosphere/loader/source/ldr_map.hpp @@ -1,9 +1,28 @@ #pragma once #include +#include "ldr_registration.hpp" + class MapUtils { public: + struct AddressSpaceInfo { + u64 heap_base; + u64 heap_size; + u64 heap_end; + u64 map_base; + u64 map_size; + u64 map_end; + u64 addspace_base; + u64 addspace_size; + u64 addspace_end; + }; + static Result GetAddressSpaceInfo(AddressSpaceInfo *out, Handle process_h); static Result LocateSpaceForMapDeprecated(u64 *out, u64 out_size); static Result LocateSpaceForMapModern(u64 *out, u64 out_size); static Result LocateSpaceForMap(u64 *out, u64 out_size); + + + static Result MapCodeMemoryForProcessDeprecated(Handle process_h, bool is_64_bit_address_space, u64 base_address, u64 size, u64 *out_code_memory_address); + static Result MapCodeMemoryForProcessModern(Handle process_h, u64 base_address, u64 size, u64 *out_code_memory_address); + static Result MapCodeMemoryForProcess(Handle process_h, bool is_64_bit_address_space, u64 base_address, u64 size, u64 *out_code_memory_address); }; \ No newline at end of file