summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt1
-rw-r--r--src/core/hle/kernel/vm_manager.cpp13
-rw-r--r--src/core/memory.cpp177
-rw-r--r--src/core/memory.h59
-rw-r--r--src/core/memory_setup.h43
-rw-r--r--src/tests/core/arm/arm_test_common.cpp15
6 files changed, 180 insertions, 128 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index f2e774a6b..2dfdcb0d7 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -509,7 +509,6 @@ add_library(core STATIC
509 memory/dmnt_cheat_vm.h 509 memory/dmnt_cheat_vm.h
510 memory.cpp 510 memory.cpp
511 memory.h 511 memory.h
512 memory_setup.h
513 perf_stats.cpp 512 perf_stats.cpp
514 perf_stats.h 513 perf_stats.h
515 reporter.cpp 514 reporter.cpp
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index e6eee09d7..a9a20ef76 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -16,7 +16,6 @@
16#include "core/hle/kernel/resource_limit.h" 16#include "core/hle/kernel/resource_limit.h"
17#include "core/hle/kernel/vm_manager.h" 17#include "core/hle/kernel/vm_manager.h"
18#include "core/memory.h" 18#include "core/memory.h"
19#include "core/memory_setup.h"
20 19
21namespace Kernel { 20namespace Kernel {
22namespace { 21namespace {
@@ -786,19 +785,21 @@ void VMManager::MergeAdjacentVMA(VirtualMemoryArea& left, const VirtualMemoryAre
786} 785}
787 786
788void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { 787void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
788 auto& memory = system.Memory();
789
789 switch (vma.type) { 790 switch (vma.type) {
790 case VMAType::Free: 791 case VMAType::Free:
791 Memory::UnmapRegion(page_table, vma.base, vma.size); 792 memory.UnmapRegion(page_table, vma.base, vma.size);
792 break; 793 break;
793 case VMAType::AllocatedMemoryBlock: 794 case VMAType::AllocatedMemoryBlock:
794 Memory::MapMemoryRegion(page_table, vma.base, vma.size, 795 memory.MapMemoryRegion(page_table, vma.base, vma.size,
795 vma.backing_block->data() + vma.offset); 796 vma.backing_block->data() + vma.offset);
796 break; 797 break;
797 case VMAType::BackingMemory: 798 case VMAType::BackingMemory:
798 Memory::MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory); 799 memory.MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory);
799 break; 800 break;
800 case VMAType::MMIO: 801 case VMAType::MMIO:
801 Memory::MapIoRegion(page_table, vma.base, vma.size, vma.mmio_handler); 802 memory.MapIoRegion(page_table, vma.base, vma.size, vma.mmio_handler);
802 break; 803 break;
803 } 804 }
804} 805}
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/**
diff --git a/src/core/memory.h b/src/core/memory.h
index c690df3c3..87ed3b696 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -5,8 +5,14 @@
5#pragma once 5#pragma once
6 6
7#include <cstddef> 7#include <cstddef>
8#include <memory>
8#include <string> 9#include <string>
9#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/memory_hook.h"
12
13namespace Common {
14struct PageTable;
15}
10 16
11namespace Core { 17namespace Core {
12class System; 18class System;
@@ -52,6 +58,59 @@ public:
52 Memory(Memory&&) = default; 58 Memory(Memory&&) = default;
53 Memory& operator=(Memory&&) = default; 59 Memory& operator=(Memory&&) = default;
54 60
61 /**
62 * Maps an allocated buffer onto a region of the emulated process address space.
63 *
64 * @param page_table The page table of the emulated process.
65 * @param base The address to start mapping at. Must be page-aligned.
66 * @param size The amount of bytes to map. Must be page-aligned.
67 * @param target Buffer with the memory backing the mapping. Must be of length at least
68 * `size`.
69 */
70 void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target);
71
72 /**
73 * Maps a region of the emulated process address space as a IO region.
74 *
75 * @param page_table The page table of the emulated process.
76 * @param base The address to start mapping at. Must be page-aligned.
77 * @param size The amount of bytes to map. Must be page-aligned.
78 * @param mmio_handler The handler that backs the mapping.
79 */
80 void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size,
81 Common::MemoryHookPointer mmio_handler);
82
83 /**
84 * Unmaps a region of the emulated process address space.
85 *
86 * @param page_table The page table of the emulated process.
87 * @param base The address to begin unmapping at.
88 * @param size The amount of bytes to unmap.
89 */
90 void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size);
91
92 /**
93 * Adds a memory hook to intercept reads and writes to given region of memory.
94 *
95 * @param page_table The page table of the emulated process
96 * @param base The starting address to apply the hook to.
97 * @param size The size of the memory region to apply the hook to, in bytes.
98 * @param hook The hook to apply to the region of memory.
99 */
100 void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
101 Common::MemoryHookPointer hook);
102
103 /**
104 * Removes a memory hook from a given range of memory.
105 *
106 * @param page_table The page table of the emulated process.
107 * @param base The starting address to remove the hook from.
108 * @param size The size of the memory region to remove the hook from, in bytes.
109 * @param hook The hook to remove from the specified region of memory.
110 */
111 void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
112 Common::MemoryHookPointer hook);
113
55private: 114private:
56 struct Impl; 115 struct Impl;
57 std::unique_ptr<Impl> impl; 116 std::unique_ptr<Impl> impl;
diff --git a/src/core/memory_setup.h b/src/core/memory_setup.h
deleted file mode 100644
index 5225ee8e2..000000000
--- a/src/core/memory_setup.h
+++ /dev/null
@@ -1,43 +0,0 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "common/memory_hook.h"
9
10namespace Common {
11struct PageTable;
12}
13
14namespace Memory {
15
16/**
17 * Maps an allocated buffer onto a region of the emulated process address space.
18 *
19 * @param page_table The page table of the emulated process.
20 * @param base The address to start mapping at. Must be page-aligned.
21 * @param size The amount of bytes to map. Must be page-aligned.
22 * @param target Buffer with the memory backing the mapping. Must be of length at least `size`.
23 */
24void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, u8* target);
25
26/**
27 * Maps a region of the emulated process address space as a IO region.
28 * @param page_table The page table of the emulated process.
29 * @param base The address to start mapping at. Must be page-aligned.
30 * @param size The amount of bytes to map. Must be page-aligned.
31 * @param mmio_handler The handler that backs the mapping.
32 */
33void MapIoRegion(Common::PageTable& page_table, VAddr base, u64 size,
34 Common::MemoryHookPointer mmio_handler);
35
36void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size);
37
38void AddDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
39 Common::MemoryHookPointer hook);
40void RemoveDebugHook(Common::PageTable& page_table, VAddr base, u64 size,
41 Common::MemoryHookPointer hook);
42
43} // namespace Memory
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp
index ac7ae3e52..17043346b 100644
--- a/src/tests/core/arm/arm_test_common.cpp
+++ b/src/tests/core/arm/arm_test_common.cpp
@@ -8,7 +8,6 @@
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/kernel/process.h" 9#include "core/hle/kernel/process.h"
10#include "core/memory.h" 10#include "core/memory.h"
11#include "core/memory_setup.h"
12#include "tests/core/arm/arm_test_common.h" 11#include "tests/core/arm/arm_test_common.h"
13 12
14namespace ArmTests { 13namespace ArmTests {
@@ -16,8 +15,9 @@ namespace ArmTests {
16TestEnvironment::TestEnvironment(bool mutable_memory_) 15TestEnvironment::TestEnvironment(bool mutable_memory_)
17 : mutable_memory(mutable_memory_), 16 : mutable_memory(mutable_memory_),
18 test_memory(std::make_shared<TestMemory>(this)), kernel{Core::System::GetInstance()} { 17 test_memory(std::make_shared<TestMemory>(this)), kernel{Core::System::GetInstance()} {
19 auto process = Kernel::Process::Create(Core::System::GetInstance(), "", 18 auto& system = Core::System::GetInstance();
20 Kernel::Process::ProcessType::Userland); 19
20 auto process = Kernel::Process::Create(system, "", Kernel::Process::ProcessType::Userland);
21 page_table = &process->VMManager().page_table; 21 page_table = &process->VMManager().page_table;
22 22
23 std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr); 23 std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr);
@@ -25,15 +25,16 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
25 std::fill(page_table->attributes.begin(), page_table->attributes.end(), 25 std::fill(page_table->attributes.begin(), page_table->attributes.end(),
26 Common::PageType::Unmapped); 26 Common::PageType::Unmapped);
27 27
28 Memory::MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory); 28 system.Memory().MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory);
29 Memory::MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory); 29 system.Memory().MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory);
30 30
31 kernel.MakeCurrentProcess(process.get()); 31 kernel.MakeCurrentProcess(process.get());
32} 32}
33 33
34TestEnvironment::~TestEnvironment() { 34TestEnvironment::~TestEnvironment() {
35 Memory::UnmapRegion(*page_table, 0x80000000, 0x80000000); 35 auto& system = Core::System::GetInstance();
36 Memory::UnmapRegion(*page_table, 0x00000000, 0x80000000); 36 system.Memory().UnmapRegion(*page_table, 0x80000000, 0x80000000);
37 system.Memory().UnmapRegion(*page_table, 0x00000000, 0x80000000);
37} 38}
38 39
39void TestEnvironment::SetMemory64(VAddr vaddr, u64 value) { 40void TestEnvironment::SetMemory64(VAddr vaddr, u64 value) {