diff options
Diffstat (limited to 'src/core/memory.cpp')
| -rw-r--r-- | src/core/memory.cpp | 86 |
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 | ||
| 17 | namespace Memory { | 18 | namespace Memory { |
| 18 | 19 | ||
| @@ -25,6 +26,12 @@ enum class PageType { | |||
| 25 | Special, | 26 | Special, |
| 26 | }; | 27 | }; |
| 27 | 28 | ||
| 29 | struct 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 | ||
| 83 | void MapIoRegion(VAddr base, u32 size) { | 95 | void 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 | ||
| 89 | void UnmapRegion(VAddr base, u32 size) { | 103 | void 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 | */ | ||
| 112 | static 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 | |||
| 122 | template<typename T> | ||
| 123 | T ReadMMIO(MMIORegionPointer mmio_handler, VAddr addr); | ||
| 124 | |||
| 95 | template <typename T> | 125 | template <typename T> |
| 96 | T Read(const VAddr vaddr) { | 126 | T 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 | ||
| 149 | template<typename T> | ||
| 150 | void WriteMMIO(MMIORegionPointer mmio_handler, VAddr addr, const T data); | ||
| 151 | |||
| 119 | template <typename T> | 152 | template <typename T> |
| 120 | void Write(const VAddr vaddr, const T data) { | 153 | void 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 | ||
| 228 | template<> | ||
| 229 | u8 ReadMMIO<u8>(MMIORegionPointer mmio_handler, VAddr addr) { | ||
| 230 | return mmio_handler->Read8(addr); | ||
| 231 | } | ||
| 232 | |||
| 233 | template<> | ||
| 234 | u16 ReadMMIO<u16>(MMIORegionPointer mmio_handler, VAddr addr) { | ||
| 235 | return mmio_handler->Read16(addr); | ||
| 236 | } | ||
| 237 | |||
| 238 | template<> | ||
| 239 | u32 ReadMMIO<u32>(MMIORegionPointer mmio_handler, VAddr addr) { | ||
| 240 | return mmio_handler->Read32(addr); | ||
| 241 | } | ||
| 242 | |||
| 243 | template<> | ||
| 244 | u64 ReadMMIO<u64>(MMIORegionPointer mmio_handler, VAddr addr) { | ||
| 245 | return mmio_handler->Read64(addr); | ||
| 246 | } | ||
| 247 | |||
| 248 | template<> | ||
| 249 | void WriteMMIO<u8>(MMIORegionPointer mmio_handler, VAddr addr, const u8 data) { | ||
| 250 | mmio_handler->Write8(addr, data); | ||
| 251 | } | ||
| 252 | |||
| 253 | template<> | ||
| 254 | void WriteMMIO<u16>(MMIORegionPointer mmio_handler, VAddr addr, const u16 data) { | ||
| 255 | mmio_handler->Write16(addr, data); | ||
| 256 | } | ||
| 257 | |||
| 258 | template<> | ||
| 259 | void WriteMMIO<u32>(MMIORegionPointer mmio_handler, VAddr addr, const u32 data) { | ||
| 260 | mmio_handler->Write32(addr, data); | ||
| 261 | } | ||
| 262 | |||
| 263 | template<> | ||
| 264 | void WriteMMIO<u64>(MMIORegionPointer mmio_handler, VAddr addr, const u64 data) { | ||
| 265 | mmio_handler->Write64(addr, data); | ||
| 266 | } | ||
| 267 | |||
| 194 | PAddr VirtualToPhysicalAddress(const VAddr addr) { | 268 | PAddr VirtualToPhysicalAddress(const VAddr addr) { |
| 195 | if (addr == 0) { | 269 | if (addr == 0) { |
| 196 | return 0; | 270 | return 0; |