summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
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);