mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2024-12-26 07:30:07 +00:00
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:
parent
75603b005b
commit
7fd598636e
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
* Array of memory pointers backing each page. An entry can only be non-null if the
|
explicit PageTable(std::size_t address_space_width_in_bits);
|
||||||
* corresponding entry in the `attributes` array is of type `Memory`.
|
~PageTable();
|
||||||
*/
|
|
||||||
std::array<u8*, PAGE_TABLE_NUM_ENTRIES> pointers;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains MMIO handlers that back memory regions whose entries in the `attribute` array is of
|
* Resizes the page table to be able to accomodate enough pages within
|
||||||
* type `Special`.
|
* 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;
|
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
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user