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

memory: Dehardcode the use of a 36-bit address space

Given games can also request a 32-bit or 39-bit address space, we
shouldn't be hardcoding the address space range as 36-bit.
Lioncash 7 лет назад
Родитель
Сommit
7fd598636e

+ 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

+ 13 - 5
src/core/hle/kernel/vm_manager.cpp

@@ -66,18 +66,21 @@ VMManager::~VMManager() {
 
 
 void VMManager::Reset(FileSys::ProgramAddressSpaceType type) {
 void VMManager::Reset(FileSys::ProgramAddressSpaceType type) {
     Clear();
     Clear();
+
     InitializeMemoryRegionRanges(type);
     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);
 
 
     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));
@@ -455,9 +458,10 @@ void VMManager::ClearVMAMap() {
 }
 }
 
 
 void VMManager::ClearPageTable() {
 void VMManager::ClearPageTable() {
-    page_table.pointers.fill(nullptr);
+    std::fill(page_table.pointers.begin(), page_table.pointers.end(), nullptr);
     page_table.special_regions.clear();
     page_table.special_regions.clear();
-    page_table.attributes.fill(Memory::PageType::Unmapped);
+    std::fill(page_table.attributes.begin(), page_table.attributes.end(),
+              Memory::PageType::Unmapped);
 }
 }
 
 
 u64 VMManager::GetTotalMemoryUsage() const {
 u64 VMManager::GetTotalMemoryUsage() const {
@@ -480,6 +484,10 @@ u64 VMManager::GetAddressSpaceSize() const {
     return MAX_ADDRESS;
     return MAX_ADDRESS;
 }
 }
 
 
+u64 VMManager::GetAddressSpaceWidth() const {
+    return address_space_width;
+}
+
 VAddr VMManager::GetCodeRegionBaseAddress() const {
 VAddr VMManager::GetCodeRegionBaseAddress() const {
     return code_region_base;
     return code_region_base;
 }
 }

+ 3 - 0
src/core/hle/kernel/vm_manager.h

@@ -205,6 +205,9 @@ public:
     /// Gets the total address space address size, used by svcGetInfo
     /// Gets the total address space address size, used by svcGetInfo
     u64 GetAddressSpaceSize() const;
     u64 GetAddressSpaceSize() const;
 
 
+    /// Gets the address space width in bits.
+    u64 GetAddressSpaceWidth() const;
+
     /// Gets the base address of the code region.
     /// Gets the base address of the code region.
     VAddr GetCodeRegionBaseAddress() const;
     VAddr GetCodeRegionBaseAddress() const;
 
 

+ 16 - 2
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>
 
 
@@ -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;

+ 21 - 11
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,23 +60,35 @@ 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

+ 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);