Просмотр исходного кода

Merge pull request #1395 from lioncash/vm

process/vm_manager: Initial modifications to load NPDM metadata
bunnei 7 лет назад
Родитель
Сommit
f7b69d61f2

+ 3 - 2
src/core/arm/dynarmic/arm_dynarmic.cpp

@@ -129,7 +129,8 @@ public:
 };
 };
 
 
 std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
 std::unique_ptr<Dynarmic::A64::Jit> 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;
     Dynarmic::A64::UserConfig config;
 
 
@@ -138,7 +139,7 @@ std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
 
 
     // Memory
     // Memory
     config.page_table = reinterpret_cast<void**>(page_table);
     config.page_table = reinterpret_cast<void**>(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;
     config.silently_mirror_page_table = false;
 
 
     // Multi-process state
     // Multi-process state

+ 3 - 1
src/core/file_sys/program_metadata.cpp

@@ -83,10 +83,12 @@ void ProgramMetadata::Print() const {
 
 
     auto address_space = "Unknown";
     auto address_space = "Unknown";
     switch (npdm_header.address_space_type) {
     switch (npdm_header.address_space_type) {
-    case ProgramAddressSpaceType::Is64Bit:
+    case ProgramAddressSpaceType::Is36Bit:
+    case ProgramAddressSpaceType::Is39Bit:
         address_space = "64-bit";
         address_space = "64-bit";
         break;
         break;
     case ProgramAddressSpaceType::Is32Bit:
     case ProgramAddressSpaceType::Is32Bit:
+    case ProgramAddressSpaceType::Is32BitNoMap:
         address_space = "32-bit";
         address_space = "32-bit";
         break;
         break;
     }
     }

+ 4 - 2
src/core/file_sys/program_metadata.h

@@ -17,8 +17,10 @@ enum class ResultStatus : u16;
 namespace FileSys {
 namespace FileSys {
 
 
 enum class ProgramAddressSpaceType : u8 {
 enum class ProgramAddressSpaceType : u8 {
-    Is64Bit = 1,
-    Is32Bit = 2,
+    Is32Bit = 0,
+    Is36Bit = 1,
+    Is32BitNoMap = 2,
+    Is39Bit = 3,
 };
 };
 
 
 enum class ProgramFilePermission : u64 {
 enum class ProgramFilePermission : u64 {

+ 10 - 5
src/core/gdbstub/gdbstub.cpp

@@ -37,7 +37,9 @@
 #include "core/core.h"
 #include "core/core.h"
 #include "core/core_cpu.h"
 #include "core/core_cpu.h"
 #include "core/gdbstub/gdbstub.h"
 #include "core/gdbstub/gdbstub.h"
+#include "core/hle/kernel/process.h"
 #include "core/hle/kernel/scheduler.h"
 #include "core/hle/kernel/scheduler.h"
+#include "core/hle/kernel/vm_manager.h"
 #include "core/loader/loader.h"
 #include "core/loader/loader.h"
 #include "core/memory.h"
 #include "core/memory.h"
 
 
@@ -585,7 +587,8 @@ static void HandleQuery() {
                        strlen("Xfer:features:read:target.xml:")) == 0) {
                        strlen("Xfer:features:read:target.xml:")) == 0) {
         SendReply(target_xml);
         SendReply(target_xml);
     } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) {
     } 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());
         SendReply(buffer.c_str());
     } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) {
     } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) {
         std::string val = "m";
         std::string val = "m";
@@ -893,11 +896,11 @@ static void ReadMemory() {
     static u8 reply[GDB_BUFFER_SIZE - 4];
     static u8 reply[GDB_BUFFER_SIZE - 4];
 
 
     auto start_offset = command_buffer + 1;
     auto start_offset = command_buffer + 1;
-    auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
-    VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
+    const auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
+    const VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
 
 
     start_offset = addr_pos + 1;
     start_offset = addr_pos + 1;
-    u64 len =
+    const u64 len =
         HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset));
         HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset));
 
 
     LOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len);
     LOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len);
@@ -906,7 +909,9 @@ static void ReadMemory() {
         SendReply("E01");
         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");
         return SendReply("E00");
     }
     }
 
 

+ 18 - 10
src/core/hle/kernel/process.cpp

@@ -8,6 +8,7 @@
 #include "common/common_funcs.h"
 #include "common/common_funcs.h"
 #include "common/logging/log.h"
 #include "common/logging/log.h"
 #include "core/core.h"
 #include "core/core.h"
+#include "core/file_sys/program_metadata.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/process.h"
@@ -34,14 +35,21 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) {
     process->name = std::move(name);
     process->name = std::move(name);
     process->flags.raw = 0;
     process->flags.raw = 0;
     process->flags.memory_region.Assign(MemoryRegion::APPLICATION);
     process->flags.memory_region.Assign(MemoryRegion::APPLICATION);
+    process->resource_limit = kernel.ResourceLimitForCategory(ResourceLimitCategory::APPLICATION);
     process->status = ProcessStatus::Created;
     process->status = ProcessStatus::Created;
     process->program_id = 0;
     process->program_id = 0;
     process->process_id = kernel.CreateNewProcessID();
     process->process_id = kernel.CreateNewProcessID();
+    process->svc_access_mask.set();
 
 
     kernel.AppendNewProcess(process);
     kernel.AppendNewProcess(process);
     return 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) {
 void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) {
     for (std::size_t i = 0; i < len; ++i) {
     for (std::size_t i = 0; i < len; ++i) {
         u32 descriptor = kernel_caps[i];
         u32 descriptor = kernel_caps[i];
@@ -119,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
     // TODO(bunnei): This is heap area that should be allocated by the kernel and not mapped as part
     // of the user address space.
     // of the user address space.
     vm_manager
     vm_manager
-        .MapMemoryBlock(Memory::STACK_AREA_VADDR_END - stack_size,
+        .MapMemoryBlock(vm_manager.GetTLSIORegionEndAddress() - stack_size,
                         std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size,
                         std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size,
                         MemoryState::Mapped)
                         MemoryState::Mapped)
         .Unwrap();
         .Unwrap();
@@ -185,6 +193,7 @@ static std::tuple<std::size_t, std::size_t, bool> FindFreeThreadLocalSlot(
 
 
 VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) {
 VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) {
     auto [available_page, available_slot, needs_allocation] = FindFreeThreadLocalSlot(tls_slots);
     auto [available_page, available_slot, needs_allocation] = FindFreeThreadLocalSlot(tls_slots);
+    const VAddr tls_begin = vm_manager.GetTLSIORegionBaseAddress();
 
 
     if (needs_allocation) {
     if (needs_allocation) {
         tls_slots.emplace_back(0); // The page is completely available at the start
         tls_slots.emplace_back(0); // The page is completely available at the start
@@ -197,18 +206,17 @@ VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) {
 
 
         vm_manager.RefreshMemoryBlockMappings(tls_memory.get());
         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);
     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) {
 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_page = tls_base / Memory::PAGE_SIZE;
     const VAddr tls_slot = (tls_base % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
     const VAddr tls_slot = (tls_base % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
 
 
@@ -232,8 +240,8 @@ void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
 }
 }
 
 
 ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
 ResultVal<VAddr> 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;
         return ERR_INVALID_ADDRESS;
     }
     }
 
 
@@ -268,8 +276,8 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission per
 }
 }
 
 
 ResultCode Process::HeapFree(VAddr target, u32 size) {
 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;
         return ERR_INVALID_ADDRESS;
     }
     }
 
 

+ 12 - 0
src/core/hle/kernel/process.h

@@ -17,6 +17,10 @@
 #include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/thread.h"
 #include "core/hle/kernel/vm_manager.h"
 #include "core/hle/kernel/vm_manager.h"
 
 
+namespace FileSys {
+class ProgramMetadata;
+}
+
 namespace Kernel {
 namespace Kernel {
 
 
 class KernelCore;
 class KernelCore;
@@ -141,6 +145,14 @@ public:
         return process_id;
         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
     /// Title ID corresponding to the process
     u64 program_id;
     u64 program_id;
 
 

+ 3 - 1
src/core/hle/kernel/shared_memory.cpp

@@ -8,6 +8,7 @@
 #include "common/logging/log.h"
 #include "common/logging/log.h"
 #include "core/core.h"
 #include "core/core.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/errors.h"
+#include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/shared_memory.h"
 #include "core/hle/kernel/shared_memory.h"
 #include "core/memory.h"
 #include "core/memory.h"
 
 
@@ -71,7 +72,8 @@ SharedPtr<SharedMemory> SharedMemory::CreateForApplet(
     shared_memory->other_permissions = other_permissions;
     shared_memory->other_permissions = other_permissions;
     shared_memory->backing_block = std::move(heap_block);
     shared_memory->backing_block = std::move(heap_block);
     shared_memory->backing_block_offset = offset;
     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;
     return shared_memory;
 }
 }

+ 30 - 15
src/core/hle/kernel/svc.cpp

@@ -51,8 +51,9 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
     }
     }
 
 
     auto& process = *Core::CurrentProcess();
     auto& process = *Core::CurrentProcess();
+    const VAddr heap_base = process.vm_manager.GetHeapRegionBaseAddress();
     CASCADE_RESULT(*heap_addr,
     CASCADE_RESULT(*heap_addr,
-                   process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite));
+                   process.HeapAllocate(heap_base, heap_size, VMAPermission::ReadWrite));
     return RESULT_SUCCESS;
     return RESULT_SUCCESS;
 }
 }
 
 
@@ -325,26 +326,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,
     LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
               info_sub_id, handle);
               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<GetInfoType>(info_id)) {
     switch (static_cast<GetInfoType>(info_id)) {
     case GetInfoType::AllowedCpuIdBitmask:
     case GetInfoType::AllowedCpuIdBitmask:
-        *result = Core::CurrentProcess()->allowed_processor_mask;
+        *result = current_process->allowed_processor_mask;
         break;
         break;
     case GetInfoType::AllowedThreadPrioBitmask:
     case GetInfoType::AllowedThreadPrioBitmask:
-        *result = Core::CurrentProcess()->allowed_thread_priority_mask;
+        *result = current_process->allowed_thread_priority_mask;
         break;
         break;
     case GetInfoType::MapRegionBaseAddr:
     case GetInfoType::MapRegionBaseAddr:
-        *result = Memory::MAP_REGION_VADDR;
+        *result = vm_manager.GetMapRegionBaseAddress();
         break;
         break;
     case GetInfoType::MapRegionSize:
     case GetInfoType::MapRegionSize:
-        *result = Memory::MAP_REGION_SIZE;
+        *result = vm_manager.GetMapRegionSize();
         break;
         break;
     case GetInfoType::HeapRegionBaseAddr:
     case GetInfoType::HeapRegionBaseAddr:
-        *result = Memory::HEAP_VADDR;
+        *result = vm_manager.GetHeapRegionBaseAddress();
         break;
         break;
     case GetInfoType::HeapRegionSize:
     case GetInfoType::HeapRegionSize:
-        *result = Memory::HEAP_SIZE;
+        *result = vm_manager.GetHeapRegionSize();
         break;
         break;
     case GetInfoType::TotalMemoryUsage:
     case GetInfoType::TotalMemoryUsage:
         *result = vm_manager.GetTotalMemoryUsage();
         *result = vm_manager.GetTotalMemoryUsage();
@@ -359,22 +361,35 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
         *result = 0;
         *result = 0;
         break;
         break;
     case GetInfoType::AddressSpaceBaseAddr:
     case GetInfoType::AddressSpaceBaseAddr:
-        *result = vm_manager.GetAddressSpaceBaseAddr();
+        *result = vm_manager.GetCodeRegionBaseAddress();
         break;
         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;
         break;
+    }
     case GetInfoType::NewMapRegionBaseAddr:
     case GetInfoType::NewMapRegionBaseAddr:
-        *result = Memory::NEW_MAP_REGION_VADDR;
+        *result = vm_manager.GetNewMapRegionBaseAddress();
         break;
         break;
     case GetInfoType::NewMapRegionSize:
     case GetInfoType::NewMapRegionSize:
-        *result = Memory::NEW_MAP_REGION_SIZE;
+        *result = vm_manager.GetNewMapRegionSize();
         break;
         break;
     case GetInfoType::IsVirtualAddressMemoryEnabled:
     case GetInfoType::IsVirtualAddressMemoryEnabled:
-        *result = Core::CurrentProcess()->is_virtual_address_memory_enabled;
+        *result = current_process->is_virtual_address_memory_enabled;
         break;
         break;
     case GetInfoType::TitleId:
     case GetInfoType::TitleId:
-        *result = Core::CurrentProcess()->program_id;
+        *result = current_process->program_id;
         break;
         break;
     case GetInfoType::PrivilegedProcessId:
     case GetInfoType::PrivilegedProcessId:
         LOG_WARNING(Kernel_SVC,
         LOG_WARNING(Kernel_SVC,

+ 2 - 1
src/core/hle/kernel/thread.cpp

@@ -262,8 +262,9 @@ SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 pri
     SetCurrentPageTable(&owner_process.vm_manager.page_table);
     SetCurrentPageTable(&owner_process.vm_manager.page_table);
 
 
     // Initialize new "main" thread
     // 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,
     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> thread = std::move(thread_res).Unwrap();
     SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
 
 

+ 164 - 16
src/core/hle/kernel/vm_manager.cpp

@@ -9,6 +9,7 @@
 #include "common/logging/log.h"
 #include "common/logging/log.h"
 #include "core/arm/arm_interface.h"
 #include "core/arm/arm_interface.h"
 #include "core/core.h"
 #include "core/core.h"
+#include "core/file_sys/program_metadata.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/errors.h"
 #include "core/hle/kernel/vm_manager.h"
 #include "core/hle/kernel/vm_manager.h"
 #include "core/memory.h"
 #include "core/memory.h"
@@ -54,30 +55,32 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
 }
 }
 
 
 VMManager::VMManager() {
 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() {
 VMManager::~VMManager() {
-    Reset();
+    Reset(FileSys::ProgramAddressSpaceType::Is39Bit);
 }
 }
 
 
-void VMManager::Reset() {
-    vma_map.clear();
+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.
     // Initialize the map with a single free region covering the entire managed space.
     VirtualMemoryArea initial_vma;
     VirtualMemoryArea initial_vma;
-    initial_vma.size = MAX_ADDRESS;
+    initial_vma.size = address_space_end;
     vma_map.emplace(initial_vma.base, initial_vma);
     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);
     UpdatePageTableForVMA(initial_vma);
 }
 }
 
 
 VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
 VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
-    if (target >= MAX_ADDRESS) {
+    if (target >= address_space_end) {
         return vma_map.end();
         return vma_map.end();
     } else {
     } else {
         return std::prev(vma_map.upper_bound(target));
         return std::prev(vma_map.upper_bound(target));
@@ -291,7 +294,7 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u64 size) {
 
 
     const VAddr target_end = target + size;
     const VAddr target_end = target + size;
     ASSERT(target_end >= target);
     ASSERT(target_end >= target);
-    ASSERT(target_end <= MAX_ADDRESS);
+    ASSERT(target_end <= address_space_end);
     ASSERT(size > 0);
     ASSERT(size > 0);
 
 
     VMAIter begin_vma = StripIterConstness(FindVMA(target));
     VMAIter begin_vma = StripIterConstness(FindVMA(target));
@@ -382,6 +385,85 @@ 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<u32>(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() {
+    std::fill(page_table.pointers.begin(), page_table.pointers.end(), nullptr);
+    page_table.special_regions.clear();
+    std::fill(page_table.attributes.begin(), page_table.attributes.end(),
+              Memory::PageType::Unmapped);
+}
+
 u64 VMManager::GetTotalMemoryUsage() const {
 u64 VMManager::GetTotalMemoryUsage() const {
     LOG_WARNING(Kernel, "(STUBBED) called");
     LOG_WARNING(Kernel, "(STUBBED) called");
     return 0xF8000000;
     return 0xF8000000;
@@ -392,14 +474,80 @@ u64 VMManager::GetTotalHeapUsage() const {
     return 0x0;
     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 {
 u64 VMManager::GetAddressSpaceSize() const {
-    LOG_WARNING(Kernel, "(STUBBED) called");
-    return MAX_ADDRESS;
+    return address_space_end - address_space_base;
+}
+
+u64 VMManager::GetAddressSpaceWidth() const {
+    return address_space_width;
+}
+
+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
 } // namespace Kernel

+ 90 - 10
src/core/hle/kernel/vm_manager.h

@@ -12,6 +12,10 @@
 #include "core/memory.h"
 #include "core/memory.h"
 #include "core/memory_hook.h"
 #include "core/memory_hook.h"
 
 
+namespace FileSys {
+enum class ProgramAddressSpaceType : u8;
+}
+
 namespace Kernel {
 namespace Kernel {
 
 
 enum class VMAType : u8 {
 enum class VMAType : u8 {
@@ -110,12 +114,6 @@ struct VirtualMemoryArea {
  */
  */
 class VMManager final {
 class VMManager final {
 public:
 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
      * 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
      * VMA. It must always be modified by splitting or merging VMAs, so that the invariant
@@ -130,7 +128,7 @@ public:
     ~VMManager();
     ~VMManager();
 
 
     /// Clears the address space map, re-initializing with a single free area.
     /// 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()`.
     /// Finds the VMA in which the given address is included in, or `vma_map.end()`.
     VMAHandle FindVMA(VAddr target) const;
     VMAHandle FindVMA(VAddr target) const;
@@ -195,12 +193,63 @@ public:
     /// Gets the total heap usage, used by svcGetInfo
     /// Gets the total heap usage, used by svcGetInfo
     u64 GetTotalHeapUsage() const;
     u64 GetTotalHeapUsage() const;
 
 
-    /// Gets the total 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;
     u64 GetAddressSpaceSize() const;
 
 
+    /// Gets the address space width in bits.
+    u64 GetAddressSpaceWidth() 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
     /// Each VMManager has its own page table, which is set as the main one when the owning process
     /// is scheduled.
     /// is scheduled.
     Memory::PageTable page_table;
     Memory::PageTable page_table;
@@ -240,5 +289,36 @@ private:
 
 
     /// Updates the pages corresponding to this VMA so they match the VMA's attributes.
     /// Updates the pages corresponding to this VMA so they match the VMA's attributes.
     void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
     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
 } // namespace Kernel

+ 7 - 11
src/core/loader/deconstructed_rom_directory.cpp

@@ -14,11 +14,9 @@
 #include "core/gdbstub/gdbstub.h"
 #include "core/gdbstub/gdbstub.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/process.h"
-#include "core/hle/kernel/resource_limit.h"
 #include "core/hle/service/filesystem/filesystem.h"
 #include "core/hle/service/filesystem/filesystem.h"
 #include "core/loader/deconstructed_rom_directory.h"
 #include "core/loader/deconstructed_rom_directory.h"
 #include "core/loader/nso.h"
 #include "core/loader/nso.h"
-#include "core/memory.h"
 
 
 namespace Loader {
 namespace Loader {
 
 
@@ -127,12 +125,16 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
     metadata.Print();
     metadata.Print();
 
 
     const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()};
     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;
         return ResultStatus::Error32BitISA;
     }
     }
 
 
+    process->LoadFromMetadata(metadata);
+
     // Load NSO modules
     // 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",
     for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",
                                "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) {
                                "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) {
         const FileSys::VirtualFile module_file = dir->GetFile(module);
         const FileSys::VirtualFile module_file = dir->GetFile(module);
@@ -145,13 +147,7 @@ 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());
+    process->Run(base_address, metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize());
 
 
     // Find the RomFS by searching for a ".romfs" file in this directory
     // Find the RomFS by searching for a ".romfs" file in this directory
     const auto& files = dir->GetFiles();
     const auto& files = dir->GetFiles();

+ 13 - 19
src/core/loader/elf.cpp

@@ -12,7 +12,7 @@
 #include "core/core.h"
 #include "core/core.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/process.h"
-#include "core/hle/kernel/resource_limit.h"
+#include "core/hle/kernel/vm_manager.h"
 #include "core/loader/elf.h"
 #include "core/loader/elf.h"
 #include "core/memory.h"
 #include "core/memory.h"
 
 
@@ -189,7 +189,7 @@ private:
 
 
     u32* sectionAddrs;
     u32* sectionAddrs;
     bool relocate;
     bool relocate;
-    u32 entryPoint;
+    VAddr entryPoint;
 
 
 public:
 public:
     explicit ElfReader(void* ptr);
     explicit ElfReader(void* ptr);
@@ -205,13 +205,13 @@ public:
     ElfMachine GetMachine() const {
     ElfMachine GetMachine() const {
         return (ElfMachine)(header->e_machine);
         return (ElfMachine)(header->e_machine);
     }
     }
-    u32 GetEntryPoint() const {
+    VAddr GetEntryPoint() const {
         return entryPoint;
         return entryPoint;
     }
     }
     u32 GetFlags() const {
     u32 GetFlags() const {
         return (u32)(header->e_flags);
         return (u32)(header->e_flags);
     }
     }
-    SharedPtr<CodeSet> LoadInto(u32 vaddr);
+    SharedPtr<CodeSet> LoadInto(VAddr vaddr);
 
 
     int GetNumSegments() const {
     int GetNumSegments() const {
         return (int)(header->e_phnum);
         return (int)(header->e_phnum);
@@ -274,7 +274,7 @@ const char* ElfReader::GetSectionName(int section) const {
     return nullptr;
     return nullptr;
 }
 }
 
 
-SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
+SharedPtr<CodeSet> ElfReader::LoadInto(VAddr vaddr) {
     LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx);
     LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx);
 
 
     // Should we relocate?
     // Should we relocate?
@@ -289,11 +289,11 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
     LOG_DEBUG(Loader, "{} segments:", header->e_phnum);
     LOG_DEBUG(Loader, "{} segments:", header->e_phnum);
 
 
     // First pass : Get the bits into RAM
     // 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) {
     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) {
         if (p->p_type == PT_LOAD) {
             total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF;
             total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF;
         }
         }
@@ -306,7 +306,7 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
     SharedPtr<CodeSet> codeset = CodeSet::Create(kernel, "");
     SharedPtr<CodeSet> codeset = CodeSet::Create(kernel, "");
 
 
     for (unsigned int i = 0; i < header->e_phnum; ++i) {
     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,
         LOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type,
                   p->p_vaddr, p->p_filesz, p->p_memsz);
                   p->p_vaddr, p->p_filesz, p->p_memsz);
 
 
@@ -333,8 +333,8 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
                 continue;
                 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->offset = current_image_position;
             codeset_segment->addr = segment_addr;
             codeset_segment->addr = segment_addr;
@@ -395,18 +395,12 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
     if (buffer.size() != file->GetSize())
     if (buffer.size() != file->GetSize())
         return ResultStatus::ErrorIncorrectELFFileSize;
         return ResultStatus::ErrorIncorrectELFFileSize;
 
 
+    const VAddr base_address = process->vm_manager.GetCodeRegionBaseAddress();
     ElfReader elf_reader(&buffer[0]);
     ElfReader elf_reader(&buffer[0]);
-    SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR);
+    SharedPtr<CodeSet> codeset = elf_reader.LoadInto(base_address);
     codeset->name = file->GetName();
     codeset->name = file->GetName();
 
 
     process->LoadModule(codeset, codeset->entrypoint);
     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);
     process->Run(codeset->entrypoint, 48, Memory::DEFAULT_STACK_SIZE);
 
 
     is_loaded = true;
     is_loaded = true;

+ 4 - 8
src/core/loader/nro.cpp

@@ -16,7 +16,7 @@
 #include "core/gdbstub/gdbstub.h"
 #include "core/gdbstub/gdbstub.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/process.h"
-#include "core/hle/kernel/resource_limit.h"
+#include "core/hle/kernel/vm_manager.h"
 #include "core/loader/nro.h"
 #include "core/loader/nro.h"
 #include "core/memory.h"
 #include "core/memory.h"
 
 
@@ -181,17 +181,13 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
     }
     }
 
 
     // Load NRO
     // 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;
         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);
+    process->Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
 
 
     is_loaded = true;
     is_loaded = true;
     return ResultStatus::Success;
     return ResultStatus::Success;

+ 5 - 9
src/core/loader/nso.cpp

@@ -13,7 +13,7 @@
 #include "core/gdbstub/gdbstub.h"
 #include "core/gdbstub/gdbstub.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/kernel.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/process.h"
-#include "core/hle/kernel/resource_limit.h"
+#include "core/hle/kernel/vm_manager.h"
 #include "core/loader/nso.h"
 #include "core/loader/nso.h"
 #include "core/memory.h"
 #include "core/memory.h"
 
 
@@ -159,15 +159,11 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
     }
     }
 
 
     // Load module
     // 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);
 
 
-    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);
+    process->Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
 
 
     is_loaded = true;
     is_loaded = true;
     return ResultStatus::Success;
     return ResultStatus::Success;

+ 23 - 7
src/core/memory.cpp

@@ -3,7 +3,6 @@
 // Refer to the license.txt file included.
 // Refer to the license.txt file included.
 
 
 #include <algorithm>
 #include <algorithm>
-#include <array>
 #include <cstring>
 #include <cstring>
 #include <utility>
 #include <utility>
 
 
@@ -15,11 +14,11 @@
 #include "core/arm/arm_interface.h"
 #include "core/arm/arm_interface.h"
 #include "core/core.h"
 #include "core/core.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/process.h"
+#include "core/hle/kernel/vm_manager.h"
 #include "core/hle/lock.h"
 #include "core/hle/lock.h"
 #include "core/memory.h"
 #include "core/memory.h"
 #include "core/memory_setup.h"
 #include "core/memory_setup.h"
 #include "video_core/renderer_base.h"
 #include "video_core/renderer_base.h"
-#include "video_core/video_core.h"
 
 
 namespace Memory {
 namespace Memory {
 
 
@@ -41,6 +40,21 @@ PageTable* GetCurrentPageTable() {
     return current_page_table;
     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) {
 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,
     LOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE,
               (base + size) * 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;
     VAddr end = base + size;
     while (base != end) {
     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.attributes[base] = type;
         page_table.pointers[base] = memory;
         page_table.pointers[base] = memory;
@@ -323,7 +337,7 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) {
         return;
         return;
     }
     }
 
 
-    VAddr end = start + size;
+    const VAddr end = start + size;
 
 
     const auto CheckRegion = [&](VAddr region_start, VAddr region_end) {
     const auto CheckRegion = [&](VAddr region_start, VAddr region_end) {
         if (start >= region_end || end <= region_start) {
         if (start >= region_end || end <= region_start) {
@@ -333,7 +347,7 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) {
 
 
         const VAddr overlap_start = std::max(start, region_start);
         const VAddr overlap_start = std::max(start, region_start);
         const VAddr overlap_end = std::min(end, region_end);
         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();
         auto& rasterizer = system_instance.Renderer().Rasterizer();
         switch (mode) {
         switch (mode) {
@@ -349,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) {
 u8 Read8(const VAddr addr) {

+ 22 - 41
src/core/memory.h

@@ -4,10 +4,10 @@
 
 
 #pragma once
 #pragma once
 
 
-#include <array>
 #include <cstddef>
 #include <cstddef>
 #include <string>
 #include <string>
 #include <tuple>
 #include <tuple>
+#include <vector>
 #include <boost/icl/interval_map.hpp>
 #include <boost/icl/interval_map.hpp>
 #include "common/common_types.h"
 #include "common/common_types.h"
 #include "core/memory_hook.h"
 #include "core/memory_hook.h"
@@ -23,10 +23,8 @@ namespace Memory {
  * be mapped.
  * be mapped.
  */
  */
 constexpr std::size_t PAGE_BITS = 12;
 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 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 {
 enum class PageType : u8 {
     /// Page is unmapped and should cause an access error.
     /// Page is unmapped and should cause an access error.
@@ -62,32 +60,39 @@ struct SpecialRegion {
  * mimics the way a real CPU page table works.
  * mimics the way a real CPU page table works.
  */
  */
 struct PageTable {
 struct PageTable {
+    explicit PageTable();
+    explicit PageTable(std::size_t address_space_width_in_bits);
+    ~PageTable();
+
+    /**
+     * 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);
+
     /**
     /**
-     * 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`.
+     * 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::array<u8*, PAGE_TABLE_NUM_ENTRIES> pointers;
+    std::vector<u8*> pointers;
 
 
     /**
     /**
-     * Contains MMIO handlers that back memory regions whose entries in the `attribute` array is of
-     * type `Special`.
+     * Contains MMIO handlers that back memory regions whose entries in the `attribute` vector is
+     * of type `Special`.
      */
      */
     boost::icl::interval_map<VAddr, std::set<SpecialRegion>> special_regions;
     boost::icl::interval_map<VAddr, std::set<SpecialRegion>> 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.
      * the corresponding entry in `pointers` MUST be set to null.
      */
      */
-    std::array<PageType, PAGE_TABLE_NUM_ENTRIES> attributes;
+    std::vector<PageType> attributes;
 };
 };
 
 
 /// Virtual user-space memory regions
 /// Virtual user-space memory regions
 enum : VAddr {
 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.
     /// Read-only page containing kernel and system configuration values.
     CONFIG_MEMORY_VADDR = 0x1FF80000,
     CONFIG_MEMORY_VADDR = 0x1FF80000,
     CONFIG_MEMORY_SIZE = 0x00001000,
     CONFIG_MEMORY_SIZE = 0x00001000,
@@ -98,36 +103,12 @@ enum : VAddr {
     SHARED_PAGE_SIZE = 0x00001000,
     SHARED_PAGE_SIZE = 0x00001000,
     SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE,
     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_ENTRY_SIZE = 0x200,
-    TLS_AREA_SIZE = 0x10000000,
-    TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE,
 
 
     /// Application stack
     /// 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,
     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 Virtual Address Range
     KERNEL_REGION_VADDR = 0xFFFFFF8000000000,
     KERNEL_REGION_VADDR = 0xFFFFFF8000000000,
     KERNEL_REGION_SIZE = 0x7FFFE00000,
     KERNEL_REGION_SIZE = 0x7FFFE00000,

+ 5 - 2
src/tests/core/arm/arm_test_common.cpp

@@ -2,6 +2,8 @@
 // Licensed under GPLv2 or any later version
 // Licensed under GPLv2 or any later version
 // Refer to the license.txt file included.
 // Refer to the license.txt file included.
 
 
+#include <algorithm>
+
 #include "core/core.h"
 #include "core/core.h"
 #include "core/hle/kernel/process.h"
 #include "core/hle/kernel/process.h"
 #include "core/memory.h"
 #include "core/memory.h"
@@ -16,9 +18,10 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
     Core::CurrentProcess() = Kernel::Process::Create(kernel, "");
     Core::CurrentProcess() = Kernel::Process::Create(kernel, "");
     page_table = &Core::CurrentProcess()->vm_manager.page_table;
     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->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, 0x00000000, 0x80000000, test_memory);
     Memory::MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory);
     Memory::MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory);