summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/arm/skyeye_common/armstate.cpp1
-rw-r--r--src/core/arm/skyeye_common/armsupp.cpp1
-rw-r--r--src/core/hle/config_mem.cpp7
-rw-r--r--src/core/hle/config_mem.h1
-rw-r--r--src/core/hle/function_wrappers.h8
-rw-r--r--src/core/hle/hle.cpp4
-rw-r--r--src/core/hle/kernel/kernel.cpp19
-rw-r--r--src/core/hle/kernel/memory.cpp136
-rw-r--r--src/core/hle/kernel/memory.h35
-rw-r--r--src/core/hle/kernel/process.cpp152
-rw-r--r--src/core/hle/kernel/process.h39
-rw-r--r--src/core/hle/kernel/resource_limit.cpp1
-rw-r--r--src/core/hle/kernel/thread.cpp4
-rw-r--r--src/core/hle/kernel/vm_manager.cpp118
-rw-r--r--src/core/hle/kernel/vm_manager.h38
-rw-r--r--src/core/hle/service/apt/apt.cpp21
-rw-r--r--src/core/hle/service/gsp_gpu.cpp26
-rw-r--r--src/core/hle/service/gsp_gpu.h11
-rw-r--r--src/core/hle/service/y2r_u.cpp1
-rw-r--r--src/core/hle/shared_page.cpp3
-rw-r--r--src/core/hle/shared_page.h1
-rw-r--r--src/core/hle/svc.cpp158
-rw-r--r--src/core/hw/gpu.cpp69
-rw-r--r--src/core/hw/gpu.h32
-rw-r--r--src/core/mem_map.cpp163
-rw-r--r--src/core/mem_map.h46
-rw-r--r--src/core/memory.cpp40
-rw-r--r--src/core/memory.h22
-rw-r--r--src/core/memory_setup.h3
-rw-r--r--src/core/system.cpp3
31 files changed, 823 insertions, 344 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 6cc60fd58..c17290b9b 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -29,6 +29,7 @@ set(SRCS
29 hle/kernel/address_arbiter.cpp 29 hle/kernel/address_arbiter.cpp
30 hle/kernel/event.cpp 30 hle/kernel/event.cpp
31 hle/kernel/kernel.cpp 31 hle/kernel/kernel.cpp
32 hle/kernel/memory.cpp
32 hle/kernel/mutex.cpp 33 hle/kernel/mutex.cpp
33 hle/kernel/process.cpp 34 hle/kernel/process.cpp
34 hle/kernel/resource_limit.cpp 35 hle/kernel/resource_limit.cpp
@@ -115,7 +116,6 @@ set(SRCS
115 loader/loader.cpp 116 loader/loader.cpp
116 loader/ncch.cpp 117 loader/ncch.cpp
117 tracer/recorder.cpp 118 tracer/recorder.cpp
118 mem_map.cpp
119 memory.cpp 119 memory.cpp
120 settings.cpp 120 settings.cpp
121 system.cpp 121 system.cpp
@@ -157,6 +157,7 @@ set(HEADERS
157 hle/kernel/address_arbiter.h 157 hle/kernel/address_arbiter.h
158 hle/kernel/event.h 158 hle/kernel/event.h
159 hle/kernel/kernel.h 159 hle/kernel/kernel.h
160 hle/kernel/memory.h
160 hle/kernel/mutex.h 161 hle/kernel/mutex.h
161 hle/kernel/process.h 162 hle/kernel/process.h
162 hle/kernel/resource_limit.h 163 hle/kernel/resource_limit.h
@@ -245,7 +246,6 @@ set(HEADERS
245 loader/ncch.h 246 loader/ncch.h
246 tracer/recorder.h 247 tracer/recorder.h
247 tracer/citrace.h 248 tracer/citrace.h
248 mem_map.h
249 memory.h 249 memory.h
250 memory_setup.h 250 memory_setup.h
251 settings.h 251 settings.h
diff --git a/src/core/arm/skyeye_common/armstate.cpp b/src/core/arm/skyeye_common/armstate.cpp
index ccb2eb0eb..0491717dc 100644
--- a/src/core/arm/skyeye_common/armstate.cpp
+++ b/src/core/arm/skyeye_common/armstate.cpp
@@ -4,7 +4,6 @@
4 4
5#include "common/swap.h" 5#include "common/swap.h"
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/mem_map.h"
8#include "core/memory.h" 7#include "core/memory.h"
9#include "core/arm/skyeye_common/armstate.h" 8#include "core/arm/skyeye_common/armstate.h"
10#include "core/arm/skyeye_common/vfp/vfp.h" 9#include "core/arm/skyeye_common/vfp/vfp.h"
diff --git a/src/core/arm/skyeye_common/armsupp.cpp b/src/core/arm/skyeye_common/armsupp.cpp
index d31fb9449..883713e86 100644
--- a/src/core/arm/skyeye_common/armsupp.cpp
+++ b/src/core/arm/skyeye_common/armsupp.cpp
@@ -17,7 +17,6 @@
17 17
18#include "common/logging/log.h" 18#include "common/logging/log.h"
19 19
20#include "core/mem_map.h"
21#include "core/arm/skyeye_common/arm_regformat.h" 20#include "core/arm/skyeye_common/arm_regformat.h"
22#include "core/arm/skyeye_common/armstate.h" 21#include "core/arm/skyeye_common/armstate.h"
23#include "core/arm/skyeye_common/armsupp.h" 22#include "core/arm/skyeye_common/armsupp.h"
diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp
index aea936d2d..b1a72dc0c 100644
--- a/src/core/hle/config_mem.cpp
+++ b/src/core/hle/config_mem.cpp
@@ -25,10 +25,6 @@ void Init() {
25 config_mem.sys_core_ver = 0x2; 25 config_mem.sys_core_ver = 0x2;
26 config_mem.unit_info = 0x1; // Bit 0 set for Retail 26 config_mem.unit_info = 0x1; // Bit 0 set for Retail
27 config_mem.prev_firm = 0; 27 config_mem.prev_firm = 0;
28 config_mem.app_mem_type = 0x2; // Default app mem type is 0
29 config_mem.app_mem_alloc = 0x06000000; // Set to 96MB, since some games use more than the default (64MB)
30 config_mem.base_mem_alloc = 0x01400000; // Default base memory is 20MB
31 config_mem.sys_mem_alloc = Memory::FCRAM_SIZE - (config_mem.app_mem_alloc + config_mem.base_mem_alloc);
32 config_mem.firm_unk = 0; 28 config_mem.firm_unk = 0;
33 config_mem.firm_version_rev = 0; 29 config_mem.firm_version_rev = 0;
34 config_mem.firm_version_min = 0x40; 30 config_mem.firm_version_min = 0x40;
@@ -36,7 +32,4 @@ void Init() {
36 config_mem.firm_sys_core_ver = 0x2; 32 config_mem.firm_sys_core_ver = 0x2;
37} 33}
38 34
39void Shutdown() {
40}
41
42} // namespace 35} // namespace
diff --git a/src/core/hle/config_mem.h b/src/core/hle/config_mem.h
index 9825a09e8..24a1254f2 100644
--- a/src/core/hle/config_mem.h
+++ b/src/core/hle/config_mem.h
@@ -52,6 +52,5 @@ static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE, "Config Memory
52extern ConfigMemDef config_mem; 52extern ConfigMemDef config_mem;
53 53
54void Init(); 54void Init();
55void Shutdown();
56 55
57} // namespace 56} // namespace
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 1a0518926..5846a161b 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -172,6 +172,14 @@ template<ResultCode func(u32, s64, s64)> void Wrap() {
172 FuncReturn(func(PARAM(0), param1, param2).raw); 172 FuncReturn(func(PARAM(0), param1, param2).raw);
173} 173}
174 174
175template<ResultCode func(s64*, Handle, u32)> void Wrap() {
176 s64 param_1 = 0;
177 u32 retval = func(&param_1, PARAM(1), PARAM(2)).raw;
178 Core::g_app_core->SetReg(1, (u32)param_1);
179 Core::g_app_core->SetReg(2, (u32)(param_1 >> 32));
180 FuncReturn(retval);
181}
182
175//////////////////////////////////////////////////////////////////////////////////////////////////// 183////////////////////////////////////////////////////////////////////////////////////////////////////
176// Function wrappers that return type u32 184// Function wrappers that return type u32
177 185
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp
index cd0a400dc..331b1b22a 100644
--- a/src/core/hle/hle.cpp
+++ b/src/core/hle/hle.cpp
@@ -34,8 +34,6 @@ void Reschedule(const char *reason) {
34 34
35void Init() { 35void Init() {
36 Service::Init(); 36 Service::Init();
37 ConfigMem::Init();
38 SharedPage::Init();
39 37
40 g_reschedule = false; 38 g_reschedule = false;
41 39
@@ -43,8 +41,6 @@ void Init() {
43} 41}
44 42
45void Shutdown() { 43void Shutdown() {
46 ConfigMem::Shutdown();
47 SharedPage::Shutdown();
48 Service::Shutdown(); 44 Service::Shutdown();
49 45
50 LOG_DEBUG(Kernel, "shutdown OK"); 46 LOG_DEBUG(Kernel, "shutdown OK");
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 5711c0405..7a401a965 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -7,11 +7,14 @@
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9 9
10#include "core/hle/config_mem.h"
10#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/resource_limit.h" 12#include "core/hle/kernel/memory.h"
12#include "core/hle/kernel/process.h" 13#include "core/hle/kernel/process.h"
14#include "core/hle/kernel/resource_limit.h"
13#include "core/hle/kernel/thread.h" 15#include "core/hle/kernel/thread.h"
14#include "core/hle/kernel/timer.h" 16#include "core/hle/kernel/timer.h"
17#include "core/hle/shared_page.h"
15 18
16namespace Kernel { 19namespace Kernel {
17 20
@@ -119,6 +122,13 @@ void HandleTable::Clear() {
119 122
120/// Initialize the kernel 123/// Initialize the kernel
121void Init() { 124void Init() {
125 ConfigMem::Init();
126 SharedPage::Init();
127
128 // TODO(yuriks): The memory type parameter needs to be determined by the ExHeader field instead
129 // For now it defaults to the one with a largest allocation to the app
130 Kernel::MemoryInit(2); // Allocates 96MB to the application
131
122 Kernel::ResourceLimitsInit(); 132 Kernel::ResourceLimitsInit();
123 Kernel::ThreadingInit(); 133 Kernel::ThreadingInit();
124 Kernel::TimersInit(); 134 Kernel::TimersInit();
@@ -131,11 +141,14 @@ void Init() {
131 141
132/// Shutdown the kernel 142/// Shutdown the kernel
133void Shutdown() { 143void Shutdown() {
144 g_handle_table.Clear(); // Free all kernel objects
145
134 Kernel::ThreadingShutdown(); 146 Kernel::ThreadingShutdown();
147 g_current_process = nullptr;
148
135 Kernel::TimersShutdown(); 149 Kernel::TimersShutdown();
136 Kernel::ResourceLimitsShutdown(); 150 Kernel::ResourceLimitsShutdown();
137 g_handle_table.Clear(); // Free all kernel objects 151 Kernel::MemoryShutdown();
138 g_current_process = nullptr;
139} 152}
140 153
141} // namespace 154} // namespace
diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp
new file mode 100644
index 000000000..e4fc5f3c4
--- /dev/null
+++ b/src/core/hle/kernel/memory.cpp
@@ -0,0 +1,136 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <map>
6#include <memory>
7#include <utility>
8#include <vector>
9
10#include "common/common_types.h"
11#include "common/logging/log.h"
12
13#include "core/hle/config_mem.h"
14#include "core/hle/kernel/memory.h"
15#include "core/hle/kernel/vm_manager.h"
16#include "core/hle/result.h"
17#include "core/hle/shared_page.h"
18#include "core/memory.h"
19#include "core/memory_setup.h"
20
21////////////////////////////////////////////////////////////////////////////////////////////////////
22
23namespace Kernel {
24
25static MemoryRegionInfo memory_regions[3];
26
27/// Size of the APPLICATION, SYSTEM and BASE memory regions (respectively) for each sytem
28/// memory configuration type.
29static const u32 memory_region_sizes[8][3] = {
30 // Old 3DS layouts
31 {0x04000000, 0x02C00000, 0x01400000}, // 0
32 { /* This appears to be unused. */ }, // 1
33 {0x06000000, 0x00C00000, 0x01400000}, // 2
34 {0x05000000, 0x01C00000, 0x01400000}, // 3
35 {0x04800000, 0x02400000, 0x01400000}, // 4
36 {0x02000000, 0x04C00000, 0x01400000}, // 5
37
38 // New 3DS layouts
39 {0x07C00000, 0x06400000, 0x02000000}, // 6
40 {0x0B200000, 0x02E00000, 0x02000000}, // 7
41};
42
43void MemoryInit(u32 mem_type) {
44 // TODO(yuriks): On the n3DS, all o3DS configurations (<=5) are forced to 6 instead.
45 ASSERT_MSG(mem_type <= 5, "New 3DS memory configuration aren't supported yet!");
46 ASSERT(mem_type != 1);
47
48 // The kernel allocation regions (APPLICATION, SYSTEM and BASE) are laid out in sequence, with
49 // the sizes specified in the memory_region_sizes table.
50 VAddr base = 0;
51 for (int i = 0; i < 3; ++i) {
52 memory_regions[i].base = base;
53 memory_regions[i].size = memory_region_sizes[mem_type][i];
54 memory_regions[i].linear_heap_memory = std::make_shared<std::vector<u8>>();
55
56 base += memory_regions[i].size;
57 }
58
59 // We must've allocated the entire FCRAM by the end
60 ASSERT(base == Memory::FCRAM_SIZE);
61
62 using ConfigMem::config_mem;
63 config_mem.app_mem_type = mem_type;
64 // app_mem_malloc does not always match the configured size for memory_region[0]: in case the
65 // n3DS type override is in effect it reports the size the game expects, not the real one.
66 config_mem.app_mem_alloc = memory_region_sizes[mem_type][0];
67 config_mem.sys_mem_alloc = memory_regions[1].size;
68 config_mem.base_mem_alloc = memory_regions[2].size;
69}
70
71void MemoryShutdown() {
72 for (auto& region : memory_regions) {
73 region.base = 0;
74 region.size = 0;
75 region.linear_heap_memory = nullptr;
76 }
77}
78
79MemoryRegionInfo* GetMemoryRegion(MemoryRegion region) {
80 switch (region) {
81 case MemoryRegion::APPLICATION:
82 return &memory_regions[0];
83 case MemoryRegion::SYSTEM:
84 return &memory_regions[1];
85 case MemoryRegion::BASE:
86 return &memory_regions[2];
87 default:
88 UNREACHABLE();
89 }
90}
91
92}
93
94namespace Memory {
95
96namespace {
97
98struct MemoryArea {
99 u32 base;
100 u32 size;
101 const char* name;
102};
103
104// We don't declare the IO regions in here since its handled by other means.
105static MemoryArea memory_areas[] = {
106 {SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, "Shared Memory"}, // Shared memory
107 {VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM)
108 {DSP_RAM_VADDR, DSP_RAM_SIZE, "DSP RAM"}, // DSP memory
109 {TLS_AREA_VADDR, TLS_AREA_SIZE, "TLS Area"}, // TLS memory
110};
111
112}
113
114void Init() {
115 InitMemoryMap();
116 LOG_DEBUG(HW_Memory, "initialized OK");
117}
118
119void InitLegacyAddressSpace(Kernel::VMManager& address_space) {
120 using namespace Kernel;
121
122 for (MemoryArea& area : memory_areas) {
123 auto block = std::make_shared<std::vector<u8>>(area.size);
124 address_space.MapMemoryBlock(area.base, std::move(block), 0, area.size, MemoryState::Private).Unwrap();
125 }
126
127 auto cfg_mem_vma = address_space.MapBackingMemory(CONFIG_MEMORY_VADDR,
128 (u8*)&ConfigMem::config_mem, CONFIG_MEMORY_SIZE, MemoryState::Shared).MoveFrom();
129 address_space.Reprotect(cfg_mem_vma, VMAPermission::Read);
130
131 auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR,
132 (u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom();
133 address_space.Reprotect(shared_page_vma, VMAPermission::Read);
134}
135
136} // namespace
diff --git a/src/core/hle/kernel/memory.h b/src/core/hle/kernel/memory.h
new file mode 100644
index 000000000..36690b091
--- /dev/null
+++ b/src/core/hle/kernel/memory.h
@@ -0,0 +1,35 @@
1// Copyright 2014 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 <memory>
8
9#include "common/common_types.h"
10
11#include "core/hle/kernel/process.h"
12
13namespace Kernel {
14
15class VMManager;
16
17struct MemoryRegionInfo {
18 u32 base; // Not an address, but offset from start of FCRAM
19 u32 size;
20
21 std::shared_ptr<std::vector<u8>> linear_heap_memory;
22};
23
24void MemoryInit(u32 mem_type);
25void MemoryShutdown();
26MemoryRegionInfo* GetMemoryRegion(MemoryRegion region);
27
28}
29
30namespace Memory {
31
32void Init();
33void InitLegacyAddressSpace(Kernel::VMManager& address_space);
34
35} // namespace
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index a7892c652..124047a53 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -7,11 +7,11 @@
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "common/make_unique.h" 8#include "common/make_unique.h"
9 9
10#include "core/hle/kernel/memory.h"
10#include "core/hle/kernel/process.h" 11#include "core/hle/kernel/process.h"
11#include "core/hle/kernel/resource_limit.h" 12#include "core/hle/kernel/resource_limit.h"
12#include "core/hle/kernel/thread.h" 13#include "core/hle/kernel/thread.h"
13#include "core/hle/kernel/vm_manager.h" 14#include "core/hle/kernel/vm_manager.h"
14#include "core/mem_map.h"
15#include "core/memory.h" 15#include "core/memory.h"
16 16
17namespace Kernel { 17namespace Kernel {
@@ -36,8 +36,7 @@ SharedPtr<Process> Process::Create(SharedPtr<CodeSet> code_set) {
36 process->codeset = std::move(code_set); 36 process->codeset = std::move(code_set);
37 process->flags.raw = 0; 37 process->flags.raw = 0;
38 process->flags.memory_region = MemoryRegion::APPLICATION; 38 process->flags.memory_region = MemoryRegion::APPLICATION;
39 process->address_space = Common::make_unique<VMManager>(); 39 Memory::InitLegacyAddressSpace(process->vm_manager);
40 Memory::InitLegacyAddressSpace(*process->address_space);
41 40
42 return process; 41 return process;
43} 42}
@@ -93,9 +92,11 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
93 mapping.unk_flag = false; 92 mapping.unk_flag = false;
94 } else if ((type & 0xFE0) == 0xFC0) { // 0x01FF 93 } else if ((type & 0xFE0) == 0xFC0) { // 0x01FF
95 // Kernel version 94 // Kernel version
96 int minor = descriptor & 0xFF; 95 kernel_version = descriptor & 0xFFFF;
97 int major = (descriptor >> 8) & 0xFF; 96
98 LOG_INFO(Loader, "ExHeader kernel version ignored: %d.%d", major, minor); 97 int minor = kernel_version & 0xFF;
98 int major = (kernel_version >> 8) & 0xFF;
99 LOG_INFO(Loader, "ExHeader kernel version: %d.%d", major, minor);
99 } else { 100 } else {
100 LOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x%08X", descriptor); 101 LOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x%08X", descriptor);
101 } 102 }
@@ -103,20 +104,153 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
103} 104}
104 105
105void Process::Run(s32 main_thread_priority, u32 stack_size) { 106void Process::Run(s32 main_thread_priority, u32 stack_size) {
107 memory_region = GetMemoryRegion(flags.memory_region);
108
106 auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) { 109 auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) {
107 auto vma = address_space->MapMemoryBlock(segment.addr, codeset->memory, 110 auto vma = vm_manager.MapMemoryBlock(segment.addr, codeset->memory,
108 segment.offset, segment.size, memory_state).Unwrap(); 111 segment.offset, segment.size, memory_state).Unwrap();
109 address_space->Reprotect(vma, permissions); 112 vm_manager.Reprotect(vma, permissions);
113 misc_memory_used += segment.size;
110 }; 114 };
111 115
116 // Map CodeSet segments
112 MapSegment(codeset->code, VMAPermission::ReadExecute, MemoryState::Code); 117 MapSegment(codeset->code, VMAPermission::ReadExecute, MemoryState::Code);
113 MapSegment(codeset->rodata, VMAPermission::Read, MemoryState::Code); 118 MapSegment(codeset->rodata, VMAPermission::Read, MemoryState::Code);
114 MapSegment(codeset->data, VMAPermission::ReadWrite, MemoryState::Private); 119 MapSegment(codeset->data, VMAPermission::ReadWrite, MemoryState::Private);
115 120
116 address_space->LogLayout(); 121 // Allocate and map stack
122 vm_manager.MapMemoryBlock(Memory::HEAP_VADDR_END - stack_size,
123 std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, MemoryState::Locked
124 ).Unwrap();
125 misc_memory_used += stack_size;
126
127 vm_manager.LogLayout(Log::Level::Debug);
117 Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority); 128 Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority);
118} 129}
119 130
131VAddr Process::GetLinearHeapBase() const {
132 return (kernel_version < 0x22C ? Memory::LINEAR_HEAP_VADDR : Memory::NEW_LINEAR_HEAP_SIZE)
133 + memory_region->base;
134}
135
136VAddr Process::GetLinearHeapLimit() const {
137 return GetLinearHeapBase() + memory_region->size;
138}
139
140ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission perms) {
141 if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || target + size < target) {
142 return ERR_INVALID_ADDRESS;
143 }
144
145 if (heap_memory == nullptr) {
146 // Initialize heap
147 heap_memory = std::make_shared<std::vector<u8>>();
148 heap_start = heap_end = target;
149 }
150
151 // If necessary, expand backing vector to cover new heap extents.
152 if (target < heap_start) {
153 heap_memory->insert(begin(*heap_memory), heap_start - target, 0);
154 heap_start = target;
155 vm_manager.RefreshMemoryBlockMappings(heap_memory.get());
156 }
157 if (target + size > heap_end) {
158 heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0);
159 heap_end = target + size;
160 vm_manager.RefreshMemoryBlockMappings(heap_memory.get());
161 }
162 ASSERT(heap_end - heap_start == heap_memory->size());
163
164 CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start, size, MemoryState::Private));
165 vm_manager.Reprotect(vma, perms);
166
167 heap_used += size;
168
169 return MakeResult<VAddr>(heap_end - size);
170}
171
172ResultCode Process::HeapFree(VAddr target, u32 size) {
173 if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || target + size < target) {
174 return ERR_INVALID_ADDRESS;
175 }
176
177 ResultCode result = vm_manager.UnmapRange(target, size);
178 if (result.IsError()) return result;
179
180 heap_used -= size;
181
182 return RESULT_SUCCESS;
183}
184
185ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission perms) {
186 auto& linheap_memory = memory_region->linear_heap_memory;
187
188 VAddr heap_end = GetLinearHeapBase() + (u32)linheap_memory->size();
189 // Games and homebrew only ever seem to pass 0 here (which lets the kernel decide the address),
190 // but explicit addresses are also accepted and respected.
191 if (target == 0) {
192 target = heap_end;
193 }
194
195 if (target < GetLinearHeapBase() || target + size > GetLinearHeapLimit() ||
196 target > heap_end || target + size < target) {
197
198 return ERR_INVALID_ADDRESS;
199 }
200
201 // Expansion of the linear heap is only allowed if you do an allocation immediatelly at its
202 // end. It's possible to free gaps in the middle of the heap and then reallocate them later,
203 // but expansions are only allowed at the end.
204 if (target == heap_end) {
205 linheap_memory->insert(linheap_memory->end(), size, 0);
206 vm_manager.RefreshMemoryBlockMappings(linheap_memory.get());
207 }
208
209 // TODO(yuriks): As is, this lets processes map memory allocated by other processes from the
210 // same region. It is unknown if or how the 3DS kernel checks against this.
211 size_t offset = target - GetLinearHeapBase();
212 CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, linheap_memory, offset, size, MemoryState::Continuous));
213 vm_manager.Reprotect(vma, perms);
214
215 linear_heap_used += size;
216
217 return MakeResult<VAddr>(target);
218}
219
220ResultCode Process::LinearFree(VAddr target, u32 size) {
221 auto& linheap_memory = memory_region->linear_heap_memory;
222
223 if (target < GetLinearHeapBase() || target + size > GetLinearHeapLimit() ||
224 target + size < target) {
225
226 return ERR_INVALID_ADDRESS;
227 }
228
229 VAddr heap_end = GetLinearHeapBase() + (u32)linheap_memory->size();
230 if (target + size > heap_end) {
231 return ERR_INVALID_ADDRESS_STATE;
232 }
233
234 ResultCode result = vm_manager.UnmapRange(target, size);
235 if (result.IsError()) return result;
236
237 linear_heap_used -= size;
238
239 if (target + size == heap_end) {
240 // End of linear heap has been freed, so check what's the last allocated block in it and
241 // reduce the size.
242 auto vma = vm_manager.FindVMA(target);
243 ASSERT(vma != vm_manager.vma_map.end());
244 ASSERT(vma->second.type == VMAType::Free);
245 VAddr new_end = vma->second.base;
246 if (new_end >= GetLinearHeapBase()) {
247 linheap_memory->resize(new_end - GetLinearHeapBase());
248 }
249 }
250
251 return RESULT_SUCCESS;
252}
253
120Kernel::Process::Process() {} 254Kernel::Process::Process() {}
121Kernel::Process::~Process() {} 255Kernel::Process::~Process() {}
122 256
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 83d3aceae..60e17f251 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -15,6 +15,7 @@
15#include "common/common_types.h" 15#include "common/common_types.h"
16 16
17#include "core/hle/kernel/kernel.h" 17#include "core/hle/kernel/kernel.h"
18#include "core/hle/kernel/vm_manager.h"
18 19
19namespace Kernel { 20namespace Kernel {
20 21
@@ -48,7 +49,7 @@ union ProcessFlags {
48}; 49};
49 50
50class ResourceLimit; 51class ResourceLimit;
51class VMManager; 52struct MemoryRegionInfo;
52 53
53struct CodeSet final : public Object { 54struct CodeSet final : public Object {
54 static SharedPtr<CodeSet> Create(std::string name, u64 program_id); 55 static SharedPtr<CodeSet> Create(std::string name, u64 program_id);
@@ -104,14 +105,12 @@ public:
104 /// processes access to specific I/O regions and device memory. 105 /// processes access to specific I/O regions and device memory.
105 boost::container::static_vector<AddressMapping, 8> address_mappings; 106 boost::container::static_vector<AddressMapping, 8> address_mappings;
106 ProcessFlags flags; 107 ProcessFlags flags;
108 /// Kernel compatibility version for this process
109 u16 kernel_version = 0;
107 110
108 /// The id of this process 111 /// The id of this process
109 u32 process_id = next_process_id++; 112 u32 process_id = next_process_id++;
110 113
111 /// Bitmask of the used TLS slots
112 std::bitset<300> used_tls_slots;
113 std::unique_ptr<VMManager> address_space;
114
115 /** 114 /**
116 * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them 115 * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
117 * to this process. 116 * to this process.
@@ -123,6 +122,36 @@ public:
123 */ 122 */
124 void Run(s32 main_thread_priority, u32 stack_size); 123 void Run(s32 main_thread_priority, u32 stack_size);
125 124
125
126 ///////////////////////////////////////////////////////////////////////////////////////////////
127 // Memory Management
128
129 VMManager vm_manager;
130
131 // Memory used to back the allocations in the regular heap. A single vector is used to cover
132 // the entire virtual address space extents that bound the allocations, including any holes.
133 // This makes deallocation and reallocation of holes fast and keeps process memory contiguous
134 // in the emulator address space, allowing Memory::GetPointer to be reasonably safe.
135 std::shared_ptr<std::vector<u8>> heap_memory;
136 // The left/right bounds of the address space covered by heap_memory.
137 VAddr heap_start = 0, heap_end = 0;
138
139 u32 heap_used = 0, linear_heap_used = 0, misc_memory_used = 0;
140
141 MemoryRegionInfo* memory_region = nullptr;
142
143 /// Bitmask of the used TLS slots
144 std::bitset<300> used_tls_slots;
145
146 VAddr GetLinearHeapBase() const;
147 VAddr GetLinearHeapLimit() const;
148
149 ResultVal<VAddr> HeapAllocate(VAddr target, u32 size, VMAPermission perms);
150 ResultCode HeapFree(VAddr target, u32 size);
151
152 ResultVal<VAddr> LinearAllocate(VAddr target, u32 size, VMAPermission perms);
153 ResultCode LinearFree(VAddr target, u32 size);
154
126private: 155private:
127 Process(); 156 Process();
128 ~Process() override; 157 ~Process() override;
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp
index 94b3e3298..67dde08c2 100644
--- a/src/core/hle/kernel/resource_limit.cpp
+++ b/src/core/hle/kernel/resource_limit.cpp
@@ -6,7 +6,6 @@
6 6
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8 8
9#include "core/mem_map.h"
10#include "core/hle/kernel/resource_limit.h" 9#include "core/hle/kernel/resource_limit.h"
11 10
12namespace Kernel { 11namespace Kernel {
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 29ea6d531..c10126513 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -117,6 +117,7 @@ void Thread::Stop() {
117 wait_objects.clear(); 117 wait_objects.clear();
118 118
119 Kernel::g_current_process->used_tls_slots[tls_index] = false; 119 Kernel::g_current_process->used_tls_slots[tls_index] = false;
120 g_current_process->misc_memory_used -= Memory::TLS_ENTRY_SIZE;
120 121
121 HLE::Reschedule(__func__); 122 HLE::Reschedule(__func__);
122} 123}
@@ -414,6 +415,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
414 } 415 }
415 416
416 ASSERT_MSG(thread->tls_index != -1, "Out of TLS space"); 417 ASSERT_MSG(thread->tls_index != -1, "Out of TLS space");
418 g_current_process->misc_memory_used += Memory::TLS_ENTRY_SIZE;
417 419
418 // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used 420 // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
419 // to initialize the context 421 // to initialize the context
@@ -504,7 +506,7 @@ void Thread::SetWaitSynchronizationOutput(s32 output) {
504} 506}
505 507
506VAddr Thread::GetTLSAddress() const { 508VAddr Thread::GetTLSAddress() const {
507 return Memory::TLS_AREA_VADDR + tls_index * 0x200; 509 return Memory::TLS_AREA_VADDR + tls_index * Memory::TLS_ENTRY_SIZE;
508} 510}
509 511
510//////////////////////////////////////////////////////////////////////////////////////////////////// 512////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 205cc7b53..2610acf76 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -11,6 +11,15 @@
11 11
12namespace Kernel { 12namespace Kernel {
13 13
14static const char* GetMemoryStateName(MemoryState state) {
15 static const char* names[] = {
16 "Free", "Reserved", "IO", "Static", "Code", "Private", "Shared", "Continuous", "Aliased",
17 "Alias", "AliasCode", "Locked",
18 };
19
20 return names[(int)state];
21}
22
14bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const { 23bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
15 ASSERT(base + size == next.base); 24 ASSERT(base + size == next.base);
16 if (permissions != next.permissions || 25 if (permissions != next.permissions ||
@@ -51,11 +60,15 @@ void VMManager::Reset() {
51} 60}
52 61
53VMManager::VMAHandle VMManager::FindVMA(VAddr target) const { 62VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
54 return std::prev(vma_map.upper_bound(target)); 63 if (target >= MAX_ADDRESS) {
64 return vma_map.end();
65 } else {
66 return std::prev(vma_map.upper_bound(target));
67 }
55} 68}
56 69
57ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, 70ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
58 std::shared_ptr<std::vector<u8>> block, u32 offset, u32 size, MemoryState state) { 71 std::shared_ptr<std::vector<u8>> block, size_t offset, u32 size, MemoryState state) {
59 ASSERT(block != nullptr); 72 ASSERT(block != nullptr);
60 ASSERT(offset + size <= block->size()); 73 ASSERT(offset + size <= block->size());
61 74
@@ -106,10 +119,8 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u3
106 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); 119 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
107} 120}
108 121
109void VMManager::Unmap(VMAHandle vma_handle) { 122VMManager::VMAIter VMManager::Unmap(VMAIter vma_handle) {
110 VMAIter iter = StripIterConstness(vma_handle); 123 VirtualMemoryArea& vma = vma_handle->second;
111
112 VirtualMemoryArea& vma = iter->second;
113 vma.type = VMAType::Free; 124 vma.type = VMAType::Free;
114 vma.permissions = VMAPermission::None; 125 vma.permissions = VMAPermission::None;
115 vma.meminfo_state = MemoryState::Free; 126 vma.meminfo_state = MemoryState::Free;
@@ -121,26 +132,67 @@ void VMManager::Unmap(VMAHandle vma_handle) {
121 132
122 UpdatePageTableForVMA(vma); 133 UpdatePageTableForVMA(vma);
123 134
124 MergeAdjacent(iter); 135 return MergeAdjacent(vma_handle);
136}
137
138ResultCode VMManager::UnmapRange(VAddr target, u32 size) {
139 CASCADE_RESULT(VMAIter vma, CarveVMARange(target, size));
140 VAddr target_end = target + size;
141
142 VMAIter end = vma_map.end();
143 // The comparison against the end of the range must be done using addresses since VMAs can be
144 // merged during this process, causing invalidation of the iterators.
145 while (vma != end && vma->second.base < target_end) {
146 vma = std::next(Unmap(vma));
147 }
148
149 ASSERT(FindVMA(target)->second.size >= size);
150 return RESULT_SUCCESS;
125} 151}
126 152
127void VMManager::Reprotect(VMAHandle vma_handle, VMAPermission new_perms) { 153VMManager::VMAHandle VMManager::Reprotect(VMAHandle vma_handle, VMAPermission new_perms) {
128 VMAIter iter = StripIterConstness(vma_handle); 154 VMAIter iter = StripIterConstness(vma_handle);
129 155
130 VirtualMemoryArea& vma = iter->second; 156 VirtualMemoryArea& vma = iter->second;
131 vma.permissions = new_perms; 157 vma.permissions = new_perms;
132 UpdatePageTableForVMA(vma); 158 UpdatePageTableForVMA(vma);
133 159
134 MergeAdjacent(iter); 160 return MergeAdjacent(iter);
161}
162
163ResultCode VMManager::ReprotectRange(VAddr target, u32 size, VMAPermission new_perms) {
164 CASCADE_RESULT(VMAIter vma, CarveVMARange(target, size));
165 VAddr target_end = target + size;
166
167 VMAIter end = vma_map.end();
168 // The comparison against the end of the range must be done using addresses since VMAs can be
169 // merged during this process, causing invalidation of the iterators.
170 while (vma != end && vma->second.base < target_end) {
171 vma = std::next(StripIterConstness(Reprotect(vma, new_perms)));
172 }
173
174 return RESULT_SUCCESS;
135} 175}
136 176
137void VMManager::LogLayout() const { 177void VMManager::RefreshMemoryBlockMappings(const std::vector<u8>* block) {
178 // If this ever proves to have a noticeable performance impact, allow users of the function to
179 // specify a specific range of addresses to limit the scan to.
138 for (const auto& p : vma_map) { 180 for (const auto& p : vma_map) {
139 const VirtualMemoryArea& vma = p.second; 181 const VirtualMemoryArea& vma = p.second;
140 LOG_DEBUG(Kernel, "%08X - %08X size: %8X %c%c%c", vma.base, vma.base + vma.size, vma.size, 182 if (block == vma.backing_block.get()) {
183 UpdatePageTableForVMA(vma);
184 }
185 }
186}
187
188void VMManager::LogLayout(Log::Level log_level) const {
189 for (const auto& p : vma_map) {
190 const VirtualMemoryArea& vma = p.second;
191 LOG_GENERIC(Log::Class::Kernel, log_level, "%08X - %08X size: %8X %c%c%c %s",
192 vma.base, vma.base + vma.size, vma.size,
141 (u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-', 193 (u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-',
142 (u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-', 194 (u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-',
143 (u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-'); 195 (u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-', GetMemoryStateName(vma.meminfo_state));
144 } 196 }
145} 197}
146 198
@@ -151,21 +203,19 @@ VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle & iter) {
151} 203}
152 204
153ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) { 205ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) {
154 ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: %8X", size); 206 ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: 0x%8X", size);
155 ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: %08X", base); 207 ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: 0x%08X", base);
156 208
157 VMAIter vma_handle = StripIterConstness(FindVMA(base)); 209 VMAIter vma_handle = StripIterConstness(FindVMA(base));
158 if (vma_handle == vma_map.end()) { 210 if (vma_handle == vma_map.end()) {
159 // Target address is outside the range managed by the kernel 211 // Target address is outside the range managed by the kernel
160 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, 212 return ERR_INVALID_ADDRESS;
161 ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E01BF5
162 } 213 }
163 214
164 VirtualMemoryArea& vma = vma_handle->second; 215 VirtualMemoryArea& vma = vma_handle->second;
165 if (vma.type != VMAType::Free) { 216 if (vma.type != VMAType::Free) {
166 // Region is already allocated 217 // Region is already allocated
167 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, 218 return ERR_INVALID_ADDRESS_STATE;
168 ErrorSummary::InvalidState, ErrorLevel::Usage); // 0xE0A01BF5
169 } 219 }
170 220
171 u32 start_in_vma = base - vma.base; 221 u32 start_in_vma = base - vma.base;
@@ -173,8 +223,7 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) {
173 223
174 if (end_in_vma > vma.size) { 224 if (end_in_vma > vma.size) {
175 // Requested allocation doesn't fit inside VMA 225 // Requested allocation doesn't fit inside VMA
176 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, 226 return ERR_INVALID_ADDRESS_STATE;
177 ErrorSummary::InvalidState, ErrorLevel::Usage); // 0xE0A01BF5
178 } 227 }
179 228
180 if (end_in_vma != vma.size) { 229 if (end_in_vma != vma.size) {
@@ -189,6 +238,35 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) {
189 return MakeResult<VMAIter>(vma_handle); 238 return MakeResult<VMAIter>(vma_handle);
190} 239}
191 240
241ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u32 size) {
242 ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: 0x%8X", size);
243 ASSERT_MSG((target & Memory::PAGE_MASK) == 0, "non-page aligned base: 0x%08X", target);
244
245 VAddr target_end = target + size;
246 ASSERT(target_end >= target);
247 ASSERT(target_end <= MAX_ADDRESS);
248 ASSERT(size > 0);
249
250 VMAIter begin_vma = StripIterConstness(FindVMA(target));
251 VMAIter i_end = vma_map.lower_bound(target_end);
252 for (auto i = begin_vma; i != i_end; ++i) {
253 if (i->second.type == VMAType::Free) {
254 return ERR_INVALID_ADDRESS_STATE;
255 }
256 }
257
258 if (target != begin_vma->second.base) {
259 begin_vma = SplitVMA(begin_vma, target - begin_vma->second.base);
260 }
261
262 VMAIter end_vma = StripIterConstness(FindVMA(target_end));
263 if (end_vma != vma_map.end() && target_end != end_vma->second.base) {
264 end_vma = SplitVMA(end_vma, target_end - end_vma->second.base);
265 }
266
267 return MakeResult<VMAIter>(begin_vma);
268}
269
192VMManager::VMAIter VMManager::SplitVMA(VMAIter vma_handle, u32 offset_in_vma) { 270VMManager::VMAIter VMManager::SplitVMA(VMAIter vma_handle, u32 offset_in_vma) {
193 VirtualMemoryArea& old_vma = vma_handle->second; 271 VirtualMemoryArea& old_vma = vma_handle->second;
194 VirtualMemoryArea new_vma = old_vma; // Make a copy of the VMA 272 VirtualMemoryArea new_vma = old_vma; // Make a copy of the VMA
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index b3795a94a..4e95f1f0c 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -14,6 +14,14 @@
14 14
15namespace Kernel { 15namespace Kernel {
16 16
17const ResultCode ERR_INVALID_ADDRESS{ // 0xE0E01BF5
18 ErrorDescription::InvalidAddress, ErrorModule::OS,
19 ErrorSummary::InvalidArgument, ErrorLevel::Usage};
20
21const ResultCode ERR_INVALID_ADDRESS_STATE{ // 0xE0A01BF5
22 ErrorDescription::InvalidAddress, ErrorModule::OS,
23 ErrorSummary::InvalidState, ErrorLevel::Usage};
24
17enum class VMAType : u8 { 25enum class VMAType : u8 {
18 /// VMA represents an unmapped region of the address space. 26 /// VMA represents an unmapped region of the address space.
19 Free, 27 Free,
@@ -75,7 +83,7 @@ struct VirtualMemoryArea {
75 /// Memory block backing this VMA. 83 /// Memory block backing this VMA.
76 std::shared_ptr<std::vector<u8>> backing_block = nullptr; 84 std::shared_ptr<std::vector<u8>> backing_block = nullptr;
77 /// Offset into the backing_memory the mapping starts from. 85 /// Offset into the backing_memory the mapping starts from.
78 u32 offset = 0; 86 size_t offset = 0;
79 87
80 // Settings for type = BackingMemory 88 // Settings for type = BackingMemory
81 /// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed. 89 /// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed.
@@ -141,7 +149,7 @@ public:
141 * @param state MemoryState tag to attach to the VMA. 149 * @param state MemoryState tag to attach to the VMA.
142 */ 150 */
143 ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block, 151 ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block,
144 u32 offset, u32 size, MemoryState state); 152 size_t offset, u32 size, MemoryState state);
145 153
146 /** 154 /**
147 * Maps an unmanaged host memory pointer at a given address. 155 * Maps an unmanaged host memory pointer at a given address.
@@ -163,14 +171,23 @@ public:
163 */ 171 */
164 ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state); 172 ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state);
165 173
166 /// Unmaps the given VMA. 174 /// Unmaps a range of addresses, splitting VMAs as necessary.
167 void Unmap(VMAHandle vma); 175 ResultCode UnmapRange(VAddr target, u32 size);
168 176
169 /// Changes the permissions of the given VMA. 177 /// Changes the permissions of the given VMA.
170 void Reprotect(VMAHandle vma, VMAPermission new_perms); 178 VMAHandle Reprotect(VMAHandle vma, VMAPermission new_perms);
179
180 /// Changes the permissions of a range of addresses, splitting VMAs as necessary.
181 ResultCode ReprotectRange(VAddr target, u32 size, VMAPermission new_perms);
182
183 /**
184 * Scans all VMAs and updates the page table range of any that use the given vector as backing
185 * memory. This should be called after any operation that causes reallocation of the vector.
186 */
187 void RefreshMemoryBlockMappings(const std::vector<u8>* block);
171 188
172 /// Dumps the address space layout to the log, for debugging 189 /// Dumps the address space layout to the log, for debugging
173 void LogLayout() const; 190 void LogLayout(Log::Level log_level) const;
174 191
175private: 192private:
176 using VMAIter = decltype(vma_map)::iterator; 193 using VMAIter = decltype(vma_map)::iterator;
@@ -178,6 +195,9 @@ private:
178 /// Converts a VMAHandle to a mutable VMAIter. 195 /// Converts a VMAHandle to a mutable VMAIter.
179 VMAIter StripIterConstness(const VMAHandle& iter); 196 VMAIter StripIterConstness(const VMAHandle& iter);
180 197
198 /// Unmaps the given VMA.
199 VMAIter Unmap(VMAIter vma);
200
181 /** 201 /**
182 * Carves a VMA of a specific size at the specified address by splitting Free VMAs while doing 202 * Carves a VMA of a specific size at the specified address by splitting Free VMAs while doing
183 * the appropriate error checking. 203 * the appropriate error checking.
@@ -185,6 +205,12 @@ private:
185 ResultVal<VMAIter> CarveVMA(VAddr base, u32 size); 205 ResultVal<VMAIter> CarveVMA(VAddr base, u32 size);
186 206
187 /** 207 /**
208 * Splits the edges of the given range of non-Free VMAs so that there is a VMA split at each
209 * end of the range.
210 */
211 ResultVal<VMAIter> CarveVMARange(VAddr base, u32 size);
212
213 /**
188 * Splits a VMA in two, at the specified offset. 214 * Splits a VMA in two, at the specified offset.
189 * @returns the right side of the split, with the original iterator becoming the left side. 215 * @returns the right side of the split, with the original iterator becoming the left side.
190 */ 216 */
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 35402341b..6a2fdea2b 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -16,6 +16,7 @@
16#include "core/hle/hle.h" 16#include "core/hle/hle.h"
17#include "core/hle/kernel/event.h" 17#include "core/hle/kernel/event.h"
18#include "core/hle/kernel/mutex.h" 18#include "core/hle/kernel/mutex.h"
19#include "core/hle/kernel/process.h"
19#include "core/hle/kernel/shared_memory.h" 20#include "core/hle/kernel/shared_memory.h"
20#include "core/hle/kernel/thread.h" 21#include "core/hle/kernel/thread.h"
21 22
@@ -37,7 +38,7 @@ static Kernel::SharedPtr<Kernel::Mutex> lock;
37static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event 38static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
38static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event 39static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event
39 40
40static std::vector<u8> shared_font; 41static std::shared_ptr<std::vector<u8>> shared_font;
41 42
42static u32 cpu_percent; ///< CPU time available to the running application 43static u32 cpu_percent; ///< CPU time available to the running application
43 44
@@ -74,11 +75,12 @@ void Initialize(Service::Interface* self) {
74void GetSharedFont(Service::Interface* self) { 75void GetSharedFont(Service::Interface* self) {
75 u32* cmd_buff = Kernel::GetCommandBuffer(); 76 u32* cmd_buff = Kernel::GetCommandBuffer();
76 77
77 if (!shared_font.empty()) { 78 if (shared_font != nullptr) {
78 // TODO(bunnei): This function shouldn't copy the shared font every time it's called. 79 // TODO(yuriks): This is a hack to keep this working right now even with our completely
79 // Instead, it should probably map the shared font as RO memory. We don't currently have 80 // broken shared memory system.
80 // an easy way to do this, but the copy should be sufficient for now. 81 shared_font_mem->base_address = SHARED_FONT_VADDR;
81 memcpy(Memory::GetPointer(SHARED_FONT_VADDR), shared_font.data(), shared_font.size()); 82 Kernel::g_current_process->vm_manager.MapMemoryBlock(shared_font_mem->base_address,
83 shared_font, 0, shared_font_mem->size, Kernel::MemoryState::Shared);
82 84
83 cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2); 85 cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2);
84 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 86 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -391,7 +393,6 @@ void Init() {
391 // a homebrew app to do this: https://github.com/citra-emu/3dsutils. Put the resulting file 393 // a homebrew app to do this: https://github.com/citra-emu/3dsutils. Put the resulting file
392 // "shared_font.bin" in the Citra "sysdata" directory. 394 // "shared_font.bin" in the Citra "sysdata" directory.
393 395
394 shared_font.clear();
395 std::string filepath = FileUtil::GetUserPath(D_SYSDATA_IDX) + SHARED_FONT; 396 std::string filepath = FileUtil::GetUserPath(D_SYSDATA_IDX) + SHARED_FONT;
396 397
397 FileUtil::CreateFullPath(filepath); // Create path if not already created 398 FileUtil::CreateFullPath(filepath); // Create path if not already created
@@ -399,8 +400,8 @@ void Init() {
399 400
400 if (file.IsOpen()) { 401 if (file.IsOpen()) {
401 // Read shared font data 402 // Read shared font data
402 shared_font.resize((size_t)file.GetSize()); 403 shared_font = std::make_shared<std::vector<u8>>((size_t)file.GetSize());
403 file.ReadBytes(shared_font.data(), (size_t)file.GetSize()); 404 file.ReadBytes(shared_font->data(), shared_font->size());
404 405
405 // Create shared font memory object 406 // Create shared font memory object
406 using Kernel::MemoryPermission; 407 using Kernel::MemoryPermission;
@@ -424,7 +425,7 @@ void Init() {
424} 425}
425 426
426void Shutdown() { 427void Shutdown() {
427 shared_font.clear(); 428 shared_font = nullptr;
428 shared_font_mem = nullptr; 429 shared_font_mem = nullptr;
429 lock = nullptr; 430 lock = nullptr;
430 notification_event = nullptr; 431 notification_event = nullptr;
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index e93c1b436..fde508a13 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -4,7 +4,6 @@
4 4
5#include "common/bit_field.h" 5#include "common/bit_field.h"
6 6
7#include "core/mem_map.h"
8#include "core/memory.h" 7#include "core/memory.h"
9#include "core/hle/kernel/event.h" 8#include "core/hle/kernel/event.h"
10#include "core/hle/kernel/shared_memory.h" 9#include "core/hle/kernel/shared_memory.h"
@@ -418,7 +417,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
418 417
419 case CommandId::SET_DISPLAY_TRANSFER: 418 case CommandId::SET_DISPLAY_TRANSFER:
420 { 419 {
421 auto& params = command.image_copy; 420 auto& params = command.display_transfer;
422 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_address)), 421 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_address)),
423 Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3); 422 Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3);
424 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_address)), 423 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_address)),
@@ -433,17 +432,22 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
433 // TODO: Check if texture copies are implemented correctly.. 432 // TODO: Check if texture copies are implemented correctly..
434 case CommandId::SET_TEXTURE_COPY: 433 case CommandId::SET_TEXTURE_COPY:
435 { 434 {
436 auto& params = command.image_copy; 435 auto& params = command.texture_copy;
437 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_address)), 436 WriteGPURegister((u32)GPU_REG_INDEX(display_transfer_config.input_address),
438 Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3); 437 Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3);
439 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_address)), 438 WriteGPURegister((u32)GPU_REG_INDEX(display_transfer_config.output_address),
440 Memory::VirtualToPhysicalAddress(params.out_buffer_address) >> 3); 439 Memory::VirtualToPhysicalAddress(params.out_buffer_address) >> 3);
441 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_size)), params.in_buffer_size); 440 WriteGPURegister((u32)GPU_REG_INDEX(display_transfer_config.texture_copy.size),
442 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_size)), params.out_buffer_size); 441 params.size);
443 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.flags)), params.flags); 442 WriteGPURegister((u32)GPU_REG_INDEX(display_transfer_config.texture_copy.input_size),
444 443 params.in_width_gap);
445 // TODO: Should this register be set to 1 or should instead its value be OR-ed with 1? 444 WriteGPURegister((u32)GPU_REG_INDEX(display_transfer_config.texture_copy.output_size),
446 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.trigger)), 1); 445 params.out_width_gap);
446 WriteGPURegister((u32)GPU_REG_INDEX(display_transfer_config.flags),
447 params.flags);
448
449 // NOTE: Actual GSP ORs 1 with current register instead of overwriting. Doesn't seem to matter.
450 WriteGPURegister((u32)GPU_REG_INDEX(display_transfer_config.trigger), 1);
447 break; 451 break;
448 } 452 }
449 453
diff --git a/src/core/hle/service/gsp_gpu.h b/src/core/hle/service/gsp_gpu.h
index c89d0a467..8bcb30ad1 100644
--- a/src/core/hle/service/gsp_gpu.h
+++ b/src/core/hle/service/gsp_gpu.h
@@ -127,7 +127,16 @@ struct Command {
127 u32 in_buffer_size; 127 u32 in_buffer_size;
128 u32 out_buffer_size; 128 u32 out_buffer_size;
129 u32 flags; 129 u32 flags;
130 } image_copy; 130 } display_transfer;
131
132 struct {
133 u32 in_buffer_address;
134 u32 out_buffer_address;
135 u32 size;
136 u32 in_width_gap;
137 u32 out_width_gap;
138 u32 flags;
139 } texture_copy;
131 140
132 u8 raw_data[0x1C]; 141 u8 raw_data[0x1C];
133 }; 142 };
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp
index 6e7dafaad..6b1b71fe4 100644
--- a/src/core/hle/service/y2r_u.cpp
+++ b/src/core/hle/service/y2r_u.cpp
@@ -10,7 +10,6 @@
10#include "core/hle/kernel/event.h" 10#include "core/hle/kernel/event.h"
11#include "core/hle/service/y2r_u.h" 11#include "core/hle/service/y2r_u.h"
12#include "core/hw/y2r.h" 12#include "core/hw/y2r.h"
13#include "core/mem_map.h"
14 13
15#include "video_core/renderer_base.h" 14#include "video_core/renderer_base.h"
16#include "video_core/utils.h" 15#include "video_core/utils.h"
diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp
index 26d87c7e2..50c5bc01b 100644
--- a/src/core/hle/shared_page.cpp
+++ b/src/core/hle/shared_page.cpp
@@ -18,7 +18,4 @@ void Init() {
18 shared_page.running_hw = 0x1; // product 18 shared_page.running_hw = 0x1; // product
19} 19}
20 20
21void Shutdown() {
22}
23
24} // namespace 21} // namespace
diff --git a/src/core/hle/shared_page.h b/src/core/hle/shared_page.h
index db6a5340b..379bb7b63 100644
--- a/src/core/hle/shared_page.h
+++ b/src/core/hle/shared_page.h
@@ -54,6 +54,5 @@ static_assert(sizeof(SharedPageDef) == Memory::SHARED_PAGE_SIZE, "Shared page st
54extern SharedPageDef shared_page; 54extern SharedPageDef shared_page;
55 55
56void Init(); 56void Init();
57void Shutdown();
58 57
59} // namespace 58} // namespace
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index bb64fdfb7..89ac45a6f 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -10,11 +10,11 @@
10#include "common/symbols.h" 10#include "common/symbols.h"
11 11
12#include "core/core_timing.h" 12#include "core/core_timing.h"
13#include "core/mem_map.h"
14#include "core/arm/arm_interface.h" 13#include "core/arm/arm_interface.h"
15 14
16#include "core/hle/kernel/address_arbiter.h" 15#include "core/hle/kernel/address_arbiter.h"
17#include "core/hle/kernel/event.h" 16#include "core/hle/kernel/event.h"
17#include "core/hle/kernel/memory.h"
18#include "core/hle/kernel/mutex.h" 18#include "core/hle/kernel/mutex.h"
19#include "core/hle/kernel/process.h" 19#include "core/hle/kernel/process.h"
20#include "core/hle/kernel/resource_limit.h" 20#include "core/hle/kernel/resource_limit.h"
@@ -41,32 +41,114 @@ const ResultCode ERR_NOT_FOUND(ErrorDescription::NotFound, ErrorModule::Kernel,
41const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS, 41const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS,
42 ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E 42 ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E
43 43
44const ResultCode ERR_MISALIGNED_ADDRESS{ // 0xE0E01BF1
45 ErrorDescription::MisalignedAddress, ErrorModule::OS,
46 ErrorSummary::InvalidArgument, ErrorLevel::Usage};
47const ResultCode ERR_MISALIGNED_SIZE{ // 0xE0E01BF2
48 ErrorDescription::MisalignedSize, ErrorModule::OS,
49 ErrorSummary::InvalidArgument, ErrorLevel::Usage};
50const ResultCode ERR_INVALID_COMBINATION{ // 0xE0E01BEE
51 ErrorDescription::InvalidCombination, ErrorModule::OS,
52 ErrorSummary::InvalidArgument, ErrorLevel::Usage};
53
44enum ControlMemoryOperation { 54enum ControlMemoryOperation {
45 MEMORY_OPERATION_HEAP = 0x00000003, 55 MEMOP_FREE = 1,
46 MEMORY_OPERATION_GSP_HEAP = 0x00010003, 56 MEMOP_RESERVE = 2, // This operation seems to be unsupported in the kernel
57 MEMOP_COMMIT = 3,
58 MEMOP_MAP = 4,
59 MEMOP_UNMAP = 5,
60 MEMOP_PROTECT = 6,
61 MEMOP_OPERATION_MASK = 0xFF,
62
63 MEMOP_REGION_APP = 0x100,
64 MEMOP_REGION_SYSTEM = 0x200,
65 MEMOP_REGION_BASE = 0x300,
66 MEMOP_REGION_MASK = 0xF00,
67
68 MEMOP_LINEAR = 0x10000,
47}; 69};
48 70
49/// Map application or GSP heap memory 71/// Map application or GSP heap memory
50static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { 72static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) {
51 LOG_TRACE(Kernel_SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", 73 using namespace Kernel;
74
75 LOG_DEBUG(Kernel_SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=0x%X, permissions=0x%08X",
52 operation, addr0, addr1, size, permissions); 76 operation, addr0, addr1, size, permissions);
53 77
54 switch (operation) { 78 if ((addr0 & Memory::PAGE_MASK) != 0 || (addr1 & Memory::PAGE_MASK) != 0) {
79 return ERR_MISALIGNED_ADDRESS;
80 }
81 if ((size & Memory::PAGE_MASK) != 0) {
82 return ERR_MISALIGNED_SIZE;
83 }
84
85 u32 region = operation & MEMOP_REGION_MASK;
86 operation &= ~MEMOP_REGION_MASK;
87
88 if (region != 0) {
89 LOG_WARNING(Kernel_SVC, "ControlMemory with specified region not supported, region=%X", region);
90 }
91
92 if ((permissions & (u32)MemoryPermission::ReadWrite) != permissions) {
93 return ERR_INVALID_COMBINATION;
94 }
95 VMAPermission vma_permissions = (VMAPermission)permissions;
96
97 auto& process = *g_current_process;
98
99 switch (operation & MEMOP_OPERATION_MASK) {
100 case MEMOP_FREE:
101 {
102 if (addr0 >= Memory::HEAP_VADDR && addr0 < Memory::HEAP_VADDR_END) {
103 ResultCode result = process.HeapFree(addr0, size);
104 if (result.IsError()) return result;
105 } else if (addr0 >= process.GetLinearHeapBase() && addr0 < process.GetLinearHeapLimit()) {
106 ResultCode result = process.LinearFree(addr0, size);
107 if (result.IsError()) return result;
108 } else {
109 return ERR_INVALID_ADDRESS;
110 }
111 *out_addr = addr0;
112 break;
113 }
114
115 case MEMOP_COMMIT:
116 {
117 if (operation & MEMOP_LINEAR) {
118 CASCADE_RESULT(*out_addr, process.LinearAllocate(addr0, size, vma_permissions));
119 } else {
120 CASCADE_RESULT(*out_addr, process.HeapAllocate(addr0, size, vma_permissions));
121 }
122 break;
123 }
55 124
56 // Map normal heap memory 125 case MEMOP_MAP: // TODO: This is just a hack to avoid regressions until memory aliasing is implemented
57 case MEMORY_OPERATION_HEAP: 126 {
58 *out_addr = Memory::MapBlock_Heap(size, operation, permissions); 127 CASCADE_RESULT(*out_addr, process.HeapAllocate(addr0, size, vma_permissions));
59 break; 128 break;
129 }
130
131 case MEMOP_UNMAP: // TODO: This is just a hack to avoid regressions until memory aliasing is implemented
132 {
133 ResultCode result = process.HeapFree(addr0, size);
134 if (result.IsError()) return result;
135 break;
136 }
60 137
61 // Map GSP heap memory 138 case MEMOP_PROTECT:
62 case MEMORY_OPERATION_GSP_HEAP: 139 {
63 *out_addr = Memory::MapBlock_HeapLinear(size, operation, permissions); 140 ResultCode result = process.vm_manager.ReprotectRange(addr0, size, vma_permissions);
141 if (result.IsError()) return result;
64 break; 142 break;
143 }
65 144
66 // Unknown ControlMemory operation
67 default: 145 default:
68 LOG_ERROR(Kernel_SVC, "unknown operation=0x%08X", operation); 146 LOG_ERROR(Kernel_SVC, "unknown operation=0x%08X", operation);
147 return ERR_INVALID_COMBINATION;
69 } 148 }
149
150 process.vm_manager.LogLayout(Log::Level::Trace);
151
70 return RESULT_SUCCESS; 152 return RESULT_SUCCESS;
71} 153}
72 154
@@ -537,9 +619,9 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_inf
537 if (process == nullptr) 619 if (process == nullptr)
538 return ERR_INVALID_HANDLE; 620 return ERR_INVALID_HANDLE;
539 621
540 auto vma = process->address_space->FindVMA(addr); 622 auto vma = process->vm_manager.FindVMA(addr);
541 623
542 if (vma == process->address_space->vma_map.end()) 624 if (vma == Kernel::g_current_process->vm_manager.vma_map.end())
543 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); 625 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
544 626
545 memory_info->base_address = vma->second.base; 627 memory_info->base_address = vma->second.base;
@@ -692,6 +774,52 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32
692 return RESULT_SUCCESS; 774 return RESULT_SUCCESS;
693} 775}
694 776
777static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) {
778 LOG_TRACE(Kernel_SVC, "called process=0x%08X type=%u", process_handle, type);
779
780 using Kernel::Process;
781 Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle);
782 if (process == nullptr)
783 return ERR_INVALID_HANDLE;
784
785 switch (type) {
786 case 0:
787 case 2:
788 // TODO(yuriks): Type 0 returns a slightly higher number than type 2, but I'm not sure
789 // what's the difference between them.
790 *out = process->heap_used + process->linear_heap_used + process->misc_memory_used;
791 break;
792 case 1:
793 case 3:
794 case 4:
795 case 5:
796 case 6:
797 case 7:
798 case 8:
799 // These are valid, but not implemented yet
800 LOG_ERROR(Kernel_SVC, "unimplemented GetProcessInfo type=%u", type);
801 break;
802 case 20:
803 *out = Memory::FCRAM_PADDR - process->GetLinearHeapBase();
804 break;
805 default:
806 LOG_ERROR(Kernel_SVC, "unknown GetProcessInfo type=%u", type);
807
808 if (type >= 21 && type <= 23) {
809 return ResultCode( // 0xE0E01BF4
810 ErrorDescription::NotImplemented, ErrorModule::OS,
811 ErrorSummary::InvalidArgument, ErrorLevel::Usage);
812 } else {
813 return ResultCode( // 0xD8E007ED
814 ErrorDescription::InvalidEnumValue, ErrorModule::Kernel,
815 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
816 }
817 break;
818 }
819
820 return RESULT_SUCCESS;
821}
822
695namespace { 823namespace {
696 struct FunctionDef { 824 struct FunctionDef {
697 using Func = void(); 825 using Func = void();
@@ -746,7 +874,7 @@ static const FunctionDef SVC_Table[] = {
746 {0x28, HLE::Wrap<GetSystemTick>, "GetSystemTick"}, 874 {0x28, HLE::Wrap<GetSystemTick>, "GetSystemTick"},
747 {0x29, nullptr, "GetHandleInfo"}, 875 {0x29, nullptr, "GetHandleInfo"},
748 {0x2A, nullptr, "GetSystemInfo"}, 876 {0x2A, nullptr, "GetSystemInfo"},
749 {0x2B, nullptr, "GetProcessInfo"}, 877 {0x2B, HLE::Wrap<GetProcessInfo>, "GetProcessInfo"},
750 {0x2C, nullptr, "GetThreadInfo"}, 878 {0x2C, nullptr, "GetThreadInfo"},
751 {0x2D, HLE::Wrap<ConnectToPort>, "ConnectToPort"}, 879 {0x2D, HLE::Wrap<ConnectToPort>, "ConnectToPort"},
752 {0x2E, nullptr, "SendSyncRequest1"}, 880 {0x2E, nullptr, "SendSyncRequest1"},
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 3ccbc03b2..68ae38289 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring> 5#include <cstring>
6#include <numeric>
6#include <type_traits> 7#include <type_traits>
7 8
8#include "common/color.h" 9#include "common/color.h"
@@ -158,14 +159,59 @@ inline void Write(u32 addr, const T data) {
158 u8* src_pointer = Memory::GetPhysicalPointer(config.GetPhysicalInputAddress()); 159 u8* src_pointer = Memory::GetPhysicalPointer(config.GetPhysicalInputAddress());
159 u8* dst_pointer = Memory::GetPhysicalPointer(config.GetPhysicalOutputAddress()); 160 u8* dst_pointer = Memory::GetPhysicalPointer(config.GetPhysicalOutputAddress());
160 161
162 if (config.is_texture_copy) {
163 u32 input_width = config.texture_copy.input_width * 16;
164 u32 input_gap = config.texture_copy.input_gap * 16;
165 u32 output_width = config.texture_copy.output_width * 16;
166 u32 output_gap = config.texture_copy.output_gap * 16;
167
168 size_t contiguous_input_size = config.texture_copy.size / input_width * (input_width + input_gap);
169 VideoCore::g_renderer->hw_rasterizer->NotifyPreRead(config.GetPhysicalInputAddress(), contiguous_input_size);
170
171 u32 remaining_size = config.texture_copy.size;
172 u32 remaining_input = input_width;
173 u32 remaining_output = output_width;
174 while (remaining_size > 0) {
175 u32 copy_size = std::min({ remaining_input, remaining_output, remaining_size });
176
177 std::memcpy(dst_pointer, src_pointer, copy_size);
178 src_pointer += copy_size;
179 dst_pointer += copy_size;
180
181 remaining_input -= copy_size;
182 remaining_output -= copy_size;
183 remaining_size -= copy_size;
184
185 if (remaining_input == 0) {
186 remaining_input = input_width;
187 src_pointer += input_gap;
188 }
189 if (remaining_output == 0) {
190 remaining_output = output_width;
191 dst_pointer += output_gap;
192 }
193 }
194
195 LOG_TRACE(HW_GPU, "TextureCopy: 0x%X bytes from 0x%08X(%u+%u)-> 0x%08X(%u+%u), flags 0x%08X",
196 config.texture_copy.size,
197 config.GetPhysicalInputAddress(), input_width, input_gap,
198 config.GetPhysicalOutputAddress(), output_width, output_gap,
199 config.flags);
200
201 size_t contiguous_output_size = config.texture_copy.size / output_width * (output_width + output_gap);
202 VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetPhysicalOutputAddress(), contiguous_output_size);
203
204 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF);
205 break;
206 }
207
161 if (config.scaling > config.ScaleXY) { 208 if (config.scaling > config.ScaleXY) {
162 LOG_CRITICAL(HW_GPU, "Unimplemented display transfer scaling mode %u", config.scaling.Value()); 209 LOG_CRITICAL(HW_GPU, "Unimplemented display transfer scaling mode %u", config.scaling.Value());
163 UNIMPLEMENTED(); 210 UNIMPLEMENTED();
164 break; 211 break;
165 } 212 }
166 213
167 if (config.output_tiled && 214 if (config.input_linear && config.scaling != config.NoScale) {
168 (config.scaling == config.ScaleXY || config.scaling == config.ScaleX)) {
169 LOG_CRITICAL(HW_GPU, "Scaling is only implemented on tiled input"); 215 LOG_CRITICAL(HW_GPU, "Scaling is only implemented on tiled input");
170 UNIMPLEMENTED(); 216 UNIMPLEMENTED();
171 break; 217 break;
@@ -182,23 +228,6 @@ inline void Write(u32 addr, const T data) {
182 228
183 VideoCore::g_renderer->hw_rasterizer->NotifyPreRead(config.GetPhysicalInputAddress(), input_size); 229 VideoCore::g_renderer->hw_rasterizer->NotifyPreRead(config.GetPhysicalInputAddress(), input_size);
184 230
185 if (config.raw_copy) {
186 // Raw copies do not perform color conversion nor tiled->linear / linear->tiled conversions
187 // TODO(Subv): Verify if raw copies perform scaling
188 memcpy(dst_pointer, src_pointer, output_size);
189
190 LOG_TRACE(HW_GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), output format: %x, flags 0x%08X, Raw copy",
191 output_size,
192 config.GetPhysicalInputAddress(), config.input_width.Value(), config.input_height.Value(),
193 config.GetPhysicalOutputAddress(), config.output_width.Value(), config.output_height.Value(),
194 config.output_format.Value(), config.flags);
195
196 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF);
197
198 VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetPhysicalOutputAddress(), output_size);
199 break;
200 }
201
202 for (u32 y = 0; y < output_height; ++y) { 231 for (u32 y = 0; y < output_height; ++y) {
203 for (u32 x = 0; x < output_width; ++x) { 232 for (u32 x = 0; x < output_width; ++x) {
204 Math::Vec4<u8> src_color; 233 Math::Vec4<u8> src_color;
@@ -220,7 +249,7 @@ inline void Write(u32 addr, const T data) {
220 u32 src_offset; 249 u32 src_offset;
221 u32 dst_offset; 250 u32 dst_offset;
222 251
223 if (config.output_tiled) { 252 if (config.input_linear) {
224 if (!config.dont_swizzle) { 253 if (!config.dont_swizzle) {
225 // Interpret the input as linear and the output as tiled 254 // Interpret the input as linear and the output as tiled
226 u32 coarse_y = y & ~7; 255 u32 coarse_y = y & ~7;
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h
index daad506fe..2e3a9f779 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -201,12 +201,14 @@ struct Regs {
201 u32 flags; 201 u32 flags;
202 202
203 BitField< 0, 1, u32> flip_vertically; // flips input data vertically 203 BitField< 0, 1, u32> flip_vertically; // flips input data vertically
204 BitField< 1, 1, u32> output_tiled; // Converts from linear to tiled format 204 BitField< 1, 1, u32> input_linear; // Converts from linear to tiled format
205 BitField< 3, 1, u32> raw_copy; // Copies the data without performing any processing 205 BitField< 2, 1, u32> crop_input_lines;
206 BitField< 3, 1, u32> is_texture_copy; // Copies the data without performing any processing and respecting texture copy fields
206 BitField< 5, 1, u32> dont_swizzle; 207 BitField< 5, 1, u32> dont_swizzle;
207 BitField< 8, 3, PixelFormat> input_format; 208 BitField< 8, 3, PixelFormat> input_format;
208 BitField<12, 3, PixelFormat> output_format; 209 BitField<12, 3, PixelFormat> output_format;
209 210 /// Uses some kind of 32x32 block swizzling mode, instead of the usual 8x8 one.
211 BitField<16, 1, u32> block_32; // TODO(yuriks): unimplemented
210 BitField<24, 2, ScalingMode> scaling; // Determines the scaling mode of the transfer 212 BitField<24, 2, ScalingMode> scaling; // Determines the scaling mode of the transfer
211 }; 213 };
212 214
@@ -214,10 +216,30 @@ struct Regs {
214 216
215 // it seems that writing to this field triggers the display transfer 217 // it seems that writing to this field triggers the display transfer
216 u32 trigger; 218 u32 trigger;
219
220 INSERT_PADDING_WORDS(0x1);
221
222 struct {
223 u32 size;
224
225 union {
226 u32 input_size;
227
228 BitField< 0, 16, u32> input_width;
229 BitField<16, 16, u32> input_gap;
230 };
231
232 union {
233 u32 output_size;
234
235 BitField< 0, 16, u32> output_width;
236 BitField<16, 16, u32> output_gap;
237 };
238 } texture_copy;
217 } display_transfer_config; 239 } display_transfer_config;
218 ASSERT_MEMBER_SIZE(display_transfer_config, 0x1c); 240 ASSERT_MEMBER_SIZE(display_transfer_config, 0x2c);
219 241
220 INSERT_PADDING_WORDS(0x331); 242 INSERT_PADDING_WORDS(0x32D);
221 243
222 struct { 244 struct {
223 // command list size (in bytes) 245 // command list size (in bytes)
diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp
deleted file mode 100644
index cbe993fbe..000000000
--- a/src/core/mem_map.cpp
+++ /dev/null
@@ -1,163 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <map>
6#include <memory>
7#include <utility>
8#include <vector>
9
10#include "common/common_types.h"
11#include "common/logging/log.h"
12
13#include "core/hle/config_mem.h"
14#include "core/hle/kernel/vm_manager.h"
15#include "core/hle/result.h"
16#include "core/hle/shared_page.h"
17#include "core/mem_map.h"
18#include "core/memory.h"
19#include "core/memory_setup.h"
20
21////////////////////////////////////////////////////////////////////////////////////////////////////
22
23namespace Memory {
24
25namespace {
26
27struct MemoryArea {
28 u32 base;
29 u32 size;
30 const char* name;
31};
32
33// We don't declare the IO regions in here since its handled by other means.
34static MemoryArea memory_areas[] = {
35 {HEAP_VADDR, HEAP_SIZE, "Heap"}, // Application heap (main memory)
36 {SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, "Shared Memory"}, // Shared memory
37 {LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE, "Linear Heap"}, // Linear heap (main memory)
38 {VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM)
39 {DSP_RAM_VADDR, DSP_RAM_SIZE, "DSP RAM"}, // DSP memory
40 {TLS_AREA_VADDR, TLS_AREA_SIZE, "TLS Area"}, // TLS memory
41};
42
43/// Represents a block of memory mapped by ControlMemory/MapMemoryBlock
44struct MemoryBlock {
45 MemoryBlock() : handle(0), base_address(0), address(0), size(0), operation(0), permissions(0) {
46 }
47 u32 handle;
48 u32 base_address;
49 u32 address;
50 u32 size;
51 u32 operation;
52 u32 permissions;
53
54 const u32 GetVirtualAddress() const{
55 return base_address + address;
56 }
57};
58
59static std::map<u32, MemoryBlock> heap_map;
60static std::map<u32, MemoryBlock> heap_linear_map;
61
62}
63
64u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions) {
65 MemoryBlock block;
66
67 block.base_address = HEAP_VADDR;
68 block.size = size;
69 block.operation = operation;
70 block.permissions = permissions;
71
72 if (heap_map.size() > 0) {
73 const MemoryBlock last_block = heap_map.rbegin()->second;
74 block.address = last_block.address + last_block.size;
75 }
76 heap_map[block.GetVirtualAddress()] = block;
77
78 return block.GetVirtualAddress();
79}
80
81u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions) {
82 MemoryBlock block;
83
84 block.base_address = LINEAR_HEAP_VADDR;
85 block.size = size;
86 block.operation = operation;
87 block.permissions = permissions;
88
89 if (heap_linear_map.size() > 0) {
90 const MemoryBlock last_block = heap_linear_map.rbegin()->second;
91 block.address = last_block.address + last_block.size;
92 }
93 heap_linear_map[block.GetVirtualAddress()] = block;
94
95 return block.GetVirtualAddress();
96}
97
98PAddr VirtualToPhysicalAddress(const VAddr addr) {
99 if (addr == 0) {
100 return 0;
101 } else if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) {
102 return addr - VRAM_VADDR + VRAM_PADDR;
103 } else if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) {
104 return addr - LINEAR_HEAP_VADDR + FCRAM_PADDR;
105 } else if (addr >= DSP_RAM_VADDR && addr < DSP_RAM_VADDR_END) {
106 return addr - DSP_RAM_VADDR + DSP_RAM_PADDR;
107 } else if (addr >= IO_AREA_VADDR && addr < IO_AREA_VADDR_END) {
108 return addr - IO_AREA_VADDR + IO_AREA_PADDR;
109 }
110
111 LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x%08x", addr);
112 // To help with debugging, set bit on address so that it's obviously invalid.
113 return addr | 0x80000000;
114}
115
116VAddr PhysicalToVirtualAddress(const PAddr addr) {
117 if (addr == 0) {
118 return 0;
119 } else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) {
120 return addr - VRAM_PADDR + VRAM_VADDR;
121 } else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) {
122 return addr - FCRAM_PADDR + LINEAR_HEAP_VADDR;
123 } else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) {
124 return addr - DSP_RAM_PADDR + DSP_RAM_VADDR;
125 } else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) {
126 return addr - IO_AREA_PADDR + IO_AREA_VADDR;
127 }
128
129 LOG_ERROR(HW_Memory, "Unknown physical address @ 0x%08x", addr);
130 // To help with debugging, set bit on address so that it's obviously invalid.
131 return addr | 0x80000000;
132}
133
134void Init() {
135 InitMemoryMap();
136 LOG_DEBUG(HW_Memory, "initialized OK");
137}
138
139void InitLegacyAddressSpace(Kernel::VMManager& address_space) {
140 using namespace Kernel;
141
142 for (MemoryArea& area : memory_areas) {
143 auto block = std::make_shared<std::vector<u8>>(area.size);
144 address_space.MapMemoryBlock(area.base, std::move(block), 0, area.size, MemoryState::Private).Unwrap();
145 }
146
147 auto cfg_mem_vma = address_space.MapBackingMemory(CONFIG_MEMORY_VADDR,
148 (u8*)&ConfigMem::config_mem, CONFIG_MEMORY_SIZE, MemoryState::Shared).MoveFrom();
149 address_space.Reprotect(cfg_mem_vma, VMAPermission::Read);
150
151 auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR,
152 (u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom();
153 address_space.Reprotect(shared_page_vma, VMAPermission::Read);
154}
155
156void Shutdown() {
157 heap_map.clear();
158 heap_linear_map.clear();
159
160 LOG_DEBUG(HW_Memory, "shutdown OK");
161}
162
163} // namespace
diff --git a/src/core/mem_map.h b/src/core/mem_map.h
deleted file mode 100644
index 229ef82c5..000000000
--- a/src/core/mem_map.h
+++ /dev/null
@@ -1,46 +0,0 @@
1// Copyright 2014 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
9namespace Kernel {
10class VMManager;
11}
12
13namespace Memory {
14
15void Init();
16void InitLegacyAddressSpace(Kernel::VMManager& address_space);
17void Shutdown();
18
19/**
20 * Maps a block of memory on the heap
21 * @param size Size of block in bytes
22 * @param operation Memory map operation type
23 * @param permissions Memory allocation permissions
24 */
25u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions);
26
27/**
28 * Maps a block of memory on the GSP heap
29 * @param size Size of block in bytes
30 * @param operation Memory map operation type
31 * @param permissions Control memory permissions
32 */
33u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions);
34
35/**
36 * Converts a virtual address inside a region with 1:1 mapping to physical memory to a physical
37 * address. This should be used by services to translate addresses for use by the hardware.
38 */
39PAddr VirtualToPhysicalAddress(VAddr addr);
40
41/**
42 * Undoes a mapping performed by VirtualToPhysicalAddress().
43 */
44VAddr PhysicalToVirtualAddress(PAddr addr);
45
46} // namespace
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 1f66bb27d..cde390b8a 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -9,7 +9,7 @@
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/swap.h" 10#include "common/swap.h"
11 11
12#include "core/mem_map.h" 12#include "core/hle/kernel/process.h"
13#include "core/memory.h" 13#include "core/memory.h"
14#include "core/memory_setup.h" 14#include "core/memory_setup.h"
15 15
@@ -198,4 +198,42 @@ void WriteBlock(const VAddr addr, const u8* data, const size_t size) {
198 Write8(addr + offset, data[offset]); 198 Write8(addr + offset, data[offset]);
199} 199}
200 200
201PAddr VirtualToPhysicalAddress(const VAddr addr) {
202 if (addr == 0) {
203 return 0;
204 } else if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) {
205 return addr - VRAM_VADDR + VRAM_PADDR;
206 } else if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) {
207 return addr - LINEAR_HEAP_VADDR + FCRAM_PADDR;
208 } else if (addr >= DSP_RAM_VADDR && addr < DSP_RAM_VADDR_END) {
209 return addr - DSP_RAM_VADDR + DSP_RAM_PADDR;
210 } else if (addr >= IO_AREA_VADDR && addr < IO_AREA_VADDR_END) {
211 return addr - IO_AREA_VADDR + IO_AREA_PADDR;
212 } else if (addr >= NEW_LINEAR_HEAP_VADDR && addr < NEW_LINEAR_HEAP_VADDR_END) {
213 return addr - NEW_LINEAR_HEAP_VADDR + FCRAM_PADDR;
214 }
215
216 LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x%08X", addr);
217 // To help with debugging, set bit on address so that it's obviously invalid.
218 return addr | 0x80000000;
219}
220
221VAddr PhysicalToVirtualAddress(const PAddr addr) {
222 if (addr == 0) {
223 return 0;
224 } else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) {
225 return addr - VRAM_PADDR + VRAM_VADDR;
226 } else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) {
227 return addr - FCRAM_PADDR + Kernel::g_current_process->GetLinearHeapBase();
228 } else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) {
229 return addr - DSP_RAM_PADDR + DSP_RAM_VADDR;
230 } else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) {
231 return addr - IO_AREA_PADDR + IO_AREA_VADDR;
232 }
233
234 LOG_ERROR(HW_Memory, "Unknown physical address @ 0x%08X", addr);
235 // To help with debugging, set bit on address so that it's obviously invalid.
236 return addr | 0x80000000;
237}
238
201} // namespace 239} // namespace
diff --git a/src/core/memory.h b/src/core/memory.h
index 418609de0..5af72b7a7 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -15,6 +15,8 @@ namespace Memory {
15 * be mapped. 15 * be mapped.
16 */ 16 */
17const u32 PAGE_SIZE = 0x1000; 17const u32 PAGE_SIZE = 0x1000;
18const u32 PAGE_MASK = PAGE_SIZE - 1;
19const int PAGE_BITS = 12;
18 20
19/// Physical memory regions as seen from the ARM11 21/// Physical memory regions as seen from the ARM11
20enum : PAddr { 22enum : PAddr {
@@ -103,8 +105,15 @@ enum : VAddr {
103 // hardcoded value. 105 // hardcoded value.
104 /// Area where TLS (Thread-Local Storage) buffers are allocated. 106 /// Area where TLS (Thread-Local Storage) buffers are allocated.
105 TLS_AREA_VADDR = 0x1FF82000, 107 TLS_AREA_VADDR = 0x1FF82000,
106 TLS_AREA_SIZE = 0x00030000, // Each TLS buffer is 0x200 bytes, allows for 300 threads 108 TLS_ENTRY_SIZE = 0x200,
109 TLS_AREA_SIZE = 300 * TLS_ENTRY_SIZE + 0x800, // Space for up to 300 threads + round to page size
107 TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE, 110 TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE,
111
112
113 /// Equivalent to LINEAR_HEAP_VADDR, but expanded to cover the extra memory in the New 3DS.
114 NEW_LINEAR_HEAP_VADDR = 0x30000000,
115 NEW_LINEAR_HEAP_SIZE = 0x10000000,
116 NEW_LINEAR_HEAP_VADDR_END = NEW_LINEAR_HEAP_VADDR + NEW_LINEAR_HEAP_SIZE,
108}; 117};
109 118
110u8 Read8(VAddr addr); 119u8 Read8(VAddr addr);
@@ -122,6 +131,17 @@ void WriteBlock(VAddr addr, const u8* data, size_t size);
122u8* GetPointer(VAddr virtual_address); 131u8* GetPointer(VAddr virtual_address);
123 132
124/** 133/**
134* Converts a virtual address inside a region with 1:1 mapping to physical memory to a physical
135* address. This should be used by services to translate addresses for use by the hardware.
136*/
137PAddr VirtualToPhysicalAddress(VAddr addr);
138
139/**
140* Undoes a mapping performed by VirtualToPhysicalAddress().
141*/
142VAddr PhysicalToVirtualAddress(PAddr addr);
143
144/**
125 * Gets a pointer to the memory region beginning at the specified physical address. 145 * Gets a pointer to the memory region beginning at the specified physical address.
126 * 146 *
127 * @note This is currently implemented using PhysicalToVirtualAddress(). 147 * @note This is currently implemented using PhysicalToVirtualAddress().
diff --git a/src/core/memory_setup.h b/src/core/memory_setup.h
index 361bfc816..84ff30120 100644
--- a/src/core/memory_setup.h
+++ b/src/core/memory_setup.h
@@ -10,9 +10,6 @@
10 10
11namespace Memory { 11namespace Memory {
12 12
13const u32 PAGE_MASK = PAGE_SIZE - 1;
14const int PAGE_BITS = 12;
15
16void InitMemoryMap(); 13void InitMemoryMap();
17 14
18/** 15/**
diff --git a/src/core/system.cpp b/src/core/system.cpp
index 561ff82f0..3cd84bf5e 100644
--- a/src/core/system.cpp
+++ b/src/core/system.cpp
@@ -4,11 +4,11 @@
4 4
5#include "core/core.h" 5#include "core/core.h"
6#include "core/core_timing.h" 6#include "core/core_timing.h"
7#include "core/mem_map.h"
8#include "core/system.h" 7#include "core/system.h"
9#include "core/hw/hw.h" 8#include "core/hw/hw.h"
10#include "core/hle/hle.h" 9#include "core/hle/hle.h"
11#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/memory.h"
12 12
13#include "video_core/video_core.h" 13#include "video_core/video_core.h"
14 14
@@ -29,7 +29,6 @@ void Shutdown() {
29 HLE::Shutdown(); 29 HLE::Shutdown();
30 Kernel::Shutdown(); 30 Kernel::Shutdown();
31 HW::Shutdown(); 31 HW::Shutdown();
32 Memory::Shutdown();
33 CoreTiming::Shutdown(); 32 CoreTiming::Shutdown();
34 Core::Shutdown(); 33 Core::Shutdown();
35} 34}