|
|
|
@ -11,75 +11,18 @@ |
|
|
|
#include "core/hle/kernel/process.h"
|
|
|
|
#include "core/memory.h"
|
|
|
|
#include "core/memory_setup.h"
|
|
|
|
#include "core/mmio.h"
|
|
|
|
#include "video_core/renderer_base.h"
|
|
|
|
#include "video_core/video_core.h"
|
|
|
|
|
|
|
|
namespace Memory { |
|
|
|
|
|
|
|
enum class PageType { |
|
|
|
/// Page is unmapped and should cause an access error.
|
|
|
|
Unmapped, |
|
|
|
/// Page is mapped to regular memory. This is the only type you can get pointers to.
|
|
|
|
Memory, |
|
|
|
/// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and
|
|
|
|
/// invalidation
|
|
|
|
RasterizerCachedMemory, |
|
|
|
/// Page is mapped to a I/O region. Writing and reading to this page is handled by functions.
|
|
|
|
Special, |
|
|
|
/// Page is mapped to a I/O region, but also needs to check for rasterizer cache flushing and
|
|
|
|
/// invalidation
|
|
|
|
RasterizerCachedSpecial, |
|
|
|
}; |
|
|
|
|
|
|
|
struct SpecialRegion { |
|
|
|
VAddr base; |
|
|
|
u32 size; |
|
|
|
MMIORegionPointer handler; |
|
|
|
}; |
|
|
|
|
|
|
|
/**
|
|
|
|
* A (reasonably) fast way of allowing switchable and remappable process address spaces. It loosely |
|
|
|
* mimics the way a real CPU page table works, but instead is optimized for minimal decoding and |
|
|
|
* fetching requirements when accessing. In the usual case of an access to regular memory, it only |
|
|
|
* requires an indexed fetch and a check for NULL. |
|
|
|
*/ |
|
|
|
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; |
|
|
|
|
|
|
|
/**
|
|
|
|
* Contains MMIO handlers that back memory regions whose entries in the `attribute` array is of |
|
|
|
* type `Special`. |
|
|
|
*/ |
|
|
|
std::vector<SpecialRegion> special_regions; |
|
|
|
|
|
|
|
/**
|
|
|
|
* Array 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; |
|
|
|
|
|
|
|
/**
|
|
|
|
* Indicates the number of externally cached resources touching a page that should be |
|
|
|
* flushed before the memory is accessed |
|
|
|
*/ |
|
|
|
std::array<u8, PAGE_TABLE_NUM_ENTRIES> cached_res_count; |
|
|
|
}; |
|
|
|
|
|
|
|
/// Singular page table used for the singleton process
|
|
|
|
static PageTable main_page_table; |
|
|
|
/// Currently active page table
|
|
|
|
static PageTable* current_page_table = &main_page_table; |
|
|
|
PageTable* current_page_table = nullptr; |
|
|
|
|
|
|
|
std::array<u8*, PAGE_TABLE_NUM_ENTRIES>* GetCurrentPageTablePointers() { |
|
|
|
return ¤t_page_table->pointers; |
|
|
|
} |
|
|
|
|
|
|
|
static void MapPages(u32 base, u32 size, u8* memory, PageType type) { |
|
|
|
static void MapPages(PageTable& page_table, u32 base, u32 size, u8* memory, PageType type) { |
|
|
|
LOG_DEBUG(HW_Memory, "Mapping %p onto %08X-%08X", memory, base * PAGE_SIZE, |
|
|
|
(base + size) * PAGE_SIZE); |
|
|
|
|
|
|
|
@ -90,9 +33,9 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) { |
|
|
|
while (base != end) { |
|
|
|
ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at %08X", base); |
|
|
|
|
|
|
|
current_page_table->attributes[base] = type; |
|
|
|
current_page_table->pointers[base] = memory; |
|
|
|
current_page_table->cached_res_count[base] = 0; |
|
|
|
page_table.attributes[base] = type; |
|
|
|
page_table.pointers[base] = memory; |
|
|
|
page_table.cached_res_count[base] = 0; |
|
|
|
|
|
|
|
base += 1; |
|
|
|
if (memory != nullptr) |
|
|
|
@ -100,30 +43,24 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void InitMemoryMap() { |
|
|
|
main_page_table.pointers.fill(nullptr); |
|
|
|
main_page_table.attributes.fill(PageType::Unmapped); |
|
|
|
main_page_table.cached_res_count.fill(0); |
|
|
|
} |
|
|
|
|
|
|
|
void MapMemoryRegion(VAddr base, u32 size, u8* target) { |
|
|
|
void MapMemoryRegion(PageTable& page_table, VAddr base, u32 size, u8* target) { |
|
|
|
ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %08X", size); |
|
|
|
ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %08X", base); |
|
|
|
MapPages(base / PAGE_SIZE, size / PAGE_SIZE, target, PageType::Memory); |
|
|
|
MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, PageType::Memory); |
|
|
|
} |
|
|
|
|
|
|
|
void MapIoRegion(VAddr base, u32 size, MMIORegionPointer mmio_handler) { |
|
|
|
void MapIoRegion(PageTable& page_table, VAddr base, u32 size, MMIORegionPointer mmio_handler) { |
|
|
|
ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %08X", size); |
|
|
|
ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %08X", base); |
|
|
|
MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special); |
|
|
|
MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special); |
|
|
|
|
|
|
|
current_page_table->special_regions.emplace_back(SpecialRegion{base, size, mmio_handler}); |
|
|
|
page_table.special_regions.emplace_back(SpecialRegion{base, size, mmio_handler}); |
|
|
|
} |
|
|
|
|
|
|
|
void UnmapRegion(VAddr base, u32 size) { |
|
|
|
void UnmapRegion(PageTable& page_table, VAddr base, u32 size) { |
|
|
|
ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %08X", size); |
|
|
|
ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %08X", base); |
|
|
|
MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped); |
|
|
|
MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped); |
|
|
|
} |
|
|
|
|
|
|
|
/**
|
|
|
|
|