summaryrefslogtreecommitdiff
path: root/src/core/memory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/memory.cpp')
-rw-r--r--src/core/memory.cpp86
1 files changed, 80 insertions, 6 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index fc79c3ee9..4753c63a7 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -13,6 +13,7 @@
13#include "core/hle/kernel/process.h" 13#include "core/hle/kernel/process.h"
14#include "core/memory.h" 14#include "core/memory.h"
15#include "core/memory_setup.h" 15#include "core/memory_setup.h"
16#include "core/mmio.h"
16 17
17namespace Memory { 18namespace Memory {
18 19
@@ -25,6 +26,12 @@ enum class PageType {
25 Special, 26 Special,
26}; 27};
27 28
29struct SpecialRegion {
30 VAddr base;
31 u32 size;
32 MMIORegionPointer handler;
33};
34
28/** 35/**
29 * A (reasonably) fast way of allowing switchable and remappable process address spaces. It loosely 36 * A (reasonably) fast way of allowing switchable and remappable process address spaces. It loosely
30 * mimics the way a real CPU page table works, but instead is optimized for minimal decoding and 37 * mimics the way a real CPU page table works, but instead is optimized for minimal decoding and
@@ -41,8 +48,13 @@ struct PageTable {
41 std::array<u8*, NUM_ENTRIES> pointers; 48 std::array<u8*, NUM_ENTRIES> pointers;
42 49
43 /** 50 /**
51 * Contains MMIO handlers that back memory regions whose entries in the `attribute` array is of type `Special`.
52 */
53 std::vector<SpecialRegion> special_regions;
54
55 /**
44 * Array of fine grained page attributes. If it is set to any value other than `Memory`, then 56 * Array of fine grained page attributes. If it is set to any value other than `Memory`, then
45 * the corresponding entry in `pointer` MUST be set to null. 57 * the corresponding entry in `pointers` MUST be set to null.
46 */ 58 */
47 std::array<PageType, NUM_ENTRIES> attributes; 59 std::array<PageType, NUM_ENTRIES> attributes;
48}; 60};
@@ -80,10 +92,12 @@ void MapMemoryRegion(VAddr base, u32 size, u8* target) {
80 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, target, PageType::Memory); 92 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, target, PageType::Memory);
81} 93}
82 94
83void MapIoRegion(VAddr base, u32 size) { 95void MapIoRegion(VAddr base, u32 size, MMIORegionPointer mmio_handler) {
84 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %08X", size); 96 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %08X", size);
85 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %08X", base); 97 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %08X", base);
86 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special); 98 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special);
99
100 current_page_table->special_regions.emplace_back(SpecialRegion{base, size, mmio_handler});
87} 101}
88 102
89void UnmapRegion(VAddr base, u32 size) { 103void UnmapRegion(VAddr base, u32 size) {
@@ -92,6 +106,22 @@ void UnmapRegion(VAddr base, u32 size) {
92 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped); 106 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped);
93} 107}
94 108
109/**
110 * This function should only be called for virtual addreses with attribute `PageType::Special`.
111 */
112static MMIORegionPointer GetMMIOHandler(VAddr vaddr) {
113 for (const auto& region : current_page_table->special_regions) {
114 if (vaddr >= region.base && vaddr < (region.base + region.size)) {
115 return region.handler;
116 }
117 }
118 ASSERT_MSG(false, "Mapped IO page without a handler @ %08X", vaddr);
119 return nullptr; // Should never happen
120}
121
122template<typename T>
123T ReadMMIO(MMIORegionPointer mmio_handler, VAddr addr);
124
95template <typename T> 125template <typename T>
96T Read(const VAddr vaddr) { 126T Read(const VAddr vaddr) {
97 const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; 127 const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
@@ -108,14 +138,17 @@ T Read(const VAddr vaddr) {
108 return 0; 138 return 0;
109 case PageType::Memory: 139 case PageType::Memory:
110 ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); 140 ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr);
141 break;
111 case PageType::Special: 142 case PageType::Special:
112 LOG_ERROR(HW_Memory, "I/O reads aren't implemented yet @ %08X", vaddr); 143 return ReadMMIO<T>(GetMMIOHandler(vaddr), vaddr);
113 return 0;
114 default: 144 default:
115 UNREACHABLE(); 145 UNREACHABLE();
116 } 146 }
117} 147}
118 148
149template<typename T>
150void WriteMMIO(MMIORegionPointer mmio_handler, VAddr addr, const T data);
151
119template <typename T> 152template <typename T>
120void Write(const VAddr vaddr, const T data) { 153void Write(const VAddr vaddr, const T data) {
121 u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; 154 u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
@@ -131,9 +164,10 @@ void Write(const VAddr vaddr, const T data) {
131 return; 164 return;
132 case PageType::Memory: 165 case PageType::Memory:
133 ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr); 166 ASSERT_MSG(false, "Mapped memory page without a pointer @ %08X", vaddr);
167 break;
134 case PageType::Special: 168 case PageType::Special:
135 LOG_ERROR(HW_Memory, "I/O writes aren't implemented yet @ %08X", vaddr); 169 WriteMMIO<T>(GetMMIOHandler(vaddr), vaddr, data);
136 return; 170 break;
137 default: 171 default:
138 UNREACHABLE(); 172 UNREACHABLE();
139 } 173 }
@@ -191,6 +225,46 @@ void WriteBlock(const VAddr addr, const u8* data, const size_t size) {
191 } 225 }
192} 226}
193 227
228template<>
229u8 ReadMMIO<u8>(MMIORegionPointer mmio_handler, VAddr addr) {
230 return mmio_handler->Read8(addr);
231}
232
233template<>
234u16 ReadMMIO<u16>(MMIORegionPointer mmio_handler, VAddr addr) {
235 return mmio_handler->Read16(addr);
236}
237
238template<>
239u32 ReadMMIO<u32>(MMIORegionPointer mmio_handler, VAddr addr) {
240 return mmio_handler->Read32(addr);
241}
242
243template<>
244u64 ReadMMIO<u64>(MMIORegionPointer mmio_handler, VAddr addr) {
245 return mmio_handler->Read64(addr);
246}
247
248template<>
249void WriteMMIO<u8>(MMIORegionPointer mmio_handler, VAddr addr, const u8 data) {
250 mmio_handler->Write8(addr, data);
251}
252
253template<>
254void WriteMMIO<u16>(MMIORegionPointer mmio_handler, VAddr addr, const u16 data) {
255 mmio_handler->Write16(addr, data);
256}
257
258template<>
259void WriteMMIO<u32>(MMIORegionPointer mmio_handler, VAddr addr, const u32 data) {
260 mmio_handler->Write32(addr, data);
261}
262
263template<>
264void WriteMMIO<u64>(MMIORegionPointer mmio_handler, VAddr addr, const u64 data) {
265 mmio_handler->Write64(addr, data);
266}
267
194PAddr VirtualToPhysicalAddress(const VAddr addr) { 268PAddr VirtualToPhysicalAddress(const VAddr addr) {
195 if (addr == 0) { 269 if (addr == 0) {
196 return 0; 270 return 0;