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.
This commit is contained in:
Lioncash 2018-09-24 10:29:56 -04:00
parent 75603b005b
commit 7fd598636e
6 changed files with 63 additions and 24 deletions

View File

@ -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

View File

@ -66,18 +66,21 @@ VMManager::~VMManager() {
void VMManager::Reset(FileSys::ProgramAddressSpaceType type) {
Clear();
InitializeMemoryRegionRanges(type);
page_table.Resize(address_space_width);
// Initialize the map with a single free region covering the entire managed space.
VirtualMemoryArea initial_vma;
initial_vma.size = MAX_ADDRESS;
initial_vma.size = address_space_end;
vma_map.emplace(initial_vma.base, initial_vma);
UpdatePageTableForVMA(initial_vma);
}
VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
if (target >= MAX_ADDRESS) {
if (target >= address_space_end) {
return vma_map.end();
} else {
return std::prev(vma_map.upper_bound(target));
@ -291,7 +294,7 @@ ResultVal<VMManager::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));
@ -455,9 +458,10 @@ void VMManager::ClearVMAMap() {
}
void VMManager::ClearPageTable() {
page_table.pointers.fill(nullptr);
std::fill(page_table.pointers.begin(), page_table.pointers.end(), nullptr);
page_table.special_regions.clear();
page_table.attributes.fill(Memory::PageType::Unmapped);
std::fill(page_table.attributes.begin(), page_table.attributes.end(),
Memory::PageType::Unmapped);
}
u64 VMManager::GetTotalMemoryUsage() const {
@ -480,6 +484,10 @@ u64 VMManager::GetAddressSpaceSize() const {
return MAX_ADDRESS;
}
u64 VMManager::GetAddressSpaceWidth() const {
return address_space_width;
}
VAddr VMManager::GetCodeRegionBaseAddress() const {
return code_region_base;
}

View File

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

View File

@ -3,7 +3,6 @@
// Refer to the license.txt file included.
#include <algorithm>
#include <array>
#include <cstring>
#include <utility>
@ -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;

View File

@ -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,23 +60,35 @@ struct SpecialRegion {
* mimics the way a real CPU page table works.
*/
struct PageTable {
/**
* Array of memory pointers backing each page. An entry can only be non-null if the
* corresponding entry in the `attributes` array is of type `Memory`.
*/
std::array<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

View File

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