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.cpp177
1 files changed, 106 insertions, 71 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 2098f13f7..28b65ca5e 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -17,7 +17,6 @@
17#include "core/hle/kernel/process.h" 17#include "core/hle/kernel/process.h"
18#include "core/hle/kernel/vm_manager.h" 18#include "core/hle/kernel/vm_manager.h"
19#include "core/memory.h" 19#include "core/memory.h"
20#include "core/memory_setup.h"
21#include "video_core/gpu.h" 20#include "video_core/gpu.h"
22 21
23namespace Memory { 22namespace Memory {
@@ -30,99 +29,135 @@ static Common::PageTable* current_page_table = nullptr;
30struct Memory::Impl { 29struct Memory::Impl {
31 explicit Impl(Core::System& system_) : system{system_} {} 30 explicit Impl(Core::System& system_) : system{system_} {}
32 31
33 Core::System& system; 32 void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) {
34}; 33 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size);
34 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
35 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, Common::PageType::Memory);
36 }
35 37
36Memory::Memory(Core::System& system) : impl{std::make_unique<Impl>(system)} {} 38 void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size,
37Memory::~Memory() = default; 39 Common::MemoryHookPointer mmio_handler) {
40 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size);
41 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
42 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr,
43 Common::PageType::Special);
44
45 const auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1);
46 const Common::SpecialRegion region{Common::SpecialRegion::Type::IODevice,
47 std::move(mmio_handler)};
48 page_table.special_regions.add(
49 std::make_pair(interval, std::set<Common::SpecialRegion>{region}));
50 }
38 51
39void SetCurrentPageTable(Kernel::Process& process) { 52 void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) {
40 current_page_table = &process.VMManager().page_table; 53 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size);
54 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
55 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr,
56 Common::PageType::Unmapped);
41 57
42 const std::size_t address_space_width = process.VMManager().GetAddressSpaceWidth(); 58 const auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1);
59 page_table.special_regions.erase(interval);
60 }
43 61
44 auto& system = Core::System::GetInstance(); 62 void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
45 system.ArmInterface(0).PageTableChanged(*current_page_table, address_space_width); 63 Common::MemoryHookPointer hook) {
46 system.ArmInterface(1).PageTableChanged(*current_page_table, address_space_width); 64 const auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1);
47 system.ArmInterface(2).PageTableChanged(*current_page_table, address_space_width); 65 const Common::SpecialRegion region{Common::SpecialRegion::Type::DebugHook, std::move(hook)};
48 system.ArmInterface(3).PageTableChanged(*current_page_table, address_space_width); 66 page_table.special_regions.add(
49} 67 std::make_pair(interval, std::set<Common::SpecialRegion>{region}));
68 }
69
70 void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
71 Common::MemoryHookPointer hook) {
72 const auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1);
73 const Common::SpecialRegion region{Common::SpecialRegion::Type::DebugHook, std::move(hook)};
74 page_table.special_regions.subtract(
75 std::make_pair(interval, std::set<Common::SpecialRegion>{region}));
76 }
50 77
51static void MapPages(Common::PageTable& page_table, VAddr base, u64 size, u8* memory, 78 /**
52 Common::PageType type) { 79 * Maps a region of pages as a specific type.
53 LOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE, 80 *
54 (base + size) * PAGE_SIZE); 81 * @param page_table The page table to use to perform the mapping.
55 82 * @param base The base address to begin mapping at.
56 // During boot, current_page_table might not be set yet, in which case we need not flush 83 * @param size The total size of the range in bytes.
57 if (Core::System::GetInstance().IsPoweredOn()) { 84 * @param memory The memory to map.
58 auto& gpu = Core::System::GetInstance().GPU(); 85 * @param type The page type to map the memory as.
59 for (u64 i = 0; i < size; i++) { 86 */
60 const auto page = base + i; 87 void MapPages(Common::PageTable& page_table, VAddr base, u64 size, u8* memory,
61 if (page_table.attributes[page] == Common::PageType::RasterizerCachedMemory) { 88 Common::PageType type) {
62 gpu.FlushAndInvalidateRegion(page << PAGE_BITS, PAGE_SIZE); 89 LOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE,
90 (base + size) * PAGE_SIZE);
91
92 // During boot, current_page_table might not be set yet, in which case we need not flush
93 if (system.IsPoweredOn()) {
94 auto& gpu = system.GPU();
95 for (u64 i = 0; i < size; i++) {
96 const auto page = base + i;
97 if (page_table.attributes[page] == Common::PageType::RasterizerCachedMemory) {
98 gpu.FlushAndInvalidateRegion(page << PAGE_BITS, PAGE_SIZE);
99 }
63 } 100 }
64 } 101 }
65 }
66 102
67 VAddr end = base + size; 103 const VAddr end = base + size;
68 ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}", 104 ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}",
69 base + page_table.pointers.size()); 105 base + page_table.pointers.size());
70 106
71 std::fill(page_table.attributes.begin() + base, page_table.attributes.begin() + end, type); 107 std::fill(page_table.attributes.begin() + base, page_table.attributes.begin() + end, type);
72 108
73 if (memory == nullptr) { 109 if (memory == nullptr) {
74 std::fill(page_table.pointers.begin() + base, page_table.pointers.begin() + end, memory); 110 std::fill(page_table.pointers.begin() + base, page_table.pointers.begin() + end,
75 } else { 111 memory);
76 while (base != end) { 112 } else {
77 page_table.pointers[base] = memory; 113 while (base != end) {
114 page_table.pointers[base] = memory;
78 115
79 base += 1; 116 base += 1;
80 memory += PAGE_SIZE; 117 memory += PAGE_SIZE;
118 }
81 } 119 }
82 } 120 }
83}
84 121
85void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) { 122 Core::System& system;
86 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size); 123};
87 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
88 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, Common::PageType::Memory);
89}
90 124
91void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size, 125Memory::Memory(Core::System& system) : impl{std::make_unique<Impl>(system)} {}
92 Common::MemoryHookPointer mmio_handler) { 126Memory::~Memory() = default;
93 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size);
94 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base);
95 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, Common::PageType::Special);
96 127
97 auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1); 128void Memory::MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target) {
98 Common::SpecialRegion region{Common::SpecialRegion::Type::IODevice, std::move(mmio_handler)}; 129 impl->MapMemoryRegion(page_table, base, size, target);
99 page_table.special_regions.add(
100 std::make_pair(interval, std::set<Common::SpecialRegion>{region}));
101} 130}
102 131
103void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) { 132void Memory::MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size,
104 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size); 133 Common::MemoryHookPointer mmio_handler) {
105 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base); 134 impl->MapIoRegion(page_table, base, size, std::move(mmio_handler));
106 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, Common::PageType::Unmapped); 135}
136
137void Memory::UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) {
138 impl->UnmapRegion(page_table, base, size);
139}
107 140
108 auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1); 141void Memory::AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
109 page_table.special_regions.erase(interval); 142 Common::MemoryHookPointer hook) {
143 impl->AddDebugHook(page_table, base, size, std::move(hook));
110} 144}
111 145
112void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size, 146void Memory::RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
113 Common::MemoryHookPointer hook) { 147 Common::MemoryHookPointer hook) {
114 auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1); 148 impl->RemoveDebugHook(page_table, base, size, std::move(hook));
115 Common::SpecialRegion region{Common::SpecialRegion::Type::DebugHook, std::move(hook)};
116 page_table.special_regions.add(
117 std::make_pair(interval, std::set<Common::SpecialRegion>{region}));
118} 149}
119 150
120void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size, 151void SetCurrentPageTable(Kernel::Process& process) {
121 Common::MemoryHookPointer hook) { 152 current_page_table = &process.VMManager().page_table;
122 auto interval = boost::icl::discrete_interval<VAddr>::closed(base, base + size - 1); 153
123 Common::SpecialRegion region{Common::SpecialRegion::Type::DebugHook, std::move(hook)}; 154 const std::size_t address_space_width = process.VMManager().GetAddressSpaceWidth();
124 page_table.special_regions.subtract( 155
125 std::make_pair(interval, std::set<Common::SpecialRegion>{region})); 156 auto& system = Core::System::GetInstance();
157 system.ArmInterface(0).PageTableChanged(*current_page_table, address_space_width);
158 system.ArmInterface(1).PageTableChanged(*current_page_table, address_space_width);
159 system.ArmInterface(2).PageTableChanged(*current_page_table, address_space_width);
160 system.ArmInterface(3).PageTableChanged(*current_page_table, address_space_width);
126} 161}
127 162
128/** 163/**