From 75603b005bb9163810a02376cd33854cd1b16ef9 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 22 Sep 2018 20:09:32 -0400 Subject: [PATCH 1/4] process/vm_manager: Amend API to allow reading parameters from NPDM metadata Rather than hard-code the address range to be 36-bit, we can derive the parameters from supplied NPDM metadata if the supplied exectuable supports it. This is the bare minimum necessary for this to be possible. The following commits will rework the memory code further to adjust to this. --- src/core/file_sys/program_metadata.cpp | 4 +- src/core/file_sys/program_metadata.h | 6 +- src/core/hle/kernel/process.cpp | 8 + src/core/hle/kernel/process.h | 12 ++ src/core/hle/kernel/vm_manager.cpp | 154 +++++++++++++++++- src/core/hle/kernel/vm_manager.h | 84 +++++++++- .../loader/deconstructed_rom_directory.cpp | 11 +- src/core/loader/elf.cpp | 8 - src/core/loader/nro.cpp | 5 - src/core/loader/nso.cpp | 5 - 10 files changed, 259 insertions(+), 38 deletions(-) diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp index 02319ce0f6..8903ed1d3f 100644 --- a/src/core/file_sys/program_metadata.cpp +++ b/src/core/file_sys/program_metadata.cpp @@ -83,10 +83,12 @@ void ProgramMetadata::Print() const { auto address_space = "Unknown"; switch (npdm_header.address_space_type) { - case ProgramAddressSpaceType::Is64Bit: + case ProgramAddressSpaceType::Is36Bit: + case ProgramAddressSpaceType::Is39Bit: address_space = "64-bit"; break; case ProgramAddressSpaceType::Is32Bit: + case ProgramAddressSpaceType::Is32BitNoMap: address_space = "32-bit"; break; } diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h index 1143e36c44..e4470d6f08 100644 --- a/src/core/file_sys/program_metadata.h +++ b/src/core/file_sys/program_metadata.h @@ -17,8 +17,10 @@ enum class ResultStatus : u16; namespace FileSys { enum class ProgramAddressSpaceType : u8 { - Is64Bit = 1, - Is32Bit = 2, + Is32Bit = 0, + Is36Bit = 1, + Is32BitNoMap = 2, + Is39Bit = 3, }; enum class ProgramFilePermission : u64 { diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 121f741fd1..f337f626fd 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -8,6 +8,7 @@ #include "common/common_funcs.h" #include "common/logging/log.h" #include "core/core.h" +#include "core/file_sys/program_metadata.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" @@ -34,14 +35,21 @@ SharedPtr Process::Create(KernelCore& kernel, std::string&& name) { process->name = std::move(name); process->flags.raw = 0; process->flags.memory_region.Assign(MemoryRegion::APPLICATION); + process->resource_limit = kernel.ResourceLimitForCategory(ResourceLimitCategory::APPLICATION); process->status = ProcessStatus::Created; process->program_id = 0; process->process_id = kernel.CreateNewProcessID(); + process->svc_access_mask.set(); kernel.AppendNewProcess(process); return process; } +void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { + program_id = metadata.GetTitleID(); + vm_manager.Reset(metadata.GetAddressSpaceType()); +} + void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) { for (std::size_t i = 0; i < len; ++i) { u32 descriptor = kernel_caps[i]; diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 04d74e5724..adb03c2288 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -17,6 +17,10 @@ #include "core/hle/kernel/thread.h" #include "core/hle/kernel/vm_manager.h" +namespace FileSys { +class ProgramMetadata; +} + namespace Kernel { class KernelCore; @@ -141,6 +145,14 @@ public: return process_id; } + /** + * Loads process-specifics configuration info with metadata provided + * by an executable. + * + * @param metadata The provided metadata to load process specific info. + */ + void LoadFromMetadata(const FileSys::ProgramMetadata& metadata); + /// Title ID corresponding to the process u64 program_id; diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 608cbd57bc..337f17b7bf 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -9,6 +9,7 @@ #include "common/logging/log.h" #include "core/arm/arm_interface.h" #include "core/core.h" +#include "core/file_sys/program_metadata.h" #include "core/hle/kernel/errors.h" #include "core/hle/kernel/vm_manager.h" #include "core/memory.h" @@ -54,25 +55,24 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const { } VMManager::VMManager() { - Reset(); + // Default to assuming a 39-bit address space. This way we have a sane + // starting point with executables that don't provide metadata. + Reset(FileSys::ProgramAddressSpaceType::Is39Bit); } VMManager::~VMManager() { - Reset(); + Reset(FileSys::ProgramAddressSpaceType::Is39Bit); } -void VMManager::Reset() { - vma_map.clear(); +void VMManager::Reset(FileSys::ProgramAddressSpaceType type) { + Clear(); + InitializeMemoryRegionRanges(type); // Initialize the map with a single free region covering the entire managed space. VirtualMemoryArea initial_vma; initial_vma.size = MAX_ADDRESS; vma_map.emplace(initial_vma.base, initial_vma); - page_table.pointers.fill(nullptr); - page_table.special_regions.clear(); - page_table.attributes.fill(Memory::PageType::Unmapped); - UpdatePageTableForVMA(initial_vma); } @@ -382,6 +382,84 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { } } +void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType type) { + u64 map_region_size = 0; + u64 heap_region_size = 0; + u64 new_map_region_size = 0; + u64 tls_io_region_size = 0; + + switch (type) { + case FileSys::ProgramAddressSpaceType::Is32Bit: + address_space_width = 32; + code_region_base = 0x200000; + code_region_end = code_region_base + 0x3FE00000; + map_region_size = 0x40000000; + heap_region_size = 0x40000000; + break; + case FileSys::ProgramAddressSpaceType::Is36Bit: + address_space_width = 36; + code_region_base = 0x8000000; + code_region_end = code_region_base + 0x78000000; + map_region_size = 0x180000000; + heap_region_size = 0x180000000; + break; + case FileSys::ProgramAddressSpaceType::Is32BitNoMap: + address_space_width = 32; + code_region_base = 0x200000; + code_region_end = code_region_base + 0x3FE00000; + map_region_size = 0; + heap_region_size = 0x80000000; + break; + case FileSys::ProgramAddressSpaceType::Is39Bit: + address_space_width = 39; + code_region_base = 0x8000000; + code_region_end = code_region_base + 0x80000000; + map_region_size = 0x1000000000; + heap_region_size = 0x180000000; + new_map_region_size = 0x80000000; + tls_io_region_size = 0x1000000000; + break; + default: + UNREACHABLE_MSG("Invalid address space type specified: {}", static_cast(type)); + return; + } + + address_space_base = 0; + address_space_end = 1ULL << address_space_width; + + map_region_base = code_region_end; + map_region_end = map_region_base + map_region_size; + + heap_region_base = map_region_end; + heap_region_end = heap_region_base + heap_region_size; + + new_map_region_base = heap_region_end; + new_map_region_end = new_map_region_base + new_map_region_size; + + tls_io_region_base = new_map_region_end; + tls_io_region_end = tls_io_region_base + tls_io_region_size; + + if (new_map_region_size == 0) { + new_map_region_base = address_space_base; + new_map_region_end = address_space_end; + } +} + +void VMManager::Clear() { + ClearVMAMap(); + ClearPageTable(); +} + +void VMManager::ClearVMAMap() { + vma_map.clear(); +} + +void VMManager::ClearPageTable() { + page_table.pointers.fill(nullptr); + page_table.special_regions.clear(); + page_table.attributes.fill(Memory::PageType::Unmapped); +} + u64 VMManager::GetTotalMemoryUsage() const { LOG_WARNING(Kernel, "(STUBBED) called"); return 0xF8000000; @@ -402,4 +480,64 @@ u64 VMManager::GetAddressSpaceSize() const { return MAX_ADDRESS; } +VAddr VMManager::GetCodeRegionBaseAddress() const { + return code_region_base; +} + +VAddr VMManager::GetCodeRegionEndAddress() const { + return code_region_end; +} + +u64 VMManager::GetCodeRegionSize() const { + return code_region_end - code_region_base; +} + +VAddr VMManager::GetHeapRegionBaseAddress() const { + return heap_region_base; +} + +VAddr VMManager::GetHeapRegionEndAddress() const { + return heap_region_end; +} + +u64 VMManager::GetHeapRegionSize() const { + return heap_region_end - heap_region_base; +} + +VAddr VMManager::GetMapRegionBaseAddress() const { + return map_region_base; +} + +VAddr VMManager::GetMapRegionEndAddress() const { + return map_region_end; +} + +u64 VMManager::GetMapRegionSize() const { + return map_region_end - map_region_base; +} + +VAddr VMManager::GetNewMapRegionBaseAddress() const { + return new_map_region_base; +} + +VAddr VMManager::GetNewMapRegionEndAddress() const { + return new_map_region_end; +} + +u64 VMManager::GetNewMapRegionSize() const { + return new_map_region_end - new_map_region_base; +} + +VAddr VMManager::GetTLSIORegionBaseAddress() const { + return tls_io_region_base; +} + +VAddr VMManager::GetTLSIORegionEndAddress() const { + return tls_io_region_end; +} + +u64 VMManager::GetTLSIORegionSize() const { + return tls_io_region_end - tls_io_region_base; +} + } // namespace Kernel diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index de75036c07..0ce240126d 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -12,6 +12,10 @@ #include "core/memory.h" #include "core/memory_hook.h" +namespace FileSys { +enum class ProgramAddressSpaceType : u8; +} + namespace Kernel { enum class VMAType : u8 { @@ -130,7 +134,7 @@ public: ~VMManager(); /// Clears the address space map, re-initializing with a single free area. - void Reset(); + void Reset(FileSys::ProgramAddressSpaceType type); /// Finds the VMA in which the given address is included in, or `vma_map.end()`. VMAHandle FindVMA(VAddr target) const; @@ -195,12 +199,57 @@ public: /// Gets the total heap usage, used by svcGetInfo u64 GetTotalHeapUsage() const; - /// Gets the total address space base address, used by svcGetInfo + /// Gets the address space base address, used by svcGetInfo VAddr GetAddressSpaceBaseAddr() const; /// Gets the total address space address size, used by svcGetInfo u64 GetAddressSpaceSize() const; + /// Gets the base address of the code region. + VAddr GetCodeRegionBaseAddress() const; + + /// Gets the end address of the code region. + VAddr GetCodeRegionEndAddress() const; + + /// Gets the total size of the code region in bytes. + u64 GetCodeRegionSize() const; + + /// Gets the base address of the heap region. + VAddr GetHeapRegionBaseAddress() const; + + /// Gets the end address of the heap region; + VAddr GetHeapRegionEndAddress() const; + + /// Gets the total size of the heap region in bytes. + u64 GetHeapRegionSize() const; + + /// Gets the base address of the map region. + VAddr GetMapRegionBaseAddress() const; + + /// Gets the end address of the map region. + VAddr GetMapRegionEndAddress() const; + + /// Gets the total size of the map region in bytes. + u64 GetMapRegionSize() const; + + /// Gets the base address of the new map region. + VAddr GetNewMapRegionBaseAddress() const; + + /// Gets the end address of the new map region. + VAddr GetNewMapRegionEndAddress() const; + + /// Gets the total size of the new map region in bytes. + u64 GetNewMapRegionSize() const; + + /// Gets the base address of the TLS IO region. + VAddr GetTLSIORegionBaseAddress() const; + + /// Gets the end address of the TLS IO region. + VAddr GetTLSIORegionEndAddress() const; + + /// Gets the total size of the TLS IO region in bytes. + u64 GetTLSIORegionSize() const; + /// Each VMManager has its own page table, which is set as the main one when the owning process /// is scheduled. Memory::PageTable page_table; @@ -240,5 +289,36 @@ private: /// Updates the pages corresponding to this VMA so they match the VMA's attributes. void UpdatePageTableForVMA(const VirtualMemoryArea& vma); + + /// Initializes memory region ranges to adhere to a given address space type. + void InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType type); + + /// Clears the underlying map and page table. + void Clear(); + + /// Clears out the VMA map, unmapping any previously mapped ranges. + void ClearVMAMap(); + + /// Clears out the page table + void ClearPageTable(); + + u32 address_space_width = 0; + VAddr address_space_base = 0; + VAddr address_space_end = 0; + + VAddr code_region_base = 0; + VAddr code_region_end = 0; + + VAddr heap_region_base = 0; + VAddr heap_region_end = 0; + + VAddr map_region_base = 0; + VAddr map_region_end = 0; + + VAddr new_map_region_base = 0; + VAddr new_map_region_end = 0; + + VAddr tls_io_region_base = 0; + VAddr tls_io_region_end = 0; }; } // namespace Kernel diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 2b8f781360..44d62ab7f4 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -14,7 +14,6 @@ #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" -#include "core/hle/kernel/resource_limit.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/deconstructed_rom_directory.h" #include "core/loader/nso.h" @@ -127,10 +126,13 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( metadata.Print(); const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()}; - if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit) { + if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit || + arch_bits == FileSys::ProgramAddressSpaceType::Is32BitNoMap) { return ResultStatus::Error32BitISA; } + process->LoadFromMetadata(metadata); + // Load NSO modules VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR}; for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", @@ -145,11 +147,6 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( } } - auto& kernel = Core::System::GetInstance().Kernel(); - process->program_id = metadata.GetTitleID(); - process->svc_access_mask.set(); - process->resource_limit = - kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION); process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()); diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 0e2af20b40..00d8a82b89 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -12,7 +12,6 @@ #include "core/core.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" -#include "core/hle/kernel/resource_limit.h" #include "core/loader/elf.h" #include "core/memory.h" @@ -400,13 +399,6 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr& process) { codeset->name = file->GetName(); process->LoadModule(codeset, codeset->entrypoint); - process->svc_access_mask.set(); - - // Attach the default resource limit (APPLICATION) to the process - auto& kernel = Core::System::GetInstance().Kernel(); - process->resource_limit = - kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION); - process->Run(codeset->entrypoint, 48, Memory::DEFAULT_STACK_SIZE); is_loaded = true; diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index c49ec34ab2..2385012eb8 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -16,7 +16,6 @@ #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" -#include "core/hle/kernel/resource_limit.h" #include "core/loader/nro.h" #include "core/memory.h" @@ -187,10 +186,6 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr& process) { return ResultStatus::ErrorLoadingNRO; } - auto& kernel = Core::System::GetInstance().Kernel(); - process->svc_access_mask.set(); - process->resource_limit = - kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION); process->Run(base_addr, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); is_loaded = true; diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 78a4438c47..9fd9933fb4 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -13,7 +13,6 @@ #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" -#include "core/hle/kernel/resource_limit.h" #include "core/loader/nso.h" #include "core/memory.h" @@ -162,10 +161,6 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr& process) { LoadModule(file, Memory::PROCESS_IMAGE_VADDR); LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), Memory::PROCESS_IMAGE_VADDR); - auto& kernel = Core::System::GetInstance().Kernel(); - process->svc_access_mask.set(); - process->resource_limit = - kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION); process->Run(Memory::PROCESS_IMAGE_VADDR, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); From 7fd598636e819d4e86874b20081945936a05c5f1 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 24 Sep 2018 10:29:56 -0400 Subject: [PATCH 2/4] memory: Dehardcode the use of a 36-bit address space Given games can also request a 32-bit or 39-bit address space, we shouldn't be hardcoding the address space range as 36-bit. --- src/core/arm/dynarmic/arm_dynarmic.cpp | 5 ++-- src/core/hle/kernel/vm_manager.cpp | 18 +++++++++---- src/core/hle/kernel/vm_manager.h | 3 +++ src/core/memory.cpp | 18 +++++++++++-- src/core/memory.h | 36 ++++++++++++++++---------- src/tests/core/arm/arm_test_common.cpp | 7 +++-- 6 files changed, 63 insertions(+), 24 deletions(-) diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index 7be5a38de5..928bbc0969 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp @@ -129,7 +129,8 @@ public: }; std::unique_ptr ARM_Dynarmic::MakeJit() const { - auto** const page_table = Core::CurrentProcess()->vm_manager.page_table.pointers.data(); + auto& current_process = Core::CurrentProcess(); + auto** const page_table = current_process->vm_manager.page_table.pointers.data(); Dynarmic::A64::UserConfig config; @@ -138,7 +139,7 @@ std::unique_ptr ARM_Dynarmic::MakeJit() const { // Memory config.page_table = reinterpret_cast(page_table); - config.page_table_address_space_bits = Memory::ADDRESS_SPACE_BITS; + config.page_table_address_space_bits = current_process->vm_manager.GetAddressSpaceWidth(); config.silently_mirror_page_table = false; // Multi-process state diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 337f17b7bf..20d06f0007 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -66,18 +66,21 @@ VMManager::~VMManager() { void VMManager::Reset(FileSys::ProgramAddressSpaceType type) { Clear(); + InitializeMemoryRegionRanges(type); + page_table.Resize(address_space_width); + // Initialize the map with a single free region covering the entire managed space. VirtualMemoryArea initial_vma; - initial_vma.size = MAX_ADDRESS; + initial_vma.size = address_space_end; vma_map.emplace(initial_vma.base, initial_vma); UpdatePageTableForVMA(initial_vma); } VMManager::VMAHandle VMManager::FindVMA(VAddr target) const { - if (target >= MAX_ADDRESS) { + if (target >= address_space_end) { return vma_map.end(); } else { return std::prev(vma_map.upper_bound(target)); @@ -291,7 +294,7 @@ ResultVal VMManager::CarveVMARange(VAddr target, u64 size) { const VAddr target_end = target + size; ASSERT(target_end >= target); - ASSERT(target_end <= MAX_ADDRESS); + ASSERT(target_end <= address_space_end); ASSERT(size > 0); VMAIter begin_vma = StripIterConstness(FindVMA(target)); @@ -455,9 +458,10 @@ void VMManager::ClearVMAMap() { } void VMManager::ClearPageTable() { - page_table.pointers.fill(nullptr); + std::fill(page_table.pointers.begin(), page_table.pointers.end(), nullptr); page_table.special_regions.clear(); - page_table.attributes.fill(Memory::PageType::Unmapped); + std::fill(page_table.attributes.begin(), page_table.attributes.end(), + Memory::PageType::Unmapped); } u64 VMManager::GetTotalMemoryUsage() const { @@ -480,6 +484,10 @@ u64 VMManager::GetAddressSpaceSize() const { return MAX_ADDRESS; } +u64 VMManager::GetAddressSpaceWidth() const { + return address_space_width; +} + VAddr VMManager::GetCodeRegionBaseAddress() const { return code_region_base; } diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 0ce240126d..581bf3d009 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -205,6 +205,9 @@ public: /// Gets the total address space address size, used by svcGetInfo u64 GetAddressSpaceSize() const; + /// Gets the address space width in bits. + u64 GetAddressSpaceWidth() const; + /// Gets the base address of the code region. VAddr GetCodeRegionBaseAddress() const; diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 316b468201..674ef08291 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -3,7 +3,6 @@ // Refer to the license.txt file included. #include -#include #include #include @@ -41,6 +40,21 @@ PageTable* GetCurrentPageTable() { return current_page_table; } +PageTable::PageTable() = default; + +PageTable::PageTable(std::size_t address_space_width_in_bits) { + Resize(address_space_width_in_bits); +} + +PageTable::~PageTable() = default; + +void PageTable::Resize(std::size_t address_space_width_in_bits) { + const std::size_t num_page_table_entries = 1ULL << (address_space_width_in_bits - PAGE_BITS); + + pointers.resize(num_page_table_entries); + attributes.resize(num_page_table_entries); +} + static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, PageType type) { LOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE, (base + size) * PAGE_SIZE); @@ -50,7 +64,7 @@ static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, Pa VAddr end = base + size; while (base != end) { - ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at {:016X}", base); + ASSERT_MSG(base < page_table.pointers.size(), "out of range mapping at {:016X}", base); page_table.attributes[base] = type; page_table.pointers[base] = memory; diff --git a/src/core/memory.h b/src/core/memory.h index 2a27c02518..739e5be94d 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -4,10 +4,10 @@ #pragma once -#include #include #include #include +#include #include #include "common/common_types.h" #include "core/memory_hook.h" @@ -23,10 +23,8 @@ namespace Memory { * be mapped. */ constexpr std::size_t PAGE_BITS = 12; -constexpr u64 PAGE_SIZE = 1 << PAGE_BITS; +constexpr u64 PAGE_SIZE = 1ULL << PAGE_BITS; constexpr u64 PAGE_MASK = PAGE_SIZE - 1; -constexpr std::size_t ADDRESS_SPACE_BITS = 36; -constexpr std::size_t PAGE_TABLE_NUM_ENTRIES = 1ULL << (ADDRESS_SPACE_BITS - PAGE_BITS); enum class PageType : u8 { /// Page is unmapped and should cause an access error. @@ -62,23 +60,35 @@ struct SpecialRegion { * mimics the way a real CPU page table works. */ struct PageTable { - /** - * Array of memory pointers backing each page. An entry can only be non-null if the - * corresponding entry in the `attributes` array is of type `Memory`. - */ - std::array pointers; + explicit PageTable(); + explicit PageTable(std::size_t address_space_width_in_bits); + ~PageTable(); /** - * Contains MMIO handlers that back memory regions whose entries in the `attribute` array is of - * type `Special`. + * Resizes the page table to be able to accomodate enough pages within + * a given address space. + * + * @param address_space_width_in_bits The address size width in bits. + */ + void Resize(std::size_t address_space_width_in_bits); + + /** + * Vector of memory pointers backing each page. An entry can only be non-null if the + * corresponding entry in the `attributes` vector is of type `Memory`. + */ + std::vector pointers; + + /** + * Contains MMIO handlers that back memory regions whose entries in the `attribute` vector is + * of type `Special`. */ boost::icl::interval_map> special_regions; /** - * Array of fine grained page attributes. If it is set to any value other than `Memory`, then + * Vector of fine grained page attributes. If it is set to any value other than `Memory`, then * the corresponding entry in `pointers` MUST be set to null. */ - std::array attributes; + std::vector attributes; }; /// Virtual user-space memory regions diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp index 7c69fc26e7..c17a122cd1 100644 --- a/src/tests/core/arm/arm_test_common.cpp +++ b/src/tests/core/arm/arm_test_common.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include + #include "core/core.h" #include "core/hle/kernel/process.h" #include "core/memory.h" @@ -16,9 +18,10 @@ TestEnvironment::TestEnvironment(bool mutable_memory_) Core::CurrentProcess() = Kernel::Process::Create(kernel, ""); page_table = &Core::CurrentProcess()->vm_manager.page_table; - page_table->pointers.fill(nullptr); + std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr); page_table->special_regions.clear(); - page_table->attributes.fill(Memory::PageType::Unmapped); + std::fill(page_table->attributes.begin(), page_table->attributes.end(), + Memory::PageType::Unmapped); Memory::MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory); Memory::MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory); From 6c6f95d071b25f2743fcb6652f4389c9e25a7506 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 24 Sep 2018 11:16:17 -0400 Subject: [PATCH 3/4] svc: Report correct memory-related values within some of the cases in svcGetInfo() Previously, these were reporting hardcoded values, but given the regions can change depending on the requested address spaces, these need to report the values that the memory manager contains. --- src/core/hle/kernel/svc.cpp | 42 ++++++++++++++++++++---------- src/core/hle/kernel/vm_manager.cpp | 12 +++++---- src/core/hle/kernel/vm_manager.h | 15 +++++------ 3 files changed, 41 insertions(+), 28 deletions(-) diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 0bc407098b..e0f5e3f39a 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -325,26 +325,27 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, info_sub_id, handle); - const auto& vm_manager = Core::CurrentProcess()->vm_manager; + const auto& current_process = Core::CurrentProcess(); + const auto& vm_manager = current_process->vm_manager; switch (static_cast(info_id)) { case GetInfoType::AllowedCpuIdBitmask: - *result = Core::CurrentProcess()->allowed_processor_mask; + *result = current_process->allowed_processor_mask; break; case GetInfoType::AllowedThreadPrioBitmask: - *result = Core::CurrentProcess()->allowed_thread_priority_mask; + *result = current_process->allowed_thread_priority_mask; break; case GetInfoType::MapRegionBaseAddr: - *result = Memory::MAP_REGION_VADDR; + *result = vm_manager.GetMapRegionBaseAddress(); break; case GetInfoType::MapRegionSize: - *result = Memory::MAP_REGION_SIZE; + *result = vm_manager.GetMapRegionSize(); break; case GetInfoType::HeapRegionBaseAddr: - *result = Memory::HEAP_VADDR; + *result = vm_manager.GetHeapRegionBaseAddress(); break; case GetInfoType::HeapRegionSize: - *result = Memory::HEAP_SIZE; + *result = vm_manager.GetHeapRegionSize(); break; case GetInfoType::TotalMemoryUsage: *result = vm_manager.GetTotalMemoryUsage(); @@ -359,22 +360,35 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) *result = 0; break; case GetInfoType::AddressSpaceBaseAddr: - *result = vm_manager.GetAddressSpaceBaseAddr(); + *result = vm_manager.GetCodeRegionBaseAddress(); break; - case GetInfoType::AddressSpaceSize: - *result = vm_manager.GetAddressSpaceSize(); + case GetInfoType::AddressSpaceSize: { + const u64 width = vm_manager.GetAddressSpaceWidth(); + + switch (width) { + case 32: + *result = 0xFFE00000; + break; + case 36: + *result = 0xFF8000000; + break; + case 39: + *result = 0x7FF8000000; + break; + } break; + } case GetInfoType::NewMapRegionBaseAddr: - *result = Memory::NEW_MAP_REGION_VADDR; + *result = vm_manager.GetNewMapRegionBaseAddress(); break; case GetInfoType::NewMapRegionSize: - *result = Memory::NEW_MAP_REGION_SIZE; + *result = vm_manager.GetNewMapRegionSize(); break; case GetInfoType::IsVirtualAddressMemoryEnabled: - *result = Core::CurrentProcess()->is_virtual_address_memory_enabled; + *result = current_process->is_virtual_address_memory_enabled; break; case GetInfoType::TitleId: - *result = Core::CurrentProcess()->program_id; + *result = current_process->program_id; break; case GetInfoType::PrivilegedProcessId: LOG_WARNING(Kernel_SVC, diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index 20d06f0007..e412309fdd 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp @@ -474,14 +474,16 @@ u64 VMManager::GetTotalHeapUsage() const { return 0x0; } -VAddr VMManager::GetAddressSpaceBaseAddr() const { - LOG_WARNING(Kernel, "(STUBBED) called"); - return 0x8000000; +VAddr VMManager::GetAddressSpaceBaseAddress() const { + return address_space_base; +} + +VAddr VMManager::GetAddressSpaceEndAddress() const { + return address_space_end; } u64 VMManager::GetAddressSpaceSize() const { - LOG_WARNING(Kernel, "(STUBBED) called"); - return MAX_ADDRESS; + return address_space_end - address_space_base; } u64 VMManager::GetAddressSpaceWidth() const { diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index 581bf3d009..015559a64c 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h @@ -114,12 +114,6 @@ struct VirtualMemoryArea { */ class VMManager final { public: - /** - * The maximum amount of address space managed by the kernel. - * @todo This was selected arbitrarily, and should be verified for Switch OS. - */ - static constexpr VAddr MAX_ADDRESS{0x1000000000ULL}; - /** * A map covering the entirety of the managed address space, keyed by the `base` field of each * VMA. It must always be modified by splitting or merging VMAs, so that the invariant @@ -199,10 +193,13 @@ public: /// Gets the total heap usage, used by svcGetInfo u64 GetTotalHeapUsage() const; - /// Gets the address space base address, used by svcGetInfo - VAddr GetAddressSpaceBaseAddr() const; + /// Gets the address space base address + VAddr GetAddressSpaceBaseAddress() const; - /// Gets the total address space address size, used by svcGetInfo + /// Gets the address space end address + VAddr GetAddressSpaceEndAddress() const; + + /// Gets the total address space address size in bytes u64 GetAddressSpaceSize() const; /// Gets the address space width in bits. From 83377113bfe7791483a1b67e06dd0f51620c04ec Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 24 Sep 2018 20:01:45 -0400 Subject: [PATCH 4/4] memory: Dehardcode the use of fixed memory range constants The locations of these can actually vary depending on the address space layout, so we shouldn't be using these when determining where to map memory or be using them as offsets for calculations. This keeps all the memory ranges flexible and malleable based off of the virtual memory manager instance state. --- src/core/gdbstub/gdbstub.cpp | 15 ++++++--- src/core/hle/kernel/process.cpp | 20 ++++++------ src/core/hle/kernel/shared_memory.cpp | 4 ++- src/core/hle/kernel/svc.cpp | 3 +- src/core/hle/kernel/thread.cpp | 3 +- .../loader/deconstructed_rom_directory.cpp | 7 ++--- src/core/loader/elf.cpp | 24 +++++++------- src/core/loader/nro.cpp | 7 +++-- src/core/loader/nso.cpp | 9 +++--- src/core/memory.cpp | 12 ++++--- src/core/memory.h | 31 +------------------ 11 files changed, 60 insertions(+), 75 deletions(-) diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 0ecdd9f821..d8c7b34922 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp @@ -37,7 +37,9 @@ #include "core/core.h" #include "core/core_cpu.h" #include "core/gdbstub/gdbstub.h" +#include "core/hle/kernel/process.h" #include "core/hle/kernel/scheduler.h" +#include "core/hle/kernel/vm_manager.h" #include "core/loader/loader.h" #include "core/memory.h" @@ -585,7 +587,8 @@ static void HandleQuery() { strlen("Xfer:features:read:target.xml:")) == 0) { SendReply(target_xml); } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) { - std::string buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR); + const VAddr base_address = Core::CurrentProcess()->vm_manager.GetCodeRegionBaseAddress(); + std::string buffer = fmt::format("TextSeg={:0x}", base_address); SendReply(buffer.c_str()); } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { std::string val = "m"; @@ -893,11 +896,11 @@ static void ReadMemory() { static u8 reply[GDB_BUFFER_SIZE - 4]; auto start_offset = command_buffer + 1; - auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); - VAddr addr = HexToLong(start_offset, static_cast(addr_pos - start_offset)); + const auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); + const VAddr addr = HexToLong(start_offset, static_cast(addr_pos - start_offset)); start_offset = addr_pos + 1; - u64 len = + const u64 len = HexToLong(start_offset, static_cast((command_buffer + command_length) - start_offset)); LOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len); @@ -906,7 +909,9 @@ static void ReadMemory() { SendReply("E01"); } - if (addr < Memory::PROCESS_IMAGE_VADDR || addr >= Memory::MAP_REGION_VADDR_END) { + const auto& vm_manager = Core::CurrentProcess()->vm_manager; + if (addr < vm_manager.GetCodeRegionBaseAddress() || + addr >= vm_manager.GetMapRegionEndAddress()) { return SendReply("E00"); } diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index f337f626fd..a8e3098ca4 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -127,7 +127,7 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { // TODO(bunnei): This is heap area that should be allocated by the kernel and not mapped as part // of the user address space. vm_manager - .MapMemoryBlock(Memory::STACK_AREA_VADDR_END - stack_size, + .MapMemoryBlock(vm_manager.GetTLSIORegionEndAddress() - stack_size, std::make_shared>(stack_size, 0), 0, stack_size, MemoryState::Mapped) .Unwrap(); @@ -193,6 +193,7 @@ static std::tuple FindFreeThreadLocalSlot( VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) { auto [available_page, available_slot, needs_allocation] = FindFreeThreadLocalSlot(tls_slots); + const VAddr tls_begin = vm_manager.GetTLSIORegionBaseAddress(); if (needs_allocation) { tls_slots.emplace_back(0); // The page is completely available at the start @@ -205,18 +206,17 @@ VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) { vm_manager.RefreshMemoryBlockMappings(tls_memory.get()); - vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE, - tls_memory, 0, Memory::PAGE_SIZE, MemoryState::ThreadLocal); + vm_manager.MapMemoryBlock(tls_begin + available_page * Memory::PAGE_SIZE, tls_memory, 0, + Memory::PAGE_SIZE, MemoryState::ThreadLocal); } tls_slots[available_page].set(available_slot); - return Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE + - available_slot * Memory::TLS_ENTRY_SIZE; + return tls_begin + available_page * Memory::PAGE_SIZE + available_slot * Memory::TLS_ENTRY_SIZE; } void Process::FreeTLSSlot(VAddr tls_address) { - const VAddr tls_base = tls_address - Memory::TLS_AREA_VADDR; + const VAddr tls_base = tls_address - vm_manager.GetTLSIORegionBaseAddress(); const VAddr tls_page = tls_base / Memory::PAGE_SIZE; const VAddr tls_slot = (tls_base % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; @@ -240,8 +240,8 @@ void Process::LoadModule(SharedPtr module_, VAddr base_addr) { } ResultVal Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { - if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || - target + size < target) { + if (target < vm_manager.GetHeapRegionBaseAddress() || + target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) { return ERR_INVALID_ADDRESS; } @@ -276,8 +276,8 @@ ResultVal Process::HeapAllocate(VAddr target, u64 size, VMAPermission per } ResultCode Process::HeapFree(VAddr target, u32 size) { - if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || - target + size < target) { + if (target < vm_manager.GetHeapRegionBaseAddress() || + target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) { return ERR_INVALID_ADDRESS; } diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index abb1d09cd3..9b78c8cb50 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -8,6 +8,7 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/hle/kernel/errors.h" +#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/shared_memory.h" #include "core/memory.h" @@ -71,7 +72,8 @@ SharedPtr SharedMemory::CreateForApplet( shared_memory->other_permissions = other_permissions; shared_memory->backing_block = std::move(heap_block); shared_memory->backing_block_offset = offset; - shared_memory->base_address = Memory::HEAP_VADDR + offset; + shared_memory->base_address = + kernel.CurrentProcess()->vm_manager.GetHeapRegionBaseAddress() + offset; return shared_memory; } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index e0f5e3f39a..c2b77eb493 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -51,8 +51,9 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { } auto& process = *Core::CurrentProcess(); + const VAddr heap_base = process.vm_manager.GetHeapRegionBaseAddress(); CASCADE_RESULT(*heap_addr, - process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite)); + process.HeapAllocate(heap_base, heap_size, VMAPermission::ReadWrite)); return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 315f653385..064ed908d1 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -262,8 +262,9 @@ SharedPtr SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 pri SetCurrentPageTable(&owner_process.vm_manager.page_table); // Initialize new "main" thread + const VAddr stack_top = owner_process.vm_manager.GetTLSIORegionEndAddress(); auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0, - Memory::STACK_AREA_VADDR_END, &owner_process); + stack_top, &owner_process); SharedPtr thread = std::move(thread_res).Unwrap(); diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 44d62ab7f4..7e8035d0fc 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -17,7 +17,6 @@ #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/deconstructed_rom_directory.h" #include "core/loader/nso.h" -#include "core/memory.h" namespace Loader { @@ -134,7 +133,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( process->LoadFromMetadata(metadata); // Load NSO modules - VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR}; + const VAddr base_address = process->vm_manager.GetCodeRegionBaseAddress(); + VAddr next_load_addr = base_address; for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { const FileSys::VirtualFile module_file = dir->GetFile(module); @@ -147,8 +147,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( } } - process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(), - metadata.GetMainThreadStackSize()); + process->Run(base_address, metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()); // Find the RomFS by searching for a ".romfs" file in this directory const auto& files = dir->GetFiles(); diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 00d8a82b89..ff1221574a 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -12,6 +12,7 @@ #include "core/core.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/vm_manager.h" #include "core/loader/elf.h" #include "core/memory.h" @@ -188,7 +189,7 @@ private: u32* sectionAddrs; bool relocate; - u32 entryPoint; + VAddr entryPoint; public: explicit ElfReader(void* ptr); @@ -204,13 +205,13 @@ public: ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); } - u32 GetEntryPoint() const { + VAddr GetEntryPoint() const { return entryPoint; } u32 GetFlags() const { return (u32)(header->e_flags); } - SharedPtr LoadInto(u32 vaddr); + SharedPtr LoadInto(VAddr vaddr); int GetNumSegments() const { return (int)(header->e_phnum); @@ -273,7 +274,7 @@ const char* ElfReader::GetSectionName(int section) const { return nullptr; } -SharedPtr ElfReader::LoadInto(u32 vaddr) { +SharedPtr ElfReader::LoadInto(VAddr vaddr) { LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx); // Should we relocate? @@ -288,11 +289,11 @@ SharedPtr ElfReader::LoadInto(u32 vaddr) { LOG_DEBUG(Loader, "{} segments:", header->e_phnum); // First pass : Get the bits into RAM - u32 base_addr = relocate ? vaddr : 0; + const VAddr base_addr = relocate ? vaddr : 0; - u32 total_image_size = 0; + u64 total_image_size = 0; for (unsigned int i = 0; i < header->e_phnum; ++i) { - Elf32_Phdr* p = &segments[i]; + const Elf32_Phdr* p = &segments[i]; if (p->p_type == PT_LOAD) { total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF; } @@ -305,7 +306,7 @@ SharedPtr ElfReader::LoadInto(u32 vaddr) { SharedPtr codeset = CodeSet::Create(kernel, ""); for (unsigned int i = 0; i < header->e_phnum; ++i) { - Elf32_Phdr* p = &segments[i]; + const Elf32_Phdr* p = &segments[i]; LOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type, p->p_vaddr, p->p_filesz, p->p_memsz); @@ -332,8 +333,8 @@ SharedPtr ElfReader::LoadInto(u32 vaddr) { continue; } - u32 segment_addr = base_addr + p->p_vaddr; - u32 aligned_size = (p->p_memsz + 0xFFF) & ~0xFFF; + const VAddr segment_addr = base_addr + p->p_vaddr; + const u32 aligned_size = (p->p_memsz + 0xFFF) & ~0xFFF; codeset_segment->offset = current_image_position; codeset_segment->addr = segment_addr; @@ -394,8 +395,9 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr& process) { if (buffer.size() != file->GetSize()) return ResultStatus::ErrorIncorrectELFFileSize; + const VAddr base_address = process->vm_manager.GetCodeRegionBaseAddress(); ElfReader elf_reader(&buffer[0]); - SharedPtr codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR); + SharedPtr codeset = elf_reader.LoadInto(base_address); codeset->name = file->GetName(); process->LoadModule(codeset, codeset->entrypoint); diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index 2385012eb8..b72871efa3 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -16,6 +16,7 @@ #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/vm_manager.h" #include "core/loader/nro.h" #include "core/memory.h" @@ -180,13 +181,13 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr& process) { } // Load NRO - static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR}; + const VAddr base_address = process->vm_manager.GetCodeRegionBaseAddress(); - if (!LoadNro(file, base_addr)) { + if (!LoadNro(file, base_address)) { return ResultStatus::ErrorLoadingNRO; } - process->Run(base_addr, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); + process->Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); is_loaded = true; return ResultStatus::Success; diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index 9fd9933fb4..1a6876a229 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -13,6 +13,7 @@ #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/vm_manager.h" #include "core/loader/nso.h" #include "core/memory.h" @@ -158,11 +159,11 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr& process) { } // Load module - LoadModule(file, Memory::PROCESS_IMAGE_VADDR); - LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), Memory::PROCESS_IMAGE_VADDR); + const VAddr base_address = process->vm_manager.GetCodeRegionBaseAddress(); + LoadModule(file, base_address); + LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); - process->Run(Memory::PROCESS_IMAGE_VADDR, Kernel::THREADPRIO_DEFAULT, - Memory::DEFAULT_STACK_SIZE); + process->Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); is_loaded = true; return ResultStatus::Success; diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 674ef08291..6430daad4b 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -14,11 +14,11 @@ #include "core/arm/arm_interface.h" #include "core/core.h" #include "core/hle/kernel/process.h" +#include "core/hle/kernel/vm_manager.h" #include "core/hle/lock.h" #include "core/memory.h" #include "core/memory_setup.h" #include "video_core/renderer_base.h" -#include "video_core/video_core.h" namespace Memory { @@ -337,7 +337,7 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) { return; } - VAddr end = start + size; + const VAddr end = start + size; const auto CheckRegion = [&](VAddr region_start, VAddr region_end) { if (start >= region_end || end <= region_start) { @@ -347,7 +347,7 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) { const VAddr overlap_start = std::max(start, region_start); const VAddr overlap_end = std::min(end, region_end); - const u64 overlap_size = overlap_end - overlap_start; + const VAddr overlap_size = overlap_end - overlap_start; auto& rasterizer = system_instance.Renderer().Rasterizer(); switch (mode) { @@ -363,8 +363,10 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) { } }; - CheckRegion(PROCESS_IMAGE_VADDR, PROCESS_IMAGE_VADDR_END); - CheckRegion(HEAP_VADDR, HEAP_VADDR_END); + const auto& vm_manager = Core::CurrentProcess()->vm_manager; + + CheckRegion(vm_manager.GetCodeRegionBaseAddress(), vm_manager.GetCodeRegionEndAddress()); + CheckRegion(vm_manager.GetHeapRegionBaseAddress(), vm_manager.GetHeapRegionEndAddress()); } u8 Read8(const VAddr addr) { diff --git a/src/core/memory.h b/src/core/memory.h index 739e5be94d..1acf5ce8cc 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -93,11 +93,6 @@ struct PageTable { /// Virtual user-space memory regions enum : VAddr { - /// Where the application text, data and bss reside. - PROCESS_IMAGE_VADDR = 0x08000000, - PROCESS_IMAGE_MAX_SIZE = 0x08000000, - PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE, - /// Read-only page containing kernel and system configuration values. CONFIG_MEMORY_VADDR = 0x1FF80000, CONFIG_MEMORY_SIZE = 0x00001000, @@ -108,36 +103,12 @@ enum : VAddr { SHARED_PAGE_SIZE = 0x00001000, SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE, - /// Area where TLS (Thread-Local Storage) buffers are allocated. - TLS_AREA_VADDR = 0x40000000, + /// TLS (Thread-Local Storage) related. TLS_ENTRY_SIZE = 0x200, - TLS_AREA_SIZE = 0x10000000, - TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE, /// Application stack - STACK_AREA_VADDR = TLS_AREA_VADDR_END, - STACK_AREA_SIZE = 0x10000000, - STACK_AREA_VADDR_END = STACK_AREA_VADDR + STACK_AREA_SIZE, DEFAULT_STACK_SIZE = 0x100000, - /// Application heap - /// Size is confirmed to be a static value on fw 3.0.0 - HEAP_VADDR = 0x108000000, - HEAP_SIZE = 0x180000000, - HEAP_VADDR_END = HEAP_VADDR + HEAP_SIZE, - - /// New map region - /// Size is confirmed to be a static value on fw 3.0.0 - NEW_MAP_REGION_VADDR = HEAP_VADDR_END, - NEW_MAP_REGION_SIZE = 0x80000000, - NEW_MAP_REGION_VADDR_END = NEW_MAP_REGION_VADDR + NEW_MAP_REGION_SIZE, - - /// Map region - /// Size is confirmed to be a static value on fw 3.0.0 - MAP_REGION_VADDR = NEW_MAP_REGION_VADDR_END, - MAP_REGION_SIZE = 0x1000000000, - MAP_REGION_VADDR_END = MAP_REGION_VADDR + MAP_REGION_SIZE, - /// Kernel Virtual Address Range KERNEL_REGION_VADDR = 0xFFFFFF8000000000, KERNEL_REGION_SIZE = 0x7FFFE00000,