Merge pull request #1395 from lioncash/vm
process/vm_manager: Initial modifications to load NPDM metadata
This commit is contained in:
		| @@ -129,7 +129,8 @@ public: | ||||
| }; | ||||
|  | ||||
| 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; | ||||
|  | ||||
| @@ -138,7 +139,7 @@ std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const { | ||||
|  | ||||
|     // Memory | ||||
|     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; | ||||
|  | ||||
|     // Multi-process state | ||||
|   | ||||
| @@ -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; | ||||
|     } | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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<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; | ||||
|     u64 len = | ||||
|     const u64 len = | ||||
|         HexToLong(start_offset, static_cast<u64>((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"); | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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> 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]; | ||||
| @@ -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 | ||||
|     // of the user address space. | ||||
|     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, | ||||
|                         MemoryState::Mapped) | ||||
|         .Unwrap(); | ||||
| @@ -185,6 +193,7 @@ static std::tuple<std::size_t, std::size_t, bool> 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 | ||||
| @@ -197,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; | ||||
|  | ||||
| @@ -232,8 +240,8 @@ void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) { | ||||
| } | ||||
|  | ||||
| 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; | ||||
|     } | ||||
|  | ||||
| @@ -268,8 +276,8 @@ ResultVal<VAddr> 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; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
|  | ||||
|   | ||||
| @@ -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> 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; | ||||
| } | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
|  | ||||
| @@ -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, | ||||
|               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)) { | ||||
|     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 +361,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, | ||||
|   | ||||
| @@ -262,8 +262,9 @@ SharedPtr<Thread> 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> thread = std::move(thread_res).Unwrap(); | ||||
|  | ||||
|   | ||||
| @@ -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,30 +55,32 @@ 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); | ||||
|  | ||||
|     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); | ||||
|  | ||||
|     page_table.pointers.fill(nullptr); | ||||
|     page_table.special_regions.clear(); | ||||
|     page_table.attributes.fill(Memory::PageType::Unmapped); | ||||
|  | ||||
|     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::VMAIter> 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)); | ||||
| @@ -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 { | ||||
|     LOG_WARNING(Kernel, "(STUBBED) called"); | ||||
|     return 0xF8000000; | ||||
| @@ -392,14 +474,80 @@ 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 { | ||||
|     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 | ||||
|   | ||||
| @@ -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 { | ||||
| @@ -110,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 | ||||
| @@ -130,7 +128,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 +193,63 @@ public: | ||||
|     /// Gets the total heap usage, used by svcGetInfo | ||||
|     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; | ||||
|  | ||||
|     /// 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 | ||||
|     /// 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 | ||||
|   | ||||
| @@ -14,11 +14,9 @@ | ||||
| #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" | ||||
| #include "core/memory.h" | ||||
|  | ||||
| namespace Loader { | ||||
|  | ||||
| @@ -127,12 +125,16 @@ 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}; | ||||
|     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); | ||||
| @@ -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 | ||||
|     const auto& files = dir->GetFiles(); | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
| #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/hle/kernel/vm_manager.h" | ||||
| #include "core/loader/elf.h" | ||||
| #include "core/memory.h" | ||||
|  | ||||
| @@ -189,7 +189,7 @@ private: | ||||
|  | ||||
|     u32* sectionAddrs; | ||||
|     bool relocate; | ||||
|     u32 entryPoint; | ||||
|     VAddr entryPoint; | ||||
|  | ||||
| public: | ||||
|     explicit ElfReader(void* ptr); | ||||
| @@ -205,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<CodeSet> LoadInto(u32 vaddr); | ||||
|     SharedPtr<CodeSet> LoadInto(VAddr vaddr); | ||||
|  | ||||
|     int GetNumSegments() const { | ||||
|         return (int)(header->e_phnum); | ||||
| @@ -274,7 +274,7 @@ const char* ElfReader::GetSectionName(int section) const { | ||||
|     return nullptr; | ||||
| } | ||||
|  | ||||
| SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) { | ||||
| SharedPtr<CodeSet> ElfReader::LoadInto(VAddr vaddr) { | ||||
|     LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx); | ||||
|  | ||||
|     // Should we relocate? | ||||
| @@ -289,11 +289,11 @@ SharedPtr<CodeSet> 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; | ||||
|         } | ||||
| @@ -306,7 +306,7 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) { | ||||
|     SharedPtr<CodeSet> 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); | ||||
|  | ||||
| @@ -333,8 +333,8 @@ SharedPtr<CodeSet> 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; | ||||
| @@ -395,18 +395,12 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) { | ||||
|     if (buffer.size() != file->GetSize()) | ||||
|         return ResultStatus::ErrorIncorrectELFFileSize; | ||||
|  | ||||
|     const VAddr base_address = process->vm_manager.GetCodeRegionBaseAddress(); | ||||
|     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(); | ||||
|  | ||||
|     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; | ||||
|   | ||||
| @@ -16,7 +16,7 @@ | ||||
| #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/kernel/vm_manager.h" | ||||
| #include "core/loader/nro.h" | ||||
| #include "core/memory.h" | ||||
|  | ||||
| @@ -181,17 +181,13 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& 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; | ||||
|     } | ||||
|  | ||||
|     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; | ||||
|     return ResultStatus::Success; | ||||
|   | ||||
| @@ -13,7 +13,7 @@ | ||||
| #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/kernel/vm_manager.h" | ||||
| #include "core/loader/nso.h" | ||||
| #include "core/memory.h" | ||||
|  | ||||
| @@ -159,15 +159,11 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& 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); | ||||
|  | ||||
|     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; | ||||
|     return ResultStatus::Success; | ||||
|   | ||||
| @@ -3,7 +3,6 @@ | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include <algorithm> | ||||
| #include <array> | ||||
| #include <cstring> | ||||
| #include <utility> | ||||
|  | ||||
| @@ -15,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 { | ||||
|  | ||||
| @@ -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; | ||||
| @@ -323,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) { | ||||
| @@ -333,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) { | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -4,10 +4,10 @@ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <array> | ||||
| #include <cstddef> | ||||
| #include <string> | ||||
| #include <tuple> | ||||
| #include <vector> | ||||
| #include <boost/icl/interval_map.hpp> | ||||
| #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,32 +60,39 @@ 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<u8*, PAGE_TABLE_NUM_ENTRIES> 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<u8*> pointers; | ||||
|  | ||||
|     /** | ||||
|      * 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; | ||||
|  | ||||
|     /** | ||||
|      * 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<PageType, PAGE_TABLE_NUM_ENTRIES> attributes; | ||||
|     std::vector<PageType> attributes; | ||||
| }; | ||||
|  | ||||
| /// 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, | ||||
| @@ -98,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, | ||||
|   | ||||
| @@ -2,6 +2,8 @@ | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #include <algorithm> | ||||
|  | ||||
| #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); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user