summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Yuri Kunde Schlesner2015-08-05 21:26:52 -0300
committerGravatar Yuri Kunde Schlesner2015-08-16 01:03:47 -0300
commit74d4bc0af1d2f22105bf3c00efcb85613d59cc19 (patch)
tree171c5d0508d99f9ef4dcba2a0e3543eb9bdfa1db /src
parentHLE: Remove empty ConfigMem and SharedPage Shutdown functions (diff)
downloadyuzu-74d4bc0af1d2f22105bf3c00efcb85613d59cc19.tar.gz
yuzu-74d4bc0af1d2f22105bf3c00efcb85613d59cc19.tar.xz
yuzu-74d4bc0af1d2f22105bf3c00efcb85613d59cc19.zip
Kernel: Add more infrastructure to support different memory layouts
This adds some structures necessary to support multiple memory regions in the future. It also adds support for different system memory types and the new linear heap mapping at 0x30000000.
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/config_mem.cpp4
-rw-r--r--src/core/hle/hle.cpp2
-rw-r--r--src/core/hle/kernel/kernel.cpp19
-rw-r--r--src/core/hle/kernel/memory.cpp72
-rw-r--r--src/core/hle/kernel/memory.h17
-rw-r--r--src/core/hle/kernel/process.cpp44
-rw-r--r--src/core/hle/kernel/process.h6
-rw-r--r--src/core/hle/svc.cpp2
-rw-r--r--src/core/memory.cpp5
-rw-r--r--src/core/memory.h5
10 files changed, 148 insertions, 28 deletions
diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp
index 94bca0378..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;
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp
index 98dc8dd58..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
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
index 57e1912d3..e69b121eb 100644
--- a/src/core/hle/kernel/memory.cpp
+++ b/src/core/hle/kernel/memory.cpp
@@ -11,6 +11,7 @@
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12 12
13#include "core/hle/config_mem.h" 13#include "core/hle/config_mem.h"
14#include "core/hle/kernel/memory.h"
14#include "core/hle/kernel/vm_manager.h" 15#include "core/hle/kernel/vm_manager.h"
15#include "core/hle/result.h" 16#include "core/hle/result.h"
16#include "core/hle/shared_page.h" 17#include "core/hle/shared_page.h"
@@ -19,6 +20,77 @@
19 20
20//////////////////////////////////////////////////////////////////////////////////////////////////// 21////////////////////////////////////////////////////////////////////////////////////////////////////
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
22namespace Memory { 94namespace Memory {
23 95
24namespace { 96namespace {
diff --git a/src/core/hle/kernel/memory.h b/src/core/hle/kernel/memory.h
index cba8a0714..2e2cae17d 100644
--- a/src/core/hle/kernel/memory.h
+++ b/src/core/hle/kernel/memory.h
@@ -4,10 +4,27 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8
7#include "common/common_types.h" 9#include "common/common_types.h"
8 10
11#include "core/hle/kernel/process.h"
12
9namespace Kernel { 13namespace Kernel {
14
10class VMManager; 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
11} 28}
12 29
13namespace Memory { 30namespace Memory {
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 2cd1cfc14..1f45e6cf8 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -96,7 +96,7 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
96 96
97 int minor = kernel_version & 0xFF; 97 int minor = kernel_version & 0xFF;
98 int major = (kernel_version >> 8) & 0xFF; 98 int major = (kernel_version >> 8) & 0xFF;
99 LOG_DEBUG(Loader, "ExHeader kernel version: %d.%d", major, minor); 99 LOG_INFO(Loader, "ExHeader kernel version: %d.%d", major, minor);
100 } else { 100 } else {
101 LOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x%08X", descriptor); 101 LOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x%08X", descriptor);
102 } 102 }
@@ -104,6 +104,8 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
104} 104}
105 105
106void 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
107 auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) { 109 auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) {
108 auto vma = vm_manager.MapMemoryBlock(segment.addr, codeset->memory, 110 auto vma = vm_manager.MapMemoryBlock(segment.addr, codeset->memory,
109 segment.offset, segment.size, memory_state).Unwrap(); 111 segment.offset, segment.size, memory_state).Unwrap();
@@ -124,6 +126,15 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) {
124 Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority); 126 Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority);
125} 127}
126 128
129VAddr Process::GetLinearHeapBase() const {
130 return (kernel_version < 0x22C ? Memory::LINEAR_HEAP_VADDR : Memory::NEW_LINEAR_HEAP_SIZE)
131 + memory_region->base;
132}
133
134VAddr Process::GetLinearHeapLimit() const {
135 return GetLinearHeapBase() + memory_region->size;
136}
137
127ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission perms) { 138ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission perms) {
128 if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || target + size < target) { 139 if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || target + size < target) {
129 return ERR_INVALID_ADDRESS; 140 return ERR_INVALID_ADDRESS;
@@ -166,19 +177,16 @@ ResultCode Process::HeapFree(VAddr target, u32 size) {
166} 177}
167 178
168ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission perms) { 179ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission perms) {
169 if (linear_heap_memory == nullptr) { 180 auto& linheap_memory = memory_region->linear_heap_memory;
170 // Initialize heap
171 linear_heap_memory = std::make_shared<std::vector<u8>>();
172 }
173 181
174 VAddr heap_end = Memory::LINEAR_HEAP_VADDR + (u32)linear_heap_memory->size(); 182 VAddr heap_end = GetLinearHeapBase() + (u32)linheap_memory->size();
175 // Games and homebrew only ever seem to pass 0 here (which lets the kernel decide the address), 183 // Games and homebrew only ever seem to pass 0 here (which lets the kernel decide the address),
176 // but explicit addresses are also accepted and respected. 184 // but explicit addresses are also accepted and respected.
177 if (target == 0) { 185 if (target == 0) {
178 target = heap_end; 186 target = heap_end;
179 } 187 }
180 188
181 if (target < Memory::LINEAR_HEAP_VADDR || target + size > Memory::LINEAR_HEAP_VADDR_END || 189 if (target < GetLinearHeapBase() || target + size > GetLinearHeapLimit() ||
182 target > heap_end || target + size < target) { 190 target > heap_end || target + size < target) {
183 191
184 return ERR_INVALID_ADDRESS; 192 return ERR_INVALID_ADDRESS;
@@ -188,25 +196,29 @@ ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission p
188 // end. It's possible to free gaps in the middle of the heap and then reallocate them later, 196 // end. It's possible to free gaps in the middle of the heap and then reallocate them later,
189 // but expansions are only allowed at the end. 197 // but expansions are only allowed at the end.
190 if (target == heap_end) { 198 if (target == heap_end) {
191 linear_heap_memory->insert(linear_heap_memory->end(), size, 0); 199 linheap_memory->insert(linheap_memory->end(), size, 0);
192 vm_manager.RefreshMemoryBlockMappings(linear_heap_memory.get()); 200 vm_manager.RefreshMemoryBlockMappings(linheap_memory.get());
193 } 201 }
194 202
195 size_t offset = target - Memory::LINEAR_HEAP_VADDR; 203 // TODO(yuriks): As is, this lets processes map memory allocated by other processes from the
196 CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, linear_heap_memory, offset, size, MemoryState::Continuous)); 204 // same region. It is unknown if or how the 3DS kernel checks against this.
205 size_t offset = target - GetLinearHeapBase();
206 CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, linheap_memory, offset, size, MemoryState::Continuous));
197 vm_manager.Reprotect(vma, perms); 207 vm_manager.Reprotect(vma, perms);
198 208
199 return MakeResult<VAddr>(target); 209 return MakeResult<VAddr>(target);
200} 210}
201 211
202ResultCode Process::LinearFree(VAddr target, u32 size) { 212ResultCode Process::LinearFree(VAddr target, u32 size) {
203 if (linear_heap_memory == nullptr || target < Memory::LINEAR_HEAP_VADDR || 213 auto& linheap_memory = memory_region->linear_heap_memory;
204 target + size > Memory::LINEAR_HEAP_VADDR_END || target + size < target) { 214
215 if (target < GetLinearHeapBase() || target + size > GetLinearHeapLimit() ||
216 target + size < target) {
205 217
206 return ERR_INVALID_ADDRESS; 218 return ERR_INVALID_ADDRESS;
207 } 219 }
208 220
209 VAddr heap_end = Memory::LINEAR_HEAP_VADDR + (u32)linear_heap_memory->size(); 221 VAddr heap_end = GetLinearHeapBase() + (u32)linheap_memory->size();
210 if (target + size > heap_end) { 222 if (target + size > heap_end) {
211 return ERR_INVALID_ADDRESS_STATE; 223 return ERR_INVALID_ADDRESS_STATE;
212 } 224 }
@@ -221,8 +233,8 @@ ResultCode Process::LinearFree(VAddr target, u32 size) {
221 ASSERT(vma != vm_manager.vma_map.end()); 233 ASSERT(vma != vm_manager.vma_map.end());
222 ASSERT(vma->second.type == VMAType::Free); 234 ASSERT(vma->second.type == VMAType::Free);
223 VAddr new_end = vma->second.base; 235 VAddr new_end = vma->second.base;
224 if (new_end >= Memory::LINEAR_HEAP_VADDR) { 236 if (new_end >= GetLinearHeapBase()) {
225 linear_heap_memory->resize(new_end - Memory::LINEAR_HEAP_VADDR); 237 linheap_memory->resize(new_end - GetLinearHeapBase());
226 } 238 }
227 } 239 }
228 240
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 5c7de9044..7c3a78b9e 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -49,6 +49,7 @@ union ProcessFlags {
49}; 49};
50 50
51class ResourceLimit; 51class ResourceLimit;
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);
@@ -135,11 +136,14 @@ public:
135 // The left/right bounds of the address space covered by heap_memory. 136 // The left/right bounds of the address space covered by heap_memory.
136 VAddr heap_start = 0, heap_end = 0; 137 VAddr heap_start = 0, heap_end = 0;
137 138
138 std::shared_ptr<std::vector<u8>> linear_heap_memory; 139 MemoryRegionInfo* memory_region = nullptr;
139 140
140 /// Bitmask of the used TLS slots 141 /// Bitmask of the used TLS slots
141 std::bitset<300> used_tls_slots; 142 std::bitset<300> used_tls_slots;
142 143
144 VAddr GetLinearHeapBase() const;
145 VAddr GetLinearHeapLimit() const;
146
143 ResultVal<VAddr> HeapAllocate(VAddr target, u32 size, VMAPermission perms); 147 ResultVal<VAddr> HeapAllocate(VAddr target, u32 size, VMAPermission perms);
144 ResultCode HeapFree(VAddr target, u32 size); 148 ResultCode HeapFree(VAddr target, u32 size);
145 149
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index b944f4af0..e1a416def 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -102,7 +102,7 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add
102 if (addr0 >= Memory::HEAP_VADDR && addr0 < Memory::HEAP_VADDR_END) { 102 if (addr0 >= Memory::HEAP_VADDR && addr0 < Memory::HEAP_VADDR_END) {
103 ResultCode result = process.HeapFree(addr0, size); 103 ResultCode result = process.HeapFree(addr0, size);
104 if (result.IsError()) return result; 104 if (result.IsError()) return result;
105 } else if (addr0 >= Memory::LINEAR_HEAP_VADDR && addr0 < Memory::LINEAR_HEAP_VADDR_END) { 105 } else if (addr0 >= process.GetLinearHeapBase() && addr0 < process.GetLinearHeapLimit()) {
106 ResultCode result = process.LinearFree(addr0, size); 106 ResultCode result = process.LinearFree(addr0, size);
107 if (result.IsError()) return result; 107 if (result.IsError()) return result;
108 } else { 108 } else {
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 935dac90f..cde390b8a 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -9,6 +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/hle/kernel/process.h"
12#include "core/memory.h" 13#include "core/memory.h"
13#include "core/memory_setup.h" 14#include "core/memory_setup.h"
14 15
@@ -208,6 +209,8 @@ PAddr VirtualToPhysicalAddress(const VAddr addr) {
208 return addr - DSP_RAM_VADDR + DSP_RAM_PADDR; 209 return addr - DSP_RAM_VADDR + DSP_RAM_PADDR;
209 } else if (addr >= IO_AREA_VADDR && addr < IO_AREA_VADDR_END) { 210 } else if (addr >= IO_AREA_VADDR && addr < IO_AREA_VADDR_END) {
210 return addr - IO_AREA_VADDR + IO_AREA_PADDR; 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;
211 } 214 }
212 215
213 LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x%08X", addr); 216 LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x%08X", addr);
@@ -221,7 +224,7 @@ VAddr PhysicalToVirtualAddress(const PAddr addr) {
221 } else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) { 224 } else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) {
222 return addr - VRAM_PADDR + VRAM_VADDR; 225 return addr - VRAM_PADDR + VRAM_VADDR;
223 } else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) { 226 } else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) {
224 return addr - FCRAM_PADDR + LINEAR_HEAP_VADDR; 227 return addr - FCRAM_PADDR + Kernel::g_current_process->GetLinearHeapBase();
225 } else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) { 228 } else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) {
226 return addr - DSP_RAM_PADDR + DSP_RAM_VADDR; 229 return addr - DSP_RAM_PADDR + DSP_RAM_VADDR;
227 } else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) { 230 } else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) {
diff --git a/src/core/memory.h b/src/core/memory.h
index e6da3e2a5..d1d32f0dd 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -107,6 +107,11 @@ enum : VAddr {
107 TLS_AREA_VADDR = 0x1FF82000, 107 TLS_AREA_VADDR = 0x1FF82000,
108 TLS_AREA_SIZE = 0x00030000, // Each TLS buffer is 0x200 bytes, allows for 300 threads 108 TLS_AREA_SIZE = 0x00030000, // Each TLS buffer is 0x200 bytes, allows for 300 threads
109 TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE, 109 TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE,
110
111 /// Equivalent to LINEAR_HEAP_VADDR, but expanded to cover the extra memory in the New 3DS.
112 NEW_LINEAR_HEAP_VADDR = 0x30000000,
113 NEW_LINEAR_HEAP_SIZE = 0x10000000,
114 NEW_LINEAR_HEAP_VADDR_END = NEW_LINEAR_HEAP_VADDR + NEW_LINEAR_HEAP_SIZE,
110}; 115};
111 116
112u8 Read8(VAddr addr); 117u8 Read8(VAddr addr);