From 5c5cf2f8e000d1bf4fc12ff20351aa60367cb563 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Thu, 9 Jul 2015 22:52:15 -0300 Subject: Core: Properly configure address space when loading a binary The code now properly configures the process image to match the loaded binary segments (code, rodata, data) instead of just blindly allocating a large chunk of dummy memory. --- src/core/hle/kernel/kernel.h | 1 + src/core/hle/kernel/process.cpp | 38 +++++++++++++++++++++++++++------ src/core/hle/kernel/process.h | 43 +++++++++++++++++++++++++++++++------- src/core/hle/kernel/vm_manager.cpp | 14 +++++++++++++ src/core/hle/kernel/vm_manager.h | 6 +++++- 5 files changed, 88 insertions(+), 14 deletions(-) (limited to 'src/core/hle') diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index b29260b5..4c4486c1 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -47,6 +47,7 @@ enum class HandleType : u32 { Semaphore = 10, Timer = 11, ResourceLimit = 12, + CodeSet = 13, }; enum { diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index b0e75ba5..a7892c65 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -5,24 +5,39 @@ #include "common/assert.h" #include "common/common_funcs.h" #include "common/logging/log.h" +#include "common/make_unique.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/thread.h" +#include "core/hle/kernel/vm_manager.h" +#include "core/mem_map.h" #include "core/memory.h" namespace Kernel { +SharedPtr CodeSet::Create(std::string name, u64 program_id) { + SharedPtr codeset(new CodeSet); + + codeset->name = std::move(name); + codeset->program_id = program_id; + + return codeset; +} + +CodeSet::CodeSet() {} +CodeSet::~CodeSet() {} + u32 Process::next_process_id; -SharedPtr Process::Create(std::string name, u64 program_id) { +SharedPtr Process::Create(SharedPtr code_set) { SharedPtr process(new Process); - process->name = std::move(name); - process->program_id = program_id; - + process->codeset = std::move(code_set); process->flags.raw = 0; process->flags.memory_region = MemoryRegion::APPLICATION; + process->address_space = Common::make_unique(); + Memory::InitLegacyAddressSpace(*process->address_space); return process; } @@ -87,8 +102,19 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) { } } -void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { - Kernel::SetupMainThread(entry_point, main_thread_priority); +void Process::Run(s32 main_thread_priority, u32 stack_size) { + auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) { + auto vma = address_space->MapMemoryBlock(segment.addr, codeset->memory, + segment.offset, segment.size, memory_state).Unwrap(); + address_space->Reprotect(vma, permissions); + }; + + MapSegment(codeset->code, VMAPermission::ReadExecute, MemoryState::Code); + MapSegment(codeset->rodata, VMAPermission::Read, MemoryState::Code); + MapSegment(codeset->data, VMAPermission::ReadWrite, MemoryState::Private); + + address_space->LogLayout(); + Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority); } Kernel::Process::Process() {} diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 674f5093..92fa0fa6 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -47,23 +47,51 @@ union ProcessFlags { }; class ResourceLimit; +class VMManager; + +struct CodeSet final : public Object { + static SharedPtr Create(std::string name, u64 program_id); + + std::string GetTypeName() const override { return "CodeSet"; } + std::string GetName() const override { return name; } + + static const HandleType HANDLE_TYPE = HandleType::CodeSet; + HandleType GetHandleType() const override { return HANDLE_TYPE; } + + /// Name of the process + std::string name; + /// Title ID corresponding to the process + u64 program_id; + + std::shared_ptr> memory; + + struct Segment { + size_t offset = 0; + VAddr addr = 0; + u32 size = 0; + }; + + Segment code, rodata, data; + VAddr entrypoint; + +private: + CodeSet(); + ~CodeSet() override; +}; class Process final : public Object { public: - static SharedPtr Create(std::string name, u64 program_id); + static SharedPtr Create(SharedPtr code_set); std::string GetTypeName() const override { return "Process"; } - std::string GetName() const override { return name; } + std::string GetName() const override { return codeset->name; } static const HandleType HANDLE_TYPE = HandleType::Process; HandleType GetHandleType() const override { return HANDLE_TYPE; } static u32 next_process_id; - /// Name of the process - std::string name; - /// Title ID corresponding to the process - u64 program_id; + SharedPtr codeset; /// Resource limit descriptor for this process SharedPtr resource_limit; @@ -81,6 +109,7 @@ public: /// Bitmask of the used TLS slots std::bitset<300> used_tls_slots; + std::unique_ptr address_space; /** * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them @@ -91,7 +120,7 @@ public: /** * Applies address space changes and launches the process main thread. */ - void Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size); + void Run(s32 main_thread_priority, u32 stack_size); private: Process(); diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index ec437cd6..205cc7b5 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -35,6 +35,10 @@ VMManager::VMManager() { Reset(); } +VMManager::~VMManager() { + Reset(); +} + void VMManager::Reset() { vma_map.clear(); @@ -130,6 +134,16 @@ void VMManager::Reprotect(VMAHandle vma_handle, VMAPermission new_perms) { MergeAdjacent(iter); } +void VMManager::LogLayout() const { + for (const auto& p : vma_map) { + const VirtualMemoryArea& vma = p.second; + LOG_DEBUG(Kernel, "%08X - %08X size: %8X %c%c%c", vma.base, vma.base + vma.size, vma.size, + (u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-', + (u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-', + (u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-'); + } +} + VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle & iter) { // This uses a neat C++ trick to convert a const_iterator to a regular iterator, given // non-const access to its container. diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 271e2333..b3795a94 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -101,7 +101,7 @@ struct VirtualMemoryArea { * - http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory/ * - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/ */ -class VMManager { +class VMManager final { // TODO(yuriks): Make page tables switchable to support multiple VMManagers public: /** @@ -121,6 +121,7 @@ public: using VMAHandle = decltype(vma_map)::const_iterator; VMManager(); + ~VMManager(); /// Clears the address space map, re-initializing with a single free area. void Reset(); @@ -168,6 +169,9 @@ public: /// Changes the permissions of the given VMA. void Reprotect(VMAHandle vma, VMAPermission new_perms); + /// Dumps the address space layout to the log, for debugging + void LogLayout() const; + private: using VMAIter = decltype(vma_map)::iterator; -- cgit v1.2.3