summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/audio_core/audio_renderer.cpp2
-rw-r--r--src/audio_core/audio_renderer.h2
-rw-r--r--src/audio_core/stream.cpp4
-rw-r--r--src/audio_core/stream.h14
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp5
-rw-r--r--src/core/file_sys/program_metadata.cpp4
-rw-r--r--src/core/file_sys/program_metadata.h6
-rw-r--r--src/core/gdbstub/gdbstub.cpp15
-rw-r--r--src/core/hle/kernel/process.cpp28
-rw-r--r--src/core/hle/kernel/process.h12
-rw-r--r--src/core/hle/kernel/shared_memory.cpp4
-rw-r--r--src/core/hle/kernel/svc.cpp45
-rw-r--r--src/core/hle/kernel/thread.cpp3
-rw-r--r--src/core/hle/kernel/vm_manager.cpp180
-rw-r--r--src/core/hle/kernel/vm_manager.h100
-rw-r--r--src/core/hle/service/audio/audren_u.cpp2
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp18
-rw-r--r--src/core/loader/elf.cpp32
-rw-r--r--src/core/loader/nro.cpp12
-rw-r--r--src/core/loader/nso.cpp14
-rw-r--r--src/core/memory.cpp30
-rw-r--r--src/core/memory.h63
-rw-r--r--src/tests/core/arm/arm_test_common.cpp7
-rw-r--r--src/video_core/engines/maxwell_3d.h8
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp7
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h5
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h3
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp31
-rw-r--r--src/video_core/renderer_opengl/gl_state.h7
-rw-r--r--src/yuzu/game_list.cpp14
-rw-r--r--src/yuzu/game_list.h32
-rw-r--r--src/yuzu/game_list_p.h40
32 files changed, 533 insertions, 216 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 521b19ff7..6f0ff953a 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -79,7 +79,7 @@ u32 AudioRenderer::GetMixBufferCount() const {
79 return worker_params.mix_buffer_count; 79 return worker_params.mix_buffer_count;
80} 80}
81 81
82u32 AudioRenderer::GetState() const { 82Stream::State AudioRenderer::GetStreamState() const {
83 return stream->GetState(); 83 return stream->GetState();
84} 84}
85 85
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index be923ee65..dfef89e1d 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -170,7 +170,7 @@ public:
170 u32 GetSampleRate() const; 170 u32 GetSampleRate() const;
171 u32 GetSampleCount() const; 171 u32 GetSampleCount() const;
172 u32 GetMixBufferCount() const; 172 u32 GetMixBufferCount() const;
173 u32 GetState() const; 173 Stream::State GetStreamState() const;
174 174
175private: 175private:
176 class VoiceState; 176 class VoiceState;
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index ee4aa98af..742a5e0a0 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -53,8 +53,8 @@ void Stream::Stop() {
53 ASSERT_MSG(false, "Unimplemented"); 53 ASSERT_MSG(false, "Unimplemented");
54} 54}
55 55
56u32 Stream::GetState() const { 56Stream::State Stream::GetState() const {
57 return static_cast<u32>(state); 57 return state;
58} 58}
59 59
60s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const { 60s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const {
diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h
index 43eca74e1..aebfeb51d 100644
--- a/src/audio_core/stream.h
+++ b/src/audio_core/stream.h
@@ -33,6 +33,12 @@ public:
33 Multi51Channel16, 33 Multi51Channel16,
34 }; 34 };
35 35
36 /// Current state of the stream
37 enum class State {
38 Stopped,
39 Playing,
40 };
41
36 /// Callback function type, used to change guest state on a buffer being released 42 /// Callback function type, used to change guest state on a buffer being released
37 using ReleaseCallback = std::function<void()>; 43 using ReleaseCallback = std::function<void()>;
38 44
@@ -73,15 +79,9 @@ public:
73 u32 GetNumChannels() const; 79 u32 GetNumChannels() const;
74 80
75 /// Get the state 81 /// Get the state
76 u32 GetState() const; 82 State GetState() const;
77 83
78private: 84private:
79 /// Current state of the stream
80 enum class State {
81 Stopped,
82 Playing,
83 };
84
85 /// Plays the next queued buffer in the audio stream, starting playback if necessary 85 /// Plays the next queued buffer in the audio stream, starting playback if necessary
86 void PlayNextBuffer(); 86 void PlayNextBuffer();
87 87
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 8760d17a8..8cad070b4 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -129,7 +129,8 @@ public:
129}; 129};
130 130
131std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const { 131std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
132 auto** const page_table = Core::CurrentProcess()->vm_manager.page_table.pointers.data(); 132 auto& current_process = Core::CurrentProcess();
133 auto** const page_table = current_process->vm_manager.page_table.pointers.data();
133 134
134 Dynarmic::A64::UserConfig config; 135 Dynarmic::A64::UserConfig config;
135 136
@@ -138,7 +139,7 @@ std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
138 139
139 // Memory 140 // Memory
140 config.page_table = reinterpret_cast<void**>(page_table); 141 config.page_table = reinterpret_cast<void**>(page_table);
141 config.page_table_address_space_bits = Memory::ADDRESS_SPACE_BITS; 142 config.page_table_address_space_bits = current_process->vm_manager.GetAddressSpaceWidth();
142 config.silently_mirror_page_table = false; 143 config.silently_mirror_page_table = false;
143 144
144 // Multi-process state 145 // Multi-process state
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index 02319ce0f..8903ed1d3 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -83,10 +83,12 @@ void ProgramMetadata::Print() const {
83 83
84 auto address_space = "Unknown"; 84 auto address_space = "Unknown";
85 switch (npdm_header.address_space_type) { 85 switch (npdm_header.address_space_type) {
86 case ProgramAddressSpaceType::Is64Bit: 86 case ProgramAddressSpaceType::Is36Bit:
87 case ProgramAddressSpaceType::Is39Bit:
87 address_space = "64-bit"; 88 address_space = "64-bit";
88 break; 89 break;
89 case ProgramAddressSpaceType::Is32Bit: 90 case ProgramAddressSpaceType::Is32Bit:
91 case ProgramAddressSpaceType::Is32BitNoMap:
90 address_space = "32-bit"; 92 address_space = "32-bit";
91 break; 93 break;
92 } 94 }
diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h
index 1143e36c4..e4470d6f0 100644
--- a/src/core/file_sys/program_metadata.h
+++ b/src/core/file_sys/program_metadata.h
@@ -17,8 +17,10 @@ enum class ResultStatus : u16;
17namespace FileSys { 17namespace FileSys {
18 18
19enum class ProgramAddressSpaceType : u8 { 19enum class ProgramAddressSpaceType : u8 {
20 Is64Bit = 1, 20 Is32Bit = 0,
21 Is32Bit = 2, 21 Is36Bit = 1,
22 Is32BitNoMap = 2,
23 Is39Bit = 3,
22}; 24};
23 25
24enum class ProgramFilePermission : u64 { 26enum class ProgramFilePermission : u64 {
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 0ecdd9f82..d8c7b3492 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -37,7 +37,9 @@
37#include "core/core.h" 37#include "core/core.h"
38#include "core/core_cpu.h" 38#include "core/core_cpu.h"
39#include "core/gdbstub/gdbstub.h" 39#include "core/gdbstub/gdbstub.h"
40#include "core/hle/kernel/process.h"
40#include "core/hle/kernel/scheduler.h" 41#include "core/hle/kernel/scheduler.h"
42#include "core/hle/kernel/vm_manager.h"
41#include "core/loader/loader.h" 43#include "core/loader/loader.h"
42#include "core/memory.h" 44#include "core/memory.h"
43 45
@@ -585,7 +587,8 @@ static void HandleQuery() {
585 strlen("Xfer:features:read:target.xml:")) == 0) { 587 strlen("Xfer:features:read:target.xml:")) == 0) {
586 SendReply(target_xml); 588 SendReply(target_xml);
587 } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) { 589 } else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) {
588 std::string buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR); 590 const VAddr base_address = Core::CurrentProcess()->vm_manager.GetCodeRegionBaseAddress();
591 std::string buffer = fmt::format("TextSeg={:0x}", base_address);
589 SendReply(buffer.c_str()); 592 SendReply(buffer.c_str());
590 } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { 593 } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) {
591 std::string val = "m"; 594 std::string val = "m";
@@ -893,11 +896,11 @@ static void ReadMemory() {
893 static u8 reply[GDB_BUFFER_SIZE - 4]; 896 static u8 reply[GDB_BUFFER_SIZE - 4];
894 897
895 auto start_offset = command_buffer + 1; 898 auto start_offset = command_buffer + 1;
896 auto addr_pos = std::find(start_offset, command_buffer + command_length, ','); 899 const auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
897 VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset)); 900 const VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
898 901
899 start_offset = addr_pos + 1; 902 start_offset = addr_pos + 1;
900 u64 len = 903 const u64 len =
901 HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset)); 904 HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset));
902 905
903 LOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len); 906 LOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len);
@@ -906,7 +909,9 @@ static void ReadMemory() {
906 SendReply("E01"); 909 SendReply("E01");
907 } 910 }
908 911
909 if (addr < Memory::PROCESS_IMAGE_VADDR || addr >= Memory::MAP_REGION_VADDR_END) { 912 const auto& vm_manager = Core::CurrentProcess()->vm_manager;
913 if (addr < vm_manager.GetCodeRegionBaseAddress() ||
914 addr >= vm_manager.GetMapRegionEndAddress()) {
910 return SendReply("E00"); 915 return SendReply("E00");
911 } 916 }
912 917
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 121f741fd..a8e3098ca 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -8,6 +8,7 @@
8#include "common/common_funcs.h" 8#include "common/common_funcs.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "core/core.h" 10#include "core/core.h"
11#include "core/file_sys/program_metadata.h"
11#include "core/hle/kernel/errors.h" 12#include "core/hle/kernel/errors.h"
12#include "core/hle/kernel/kernel.h" 13#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/process.h" 14#include "core/hle/kernel/process.h"
@@ -34,14 +35,21 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) {
34 process->name = std::move(name); 35 process->name = std::move(name);
35 process->flags.raw = 0; 36 process->flags.raw = 0;
36 process->flags.memory_region.Assign(MemoryRegion::APPLICATION); 37 process->flags.memory_region.Assign(MemoryRegion::APPLICATION);
38 process->resource_limit = kernel.ResourceLimitForCategory(ResourceLimitCategory::APPLICATION);
37 process->status = ProcessStatus::Created; 39 process->status = ProcessStatus::Created;
38 process->program_id = 0; 40 process->program_id = 0;
39 process->process_id = kernel.CreateNewProcessID(); 41 process->process_id = kernel.CreateNewProcessID();
42 process->svc_access_mask.set();
40 43
41 kernel.AppendNewProcess(process); 44 kernel.AppendNewProcess(process);
42 return process; 45 return process;
43} 46}
44 47
48void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
49 program_id = metadata.GetTitleID();
50 vm_manager.Reset(metadata.GetAddressSpaceType());
51}
52
45void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) { 53void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) {
46 for (std::size_t i = 0; i < len; ++i) { 54 for (std::size_t i = 0; i < len; ++i) {
47 u32 descriptor = kernel_caps[i]; 55 u32 descriptor = kernel_caps[i];
@@ -119,7 +127,7 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
119 // TODO(bunnei): This is heap area that should be allocated by the kernel and not mapped as part 127 // TODO(bunnei): This is heap area that should be allocated by the kernel and not mapped as part
120 // of the user address space. 128 // of the user address space.
121 vm_manager 129 vm_manager
122 .MapMemoryBlock(Memory::STACK_AREA_VADDR_END - stack_size, 130 .MapMemoryBlock(vm_manager.GetTLSIORegionEndAddress() - stack_size,
123 std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, 131 std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size,
124 MemoryState::Mapped) 132 MemoryState::Mapped)
125 .Unwrap(); 133 .Unwrap();
@@ -185,6 +193,7 @@ static std::tuple<std::size_t, std::size_t, bool> FindFreeThreadLocalSlot(
185 193
186VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) { 194VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) {
187 auto [available_page, available_slot, needs_allocation] = FindFreeThreadLocalSlot(tls_slots); 195 auto [available_page, available_slot, needs_allocation] = FindFreeThreadLocalSlot(tls_slots);
196 const VAddr tls_begin = vm_manager.GetTLSIORegionBaseAddress();
188 197
189 if (needs_allocation) { 198 if (needs_allocation) {
190 tls_slots.emplace_back(0); // The page is completely available at the start 199 tls_slots.emplace_back(0); // The page is completely available at the start
@@ -197,18 +206,17 @@ VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) {
197 206
198 vm_manager.RefreshMemoryBlockMappings(tls_memory.get()); 207 vm_manager.RefreshMemoryBlockMappings(tls_memory.get());
199 208
200 vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE, 209 vm_manager.MapMemoryBlock(tls_begin + available_page * Memory::PAGE_SIZE, tls_memory, 0,
201 tls_memory, 0, Memory::PAGE_SIZE, MemoryState::ThreadLocal); 210 Memory::PAGE_SIZE, MemoryState::ThreadLocal);
202 } 211 }
203 212
204 tls_slots[available_page].set(available_slot); 213 tls_slots[available_page].set(available_slot);
205 214
206 return Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE + 215 return tls_begin + available_page * Memory::PAGE_SIZE + available_slot * Memory::TLS_ENTRY_SIZE;
207 available_slot * Memory::TLS_ENTRY_SIZE;
208} 216}
209 217
210void Process::FreeTLSSlot(VAddr tls_address) { 218void Process::FreeTLSSlot(VAddr tls_address) {
211 const VAddr tls_base = tls_address - Memory::TLS_AREA_VADDR; 219 const VAddr tls_base = tls_address - vm_manager.GetTLSIORegionBaseAddress();
212 const VAddr tls_page = tls_base / Memory::PAGE_SIZE; 220 const VAddr tls_page = tls_base / Memory::PAGE_SIZE;
213 const VAddr tls_slot = (tls_base % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; 221 const VAddr tls_slot = (tls_base % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
214 222
@@ -232,8 +240,8 @@ void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
232} 240}
233 241
234ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { 242ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
235 if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || 243 if (target < vm_manager.GetHeapRegionBaseAddress() ||
236 target + size < target) { 244 target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) {
237 return ERR_INVALID_ADDRESS; 245 return ERR_INVALID_ADDRESS;
238 } 246 }
239 247
@@ -268,8 +276,8 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission per
268} 276}
269 277
270ResultCode Process::HeapFree(VAddr target, u32 size) { 278ResultCode Process::HeapFree(VAddr target, u32 size) {
271 if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || 279 if (target < vm_manager.GetHeapRegionBaseAddress() ||
272 target + size < target) { 280 target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) {
273 return ERR_INVALID_ADDRESS; 281 return ERR_INVALID_ADDRESS;
274 } 282 }
275 283
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 04d74e572..adb03c228 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -17,6 +17,10 @@
17#include "core/hle/kernel/thread.h" 17#include "core/hle/kernel/thread.h"
18#include "core/hle/kernel/vm_manager.h" 18#include "core/hle/kernel/vm_manager.h"
19 19
20namespace FileSys {
21class ProgramMetadata;
22}
23
20namespace Kernel { 24namespace Kernel {
21 25
22class KernelCore; 26class KernelCore;
@@ -141,6 +145,14 @@ public:
141 return process_id; 145 return process_id;
142 } 146 }
143 147
148 /**
149 * Loads process-specifics configuration info with metadata provided
150 * by an executable.
151 *
152 * @param metadata The provided metadata to load process specific info.
153 */
154 void LoadFromMetadata(const FileSys::ProgramMetadata& metadata);
155
144 /// Title ID corresponding to the process 156 /// Title ID corresponding to the process
145 u64 program_id; 157 u64 program_id;
146 158
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index abb1d09cd..9b78c8cb5 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -8,6 +8,7 @@
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/hle/kernel/errors.h" 10#include "core/hle/kernel/errors.h"
11#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/shared_memory.h" 12#include "core/hle/kernel/shared_memory.h"
12#include "core/memory.h" 13#include "core/memory.h"
13 14
@@ -71,7 +72,8 @@ SharedPtr<SharedMemory> SharedMemory::CreateForApplet(
71 shared_memory->other_permissions = other_permissions; 72 shared_memory->other_permissions = other_permissions;
72 shared_memory->backing_block = std::move(heap_block); 73 shared_memory->backing_block = std::move(heap_block);
73 shared_memory->backing_block_offset = offset; 74 shared_memory->backing_block_offset = offset;
74 shared_memory->base_address = Memory::HEAP_VADDR + offset; 75 shared_memory->base_address =
76 kernel.CurrentProcess()->vm_manager.GetHeapRegionBaseAddress() + offset;
75 77
76 return shared_memory; 78 return shared_memory;
77} 79}
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index c9d212a4c..44bbaf0c8 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -51,8 +51,9 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
51 } 51 }
52 52
53 auto& process = *Core::CurrentProcess(); 53 auto& process = *Core::CurrentProcess();
54 const VAddr heap_base = process.vm_manager.GetHeapRegionBaseAddress();
54 CASCADE_RESULT(*heap_addr, 55 CASCADE_RESULT(*heap_addr,
55 process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite)); 56 process.HeapAllocate(heap_base, heap_size, VMAPermission::ReadWrite));
56 return RESULT_SUCCESS; 57 return RESULT_SUCCESS;
57} 58}
58 59
@@ -325,26 +326,27 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
325 LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, 326 LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
326 info_sub_id, handle); 327 info_sub_id, handle);
327 328
328 const auto& vm_manager = Core::CurrentProcess()->vm_manager; 329 const auto& current_process = Core::CurrentProcess();
330 const auto& vm_manager = current_process->vm_manager;
329 331
330 switch (static_cast<GetInfoType>(info_id)) { 332 switch (static_cast<GetInfoType>(info_id)) {
331 case GetInfoType::AllowedCpuIdBitmask: 333 case GetInfoType::AllowedCpuIdBitmask:
332 *result = Core::CurrentProcess()->allowed_processor_mask; 334 *result = current_process->allowed_processor_mask;
333 break; 335 break;
334 case GetInfoType::AllowedThreadPrioBitmask: 336 case GetInfoType::AllowedThreadPrioBitmask:
335 *result = Core::CurrentProcess()->allowed_thread_priority_mask; 337 *result = current_process->allowed_thread_priority_mask;
336 break; 338 break;
337 case GetInfoType::MapRegionBaseAddr: 339 case GetInfoType::MapRegionBaseAddr:
338 *result = Memory::MAP_REGION_VADDR; 340 *result = vm_manager.GetMapRegionBaseAddress();
339 break; 341 break;
340 case GetInfoType::MapRegionSize: 342 case GetInfoType::MapRegionSize:
341 *result = Memory::MAP_REGION_SIZE; 343 *result = vm_manager.GetMapRegionSize();
342 break; 344 break;
343 case GetInfoType::HeapRegionBaseAddr: 345 case GetInfoType::HeapRegionBaseAddr:
344 *result = Memory::HEAP_VADDR; 346 *result = vm_manager.GetHeapRegionBaseAddress();
345 break; 347 break;
346 case GetInfoType::HeapRegionSize: 348 case GetInfoType::HeapRegionSize:
347 *result = Memory::HEAP_SIZE; 349 *result = vm_manager.GetHeapRegionSize();
348 break; 350 break;
349 case GetInfoType::TotalMemoryUsage: 351 case GetInfoType::TotalMemoryUsage:
350 *result = vm_manager.GetTotalMemoryUsage(); 352 *result = vm_manager.GetTotalMemoryUsage();
@@ -359,22 +361,35 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
359 *result = 0; 361 *result = 0;
360 break; 362 break;
361 case GetInfoType::AddressSpaceBaseAddr: 363 case GetInfoType::AddressSpaceBaseAddr:
362 *result = vm_manager.GetAddressSpaceBaseAddr(); 364 *result = vm_manager.GetCodeRegionBaseAddress();
363 break; 365 break;
364 case GetInfoType::AddressSpaceSize: 366 case GetInfoType::AddressSpaceSize: {
365 *result = vm_manager.GetAddressSpaceSize(); 367 const u64 width = vm_manager.GetAddressSpaceWidth();
368
369 switch (width) {
370 case 32:
371 *result = 0xFFE00000;
372 break;
373 case 36:
374 *result = 0xFF8000000;
375 break;
376 case 39:
377 *result = 0x7FF8000000;
378 break;
379 }
366 break; 380 break;
381 }
367 case GetInfoType::NewMapRegionBaseAddr: 382 case GetInfoType::NewMapRegionBaseAddr:
368 *result = Memory::NEW_MAP_REGION_VADDR; 383 *result = vm_manager.GetNewMapRegionBaseAddress();
369 break; 384 break;
370 case GetInfoType::NewMapRegionSize: 385 case GetInfoType::NewMapRegionSize:
371 *result = Memory::NEW_MAP_REGION_SIZE; 386 *result = vm_manager.GetNewMapRegionSize();
372 break; 387 break;
373 case GetInfoType::IsVirtualAddressMemoryEnabled: 388 case GetInfoType::IsVirtualAddressMemoryEnabled:
374 *result = Core::CurrentProcess()->is_virtual_address_memory_enabled; 389 *result = current_process->is_virtual_address_memory_enabled;
375 break; 390 break;
376 case GetInfoType::TitleId: 391 case GetInfoType::TitleId:
377 *result = Core::CurrentProcess()->program_id; 392 *result = current_process->program_id;
378 break; 393 break;
379 case GetInfoType::PrivilegedProcessId: 394 case GetInfoType::PrivilegedProcessId:
380 LOG_WARNING(Kernel_SVC, 395 LOG_WARNING(Kernel_SVC,
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 315f65338..064ed908d 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -262,8 +262,9 @@ SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 pri
262 SetCurrentPageTable(&owner_process.vm_manager.page_table); 262 SetCurrentPageTable(&owner_process.vm_manager.page_table);
263 263
264 // Initialize new "main" thread 264 // Initialize new "main" thread
265 const VAddr stack_top = owner_process.vm_manager.GetTLSIORegionEndAddress();
265 auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0, 266 auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0,
266 Memory::STACK_AREA_VADDR_END, &owner_process); 267 stack_top, &owner_process);
267 268
268 SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); 269 SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
269 270
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 608cbd57b..e412309fd 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -9,6 +9,7 @@
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "core/arm/arm_interface.h" 10#include "core/arm/arm_interface.h"
11#include "core/core.h" 11#include "core/core.h"
12#include "core/file_sys/program_metadata.h"
12#include "core/hle/kernel/errors.h" 13#include "core/hle/kernel/errors.h"
13#include "core/hle/kernel/vm_manager.h" 14#include "core/hle/kernel/vm_manager.h"
14#include "core/memory.h" 15#include "core/memory.h"
@@ -54,30 +55,32 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
54} 55}
55 56
56VMManager::VMManager() { 57VMManager::VMManager() {
57 Reset(); 58 // Default to assuming a 39-bit address space. This way we have a sane
59 // starting point with executables that don't provide metadata.
60 Reset(FileSys::ProgramAddressSpaceType::Is39Bit);
58} 61}
59 62
60VMManager::~VMManager() { 63VMManager::~VMManager() {
61 Reset(); 64 Reset(FileSys::ProgramAddressSpaceType::Is39Bit);
62} 65}
63 66
64void VMManager::Reset() { 67void VMManager::Reset(FileSys::ProgramAddressSpaceType type) {
65 vma_map.clear(); 68 Clear();
69
70 InitializeMemoryRegionRanges(type);
71
72 page_table.Resize(address_space_width);
66 73
67 // Initialize the map with a single free region covering the entire managed space. 74 // Initialize the map with a single free region covering the entire managed space.
68 VirtualMemoryArea initial_vma; 75 VirtualMemoryArea initial_vma;
69 initial_vma.size = MAX_ADDRESS; 76 initial_vma.size = address_space_end;
70 vma_map.emplace(initial_vma.base, initial_vma); 77 vma_map.emplace(initial_vma.base, initial_vma);
71 78
72 page_table.pointers.fill(nullptr);
73 page_table.special_regions.clear();
74 page_table.attributes.fill(Memory::PageType::Unmapped);
75
76 UpdatePageTableForVMA(initial_vma); 79 UpdatePageTableForVMA(initial_vma);
77} 80}
78 81
79VMManager::VMAHandle VMManager::FindVMA(VAddr target) const { 82VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
80 if (target >= MAX_ADDRESS) { 83 if (target >= address_space_end) {
81 return vma_map.end(); 84 return vma_map.end();
82 } else { 85 } else {
83 return std::prev(vma_map.upper_bound(target)); 86 return std::prev(vma_map.upper_bound(target));
@@ -291,7 +294,7 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u64 size) {
291 294
292 const VAddr target_end = target + size; 295 const VAddr target_end = target + size;
293 ASSERT(target_end >= target); 296 ASSERT(target_end >= target);
294 ASSERT(target_end <= MAX_ADDRESS); 297 ASSERT(target_end <= address_space_end);
295 ASSERT(size > 0); 298 ASSERT(size > 0);
296 299
297 VMAIter begin_vma = StripIterConstness(FindVMA(target)); 300 VMAIter begin_vma = StripIterConstness(FindVMA(target));
@@ -382,6 +385,85 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
382 } 385 }
383} 386}
384 387
388void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType type) {
389 u64 map_region_size = 0;
390 u64 heap_region_size = 0;
391 u64 new_map_region_size = 0;
392 u64 tls_io_region_size = 0;
393
394 switch (type) {
395 case FileSys::ProgramAddressSpaceType::Is32Bit:
396 address_space_width = 32;
397 code_region_base = 0x200000;
398 code_region_end = code_region_base + 0x3FE00000;
399 map_region_size = 0x40000000;
400 heap_region_size = 0x40000000;
401 break;
402 case FileSys::ProgramAddressSpaceType::Is36Bit:
403 address_space_width = 36;
404 code_region_base = 0x8000000;
405 code_region_end = code_region_base + 0x78000000;
406 map_region_size = 0x180000000;
407 heap_region_size = 0x180000000;
408 break;
409 case FileSys::ProgramAddressSpaceType::Is32BitNoMap:
410 address_space_width = 32;
411 code_region_base = 0x200000;
412 code_region_end = code_region_base + 0x3FE00000;
413 map_region_size = 0;
414 heap_region_size = 0x80000000;
415 break;
416 case FileSys::ProgramAddressSpaceType::Is39Bit:
417 address_space_width = 39;
418 code_region_base = 0x8000000;
419 code_region_end = code_region_base + 0x80000000;
420 map_region_size = 0x1000000000;
421 heap_region_size = 0x180000000;
422 new_map_region_size = 0x80000000;
423 tls_io_region_size = 0x1000000000;
424 break;
425 default:
426 UNREACHABLE_MSG("Invalid address space type specified: {}", static_cast<u32>(type));
427 return;
428 }
429
430 address_space_base = 0;
431 address_space_end = 1ULL << address_space_width;
432
433 map_region_base = code_region_end;
434 map_region_end = map_region_base + map_region_size;
435
436 heap_region_base = map_region_end;
437 heap_region_end = heap_region_base + heap_region_size;
438
439 new_map_region_base = heap_region_end;
440 new_map_region_end = new_map_region_base + new_map_region_size;
441
442 tls_io_region_base = new_map_region_end;
443 tls_io_region_end = tls_io_region_base + tls_io_region_size;
444
445 if (new_map_region_size == 0) {
446 new_map_region_base = address_space_base;
447 new_map_region_end = address_space_end;
448 }
449}
450
451void VMManager::Clear() {
452 ClearVMAMap();
453 ClearPageTable();
454}
455
456void VMManager::ClearVMAMap() {
457 vma_map.clear();
458}
459
460void VMManager::ClearPageTable() {
461 std::fill(page_table.pointers.begin(), page_table.pointers.end(), nullptr);
462 page_table.special_regions.clear();
463 std::fill(page_table.attributes.begin(), page_table.attributes.end(),
464 Memory::PageType::Unmapped);
465}
466
385u64 VMManager::GetTotalMemoryUsage() const { 467u64 VMManager::GetTotalMemoryUsage() const {
386 LOG_WARNING(Kernel, "(STUBBED) called"); 468 LOG_WARNING(Kernel, "(STUBBED) called");
387 return 0xF8000000; 469 return 0xF8000000;
@@ -392,14 +474,80 @@ u64 VMManager::GetTotalHeapUsage() const {
392 return 0x0; 474 return 0x0;
393} 475}
394 476
395VAddr VMManager::GetAddressSpaceBaseAddr() const { 477VAddr VMManager::GetAddressSpaceBaseAddress() const {
396 LOG_WARNING(Kernel, "(STUBBED) called"); 478 return address_space_base;
397 return 0x8000000; 479}
480
481VAddr VMManager::GetAddressSpaceEndAddress() const {
482 return address_space_end;
398} 483}
399 484
400u64 VMManager::GetAddressSpaceSize() const { 485u64 VMManager::GetAddressSpaceSize() const {
401 LOG_WARNING(Kernel, "(STUBBED) called"); 486 return address_space_end - address_space_base;
402 return MAX_ADDRESS; 487}
488
489u64 VMManager::GetAddressSpaceWidth() const {
490 return address_space_width;
491}
492
493VAddr VMManager::GetCodeRegionBaseAddress() const {
494 return code_region_base;
495}
496
497VAddr VMManager::GetCodeRegionEndAddress() const {
498 return code_region_end;
499}
500
501u64 VMManager::GetCodeRegionSize() const {
502 return code_region_end - code_region_base;
503}
504
505VAddr VMManager::GetHeapRegionBaseAddress() const {
506 return heap_region_base;
507}
508
509VAddr VMManager::GetHeapRegionEndAddress() const {
510 return heap_region_end;
511}
512
513u64 VMManager::GetHeapRegionSize() const {
514 return heap_region_end - heap_region_base;
515}
516
517VAddr VMManager::GetMapRegionBaseAddress() const {
518 return map_region_base;
519}
520
521VAddr VMManager::GetMapRegionEndAddress() const {
522 return map_region_end;
523}
524
525u64 VMManager::GetMapRegionSize() const {
526 return map_region_end - map_region_base;
527}
528
529VAddr VMManager::GetNewMapRegionBaseAddress() const {
530 return new_map_region_base;
531}
532
533VAddr VMManager::GetNewMapRegionEndAddress() const {
534 return new_map_region_end;
535}
536
537u64 VMManager::GetNewMapRegionSize() const {
538 return new_map_region_end - new_map_region_base;
539}
540
541VAddr VMManager::GetTLSIORegionBaseAddress() const {
542 return tls_io_region_base;
543}
544
545VAddr VMManager::GetTLSIORegionEndAddress() const {
546 return tls_io_region_end;
547}
548
549u64 VMManager::GetTLSIORegionSize() const {
550 return tls_io_region_end - tls_io_region_base;
403} 551}
404 552
405} // namespace Kernel 553} // namespace Kernel
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index de75036c0..015559a64 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -12,6 +12,10 @@
12#include "core/memory.h" 12#include "core/memory.h"
13#include "core/memory_hook.h" 13#include "core/memory_hook.h"
14 14
15namespace FileSys {
16enum class ProgramAddressSpaceType : u8;
17}
18
15namespace Kernel { 19namespace Kernel {
16 20
17enum class VMAType : u8 { 21enum class VMAType : u8 {
@@ -111,12 +115,6 @@ struct VirtualMemoryArea {
111class VMManager final { 115class VMManager final {
112public: 116public:
113 /** 117 /**
114 * The maximum amount of address space managed by the kernel.
115 * @todo This was selected arbitrarily, and should be verified for Switch OS.
116 */
117 static constexpr VAddr MAX_ADDRESS{0x1000000000ULL};
118
119 /**
120 * A map covering the entirety of the managed address space, keyed by the `base` field of each 118 * A map covering the entirety of the managed address space, keyed by the `base` field of each
121 * VMA. It must always be modified by splitting or merging VMAs, so that the invariant 119 * VMA. It must always be modified by splitting or merging VMAs, so that the invariant
122 * `elem.base + elem.size == next.base` is preserved, and mergeable regions must always be 120 * `elem.base + elem.size == next.base` is preserved, and mergeable regions must always be
@@ -130,7 +128,7 @@ public:
130 ~VMManager(); 128 ~VMManager();
131 129
132 /// Clears the address space map, re-initializing with a single free area. 130 /// Clears the address space map, re-initializing with a single free area.
133 void Reset(); 131 void Reset(FileSys::ProgramAddressSpaceType type);
134 132
135 /// Finds the VMA in which the given address is included in, or `vma_map.end()`. 133 /// Finds the VMA in which the given address is included in, or `vma_map.end()`.
136 VMAHandle FindVMA(VAddr target) const; 134 VMAHandle FindVMA(VAddr target) const;
@@ -195,12 +193,63 @@ public:
195 /// Gets the total heap usage, used by svcGetInfo 193 /// Gets the total heap usage, used by svcGetInfo
196 u64 GetTotalHeapUsage() const; 194 u64 GetTotalHeapUsage() const;
197 195
198 /// Gets the total address space base address, used by svcGetInfo 196 /// Gets the address space base address
199 VAddr GetAddressSpaceBaseAddr() const; 197 VAddr GetAddressSpaceBaseAddress() const;
200 198
201 /// Gets the total address space address size, used by svcGetInfo 199 /// Gets the address space end address
200 VAddr GetAddressSpaceEndAddress() const;
201
202 /// Gets the total address space address size in bytes
202 u64 GetAddressSpaceSize() const; 203 u64 GetAddressSpaceSize() const;
203 204
205 /// Gets the address space width in bits.
206 u64 GetAddressSpaceWidth() const;
207
208 /// Gets the base address of the code region.
209 VAddr GetCodeRegionBaseAddress() const;
210
211 /// Gets the end address of the code region.
212 VAddr GetCodeRegionEndAddress() const;
213
214 /// Gets the total size of the code region in bytes.
215 u64 GetCodeRegionSize() const;
216
217 /// Gets the base address of the heap region.
218 VAddr GetHeapRegionBaseAddress() const;
219
220 /// Gets the end address of the heap region;
221 VAddr GetHeapRegionEndAddress() const;
222
223 /// Gets the total size of the heap region in bytes.
224 u64 GetHeapRegionSize() const;
225
226 /// Gets the base address of the map region.
227 VAddr GetMapRegionBaseAddress() const;
228
229 /// Gets the end address of the map region.
230 VAddr GetMapRegionEndAddress() const;
231
232 /// Gets the total size of the map region in bytes.
233 u64 GetMapRegionSize() const;
234
235 /// Gets the base address of the new map region.
236 VAddr GetNewMapRegionBaseAddress() const;
237
238 /// Gets the end address of the new map region.
239 VAddr GetNewMapRegionEndAddress() const;
240
241 /// Gets the total size of the new map region in bytes.
242 u64 GetNewMapRegionSize() const;
243
244 /// Gets the base address of the TLS IO region.
245 VAddr GetTLSIORegionBaseAddress() const;
246
247 /// Gets the end address of the TLS IO region.
248 VAddr GetTLSIORegionEndAddress() const;
249
250 /// Gets the total size of the TLS IO region in bytes.
251 u64 GetTLSIORegionSize() const;
252
204 /// Each VMManager has its own page table, which is set as the main one when the owning process 253 /// Each VMManager has its own page table, which is set as the main one when the owning process
205 /// is scheduled. 254 /// is scheduled.
206 Memory::PageTable page_table; 255 Memory::PageTable page_table;
@@ -240,5 +289,36 @@ private:
240 289
241 /// Updates the pages corresponding to this VMA so they match the VMA's attributes. 290 /// Updates the pages corresponding to this VMA so they match the VMA's attributes.
242 void UpdatePageTableForVMA(const VirtualMemoryArea& vma); 291 void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
292
293 /// Initializes memory region ranges to adhere to a given address space type.
294 void InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType type);
295
296 /// Clears the underlying map and page table.
297 void Clear();
298
299 /// Clears out the VMA map, unmapping any previously mapped ranges.
300 void ClearVMAMap();
301
302 /// Clears out the page table
303 void ClearPageTable();
304
305 u32 address_space_width = 0;
306 VAddr address_space_base = 0;
307 VAddr address_space_end = 0;
308
309 VAddr code_region_base = 0;
310 VAddr code_region_end = 0;
311
312 VAddr heap_region_base = 0;
313 VAddr heap_region_end = 0;
314
315 VAddr map_region_base = 0;
316 VAddr map_region_end = 0;
317
318 VAddr new_map_region_base = 0;
319 VAddr new_map_region_end = 0;
320
321 VAddr tls_io_region_base = 0;
322 VAddr tls_io_region_end = 0;
243}; 323};
244} // namespace Kernel 324} // namespace Kernel
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index fa15712cf..6073f4ecd 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -66,7 +66,7 @@ private:
66 void GetAudioRendererState(Kernel::HLERequestContext& ctx) { 66 void GetAudioRendererState(Kernel::HLERequestContext& ctx) {
67 IPC::ResponseBuilder rb{ctx, 3}; 67 IPC::ResponseBuilder rb{ctx, 3};
68 rb.Push(RESULT_SUCCESS); 68 rb.Push(RESULT_SUCCESS);
69 rb.Push<u32>(renderer->GetState()); 69 rb.Push<u32>(static_cast<u32>(renderer->GetStreamState()));
70 LOG_DEBUG(Service_Audio, "called"); 70 LOG_DEBUG(Service_Audio, "called");
71 } 71 }
72 72
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 2b8f78136..7e8035d0f 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -14,11 +14,9 @@
14#include "core/gdbstub/gdbstub.h" 14#include "core/gdbstub/gdbstub.h"
15#include "core/hle/kernel/kernel.h" 15#include "core/hle/kernel/kernel.h"
16#include "core/hle/kernel/process.h" 16#include "core/hle/kernel/process.h"
17#include "core/hle/kernel/resource_limit.h"
18#include "core/hle/service/filesystem/filesystem.h" 17#include "core/hle/service/filesystem/filesystem.h"
19#include "core/loader/deconstructed_rom_directory.h" 18#include "core/loader/deconstructed_rom_directory.h"
20#include "core/loader/nso.h" 19#include "core/loader/nso.h"
21#include "core/memory.h"
22 20
23namespace Loader { 21namespace Loader {
24 22
@@ -127,12 +125,16 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
127 metadata.Print(); 125 metadata.Print();
128 126
129 const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()}; 127 const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()};
130 if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit) { 128 if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit ||
129 arch_bits == FileSys::ProgramAddressSpaceType::Is32BitNoMap) {
131 return ResultStatus::Error32BitISA; 130 return ResultStatus::Error32BitISA;
132 } 131 }
133 132
133 process->LoadFromMetadata(metadata);
134
134 // Load NSO modules 135 // Load NSO modules
135 VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR}; 136 const VAddr base_address = process->vm_manager.GetCodeRegionBaseAddress();
137 VAddr next_load_addr = base_address;
136 for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", 138 for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",
137 "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { 139 "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) {
138 const FileSys::VirtualFile module_file = dir->GetFile(module); 140 const FileSys::VirtualFile module_file = dir->GetFile(module);
@@ -145,13 +147,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
145 } 147 }
146 } 148 }
147 149
148 auto& kernel = Core::System::GetInstance().Kernel(); 150 process->Run(base_address, metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize());
149 process->program_id = metadata.GetTitleID();
150 process->svc_access_mask.set();
151 process->resource_limit =
152 kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
153 process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(),
154 metadata.GetMainThreadStackSize());
155 151
156 // Find the RomFS by searching for a ".romfs" file in this directory 152 // Find the RomFS by searching for a ".romfs" file in this directory
157 const auto& files = dir->GetFiles(); 153 const auto& files = dir->GetFiles();
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 0e2af20b4..ff1221574 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -12,7 +12,7 @@
12#include "core/core.h" 12#include "core/core.h"
13#include "core/hle/kernel/kernel.h" 13#include "core/hle/kernel/kernel.h"
14#include "core/hle/kernel/process.h" 14#include "core/hle/kernel/process.h"
15#include "core/hle/kernel/resource_limit.h" 15#include "core/hle/kernel/vm_manager.h"
16#include "core/loader/elf.h" 16#include "core/loader/elf.h"
17#include "core/memory.h" 17#include "core/memory.h"
18 18
@@ -189,7 +189,7 @@ private:
189 189
190 u32* sectionAddrs; 190 u32* sectionAddrs;
191 bool relocate; 191 bool relocate;
192 u32 entryPoint; 192 VAddr entryPoint;
193 193
194public: 194public:
195 explicit ElfReader(void* ptr); 195 explicit ElfReader(void* ptr);
@@ -205,13 +205,13 @@ public:
205 ElfMachine GetMachine() const { 205 ElfMachine GetMachine() const {
206 return (ElfMachine)(header->e_machine); 206 return (ElfMachine)(header->e_machine);
207 } 207 }
208 u32 GetEntryPoint() const { 208 VAddr GetEntryPoint() const {
209 return entryPoint; 209 return entryPoint;
210 } 210 }
211 u32 GetFlags() const { 211 u32 GetFlags() const {
212 return (u32)(header->e_flags); 212 return (u32)(header->e_flags);
213 } 213 }
214 SharedPtr<CodeSet> LoadInto(u32 vaddr); 214 SharedPtr<CodeSet> LoadInto(VAddr vaddr);
215 215
216 int GetNumSegments() const { 216 int GetNumSegments() const {
217 return (int)(header->e_phnum); 217 return (int)(header->e_phnum);
@@ -274,7 +274,7 @@ const char* ElfReader::GetSectionName(int section) const {
274 return nullptr; 274 return nullptr;
275} 275}
276 276
277SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) { 277SharedPtr<CodeSet> ElfReader::LoadInto(VAddr vaddr) {
278 LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx); 278 LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx);
279 279
280 // Should we relocate? 280 // Should we relocate?
@@ -289,11 +289,11 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
289 LOG_DEBUG(Loader, "{} segments:", header->e_phnum); 289 LOG_DEBUG(Loader, "{} segments:", header->e_phnum);
290 290
291 // First pass : Get the bits into RAM 291 // First pass : Get the bits into RAM
292 u32 base_addr = relocate ? vaddr : 0; 292 const VAddr base_addr = relocate ? vaddr : 0;
293 293
294 u32 total_image_size = 0; 294 u64 total_image_size = 0;
295 for (unsigned int i = 0; i < header->e_phnum; ++i) { 295 for (unsigned int i = 0; i < header->e_phnum; ++i) {
296 Elf32_Phdr* p = &segments[i]; 296 const Elf32_Phdr* p = &segments[i];
297 if (p->p_type == PT_LOAD) { 297 if (p->p_type == PT_LOAD) {
298 total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF; 298 total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF;
299 } 299 }
@@ -306,7 +306,7 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
306 SharedPtr<CodeSet> codeset = CodeSet::Create(kernel, ""); 306 SharedPtr<CodeSet> codeset = CodeSet::Create(kernel, "");
307 307
308 for (unsigned int i = 0; i < header->e_phnum; ++i) { 308 for (unsigned int i = 0; i < header->e_phnum; ++i) {
309 Elf32_Phdr* p = &segments[i]; 309 const Elf32_Phdr* p = &segments[i];
310 LOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type, 310 LOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type,
311 p->p_vaddr, p->p_filesz, p->p_memsz); 311 p->p_vaddr, p->p_filesz, p->p_memsz);
312 312
@@ -333,8 +333,8 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
333 continue; 333 continue;
334 } 334 }
335 335
336 u32 segment_addr = base_addr + p->p_vaddr; 336 const VAddr segment_addr = base_addr + p->p_vaddr;
337 u32 aligned_size = (p->p_memsz + 0xFFF) & ~0xFFF; 337 const u32 aligned_size = (p->p_memsz + 0xFFF) & ~0xFFF;
338 338
339 codeset_segment->offset = current_image_position; 339 codeset_segment->offset = current_image_position;
340 codeset_segment->addr = segment_addr; 340 codeset_segment->addr = segment_addr;
@@ -395,18 +395,12 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
395 if (buffer.size() != file->GetSize()) 395 if (buffer.size() != file->GetSize())
396 return ResultStatus::ErrorIncorrectELFFileSize; 396 return ResultStatus::ErrorIncorrectELFFileSize;
397 397
398 const VAddr base_address = process->vm_manager.GetCodeRegionBaseAddress();
398 ElfReader elf_reader(&buffer[0]); 399 ElfReader elf_reader(&buffer[0]);
399 SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR); 400 SharedPtr<CodeSet> codeset = elf_reader.LoadInto(base_address);
400 codeset->name = file->GetName(); 401 codeset->name = file->GetName();
401 402
402 process->LoadModule(codeset, codeset->entrypoint); 403 process->LoadModule(codeset, codeset->entrypoint);
403 process->svc_access_mask.set();
404
405 // Attach the default resource limit (APPLICATION) to the process
406 auto& kernel = Core::System::GetInstance().Kernel();
407 process->resource_limit =
408 kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
409
410 process->Run(codeset->entrypoint, 48, Memory::DEFAULT_STACK_SIZE); 404 process->Run(codeset->entrypoint, 48, Memory::DEFAULT_STACK_SIZE);
411 405
412 is_loaded = true; 406 is_loaded = true;
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index c49ec34ab..b72871efa 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -16,7 +16,7 @@
16#include "core/gdbstub/gdbstub.h" 16#include "core/gdbstub/gdbstub.h"
17#include "core/hle/kernel/kernel.h" 17#include "core/hle/kernel/kernel.h"
18#include "core/hle/kernel/process.h" 18#include "core/hle/kernel/process.h"
19#include "core/hle/kernel/resource_limit.h" 19#include "core/hle/kernel/vm_manager.h"
20#include "core/loader/nro.h" 20#include "core/loader/nro.h"
21#include "core/memory.h" 21#include "core/memory.h"
22 22
@@ -181,17 +181,13 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
181 } 181 }
182 182
183 // Load NRO 183 // Load NRO
184 static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR}; 184 const VAddr base_address = process->vm_manager.GetCodeRegionBaseAddress();
185 185
186 if (!LoadNro(file, base_addr)) { 186 if (!LoadNro(file, base_address)) {
187 return ResultStatus::ErrorLoadingNRO; 187 return ResultStatus::ErrorLoadingNRO;
188 } 188 }
189 189
190 auto& kernel = Core::System::GetInstance().Kernel(); 190 process->Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
191 process->svc_access_mask.set();
192 process->resource_limit =
193 kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
194 process->Run(base_addr, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
195 191
196 is_loaded = true; 192 is_loaded = true;
197 return ResultStatus::Success; 193 return ResultStatus::Success;
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 78a4438c4..1a6876a22 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -13,7 +13,7 @@
13#include "core/gdbstub/gdbstub.h" 13#include "core/gdbstub/gdbstub.h"
14#include "core/hle/kernel/kernel.h" 14#include "core/hle/kernel/kernel.h"
15#include "core/hle/kernel/process.h" 15#include "core/hle/kernel/process.h"
16#include "core/hle/kernel/resource_limit.h" 16#include "core/hle/kernel/vm_manager.h"
17#include "core/loader/nso.h" 17#include "core/loader/nso.h"
18#include "core/memory.h" 18#include "core/memory.h"
19 19
@@ -159,15 +159,11 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
159 } 159 }
160 160
161 // Load module 161 // Load module
162 LoadModule(file, Memory::PROCESS_IMAGE_VADDR); 162 const VAddr base_address = process->vm_manager.GetCodeRegionBaseAddress();
163 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), Memory::PROCESS_IMAGE_VADDR); 163 LoadModule(file, base_address);
164 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address);
164 165
165 auto& kernel = Core::System::GetInstance().Kernel(); 166 process->Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
166 process->svc_access_mask.set();
167 process->resource_limit =
168 kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
169 process->Run(Memory::PROCESS_IMAGE_VADDR, Kernel::THREADPRIO_DEFAULT,
170 Memory::DEFAULT_STACK_SIZE);
171 167
172 is_loaded = true; 168 is_loaded = true;
173 return ResultStatus::Success; 169 return ResultStatus::Success;
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 316b46820..6430daad4 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -3,7 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <array>
7#include <cstring> 6#include <cstring>
8#include <utility> 7#include <utility>
9 8
@@ -15,11 +14,11 @@
15#include "core/arm/arm_interface.h" 14#include "core/arm/arm_interface.h"
16#include "core/core.h" 15#include "core/core.h"
17#include "core/hle/kernel/process.h" 16#include "core/hle/kernel/process.h"
17#include "core/hle/kernel/vm_manager.h"
18#include "core/hle/lock.h" 18#include "core/hle/lock.h"
19#include "core/memory.h" 19#include "core/memory.h"
20#include "core/memory_setup.h" 20#include "core/memory_setup.h"
21#include "video_core/renderer_base.h" 21#include "video_core/renderer_base.h"
22#include "video_core/video_core.h"
23 22
24namespace Memory { 23namespace Memory {
25 24
@@ -41,6 +40,21 @@ PageTable* GetCurrentPageTable() {
41 return current_page_table; 40 return current_page_table;
42} 41}
43 42
43PageTable::PageTable() = default;
44
45PageTable::PageTable(std::size_t address_space_width_in_bits) {
46 Resize(address_space_width_in_bits);
47}
48
49PageTable::~PageTable() = default;
50
51void PageTable::Resize(std::size_t address_space_width_in_bits) {
52 const std::size_t num_page_table_entries = 1ULL << (address_space_width_in_bits - PAGE_BITS);
53
54 pointers.resize(num_page_table_entries);
55 attributes.resize(num_page_table_entries);
56}
57
44static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, PageType type) { 58static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, PageType type) {
45 LOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE, 59 LOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE,
46 (base + size) * PAGE_SIZE); 60 (base + size) * PAGE_SIZE);
@@ -50,7 +64,7 @@ static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, Pa
50 64
51 VAddr end = base + size; 65 VAddr end = base + size;
52 while (base != end) { 66 while (base != end) {
53 ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at {:016X}", base); 67 ASSERT_MSG(base < page_table.pointers.size(), "out of range mapping at {:016X}", base);
54 68
55 page_table.attributes[base] = type; 69 page_table.attributes[base] = type;
56 page_table.pointers[base] = memory; 70 page_table.pointers[base] = memory;
@@ -323,7 +337,7 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) {
323 return; 337 return;
324 } 338 }
325 339
326 VAddr end = start + size; 340 const VAddr end = start + size;
327 341
328 const auto CheckRegion = [&](VAddr region_start, VAddr region_end) { 342 const auto CheckRegion = [&](VAddr region_start, VAddr region_end) {
329 if (start >= region_end || end <= region_start) { 343 if (start >= region_end || end <= region_start) {
@@ -333,7 +347,7 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) {
333 347
334 const VAddr overlap_start = std::max(start, region_start); 348 const VAddr overlap_start = std::max(start, region_start);
335 const VAddr overlap_end = std::min(end, region_end); 349 const VAddr overlap_end = std::min(end, region_end);
336 const u64 overlap_size = overlap_end - overlap_start; 350 const VAddr overlap_size = overlap_end - overlap_start;
337 351
338 auto& rasterizer = system_instance.Renderer().Rasterizer(); 352 auto& rasterizer = system_instance.Renderer().Rasterizer();
339 switch (mode) { 353 switch (mode) {
@@ -349,8 +363,10 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) {
349 } 363 }
350 }; 364 };
351 365
352 CheckRegion(PROCESS_IMAGE_VADDR, PROCESS_IMAGE_VADDR_END); 366 const auto& vm_manager = Core::CurrentProcess()->vm_manager;
353 CheckRegion(HEAP_VADDR, HEAP_VADDR_END); 367
368 CheckRegion(vm_manager.GetCodeRegionBaseAddress(), vm_manager.GetCodeRegionEndAddress());
369 CheckRegion(vm_manager.GetHeapRegionBaseAddress(), vm_manager.GetHeapRegionEndAddress());
354} 370}
355 371
356u8 Read8(const VAddr addr) { 372u8 Read8(const VAddr addr) {
diff --git a/src/core/memory.h b/src/core/memory.h
index 2a27c0251..1acf5ce8c 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -4,10 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#include <cstddef> 7#include <cstddef>
9#include <string> 8#include <string>
10#include <tuple> 9#include <tuple>
10#include <vector>
11#include <boost/icl/interval_map.hpp> 11#include <boost/icl/interval_map.hpp>
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "core/memory_hook.h" 13#include "core/memory_hook.h"
@@ -23,10 +23,8 @@ namespace Memory {
23 * be mapped. 23 * be mapped.
24 */ 24 */
25constexpr std::size_t PAGE_BITS = 12; 25constexpr std::size_t PAGE_BITS = 12;
26constexpr u64 PAGE_SIZE = 1 << PAGE_BITS; 26constexpr u64 PAGE_SIZE = 1ULL << PAGE_BITS;
27constexpr u64 PAGE_MASK = PAGE_SIZE - 1; 27constexpr u64 PAGE_MASK = PAGE_SIZE - 1;
28constexpr std::size_t ADDRESS_SPACE_BITS = 36;
29constexpr std::size_t PAGE_TABLE_NUM_ENTRIES = 1ULL << (ADDRESS_SPACE_BITS - PAGE_BITS);
30 28
31enum class PageType : u8 { 29enum class PageType : u8 {
32 /// Page is unmapped and should cause an access error. 30 /// Page is unmapped and should cause an access error.
@@ -62,32 +60,39 @@ struct SpecialRegion {
62 * mimics the way a real CPU page table works. 60 * mimics the way a real CPU page table works.
63 */ 61 */
64struct PageTable { 62struct PageTable {
63 explicit PageTable();
64 explicit PageTable(std::size_t address_space_width_in_bits);
65 ~PageTable();
66
67 /**
68 * Resizes the page table to be able to accomodate enough pages within
69 * a given address space.
70 *
71 * @param address_space_width_in_bits The address size width in bits.
72 */
73 void Resize(std::size_t address_space_width_in_bits);
74
65 /** 75 /**
66 * Array of memory pointers backing each page. An entry can only be non-null if the 76 * Vector of memory pointers backing each page. An entry can only be non-null if the
67 * corresponding entry in the `attributes` array is of type `Memory`. 77 * corresponding entry in the `attributes` vector is of type `Memory`.
68 */ 78 */
69 std::array<u8*, PAGE_TABLE_NUM_ENTRIES> pointers; 79 std::vector<u8*> pointers;
70 80
71 /** 81 /**
72 * Contains MMIO handlers that back memory regions whose entries in the `attribute` array is of 82 * Contains MMIO handlers that back memory regions whose entries in the `attribute` vector is
73 * type `Special`. 83 * of type `Special`.
74 */ 84 */
75 boost::icl::interval_map<VAddr, std::set<SpecialRegion>> special_regions; 85 boost::icl::interval_map<VAddr, std::set<SpecialRegion>> special_regions;
76 86
77 /** 87 /**
78 * Array of fine grained page attributes. If it is set to any value other than `Memory`, then 88 * Vector of fine grained page attributes. If it is set to any value other than `Memory`, then
79 * the corresponding entry in `pointers` MUST be set to null. 89 * the corresponding entry in `pointers` MUST be set to null.
80 */ 90 */
81 std::array<PageType, PAGE_TABLE_NUM_ENTRIES> attributes; 91 std::vector<PageType> attributes;
82}; 92};
83 93
84/// Virtual user-space memory regions 94/// Virtual user-space memory regions
85enum : VAddr { 95enum : VAddr {
86 /// Where the application text, data and bss reside.
87 PROCESS_IMAGE_VADDR = 0x08000000,
88 PROCESS_IMAGE_MAX_SIZE = 0x08000000,
89 PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE,
90
91 /// Read-only page containing kernel and system configuration values. 96 /// Read-only page containing kernel and system configuration values.
92 CONFIG_MEMORY_VADDR = 0x1FF80000, 97 CONFIG_MEMORY_VADDR = 0x1FF80000,
93 CONFIG_MEMORY_SIZE = 0x00001000, 98 CONFIG_MEMORY_SIZE = 0x00001000,
@@ -98,36 +103,12 @@ enum : VAddr {
98 SHARED_PAGE_SIZE = 0x00001000, 103 SHARED_PAGE_SIZE = 0x00001000,
99 SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE, 104 SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE,
100 105
101 /// Area where TLS (Thread-Local Storage) buffers are allocated. 106 /// TLS (Thread-Local Storage) related.
102 TLS_AREA_VADDR = 0x40000000,
103 TLS_ENTRY_SIZE = 0x200, 107 TLS_ENTRY_SIZE = 0x200,
104 TLS_AREA_SIZE = 0x10000000,
105 TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE,
106 108
107 /// Application stack 109 /// Application stack
108 STACK_AREA_VADDR = TLS_AREA_VADDR_END,
109 STACK_AREA_SIZE = 0x10000000,
110 STACK_AREA_VADDR_END = STACK_AREA_VADDR + STACK_AREA_SIZE,
111 DEFAULT_STACK_SIZE = 0x100000, 110 DEFAULT_STACK_SIZE = 0x100000,
112 111
113 /// Application heap
114 /// Size is confirmed to be a static value on fw 3.0.0
115 HEAP_VADDR = 0x108000000,
116 HEAP_SIZE = 0x180000000,
117 HEAP_VADDR_END = HEAP_VADDR + HEAP_SIZE,
118
119 /// New map region
120 /// Size is confirmed to be a static value on fw 3.0.0
121 NEW_MAP_REGION_VADDR = HEAP_VADDR_END,
122 NEW_MAP_REGION_SIZE = 0x80000000,
123 NEW_MAP_REGION_VADDR_END = NEW_MAP_REGION_VADDR + NEW_MAP_REGION_SIZE,
124
125 /// Map region
126 /// Size is confirmed to be a static value on fw 3.0.0
127 MAP_REGION_VADDR = NEW_MAP_REGION_VADDR_END,
128 MAP_REGION_SIZE = 0x1000000000,
129 MAP_REGION_VADDR_END = MAP_REGION_VADDR + MAP_REGION_SIZE,
130
131 /// Kernel Virtual Address Range 112 /// Kernel Virtual Address Range
132 KERNEL_REGION_VADDR = 0xFFFFFF8000000000, 113 KERNEL_REGION_VADDR = 0xFFFFFF8000000000,
133 KERNEL_REGION_SIZE = 0x7FFFE00000, 114 KERNEL_REGION_SIZE = 0x7FFFE00000,
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp
index 7c69fc26e..c17a122cd 100644
--- a/src/tests/core/arm/arm_test_common.cpp
+++ b/src/tests/core/arm/arm_test_common.cpp
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6
5#include "core/core.h" 7#include "core/core.h"
6#include "core/hle/kernel/process.h" 8#include "core/hle/kernel/process.h"
7#include "core/memory.h" 9#include "core/memory.h"
@@ -16,9 +18,10 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
16 Core::CurrentProcess() = Kernel::Process::Create(kernel, ""); 18 Core::CurrentProcess() = Kernel::Process::Create(kernel, "");
17 page_table = &Core::CurrentProcess()->vm_manager.page_table; 19 page_table = &Core::CurrentProcess()->vm_manager.page_table;
18 20
19 page_table->pointers.fill(nullptr); 21 std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr);
20 page_table->special_regions.clear(); 22 page_table->special_regions.clear();
21 page_table->attributes.fill(Memory::PageType::Unmapped); 23 std::fill(page_table->attributes.begin(), page_table->attributes.end(),
24 Memory::PageType::Unmapped);
22 25
23 Memory::MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory); 26 Memory::MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory);
24 Memory::MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory); 27 Memory::MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory);
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 16cdfc7e2..9f5581045 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -41,6 +41,7 @@ public:
41 static constexpr std::size_t NumCBData = 16; 41 static constexpr std::size_t NumCBData = 16;
42 static constexpr std::size_t NumVertexArrays = 32; 42 static constexpr std::size_t NumVertexArrays = 32;
43 static constexpr std::size_t NumVertexAttributes = 32; 43 static constexpr std::size_t NumVertexAttributes = 32;
44 static constexpr std::size_t NumTextureSamplers = 32;
44 static constexpr std::size_t MaxShaderProgram = 6; 45 static constexpr std::size_t MaxShaderProgram = 6;
45 static constexpr std::size_t MaxShaderStage = 5; 46 static constexpr std::size_t MaxShaderStage = 5;
46 // Maximum number of const buffers per shader stage. 47 // Maximum number of const buffers per shader stage.
@@ -641,7 +642,11 @@ public:
641 642
642 u32 vb_element_base; 643 u32 vb_element_base;
643 644
644 INSERT_PADDING_WORDS(0x40); 645 INSERT_PADDING_WORDS(0x38);
646
647 float point_size;
648
649 INSERT_PADDING_WORDS(0x7);
645 650
646 u32 zeta_enable; 651 u32 zeta_enable;
647 652
@@ -1017,6 +1022,7 @@ ASSERT_REG_POSITION(stencil_front_func_mask, 0x4E6);
1017ASSERT_REG_POSITION(stencil_front_mask, 0x4E7); 1022ASSERT_REG_POSITION(stencil_front_mask, 0x4E7);
1018ASSERT_REG_POSITION(screen_y_control, 0x4EB); 1023ASSERT_REG_POSITION(screen_y_control, 0x4EB);
1019ASSERT_REG_POSITION(vb_element_base, 0x50D); 1024ASSERT_REG_POSITION(vb_element_base, 0x50D);
1025ASSERT_REG_POSITION(point_size, 0x546);
1020ASSERT_REG_POSITION(zeta_enable, 0x54E); 1026ASSERT_REG_POSITION(zeta_enable, 0x54E);
1021ASSERT_REG_POSITION(tsc, 0x557); 1027ASSERT_REG_POSITION(tsc, 0x557);
1022ASSERT_REG_POSITION(tic, 0x55D); 1028ASSERT_REG_POSITION(tic, 0x55D);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 44850d193..1fcd13f04 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -452,6 +452,7 @@ void RasterizerOpenGL::DrawArrays() {
452 SyncCullMode(); 452 SyncCullMode();
453 SyncAlphaTest(); 453 SyncAlphaTest();
454 SyncTransformFeedback(); 454 SyncTransformFeedback();
455 SyncPointState();
455 456
456 // TODO(bunnei): Sync framebuffer_scale uniform here 457 // TODO(bunnei): Sync framebuffer_scale uniform here
457 // TODO(bunnei): Sync scissorbox uniform(s) here 458 // TODO(bunnei): Sync scissorbox uniform(s) here
@@ -905,4 +906,10 @@ void RasterizerOpenGL::SyncTransformFeedback() {
905 } 906 }
906} 907}
907 908
909void RasterizerOpenGL::SyncPointState() {
910 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
911
912 state.point.size = regs.point_size;
913}
914
908} // namespace OpenGL 915} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index c3f1e14bf..4c8ecbd1c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -164,6 +164,9 @@ private:
164 /// Syncs the transform feedback state to match the guest state 164 /// Syncs the transform feedback state to match the guest state
165 void SyncTransformFeedback(); 165 void SyncTransformFeedback();
166 166
167 /// Syncs the point state to match the guest state
168 void SyncPointState();
169
167 bool has_ARB_direct_state_access = false; 170 bool has_ARB_direct_state_access = false;
168 bool has_ARB_multi_bind = false; 171 bool has_ARB_multi_bind = false;
169 bool has_ARB_separate_shader_objects = false; 172 bool has_ARB_separate_shader_objects = false;
@@ -184,7 +187,7 @@ private:
184 OGLVertexArray> 187 OGLVertexArray>
185 vertex_array_cache; 188 vertex_array_cache;
186 189
187 std::array<SamplerInfo, GLShader::NumTextureSamplers> texture_samplers; 190 std::array<SamplerInfo, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_samplers;
188 191
189 static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; 192 static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
190 OGLBufferCache buffer_cache; 193 OGLBufferCache buffer_cache;
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index b86cd96e8..3de15ba9b 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -11,9 +11,6 @@
11 11
12namespace OpenGL::GLShader { 12namespace OpenGL::GLShader {
13 13
14/// Number of OpenGL texture samplers that can be used in the fragment shader
15static constexpr std::size_t NumTextureSamplers = 32;
16
17using Tegra::Engines::Maxwell3D; 14using Tegra::Engines::Maxwell3D;
18 15
19/// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned 16/// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index e5173e20a..1fe26a2a9 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -79,6 +79,8 @@ OpenGLState::OpenGLState() {
79 viewport.height = 0; 79 viewport.height = 0;
80 80
81 clip_distance = {}; 81 clip_distance = {};
82
83 point.size = 1;
82} 84}
83 85
84void OpenGLState::Apply() const { 86void OpenGLState::Apply() const {
@@ -205,9 +207,6 @@ void OpenGLState::Apply() const {
205 glActiveTexture(TextureUnits::MaxwellTexture(static_cast<int>(i)).Enum()); 207 glActiveTexture(TextureUnits::MaxwellTexture(static_cast<int>(i)).Enum());
206 glBindTexture(texture_unit.target, texture_unit.texture); 208 glBindTexture(texture_unit.target, texture_unit.texture);
207 } 209 }
208 if (texture_unit.sampler != cur_state_texture_unit.sampler) {
209 glBindSampler(static_cast<GLuint>(i), texture_unit.sampler);
210 }
211 // Update the texture swizzle 210 // Update the texture swizzle
212 if (texture_unit.swizzle.r != cur_state_texture_unit.swizzle.r || 211 if (texture_unit.swizzle.r != cur_state_texture_unit.swizzle.r ||
213 texture_unit.swizzle.g != cur_state_texture_unit.swizzle.g || 212 texture_unit.swizzle.g != cur_state_texture_unit.swizzle.g ||
@@ -219,6 +218,27 @@ void OpenGLState::Apply() const {
219 } 218 }
220 } 219 }
221 220
221 // Samplers
222 {
223 bool has_delta{};
224 std::size_t first{}, last{};
225 std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers;
226 for (std::size_t i = 0; i < std::size(samplers); ++i) {
227 samplers[i] = texture_units[i].sampler;
228 if (samplers[i] != cur_state.texture_units[i].sampler) {
229 if (!has_delta) {
230 first = i;
231 has_delta = true;
232 }
233 last = i;
234 }
235 }
236 if (has_delta) {
237 glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
238 samplers.data());
239 }
240 }
241
222 // Framebuffer 242 // Framebuffer
223 if (draw.read_framebuffer != cur_state.draw.read_framebuffer) { 243 if (draw.read_framebuffer != cur_state.draw.read_framebuffer) {
224 glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); 244 glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer);
@@ -283,6 +303,11 @@ void OpenGLState::Apply() const {
283 } 303 }
284 } 304 }
285 305
306 // Point
307 if (point.size != cur_state.point.size) {
308 glPointSize(point.size);
309 }
310
286 cur_state = *this; 311 cur_state = *this;
287} 312}
288 313
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 9a93029d8..dc21a2ee3 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -6,6 +6,7 @@
6 6
7#include <array> 7#include <array>
8#include <glad/glad.h> 8#include <glad/glad.h>
9#include "video_core/engines/maxwell_3d.h"
9 10
10namespace OpenGL { 11namespace OpenGL {
11 12
@@ -114,7 +115,7 @@ public:
114 target = GL_TEXTURE_2D; 115 target = GL_TEXTURE_2D;
115 } 116 }
116 }; 117 };
117 std::array<TextureUnit, 32> texture_units; 118 std::array<TextureUnit, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_units;
118 119
119 struct { 120 struct {
120 GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING 121 GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING
@@ -141,6 +142,10 @@ public:
141 GLsizei height; 142 GLsizei height;
142 } viewport; 143 } viewport;
143 144
145 struct {
146 float size; // GL_POINT_SIZE
147 } point;
148
144 std::array<bool, 2> clip_distance; // GL_CLIP_DISTANCE 149 std::array<bool, 2> clip_distance; // GL_CLIP_DISTANCE
145 150
146 OpenGLState(); 151 OpenGLState();
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 991ae10cd..67890455a 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -26,10 +26,10 @@
26#include "yuzu/main.h" 26#include "yuzu/main.h"
27#include "yuzu/ui_settings.h" 27#include "yuzu/ui_settings.h"
28 28
29GameList::SearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist) : gamelist{gamelist} {} 29GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist) : gamelist{gamelist} {}
30 30
31// EventFilter in order to process systemkeys while editing the searchfield 31// EventFilter in order to process systemkeys while editing the searchfield
32bool GameList::SearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* event) { 32bool GameListSearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* event) {
33 // If it isn't a KeyRelease event then continue with standard event processing 33 // If it isn't a KeyRelease event then continue with standard event processing
34 if (event->type() != QEvent::KeyRelease) 34 if (event->type() != QEvent::KeyRelease)
35 return QObject::eventFilter(obj, event); 35 return QObject::eventFilter(obj, event);
@@ -88,21 +88,21 @@ bool GameList::SearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* e
88 return QObject::eventFilter(obj, event); 88 return QObject::eventFilter(obj, event);
89} 89}
90 90
91void GameList::SearchField::setFilterResult(int visible, int total) { 91void GameListSearchField::setFilterResult(int visible, int total) {
92 label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible)); 92 label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible));
93} 93}
94 94
95void GameList::SearchField::clear() { 95void GameListSearchField::clear() {
96 edit_filter->setText(""); 96 edit_filter->setText("");
97} 97}
98 98
99void GameList::SearchField::setFocus() { 99void GameListSearchField::setFocus() {
100 if (edit_filter->isVisible()) { 100 if (edit_filter->isVisible()) {
101 edit_filter->setFocus(); 101 edit_filter->setFocus();
102 } 102 }
103} 103}
104 104
105GameList::SearchField::SearchField(GameList* parent) : QWidget{parent} { 105GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} {
106 KeyReleaseEater* keyReleaseEater = new KeyReleaseEater(parent); 106 KeyReleaseEater* keyReleaseEater = new KeyReleaseEater(parent);
107 layout_filter = new QHBoxLayout; 107 layout_filter = new QHBoxLayout;
108 layout_filter->setMargin(8); 108 layout_filter->setMargin(8);
@@ -202,7 +202,7 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent)
202 this->main_window = parent; 202 this->main_window = parent;
203 layout = new QVBoxLayout; 203 layout = new QVBoxLayout;
204 tree_view = new QTreeView; 204 tree_view = new QTreeView;
205 search_field = new SearchField(this); 205 search_field = new GameListSearchField(this);
206 item_model = new QStandardItemModel(tree_view); 206 item_model = new QStandardItemModel(tree_view);
207 tree_view->setModel(item_model); 207 tree_view->setModel(item_model);
208 208
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index 3bf51870e..05e115e19 100644
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -22,6 +22,7 @@
22#include "yuzu/compatibility_list.h" 22#include "yuzu/compatibility_list.h"
23 23
24class GameListWorker; 24class GameListWorker;
25class GameListSearchField;
25class GMainWindow; 26class GMainWindow;
26 27
27namespace FileSys { 28namespace FileSys {
@@ -46,33 +47,6 @@ public:
46 COLUMN_COUNT, // Number of columns 47 COLUMN_COUNT, // Number of columns
47 }; 48 };
48 49
49 class SearchField : public QWidget {
50 public:
51 void setFilterResult(int visible, int total);
52 void clear();
53 void setFocus();
54 explicit SearchField(GameList* parent = nullptr);
55
56 private:
57 class KeyReleaseEater : public QObject {
58 public:
59 explicit KeyReleaseEater(GameList* gamelist);
60
61 private:
62 GameList* gamelist = nullptr;
63 QString edit_filter_text_old;
64
65 protected:
66 bool eventFilter(QObject* obj, QEvent* event) override;
67 };
68 QHBoxLayout* layout_filter = nullptr;
69 QTreeView* tree_view = nullptr;
70 QLabel* label_filter = nullptr;
71 QLineEdit* edit_filter = nullptr;
72 QLabel* label_filter_result = nullptr;
73 QToolButton* button_filter_close = nullptr;
74 };
75
76 explicit GameList(std::shared_ptr<FileSys::VfsFilesystem> vfs, GMainWindow* parent = nullptr); 50 explicit GameList(std::shared_ptr<FileSys::VfsFilesystem> vfs, GMainWindow* parent = nullptr);
77 ~GameList() override; 51 ~GameList() override;
78 52
@@ -110,7 +84,7 @@ private:
110 void RefreshGameDirectory(); 84 void RefreshGameDirectory();
111 85
112 std::shared_ptr<FileSys::VfsFilesystem> vfs; 86 std::shared_ptr<FileSys::VfsFilesystem> vfs;
113 SearchField* search_field; 87 GameListSearchField* search_field;
114 GMainWindow* main_window = nullptr; 88 GMainWindow* main_window = nullptr;
115 QVBoxLayout* layout = nullptr; 89 QVBoxLayout* layout = nullptr;
116 QTreeView* tree_view = nullptr; 90 QTreeView* tree_view = nullptr;
@@ -118,6 +92,8 @@ private:
118 GameListWorker* current_worker = nullptr; 92 GameListWorker* current_worker = nullptr;
119 QFileSystemWatcher* watcher = nullptr; 93 QFileSystemWatcher* watcher = nullptr;
120 CompatibilityList compatibility_list; 94 CompatibilityList compatibility_list;
95
96 friend class GameListSearchField;
121}; 97};
122 98
123Q_DECLARE_METATYPE(GameListOpenTarget); 99Q_DECLARE_METATYPE(GameListOpenTarget);
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h
index cee109730..3db0e90da 100644
--- a/src/yuzu/game_list_p.h
+++ b/src/yuzu/game_list_p.h
@@ -16,6 +16,7 @@
16#include <QObject> 16#include <QObject>
17#include <QStandardItem> 17#include <QStandardItem>
18#include <QString> 18#include <QString>
19#include <QWidget>
19 20
20#include "common/common_types.h" 21#include "common/common_types.h"
21#include "common/logging/log.h" 22#include "common/logging/log.h"
@@ -176,3 +177,42 @@ public:
176 return data(SizeRole).toULongLong() < other.data(SizeRole).toULongLong(); 177 return data(SizeRole).toULongLong() < other.data(SizeRole).toULongLong();
177 } 178 }
178}; 179};
180
181class GameList;
182class QHBoxLayout;
183class QTreeView;
184class QLabel;
185class QLineEdit;
186class QToolButton;
187
188class GameListSearchField : public QWidget {
189 Q_OBJECT
190
191public:
192 explicit GameListSearchField(GameList* parent = nullptr);
193
194 void setFilterResult(int visible, int total);
195
196 void clear();
197 void setFocus();
198
199private:
200 class KeyReleaseEater : public QObject {
201 public:
202 explicit KeyReleaseEater(GameList* gamelist);
203
204 private:
205 GameList* gamelist = nullptr;
206 QString edit_filter_text_old;
207
208 protected:
209 // EventFilter in order to process systemkeys while editing the searchfield
210 bool eventFilter(QObject* obj, QEvent* event) override;
211 };
212 QHBoxLayout* layout_filter = nullptr;
213 QTreeView* tree_view = nullptr;
214 QLabel* label_filter = nullptr;
215 QLineEdit* edit_filter = nullptr;
216 QLabel* label_filter_result = nullptr;
217 QToolButton* button_filter_close = nullptr;
218};