From a96f862f119877923cbf55bd873adb6516bd79b6 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Tue, 24 Apr 2018 06:01:32 -0600 Subject: [PATCH] Loader: Implement most of LoadNsosIntoProcessMemory --- stratosphere/loader/source/ldr_nso.cpp | 70 ++++++++++++++++++- stratosphere/loader/source/ldr_nso.hpp | 3 + .../loader/source/ldr_process_creation.cpp | 6 ++ 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/stratosphere/loader/source/ldr_nso.cpp b/stratosphere/loader/source/ldr_nso.cpp index 782ad6ba8..6df1ee8c9 100644 --- a/stratosphere/loader/source/ldr_nso.cpp +++ b/stratosphere/loader/source/ldr_nso.cpp @@ -2,6 +2,7 @@ #include #include #include "ldr_nso.hpp" +#include "ldr_map.hpp" #include "ldr_random.hpp" static NsoUtils::NsoHeader g_nso_headers[NSO_NUM_MAX] = {0}; @@ -168,4 +169,71 @@ Result NsoUtils::CalculateNsoLoadExtents(u32 addspace_type, u32 args_size, NsoLo } return 0x0; -} \ No newline at end of file +} + + +Result NsoUtils::LoadNsoSegment(unsigned int index, unsigned int segment, FILE *f_nso, u8 *map_base) { + /* TODO */ + return 0xA09; +} + +Result NsoUtils::LoadNsosIntoProcessMemory(Handle process_h, u64 title_id, NsoLoadExtents *extents, u8 *args, u32 args_size) { + Result rc = 0xA09; + for (unsigned int i = 0; i < NSO_NUM_MAX; i++) { + if (g_nso_present[i]) { + u64 map_addr = 0; + if (R_FAILED((rc = MapUtils::LocateSpaceForMap(&map_addr, extents->nso_sizes[i])))) { + return rc; + } + + u8 *map_base = (u8 *)map_addr; + + if (R_FAILED((rc = svcMapProcessMemory(map_base, process_h, extents->nso_addresses[i], extents->nso_sizes[i])))) { + return rc; + } + + FILE *f_nso = OpenNso(i, title_id); + if (f_nso == NULL) { + /* Is there a better error to return here? */ + return 0xA09; + } + for (unsigned int seg = 0; seg < 3; seg++) { + if (R_FAILED((rc = LoadNsoSegment(i, seg, f_nso, map_base)))) { + fclose(f_nso); + svcUnmapProcessMemory(map_base, process_h, extents->nso_addresses[i], extents->nso_sizes[i]); + return rc; + } + } + fclose(f_nso); + /* Zero out memory before .text. */ + u64 text_base = 0, text_start = g_nso_headers[i].segments[0].dst_offset; + std::fill(map_base + text_base, map_base + text_start, 0); + /* Zero out memory before .rodata. */ + u64 ro_base = text_start + g_nso_headers[i].segments[0].decomp_size, ro_start = g_nso_headers[i].segments[1].dst_offset; + std::fill(map_base + ro_base, map_base + ro_start, 0); + /* Zero out memory before .rwdata. */ + u64 rw_base = ro_start + g_nso_headers[i].segments[1].decomp_size, rw_start = g_nso_headers[i].segments[2].dst_offset; + std::fill(map_base + rw_base, map_base + rw_start, 0); + /* Zero out .bss. */ + u64 bss_base = rw_base + g_nso_headers[i].segments[2].decomp_size, bss_size = g_nso_headers[i].segments[2].align_or_total_size; + std::fill(map_base + bss_base, map_base + bss_base + bss_size, 0); + + if (R_FAILED((rc = svcUnmapProcessMemory(map_base, process_h, extents->nso_addresses[i], extents->nso_sizes[i])))) { + return rc; + } + + for (unsigned int seg = 0; seg < 3; seg++) { + u64 size = g_nso_headers[i].segments[seg].decomp_size; + size += 0xFFF; + size &= ~0xFFFULL; + const static unsigned int segment_perms[3] = {5, 1, 3}; + if (R_FAILED((rc = svcSetProcessMemoryPermission(process_h, extents->nso_addresses[i] + g_nso_headers[i].segments[seg].dst_offset, size, segment_perms[seg])))) { + return rc; + } + } + } + } + + /* TODO: Map in arguments, here. */ + return rc; +} diff --git a/stratosphere/loader/source/ldr_nso.hpp b/stratosphere/loader/source/ldr_nso.hpp index e20d6b7ee..f26998496 100644 --- a/stratosphere/loader/source/ldr_nso.hpp +++ b/stratosphere/loader/source/ldr_nso.hpp @@ -82,4 +82,7 @@ class NsoUtils { static Result LoadNsoHeaders(u64 title_id); static Result ValidateNsoLoadSet(); static Result CalculateNsoLoadExtents(u32 addspace_type, u32 args_size, NsoLoadExtents *extents); + + static Result LoadNsoSegment(unsigned int index, unsigned int segment, FILE *f_nso, u8 *map_base); + static Result LoadNsosIntoProcessMemory(Handle process_h, u64 title_id, NsoLoadExtents *extents, u8 *args, u32 args_size); }; \ No newline at end of file diff --git a/stratosphere/loader/source/ldr_process_creation.cpp b/stratosphere/loader/source/ldr_process_creation.cpp index 9d876e07b..59cf04ec0 100644 --- a/stratosphere/loader/source/ldr_process_creation.cpp +++ b/stratosphere/loader/source/ldr_process_creation.cpp @@ -159,6 +159,12 @@ Result ProcessCreation::CreateProcess(Handle *out_process_h, u64 index, char *nc goto CREATE_PROCESS_END; } + /* Load all NSOs into Process memory, and set permissions accordingly. */ + if (launch_item == NULL) { + NsoUtils::LoadNsosIntoProcessMemory(process_h, npdm_info.aci0->title_id, &nso_extents, (u8 *)launch_item->args, launch_item->arg_size); + } else { + NsoUtils::LoadNsosIntoProcessMemory(process_h, npdm_info.aci0->title_id, &nso_extents, NULL, 0); + } /* TODO: For each NSO, call svcMapProcessMemory, load the NSO into memory there (validating it), and then svcUnmapProcessMemory. */ /* TODO: svcSetProcessMemoryPermission for each memory segment in the new process. */