summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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/arm_interface.h10
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp15
-rw-r--r--src/core/core.cpp4
-rw-r--r--src/core/core_cpu.cpp8
-rw-r--r--src/core/core_cpu.h2
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.cpp62
-rw-r--r--src/core/file_sys/patch_manager.cpp56
-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/file_sys/registered_cache.cpp2
-rw-r--r--src/core/file_sys/romfs.cpp2
-rw-r--r--src/core/file_sys/romfs_factory.cpp2
-rw-r--r--src/core/file_sys/savedata_factory.cpp2
-rw-r--r--src/core/file_sys/vfs.cpp6
-rw-r--r--src/core/file_sys/vfs.h9
-rw-r--r--src/core/file_sys/vfs_concat.cpp45
-rw-r--r--src/core/file_sys/vfs_concat.h44
-rw-r--r--src/core/file_sys/vfs_layered.cpp15
-rw-r--r--src/core/file_sys/vfs_layered.h8
-rw-r--r--src/core/file_sys/vfs_static.h21
-rw-r--r--src/core/file_sys/vfs_vector.cpp6
-rw-r--r--src/core/file_sys/vfs_vector.h8
-rw-r--r--src/core/gdbstub/gdbstub.cpp17
-rw-r--r--src/core/hle/kernel/errors.h2
-rw-r--r--src/core/hle/kernel/object.h3
-rw-r--r--src/core/hle/kernel/process.cpp29
-rw-r--r--src/core/hle/kernel/process.h113
-rw-r--r--src/core/hle/kernel/scheduler.cpp16
-rw-r--r--src/core/hle/kernel/scheduler.h4
-rw-r--r--src/core/hle/kernel/shared_memory.cpp16
-rw-r--r--src/core/hle/kernel/svc.cpp95
-rw-r--r--src/core/hle/kernel/svc_wrap.h5
-rw-r--r--src/core/hle/kernel/thread.cpp5
-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/kernel/wait_object.h2
-rw-r--r--src/core/hle/service/audio/audren_u.cpp3
-rw-r--r--src/core/hle/service/fatal/fatal.cpp4
-rw-r--r--src/core/hle/service/nfp/nfp.cpp1
-rw-r--r--src/core/hle/service/nim/nim.cpp1
-rw-r--r--src/core/hle/service/ns/pl_u.cpp6
-rw-r--r--src/core/hle/service/sm/controller.cpp3
-rw-r--r--src/core/hle/service/vi/vi.cpp20
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp21
-rw-r--r--src/core/loader/deconstructed_rom_directory.h3
-rw-r--r--src/core/loader/elf.cpp38
-rw-r--r--src/core/loader/elf.h5
-rw-r--r--src/core/loader/loader.h3
-rw-r--r--src/core/loader/nax.cpp2
-rw-r--r--src/core/loader/nax.h2
-rw-r--r--src/core/loader/nca.cpp2
-rw-r--r--src/core/loader/nca.h3
-rw-r--r--src/core/loader/nro.cpp14
-rw-r--r--src/core/loader/nro.h3
-rw-r--r--src/core/loader/nso.cpp16
-rw-r--r--src/core/loader/nso.h4
-rw-r--r--src/core/loader/nsp.cpp4
-rw-r--r--src/core/loader/nsp.h2
-rw-r--r--src/core/loader/xci.cpp4
-rw-r--r--src/core/loader/xci.h2
-rw-r--r--src/core/memory.cpp42
-rw-r--r--src/core/memory.h63
-rw-r--r--src/tests/core/arm/arm_test_common.cpp9
-rw-r--r--src/video_core/engines/maxwell_3d.h20
-rw-r--r--src/video_core/engines/maxwell_compute.cpp19
-rw-r--r--src/video_core/engines/maxwell_compute.h36
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp29
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h11
-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/video_core/textures/decoders.cpp117
-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
-rw-r--r--src/yuzu/main.cpp92
80 files changed, 1102 insertions, 575 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/arm_interface.h b/src/core/arm/arm_interface.h
index 16d528994..59da33f30 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -22,10 +22,16 @@ public:
22 std::array<u64, 31> cpu_registers; 22 std::array<u64, 31> cpu_registers;
23 u64 sp; 23 u64 sp;
24 u64 pc; 24 u64 pc;
25 u64 pstate; 25 u32 pstate;
26 std::array<u8, 4> padding;
26 std::array<u128, 32> vector_registers; 27 std::array<u128, 32> vector_registers;
27 u64 fpcr; 28 u32 fpcr;
29 u32 fpsr;
30 u64 tpidr;
28 }; 31 };
32 // Internally within the kernel, it expects the AArch64 version of the
33 // thread context to be 800 bytes in size.
34 static_assert(sizeof(ThreadContext) == 0x320);
29 35
30 /// Runs the CPU until an event happens 36 /// Runs the CPU until an event happens
31 virtual void Run() = 0; 37 virtual void Run() = 0;
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 7be5a38de..05cc84458 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->VMManager().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->VMManager().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
@@ -174,7 +175,7 @@ ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
174 std::size_t core_index) 175 std::size_t core_index)
175 : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), core_index{core_index}, 176 : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), core_index{core_index},
176 exclusive_monitor{std::dynamic_pointer_cast<DynarmicExclusiveMonitor>(exclusive_monitor)} { 177 exclusive_monitor{std::dynamic_pointer_cast<DynarmicExclusiveMonitor>(exclusive_monitor)} {
177 ThreadContext ctx; 178 ThreadContext ctx{};
178 inner_unicorn.SaveContext(ctx); 179 inner_unicorn.SaveContext(ctx);
179 PageTableChanged(); 180 PageTableChanged();
180 LoadContext(ctx); 181 LoadContext(ctx);
@@ -246,15 +247,19 @@ void ARM_Dynarmic::SaveContext(ThreadContext& ctx) {
246 ctx.pstate = jit->GetPstate(); 247 ctx.pstate = jit->GetPstate();
247 ctx.vector_registers = jit->GetVectors(); 248 ctx.vector_registers = jit->GetVectors();
248 ctx.fpcr = jit->GetFpcr(); 249 ctx.fpcr = jit->GetFpcr();
250 ctx.fpsr = jit->GetFpsr();
251 ctx.tpidr = cb->tpidr_el0;
249} 252}
250 253
251void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) { 254void ARM_Dynarmic::LoadContext(const ThreadContext& ctx) {
252 jit->SetRegisters(ctx.cpu_registers); 255 jit->SetRegisters(ctx.cpu_registers);
253 jit->SetSP(ctx.sp); 256 jit->SetSP(ctx.sp);
254 jit->SetPC(ctx.pc); 257 jit->SetPC(ctx.pc);
255 jit->SetPstate(static_cast<u32>(ctx.pstate)); 258 jit->SetPstate(ctx.pstate);
256 jit->SetVectors(ctx.vector_registers); 259 jit->SetVectors(ctx.vector_registers);
257 jit->SetFpcr(static_cast<u32>(ctx.fpcr)); 260 jit->SetFpcr(ctx.fpcr);
261 jit->SetFpsr(ctx.fpsr);
262 SetTPIDR_EL0(ctx.tpidr);
258} 263}
259 264
260void ARM_Dynarmic::PrepareReschedule() { 265void ARM_Dynarmic::PrepareReschedule() {
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 50f0a42fb..b6acfb3e4 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -64,7 +64,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
64 if (concat.empty()) 64 if (concat.empty())
65 return nullptr; 65 return nullptr;
66 66
67 return FileSys::ConcatenateFiles(concat, dir->GetName()); 67 return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(concat, dir->GetName());
68 } 68 }
69 69
70 return vfs->OpenFile(path, FileSys::Mode::Read); 70 return vfs->OpenFile(path, FileSys::Mode::Read);
@@ -202,7 +202,7 @@ struct System::Impl {
202 return init_result; 202 return init_result;
203 } 203 }
204 204
205 const Loader::ResultStatus load_result{app_loader->Load(kernel.CurrentProcess())}; 205 const Loader::ResultStatus load_result{app_loader->Load(*kernel.CurrentProcess())};
206 if (load_result != Loader::ResultStatus::Success) { 206 if (load_result != Loader::ResultStatus::Success) {
207 LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result)); 207 LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result));
208 Shutdown(); 208 Shutdown();
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp
index 21568ad50..265f8ed9c 100644
--- a/src/core/core_cpu.cpp
+++ b/src/core/core_cpu.cpp
@@ -55,16 +55,16 @@ Cpu::Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
55 55
56 if (Settings::values.use_cpu_jit) { 56 if (Settings::values.use_cpu_jit) {
57#ifdef ARCHITECTURE_x86_64 57#ifdef ARCHITECTURE_x86_64
58 arm_interface = std::make_shared<ARM_Dynarmic>(exclusive_monitor, core_index); 58 arm_interface = std::make_unique<ARM_Dynarmic>(exclusive_monitor, core_index);
59#else 59#else
60 arm_interface = std::make_shared<ARM_Unicorn>(); 60 arm_interface = std::make_unique<ARM_Unicorn>();
61 LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); 61 LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
62#endif 62#endif
63 } else { 63 } else {
64 arm_interface = std::make_shared<ARM_Unicorn>(); 64 arm_interface = std::make_unique<ARM_Unicorn>();
65 } 65 }
66 66
67 scheduler = std::make_shared<Kernel::Scheduler>(arm_interface.get()); 67 scheduler = std::make_shared<Kernel::Scheduler>(*arm_interface);
68} 68}
69 69
70Cpu::~Cpu() = default; 70Cpu::~Cpu() = default;
diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h
index 685532965..ee7e04abc 100644
--- a/src/core/core_cpu.h
+++ b/src/core/core_cpu.h
@@ -76,7 +76,7 @@ public:
76private: 76private:
77 void Reschedule(); 77 void Reschedule();
78 78
79 std::shared_ptr<ARM_Interface> arm_interface; 79 std::unique_ptr<ARM_Interface> arm_interface;
80 std::shared_ptr<CpuBarrier> cpu_barrier; 80 std::shared_ptr<CpuBarrier> cpu_barrier;
81 std::shared_ptr<Kernel::Scheduler> scheduler; 81 std::shared_ptr<Kernel::Scheduler> scheduler;
82 82
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp
index 21fc3d796..2a913ce82 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.cpp
+++ b/src/core/file_sys/fsmitm_romfsbuild.cpp
@@ -23,6 +23,7 @@
23 */ 23 */
24 24
25#include <cstring> 25#include <cstring>
26#include "common/alignment.h"
26#include "common/assert.h" 27#include "common/assert.h"
27#include "core/file_sys/fsmitm_romfsbuild.h" 28#include "core/file_sys/fsmitm_romfsbuild.h"
28#include "core/file_sys/vfs.h" 29#include "core/file_sys/vfs.h"
@@ -73,7 +74,7 @@ static_assert(sizeof(RomFSFileEntry) == 0x20, "RomFSFileEntry has incorrect size
73struct RomFSBuildFileContext; 74struct RomFSBuildFileContext;
74 75
75struct RomFSBuildDirectoryContext { 76struct RomFSBuildDirectoryContext {
76 std::string path = ""; 77 std::string path;
77 u32 cur_path_ofs = 0; 78 u32 cur_path_ofs = 0;
78 u32 path_len = 0; 79 u32 path_len = 0;
79 u32 entry_offset = 0; 80 u32 entry_offset = 0;
@@ -84,7 +85,7 @@ struct RomFSBuildDirectoryContext {
84}; 85};
85 86
86struct RomFSBuildFileContext { 87struct RomFSBuildFileContext {
87 std::string path = ""; 88 std::string path;
88 u32 cur_path_ofs = 0; 89 u32 cur_path_ofs = 0;
89 u32 path_len = 0; 90 u32 path_len = 0;
90 u32 entry_offset = 0; 91 u32 entry_offset = 0;
@@ -92,12 +93,10 @@ struct RomFSBuildFileContext {
92 u64 size = 0; 93 u64 size = 0;
93 std::shared_ptr<RomFSBuildDirectoryContext> parent; 94 std::shared_ptr<RomFSBuildDirectoryContext> parent;
94 std::shared_ptr<RomFSBuildFileContext> sibling; 95 std::shared_ptr<RomFSBuildFileContext> sibling;
95 VirtualFile source = nullptr; 96 VirtualFile source;
96
97 RomFSBuildFileContext() : path(""), cur_path_ofs(0), path_len(0) {}
98}; 97};
99 98
100static u32 romfs_calc_path_hash(u32 parent, std::string path, u32 start, size_t path_len) { 99static u32 romfs_calc_path_hash(u32 parent, std::string path, u32 start, std::size_t path_len) {
101 u32 hash = parent ^ 123456789; 100 u32 hash = parent ^ 123456789;
102 for (u32 i = 0; i < path_len; i++) { 101 for (u32 i = 0; i < path_len; i++) {
103 hash = (hash >> 5) | (hash << 27); 102 hash = (hash >> 5) | (hash << 27);
@@ -107,13 +106,16 @@ static u32 romfs_calc_path_hash(u32 parent, std::string path, u32 start, size_t
107 return hash; 106 return hash;
108} 107}
109 108
110static u32 romfs_get_hash_table_count(u32 num_entries) { 109static u64 romfs_get_hash_table_count(u64 num_entries) {
111 if (num_entries < 3) { 110 if (num_entries < 3) {
112 return 3; 111 return 3;
113 } else if (num_entries < 19) { 112 }
113
114 if (num_entries < 19) {
114 return num_entries | 1; 115 return num_entries | 1;
115 } 116 }
116 u32 count = num_entries; 117
118 u64 count = num_entries;
117 while (count % 2 == 0 || count % 3 == 0 || count % 5 == 0 || count % 7 == 0 || 119 while (count % 2 == 0 || count % 3 == 0 || count % 5 == 0 || count % 7 == 0 ||
118 count % 11 == 0 || count % 13 == 0 || count % 17 == 0) { 120 count % 11 == 0 || count % 13 == 0 || count % 17 == 0) {
119 count++; 121 count++;
@@ -139,7 +141,7 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs,
139 const auto child = std::make_shared<RomFSBuildDirectoryContext>(); 141 const auto child = std::make_shared<RomFSBuildDirectoryContext>();
140 // Set child's path. 142 // Set child's path.
141 child->cur_path_ofs = parent->path_len + 1; 143 child->cur_path_ofs = parent->path_len + 1;
142 child->path_len = child->cur_path_ofs + kv.first.size(); 144 child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
143 child->path = parent->path + "/" + kv.first; 145 child->path = parent->path + "/" + kv.first;
144 146
145 // Sanity check on path_len 147 // Sanity check on path_len
@@ -152,7 +154,7 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs,
152 const auto child = std::make_shared<RomFSBuildFileContext>(); 154 const auto child = std::make_shared<RomFSBuildFileContext>();
153 // Set child's path. 155 // Set child's path.
154 child->cur_path_ofs = parent->path_len + 1; 156 child->cur_path_ofs = parent->path_len + 1;
155 child->path_len = child->cur_path_ofs + kv.first.size(); 157 child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size());
156 child->path = parent->path + "/" + kv.first; 158 child->path = parent->path + "/" + kv.first;
157 159
158 // Sanity check on path_len 160 // Sanity check on path_len
@@ -181,7 +183,7 @@ bool RomFSBuildContext::AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext>
181 // Add a new directory. 183 // Add a new directory.
182 num_dirs++; 184 num_dirs++;
183 dir_table_size += 185 dir_table_size +=
184 sizeof(RomFSDirectoryEntry) + ((dir_ctx->path_len - dir_ctx->cur_path_ofs + 3) & ~3); 186 sizeof(RomFSDirectoryEntry) + Common::AlignUp(dir_ctx->path_len - dir_ctx->cur_path_ofs, 4);
185 dir_ctx->parent = parent_dir_ctx; 187 dir_ctx->parent = parent_dir_ctx;
186 directories.emplace(dir_ctx->path, dir_ctx); 188 directories.emplace(dir_ctx->path, dir_ctx);
187 189
@@ -199,7 +201,7 @@ bool RomFSBuildContext::AddFile(std::shared_ptr<RomFSBuildDirectoryContext> pare
199 // Add a new file. 201 // Add a new file.
200 num_files++; 202 num_files++;
201 file_table_size += 203 file_table_size +=
202 sizeof(RomFSFileEntry) + ((file_ctx->path_len - file_ctx->cur_path_ofs + 3) & ~3); 204 sizeof(RomFSFileEntry) + Common::AlignUp(file_ctx->path_len - file_ctx->cur_path_ofs, 4);
203 file_ctx->parent = parent_dir_ctx; 205 file_ctx->parent = parent_dir_ctx;
204 files.emplace(file_ctx->path, file_ctx); 206 files.emplace(file_ctx->path, file_ctx);
205 207
@@ -219,8 +221,8 @@ RomFSBuildContext::RomFSBuildContext(VirtualDir base_) : base(std::move(base_))
219RomFSBuildContext::~RomFSBuildContext() = default; 221RomFSBuildContext::~RomFSBuildContext() = default;
220 222
221std::map<u64, VirtualFile> RomFSBuildContext::Build() { 223std::map<u64, VirtualFile> RomFSBuildContext::Build() {
222 const auto dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs); 224 const u64 dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs);
223 const auto file_hash_table_entry_count = romfs_get_hash_table_count(num_files); 225 const u64 file_hash_table_entry_count = romfs_get_hash_table_count(num_files);
224 dir_hash_table_size = 4 * dir_hash_table_entry_count; 226 dir_hash_table_size = 4 * dir_hash_table_entry_count;
225 file_hash_table_size = 4 * file_hash_table_entry_count; 227 file_hash_table_size = 4 * file_hash_table_entry_count;
226 228
@@ -233,12 +235,6 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() {
233 std::vector<u8> dir_table(dir_table_size); 235 std::vector<u8> dir_table(dir_table_size);
234 std::vector<u8> file_table(file_table_size); 236 std::vector<u8> file_table(file_table_size);
235 237
236 // Clear out hash tables.
237 for (u32 i = 0; i < dir_hash_table_entry_count; i++)
238 dir_hash_table[i] = ROMFS_ENTRY_EMPTY;
239 for (u32 i = 0; i < file_hash_table_entry_count; i++)
240 file_hash_table[i] = ROMFS_ENTRY_EMPTY;
241
242 std::shared_ptr<RomFSBuildFileContext> cur_file; 238 std::shared_ptr<RomFSBuildFileContext> cur_file;
243 239
244 // Determine file offsets. 240 // Determine file offsets.
@@ -246,12 +242,12 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() {
246 std::shared_ptr<RomFSBuildFileContext> prev_file = nullptr; 242 std::shared_ptr<RomFSBuildFileContext> prev_file = nullptr;
247 for (const auto& it : files) { 243 for (const auto& it : files) {
248 cur_file = it.second; 244 cur_file = it.second;
249 file_partition_size = (file_partition_size + 0xFULL) & ~0xFULL; 245 file_partition_size = Common::AlignUp(file_partition_size, 16);
250 cur_file->offset = file_partition_size; 246 cur_file->offset = file_partition_size;
251 file_partition_size += cur_file->size; 247 file_partition_size += cur_file->size;
252 cur_file->entry_offset = entry_offset; 248 cur_file->entry_offset = entry_offset;
253 entry_offset += 249 entry_offset += sizeof(RomFSFileEntry) +
254 sizeof(RomFSFileEntry) + ((cur_file->path_len - cur_file->cur_path_ofs + 3) & ~3); 250 Common::AlignUp(cur_file->path_len - cur_file->cur_path_ofs, 4);
255 prev_file = cur_file; 251 prev_file = cur_file;
256 } 252 }
257 // Assign deferred parent/sibling ownership. 253 // Assign deferred parent/sibling ownership.
@@ -268,8 +264,8 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() {
268 for (const auto& it : directories) { 264 for (const auto& it : directories) {
269 cur_dir = it.second; 265 cur_dir = it.second;
270 cur_dir->entry_offset = entry_offset; 266 cur_dir->entry_offset = entry_offset;
271 entry_offset += 267 entry_offset += sizeof(RomFSDirectoryEntry) +
272 sizeof(RomFSDirectoryEntry) + ((cur_dir->path_len - cur_dir->cur_path_ofs + 3) & ~3); 268 Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4);
273 } 269 }
274 // Assign deferred parent/sibling ownership. 270 // Assign deferred parent/sibling ownership.
275 for (auto it = directories.rbegin(); it->second != root; ++it) { 271 for (auto it = directories.rbegin(); it->second != root; ++it) {
@@ -302,7 +298,7 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() {
302 out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, cur_file->source); 298 out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, cur_file->source);
303 std::memcpy(file_table.data() + cur_file->entry_offset, &cur_entry, sizeof(RomFSFileEntry)); 299 std::memcpy(file_table.data() + cur_file->entry_offset, &cur_entry, sizeof(RomFSFileEntry));
304 std::memset(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 0, 300 std::memset(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 0,
305 (cur_entry.name_size + 3) & ~3); 301 Common::AlignUp(cur_entry.name_size, 4));
306 std::memcpy(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 302 std::memcpy(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry),
307 cur_file->path.data() + cur_file->cur_path_ofs, name_size); 303 cur_file->path.data() + cur_file->cur_path_ofs, name_size);
308 } 304 }
@@ -329,10 +325,8 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() {
329 325
330 std::memcpy(dir_table.data() + cur_dir->entry_offset, &cur_entry, 326 std::memcpy(dir_table.data() + cur_dir->entry_offset, &cur_entry,
331 sizeof(RomFSDirectoryEntry)); 327 sizeof(RomFSDirectoryEntry));
332 std::memcpy(dir_table.data() + cur_dir->entry_offset, &cur_entry,
333 sizeof(RomFSDirectoryEntry));
334 std::memset(dir_table.data() + cur_dir->entry_offset + sizeof(RomFSDirectoryEntry), 0, 328 std::memset(dir_table.data() + cur_dir->entry_offset + sizeof(RomFSDirectoryEntry), 0,
335 (cur_entry.name_size + 3) & ~3); 329 Common::AlignUp(cur_entry.name_size, 4));
336 std::memcpy(dir_table.data() + cur_dir->entry_offset + sizeof(RomFSDirectoryEntry), 330 std::memcpy(dir_table.data() + cur_dir->entry_offset + sizeof(RomFSDirectoryEntry),
337 cur_dir->path.data() + cur_dir->cur_path_ofs, name_size); 331 cur_dir->path.data() + cur_dir->cur_path_ofs, name_size);
338 } 332 }
@@ -344,18 +338,18 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() {
344 header.dir_hash_table_size = dir_hash_table_size; 338 header.dir_hash_table_size = dir_hash_table_size;
345 header.dir_table_size = dir_table_size; 339 header.dir_table_size = dir_table_size;
346 header.file_partition_ofs = ROMFS_FILEPARTITION_OFS; 340 header.file_partition_ofs = ROMFS_FILEPARTITION_OFS;
347 header.dir_hash_table_ofs = (header.file_partition_ofs + file_partition_size + 3ULL) & ~3ULL; 341 header.dir_hash_table_ofs = Common::AlignUp(header.file_partition_ofs + file_partition_size, 4);
348 header.dir_table_ofs = header.dir_hash_table_ofs + header.dir_hash_table_size; 342 header.dir_table_ofs = header.dir_hash_table_ofs + header.dir_hash_table_size;
349 header.file_hash_table_ofs = header.dir_table_ofs + header.dir_table_size; 343 header.file_hash_table_ofs = header.dir_table_ofs + header.dir_table_size;
350 header.file_table_ofs = header.file_hash_table_ofs + header.file_hash_table_size; 344 header.file_table_ofs = header.file_hash_table_ofs + header.file_hash_table_size;
351 345
352 std::vector<u8> header_data(sizeof(RomFSHeader)); 346 std::vector<u8> header_data(sizeof(RomFSHeader));
353 std::memcpy(header_data.data(), &header, header_data.size()); 347 std::memcpy(header_data.data(), &header, header_data.size());
354 out.emplace(0, std::make_shared<VectorVfsFile>(header_data)); 348 out.emplace(0, std::make_shared<VectorVfsFile>(std::move(header_data)));
355 349
356 std::vector<u8> metadata(file_hash_table_size + file_table_size + dir_hash_table_size + 350 std::vector<u8> metadata(file_hash_table_size + file_table_size + dir_hash_table_size +
357 dir_table_size); 351 dir_table_size);
358 auto index = 0; 352 std::size_t index = 0;
359 std::memcpy(metadata.data(), dir_hash_table.data(), dir_hash_table.size() * sizeof(u32)); 353 std::memcpy(metadata.data(), dir_hash_table.data(), dir_hash_table.size() * sizeof(u32));
360 index += dir_hash_table.size() * sizeof(u32); 354 index += dir_hash_table.size() * sizeof(u32);
361 std::memcpy(metadata.data() + index, dir_table.data(), dir_table.size()); 355 std::memcpy(metadata.data() + index, dir_table.data(), dir_table.size());
@@ -364,7 +358,7 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() {
364 file_hash_table.size() * sizeof(u32)); 358 file_hash_table.size() * sizeof(u32));
365 index += file_hash_table.size() * sizeof(u32); 359 index += file_hash_table.size() * sizeof(u32);
366 std::memcpy(metadata.data() + index, file_table.data(), file_table.size()); 360 std::memcpy(metadata.data() + index, file_table.data(), file_table.size());
367 out.emplace(header.dir_hash_table_ofs, std::make_shared<VectorVfsFile>(metadata)); 361 out.emplace(header.dir_hash_table_ofs, std::make_shared<VectorVfsFile>(std::move(metadata)));
368 362
369 return out; 363 return out;
370} 364}
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index af3f9a78f..4b3b5e665 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -70,38 +70,40 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
70 70
71static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) { 71static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) {
72 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); 72 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
73 if (type == ContentRecordType::Program && load_dir != nullptr && load_dir->GetSize() > 0) { 73 if (type != ContentRecordType::Program || load_dir == nullptr || load_dir->GetSize() <= 0) {
74 auto extracted = ExtractRomFS(romfs); 74 return;
75 75 }
76 if (extracted != nullptr) {
77 auto patch_dirs = load_dir->GetSubdirectories();
78 std::sort(patch_dirs.begin(), patch_dirs.end(),
79 [](const VirtualDir& l, const VirtualDir& r) {
80 return l->GetName() < r->GetName();
81 });
82
83 std::vector<VirtualDir> layers;
84 layers.reserve(patch_dirs.size() + 1);
85 for (const auto& subdir : patch_dirs) {
86 auto romfs_dir = subdir->GetSubdirectory("romfs");
87 if (romfs_dir != nullptr)
88 layers.push_back(std::move(romfs_dir));
89 }
90 76
91 layers.push_back(std::move(extracted)); 77 auto extracted = ExtractRomFS(romfs);
78 if (extracted == nullptr) {
79 return;
80 }
92 81
93 const auto layered = LayerDirectories(layers); 82 auto patch_dirs = load_dir->GetSubdirectories();
83 std::sort(patch_dirs.begin(), patch_dirs.end(),
84 [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
94 85
95 if (layered != nullptr) { 86 std::vector<VirtualDir> layers;
96 auto packed = CreateRomFS(layered); 87 layers.reserve(patch_dirs.size() + 1);
88 for (const auto& subdir : patch_dirs) {
89 auto romfs_dir = subdir->GetSubdirectory("romfs");
90 if (romfs_dir != nullptr)
91 layers.push_back(std::move(romfs_dir));
92 }
93 layers.push_back(std::move(extracted));
97 94
98 if (packed != nullptr) { 95 auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers));
99 LOG_INFO(Loader, " RomFS: LayeredFS patches applied successfully"); 96 if (layered == nullptr) {
100 romfs = std::move(packed); 97 return;
101 } 98 }
102 } 99
103 } 100 auto packed = CreateRomFS(std::move(layered));
101 if (packed == nullptr) {
102 return;
104 } 103 }
104
105 LOG_INFO(Loader, " RomFS: LayeredFS patches applied successfully");
106 romfs = std::move(packed);
105} 107}
106 108
107VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, 109VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset,
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/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 653ef2e7b..e9b040689 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -125,7 +125,7 @@ VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
125 if (concat.empty()) 125 if (concat.empty())
126 return nullptr; 126 return nullptr;
127 127
128 file = FileSys::ConcatenateFiles(concat, concat.front()->GetName()); 128 file = ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName());
129 } 129 }
130 130
131 return file; 131 return file;
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp
index 205284a4d..5910f7046 100644
--- a/src/core/file_sys/romfs.cpp
+++ b/src/core/file_sys/romfs.cpp
@@ -134,7 +134,7 @@ VirtualFile CreateRomFS(VirtualDir dir) {
134 return nullptr; 134 return nullptr;
135 135
136 RomFSBuildContext ctx{dir}; 136 RomFSBuildContext ctx{dir};
137 return ConcatenateFiles<0>(ctx.Build(), dir->GetName()); 137 return ConcatenatedVfsFile::MakeConcatenatedFile(0, ctx.Build(), dir->GetName());
138} 138}
139 139
140} // namespace FileSys 140} // namespace FileSys
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index 3d1a3685e..d027a8d59 100644
--- a/src/core/file_sys/romfs_factory.cpp
+++ b/src/core/file_sys/romfs_factory.cpp
@@ -34,7 +34,7 @@ ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
34 if (!updatable) 34 if (!updatable)
35 return MakeResult<VirtualFile>(file); 35 return MakeResult<VirtualFile>(file);
36 36
37 const PatchManager patch_manager(Core::CurrentProcess()->program_id); 37 const PatchManager patch_manager(Core::CurrentProcess()->GetTitleID());
38 return MakeResult<VirtualFile>(patch_manager.PatchRomFS(file, ivfc_offset)); 38 return MakeResult<VirtualFile>(patch_manager.PatchRomFS(file, ivfc_offset));
39} 39}
40 40
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index 9b2c51bbd..47f2ab9e0 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -81,7 +81,7 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
81 // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should 81 // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
82 // be interpreted as the title id of the current process. 82 // be interpreted as the title id of the current process.
83 if (type == SaveDataType::SaveData && title_id == 0) 83 if (type == SaveDataType::SaveData && title_id == 0)
84 title_id = Core::CurrentProcess()->program_id; 84 title_id = Core::CurrentProcess()->GetTitleID();
85 85
86 std::string out; 86 std::string out;
87 87
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index 5fbea1739..bfe50da73 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -463,14 +463,14 @@ bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, std::size_t
463 return true; 463 return true;
464} 464}
465 465
466bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, size_t block_size) { 466bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, std::size_t block_size) {
467 if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) 467 if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
468 return false; 468 return false;
469 if (!dest->Resize(src->GetSize())) 469 if (!dest->Resize(src->GetSize()))
470 return false; 470 return false;
471 471
472 std::vector<u8> temp(std::min(block_size, src->GetSize())); 472 std::vector<u8> temp(std::min(block_size, src->GetSize()));
473 for (size_t i = 0; i < src->GetSize(); i += block_size) { 473 for (std::size_t i = 0; i < src->GetSize(); i += block_size) {
474 const auto read = std::min(block_size, src->GetSize() - i); 474 const auto read = std::min(block_size, src->GetSize() - i);
475 const auto block = src->Read(temp.data(), read, i); 475 const auto block = src->Read(temp.data(), read, i);
476 476
@@ -481,7 +481,7 @@ bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, size_t block_si
481 return true; 481 return true;
482} 482}
483 483
484bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, size_t block_size) { 484bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, std::size_t block_size) {
485 if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) 485 if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
486 return false; 486 return false;
487 487
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h
index cea4aa8b8..270291631 100644
--- a/src/core/file_sys/vfs.h
+++ b/src/core/file_sys/vfs.h
@@ -315,18 +315,19 @@ public:
315 bool Rename(std::string_view name) override; 315 bool Rename(std::string_view name) override;
316}; 316};
317 317
318// Compare the two files, byte-for-byte, in increments specificed by block_size 318// Compare the two files, byte-for-byte, in increments specified by block_size
319bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, size_t block_size = 0x1000); 319bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2,
320 std::size_t block_size = 0x1000);
320 321
321// A method that copies the raw data between two different implementations of VirtualFile. If you 322// A method that copies the raw data between two different implementations of VirtualFile. If you
322// are using the same implementation, it is probably better to use the Copy method in the parent 323// are using the same implementation, it is probably better to use the Copy method in the parent
323// directory of src/dest. 324// directory of src/dest.
324bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, size_t block_size = 0x1000); 325bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, std::size_t block_size = 0x1000);
325 326
326// A method that performs a similar function to VfsRawCopy above, but instead copies entire 327// A method that performs a similar function to VfsRawCopy above, but instead copies entire
327// directories. It suffers the same performance penalties as above and an implementation-specific 328// directories. It suffers the same performance penalties as above and an implementation-specific
328// Copy should always be preferred. 329// Copy should always be preferred.
329bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, size_t block_size = 0x1000); 330bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, std::size_t block_size = 0x1000);
330 331
331// Checks if the directory at path relative to rel exists. If it does, returns that. If it does not 332// Checks if the directory at path relative to rel exists. If it does, returns that. If it does not
332// it attempts to create it and returns the new dir or nullptr on failure. 333// it attempts to create it and returns the new dir or nullptr on failure.
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp
index d9f9911da..16d801c0c 100644
--- a/src/core/file_sys/vfs_concat.cpp
+++ b/src/core/file_sys/vfs_concat.cpp
@@ -7,6 +7,7 @@
7 7
8#include "common/assert.h" 8#include "common/assert.h"
9#include "core/file_sys/vfs_concat.h" 9#include "core/file_sys/vfs_concat.h"
10#include "core/file_sys/vfs_static.h"
10 11
11namespace FileSys { 12namespace FileSys {
12 13
@@ -22,15 +23,6 @@ static bool VerifyConcatenationMapContinuity(const std::map<u64, VirtualFile>& m
22 return map.begin()->first == 0; 23 return map.begin()->first == 0;
23} 24}
24 25
25VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name) {
26 if (files.empty())
27 return nullptr;
28 if (files.size() == 1)
29 return files[0];
30
31 return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name)));
32}
33
34ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string name) 26ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string name)
35 : name(std::move(name)) { 27 : name(std::move(name)) {
36 std::size_t next_offset = 0; 28 std::size_t next_offset = 0;
@@ -47,6 +39,41 @@ ConcatenatedVfsFile::ConcatenatedVfsFile(std::map<u64, VirtualFile> files_, std:
47 39
48ConcatenatedVfsFile::~ConcatenatedVfsFile() = default; 40ConcatenatedVfsFile::~ConcatenatedVfsFile() = default;
49 41
42VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::vector<VirtualFile> files,
43 std::string name) {
44 if (files.empty())
45 return nullptr;
46 if (files.size() == 1)
47 return files[0];
48
49 return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name)));
50}
51
52VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte,
53 std::map<u64, VirtualFile> files,
54 std::string name) {
55 if (files.empty())
56 return nullptr;
57 if (files.size() == 1)
58 return files.begin()->second;
59
60 const auto last_valid = --files.end();
61 for (auto iter = files.begin(); iter != last_valid;) {
62 const auto old = iter++;
63 if (old->first + old->second->GetSize() != iter->first) {
64 files.emplace(old->first + old->second->GetSize(),
65 std::make_shared<StaticVfsFile>(filler_byte, iter->first - old->first -
66 old->second->GetSize()));
67 }
68 }
69
70 // Ensure the map starts at offset 0 (start of file), otherwise pad to fill.
71 if (files.begin()->first != 0)
72 files.emplace(0, std::make_shared<StaticVfsFile>(filler_byte, files.begin()->first));
73
74 return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name)));
75}
76
50std::string ConcatenatedVfsFile::GetName() const { 77std::string ConcatenatedVfsFile::GetName() const {
51 if (files.empty()) 78 if (files.empty())
52 return ""; 79 return "";
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h
index 76211d38a..c90f9d5d1 100644
--- a/src/core/file_sys/vfs_concat.h
+++ b/src/core/file_sys/vfs_concat.h
@@ -7,26 +7,27 @@
7#include <map> 7#include <map>
8#include <memory> 8#include <memory>
9#include <string_view> 9#include <string_view>
10#include <boost/container/flat_map.hpp>
11#include "core/file_sys/vfs.h" 10#include "core/file_sys/vfs.h"
12#include "core/file_sys/vfs_static.h"
13 11
14namespace FileSys { 12namespace FileSys {
15 13
16// Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently 14// Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently
17// read-only. 15// read-only.
18class ConcatenatedVfsFile : public VfsFile { 16class ConcatenatedVfsFile : public VfsFile {
19 friend VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name);
20
21 template <u8 filler_byte>
22 friend VirtualFile ConcatenateFiles(std::map<u64, VirtualFile> files, std::string name);
23
24 ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name); 17 ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name);
25 ConcatenatedVfsFile(std::map<u64, VirtualFile> files, std::string name); 18 ConcatenatedVfsFile(std::map<u64, VirtualFile> files, std::string name);
26 19
27public: 20public:
28 ~ConcatenatedVfsFile() override; 21 ~ConcatenatedVfsFile() override;
29 22
23 /// Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases.
24 static VirtualFile MakeConcatenatedFile(std::vector<VirtualFile> files, std::string name);
25
26 /// Convenience function that turns a map of offsets to files into a concatenated file, filling
27 /// gaps with a given filler byte.
28 static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::map<u64, VirtualFile> files,
29 std::string name);
30
30 std::string GetName() const override; 31 std::string GetName() const override;
31 std::size_t GetSize() const override; 32 std::size_t GetSize() const override;
32 bool Resize(std::size_t new_size) override; 33 bool Resize(std::size_t new_size) override;
@@ -43,33 +44,4 @@ private:
43 std::string name; 44 std::string name;
44}; 45};
45 46
46// Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases.
47VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name);
48
49// Convenience function that turns a map of offsets to files into a concatenated file, filling gaps
50// with template parameter.
51template <u8 filler_byte>
52VirtualFile ConcatenateFiles(std::map<u64, VirtualFile> files, std::string name) {
53 if (files.empty())
54 return nullptr;
55 if (files.size() == 1)
56 return files.begin()->second;
57
58 const auto last_valid = --files.end();
59 for (auto iter = files.begin(); iter != last_valid;) {
60 const auto old = iter++;
61 if (old->first + old->second->GetSize() != iter->first) {
62 files.emplace(old->first + old->second->GetSize(),
63 std::make_shared<StaticVfsFile<filler_byte>>(iter->first - old->first -
64 old->second->GetSize()));
65 }
66 }
67
68 // Ensure the map starts at offset 0 (start of file), otherwise pad to fill.
69 if (files.begin()->first != 0)
70 files.emplace(0, std::make_shared<StaticVfsFile<filler_byte>>(files.begin()->first));
71
72 return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name)));
73}
74
75} // namespace FileSys 47} // namespace FileSys
diff --git a/src/core/file_sys/vfs_layered.cpp b/src/core/file_sys/vfs_layered.cpp
index 45563d7ae..bfee01725 100644
--- a/src/core/file_sys/vfs_layered.cpp
+++ b/src/core/file_sys/vfs_layered.cpp
@@ -8,7 +8,13 @@
8 8
9namespace FileSys { 9namespace FileSys {
10 10
11VirtualDir LayerDirectories(std::vector<VirtualDir> dirs, std::string name) { 11LayeredVfsDirectory::LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name)
12 : dirs(std::move(dirs)), name(std::move(name)) {}
13
14LayeredVfsDirectory::~LayeredVfsDirectory() = default;
15
16VirtualDir LayeredVfsDirectory::MakeLayeredDirectory(std::vector<VirtualDir> dirs,
17 std::string name) {
12 if (dirs.empty()) 18 if (dirs.empty())
13 return nullptr; 19 return nullptr;
14 if (dirs.size() == 1) 20 if (dirs.size() == 1)
@@ -17,11 +23,6 @@ VirtualDir LayerDirectories(std::vector<VirtualDir> dirs, std::string name) {
17 return std::shared_ptr<VfsDirectory>(new LayeredVfsDirectory(std::move(dirs), std::move(name))); 23 return std::shared_ptr<VfsDirectory>(new LayeredVfsDirectory(std::move(dirs), std::move(name)));
18} 24}
19 25
20LayeredVfsDirectory::LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name)
21 : dirs(std::move(dirs)), name(std::move(name)) {}
22
23LayeredVfsDirectory::~LayeredVfsDirectory() = default;
24
25std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFileRelative(std::string_view path) const { 26std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFileRelative(std::string_view path) const {
26 for (const auto& layer : dirs) { 27 for (const auto& layer : dirs) {
27 const auto file = layer->GetFileRelative(path); 28 const auto file = layer->GetFileRelative(path);
@@ -41,7 +42,7 @@ std::shared_ptr<VfsDirectory> LayeredVfsDirectory::GetDirectoryRelative(
41 out.push_back(std::move(dir)); 42 out.push_back(std::move(dir));
42 } 43 }
43 44
44 return LayerDirectories(std::move(out)); 45 return MakeLayeredDirectory(std::move(out));
45} 46}
46 47
47std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFile(std::string_view name) const { 48std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFile(std::string_view name) const {
diff --git a/src/core/file_sys/vfs_layered.h b/src/core/file_sys/vfs_layered.h
index 4f6e341ab..d85310f57 100644
--- a/src/core/file_sys/vfs_layered.h
+++ b/src/core/file_sys/vfs_layered.h
@@ -9,20 +9,18 @@
9 9
10namespace FileSys { 10namespace FileSys {
11 11
12// Wrapper function to allow for more efficient handling of dirs.size() == 0, 1 cases.
13VirtualDir LayerDirectories(std::vector<VirtualDir> dirs, std::string name = "");
14
15// Class that stacks multiple VfsDirectories on top of each other, attempting to read from the first 12// Class that stacks multiple VfsDirectories on top of each other, attempting to read from the first
16// one and falling back to the one after. The highest priority directory (overwrites all others) 13// one and falling back to the one after. The highest priority directory (overwrites all others)
17// should be element 0 in the dirs vector. 14// should be element 0 in the dirs vector.
18class LayeredVfsDirectory : public VfsDirectory { 15class LayeredVfsDirectory : public VfsDirectory {
19 friend VirtualDir LayerDirectories(std::vector<VirtualDir> dirs, std::string name);
20
21 LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name); 16 LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name);
22 17
23public: 18public:
24 ~LayeredVfsDirectory() override; 19 ~LayeredVfsDirectory() override;
25 20
21 /// Wrapper function to allow for more efficient handling of dirs.size() == 0, 1 cases.
22 static VirtualDir MakeLayeredDirectory(std::vector<VirtualDir> dirs, std::string name = "");
23
26 std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override; 24 std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override;
27 std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override; 25 std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override;
28 std::shared_ptr<VfsFile> GetFile(std::string_view name) const override; 26 std::shared_ptr<VfsFile> GetFile(std::string_view name) const override;
diff --git a/src/core/file_sys/vfs_static.h b/src/core/file_sys/vfs_static.h
index 4dd47ffcc..44fab51d1 100644
--- a/src/core/file_sys/vfs_static.h
+++ b/src/core/file_sys/vfs_static.h
@@ -12,21 +12,21 @@
12 12
13namespace FileSys { 13namespace FileSys {
14 14
15template <u8 value>
16class StaticVfsFile : public VfsFile { 15class StaticVfsFile : public VfsFile {
17public: 16public:
18 explicit StaticVfsFile(size_t size = 0, std::string name = "", VirtualDir parent = nullptr) 17 explicit StaticVfsFile(u8 value, std::size_t size = 0, std::string name = "",
19 : size(size), name(std::move(name)), parent(std::move(parent)) {} 18 VirtualDir parent = nullptr)
19 : value{value}, size{size}, name{std::move(name)}, parent{std::move(parent)} {}
20 20
21 std::string GetName() const override { 21 std::string GetName() const override {
22 return name; 22 return name;
23 } 23 }
24 24
25 size_t GetSize() const override { 25 std::size_t GetSize() const override {
26 return size; 26 return size;
27 } 27 }
28 28
29 bool Resize(size_t new_size) override { 29 bool Resize(std::size_t new_size) override {
30 size = new_size; 30 size = new_size;
31 return true; 31 return true;
32 } 32 }
@@ -43,23 +43,23 @@ public:
43 return true; 43 return true;
44 } 44 }
45 45
46 size_t Read(u8* data, size_t length, size_t offset) const override { 46 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override {
47 const auto read = std::min(length, size - offset); 47 const auto read = std::min(length, size - offset);
48 std::fill(data, data + read, value); 48 std::fill(data, data + read, value);
49 return read; 49 return read;
50 } 50 }
51 51
52 size_t Write(const u8* data, size_t length, size_t offset) override { 52 std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override {
53 return 0; 53 return 0;
54 } 54 }
55 55
56 boost::optional<u8> ReadByte(size_t offset) const override { 56 boost::optional<u8> ReadByte(std::size_t offset) const override {
57 if (offset < size) 57 if (offset < size)
58 return value; 58 return value;
59 return boost::none; 59 return boost::none;
60 } 60 }
61 61
62 std::vector<u8> ReadBytes(size_t length, size_t offset) const override { 62 std::vector<u8> ReadBytes(std::size_t length, std::size_t offset) const override {
63 const auto read = std::min(length, size - offset); 63 const auto read = std::min(length, size - offset);
64 return std::vector<u8>(read, value); 64 return std::vector<u8>(read, value);
65 } 65 }
@@ -70,7 +70,8 @@ public:
70 } 70 }
71 71
72private: 72private:
73 size_t size; 73 u8 value;
74 std::size_t size;
74 std::string name; 75 std::string name;
75 VirtualDir parent; 76 VirtualDir parent;
76}; 77};
diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp
index 7033e2c88..389c7e003 100644
--- a/src/core/file_sys/vfs_vector.cpp
+++ b/src/core/file_sys/vfs_vector.cpp
@@ -9,7 +9,7 @@
9 9
10namespace FileSys { 10namespace FileSys {
11VectorVfsFile::VectorVfsFile(std::vector<u8> initial_data, std::string name, VirtualDir parent) 11VectorVfsFile::VectorVfsFile(std::vector<u8> initial_data, std::string name, VirtualDir parent)
12 : data(std::move(initial_data)), name(std::move(name)), parent(std::move(parent)) {} 12 : data(std::move(initial_data)), parent(std::move(parent)), name(std::move(name)) {}
13 13
14VectorVfsFile::~VectorVfsFile() = default; 14VectorVfsFile::~VectorVfsFile() = default;
15 15
@@ -38,13 +38,13 @@ bool VectorVfsFile::IsReadable() const {
38 return true; 38 return true;
39} 39}
40 40
41size_t VectorVfsFile::Read(u8* data_, size_t length, size_t offset) const { 41std::size_t VectorVfsFile::Read(u8* data_, std::size_t length, std::size_t offset) const {
42 const auto read = std::min(length, data.size() - offset); 42 const auto read = std::min(length, data.size() - offset);
43 std::memcpy(data_, data.data() + offset, read); 43 std::memcpy(data_, data.data() + offset, read);
44 return read; 44 return read;
45} 45}
46 46
47size_t VectorVfsFile::Write(const u8* data_, size_t length, size_t offset) { 47std::size_t VectorVfsFile::Write(const u8* data_, std::size_t length, std::size_t offset) {
48 if (offset + length > data.size()) 48 if (offset + length > data.size())
49 data.resize(offset + length); 49 data.resize(offset + length);
50 const auto write = std::min(length, data.size() - offset); 50 const auto write = std::min(length, data.size() - offset);
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h
index 115c3ae95..48a414c98 100644
--- a/src/core/file_sys/vfs_vector.h
+++ b/src/core/file_sys/vfs_vector.h
@@ -16,13 +16,13 @@ public:
16 ~VectorVfsFile() override; 16 ~VectorVfsFile() override;
17 17
18 std::string GetName() const override; 18 std::string GetName() const override;
19 size_t GetSize() const override; 19 std::size_t GetSize() const override;
20 bool Resize(size_t new_size) override; 20 bool Resize(std::size_t new_size) override;
21 std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; 21 std::shared_ptr<VfsDirectory> GetContainingDirectory() const override;
22 bool IsWritable() const override; 22 bool IsWritable() const override;
23 bool IsReadable() const override; 23 bool IsReadable() const override;
24 size_t Read(u8* data, size_t length, size_t offset) const override; 24 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
25 size_t Write(const u8* data, size_t length, size_t offset) override; 25 std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override;
26 bool Rename(std::string_view name) override; 26 bool Rename(std::string_view name) override;
27 27
28 virtual void Assign(std::vector<u8> new_data); 28 virtual void Assign(std::vector<u8> new_data);
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 0ecdd9f82..5bc947010 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
@@ -248,7 +250,7 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr)
248 } else if (id == PC_REGISTER) { 250 } else if (id == PC_REGISTER) {
249 thread->context.pc = val; 251 thread->context.pc = val;
250 } else if (id == PSTATE_REGISTER) { 252 } else if (id == PSTATE_REGISTER) {
251 thread->context.pstate = val; 253 thread->context.pstate = static_cast<u32>(val);
252 } else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) { 254 } else if (id > PSTATE_REGISTER && id < FPCR_REGISTER) {
253 thread->context.vector_registers[id - (PSTATE_REGISTER + 1)][0] = val; 255 thread->context.vector_registers[id - (PSTATE_REGISTER + 1)][0] = val;
254 } 256 }
@@ -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()->VMManager().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()->VMManager();
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/errors.h b/src/core/hle/kernel/errors.h
index 8c2be2681..e5fa67ae8 100644
--- a/src/core/hle/kernel/errors.h
+++ b/src/core/hle/kernel/errors.h
@@ -31,6 +31,7 @@ enum {
31 TooLarge = 119, 31 TooLarge = 119,
32 InvalidEnumValue = 120, 32 InvalidEnumValue = 120,
33 NoSuchEntry = 121, 33 NoSuchEntry = 121,
34 AlreadyRegistered = 122,
34 InvalidState = 125, 35 InvalidState = 125,
35 ResourceLimitExceeded = 132, 36 ResourceLimitExceeded = 132,
36}; 37};
@@ -58,6 +59,7 @@ constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel,
58constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); 59constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
59constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); 60constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
60constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize); 61constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize);
62constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::Kernel, ErrCodes::AlreadyRegistered);
61constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); 63constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState);
62constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel, 64constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel,
63 ErrCodes::InvalidThreadPriority); 65 ErrCodes::InvalidThreadPriority);
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h
index b054cbf7d..9eb72315c 100644
--- a/src/core/hle/kernel/object.h
+++ b/src/core/hle/kernel/object.h
@@ -6,7 +6,6 @@
6 6
7#include <atomic> 7#include <atomic>
8#include <string> 8#include <string>
9#include <utility>
10 9
11#include <boost/smart_ptr/intrusive_ptr.hpp> 10#include <boost/smart_ptr/intrusive_ptr.hpp>
12 11
@@ -97,7 +96,7 @@ using SharedPtr = boost::intrusive_ptr<T>;
97template <typename T> 96template <typename T>
98inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) { 97inline SharedPtr<T> DynamicObjectCast(SharedPtr<Object> object) {
99 if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) { 98 if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) {
100 return boost::static_pointer_cast<T>(std::move(object)); 99 return boost::static_pointer_cast<T>(object);
101 } 100 }
102 return nullptr; 101 return nullptr;
103} 102}
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 121f741fd..dc9fc8470 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,22 @@ 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 is_64bit_process = metadata.Is64BitProgram();
51 vm_manager.Reset(metadata.GetAddressSpaceType());
52}
53
45void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) { 54void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) {
46 for (std::size_t i = 0; i < len; ++i) { 55 for (std::size_t i = 0; i < len; ++i) {
47 u32 descriptor = kernel_caps[i]; 56 u32 descriptor = kernel_caps[i];
@@ -119,7 +128,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 128 // TODO(bunnei): This is heap area that should be allocated by the kernel and not mapped as part
120 // of the user address space. 129 // of the user address space.
121 vm_manager 130 vm_manager
122 .MapMemoryBlock(Memory::STACK_AREA_VADDR_END - stack_size, 131 .MapMemoryBlock(vm_manager.GetTLSIORegionEndAddress() - stack_size,
123 std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, 132 std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size,
124 MemoryState::Mapped) 133 MemoryState::Mapped)
125 .Unwrap(); 134 .Unwrap();
@@ -185,6 +194,7 @@ static std::tuple<std::size_t, std::size_t, bool> FindFreeThreadLocalSlot(
185 194
186VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) { 195VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) {
187 auto [available_page, available_slot, needs_allocation] = FindFreeThreadLocalSlot(tls_slots); 196 auto [available_page, available_slot, needs_allocation] = FindFreeThreadLocalSlot(tls_slots);
197 const VAddr tls_begin = vm_manager.GetTLSIORegionBaseAddress();
188 198
189 if (needs_allocation) { 199 if (needs_allocation) {
190 tls_slots.emplace_back(0); // The page is completely available at the start 200 tls_slots.emplace_back(0); // The page is completely available at the start
@@ -197,18 +207,17 @@ VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) {
197 207
198 vm_manager.RefreshMemoryBlockMappings(tls_memory.get()); 208 vm_manager.RefreshMemoryBlockMappings(tls_memory.get());
199 209
200 vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE, 210 vm_manager.MapMemoryBlock(tls_begin + available_page * Memory::PAGE_SIZE, tls_memory, 0,
201 tls_memory, 0, Memory::PAGE_SIZE, MemoryState::ThreadLocal); 211 Memory::PAGE_SIZE, MemoryState::ThreadLocal);
202 } 212 }
203 213
204 tls_slots[available_page].set(available_slot); 214 tls_slots[available_page].set(available_slot);
205 215
206 return Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE + 216 return tls_begin + available_page * Memory::PAGE_SIZE + available_slot * Memory::TLS_ENTRY_SIZE;
207 available_slot * Memory::TLS_ENTRY_SIZE;
208} 217}
209 218
210void Process::FreeTLSSlot(VAddr tls_address) { 219void Process::FreeTLSSlot(VAddr tls_address) {
211 const VAddr tls_base = tls_address - Memory::TLS_AREA_VADDR; 220 const VAddr tls_base = tls_address - vm_manager.GetTLSIORegionBaseAddress();
212 const VAddr tls_page = tls_base / Memory::PAGE_SIZE; 221 const VAddr tls_page = tls_base / Memory::PAGE_SIZE;
213 const VAddr tls_slot = (tls_base % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; 222 const VAddr tls_slot = (tls_base % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
214 223
@@ -232,8 +241,8 @@ void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
232} 241}
233 242
234ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { 243ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
235 if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || 244 if (target < vm_manager.GetHeapRegionBaseAddress() ||
236 target + size < target) { 245 target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) {
237 return ERR_INVALID_ADDRESS; 246 return ERR_INVALID_ADDRESS;
238 } 247 }
239 248
@@ -268,8 +277,8 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission per
268} 277}
269 278
270ResultCode Process::HeapFree(VAddr target, u32 size) { 279ResultCode Process::HeapFree(VAddr target, u32 size) {
271 if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || 280 if (target < vm_manager.GetHeapRegionBaseAddress() ||
272 target + size < target) { 281 target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) {
273 return ERR_INVALID_ADDRESS; 282 return ERR_INVALID_ADDRESS;
274 } 283 }
275 284
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 04d74e572..590e0c73d 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;
@@ -131,6 +135,16 @@ public:
131 return HANDLE_TYPE; 135 return HANDLE_TYPE;
132 } 136 }
133 137
138 /// Gets a reference to the process' memory manager.
139 Kernel::VMManager& VMManager() {
140 return vm_manager;
141 }
142
143 /// Gets a const reference to the process' memory manager.
144 const Kernel::VMManager& VMManager() const {
145 return vm_manager;
146 }
147
134 /// Gets the current status of the process 148 /// Gets the current status of the process
135 ProcessStatus GetStatus() const { 149 ProcessStatus GetStatus() const {
136 return status; 150 return status;
@@ -141,29 +155,52 @@ public:
141 return process_id; 155 return process_id;
142 } 156 }
143 157
144 /// Title ID corresponding to the process 158 /// Gets the title ID corresponding to this process.
145 u64 program_id; 159 u64 GetTitleID() const {
160 return program_id;
161 }
146 162
147 /// Resource limit descriptor for this process 163 /// Gets the resource limit descriptor for this process
148 SharedPtr<ResourceLimit> resource_limit; 164 ResourceLimit& GetResourceLimit() {
165 return *resource_limit;
166 }
149 167
150 /// The process may only call SVCs which have the corresponding bit set. 168 /// Gets the resource limit descriptor for this process
151 std::bitset<0x80> svc_access_mask; 169 const ResourceLimit& GetResourceLimit() const {
152 /// Maximum size of the handle table for the process. 170 return *resource_limit;
153 unsigned int handle_table_size = 0x200; 171 }
154 /// Special memory ranges mapped into this processes address space. This is used to give 172
155 /// processes access to specific I/O regions and device memory. 173 /// Gets the default CPU ID for this process
156 boost::container::static_vector<AddressMapping, 8> address_mappings; 174 u8 GetDefaultProcessorID() const {
157 ProcessFlags flags; 175 return ideal_processor;
158 /// Kernel compatibility version for this process 176 }
159 u16 kernel_version = 0; 177
160 /// The default CPU for this process, threads are scheduled on this cpu by default. 178 /// Gets the bitmask of allowed CPUs that this process' threads can run on.
161 u8 ideal_processor = 0; 179 u32 GetAllowedProcessorMask() const {
162 /// Bitmask of allowed CPUs that this process' threads can run on. TODO(Subv): Actually parse 180 return allowed_processor_mask;
163 /// this value from the process header. 181 }
164 u32 allowed_processor_mask = THREADPROCESSORID_DEFAULT_MASK; 182
165 u32 allowed_thread_priority_mask = 0xFFFFFFFF; 183 /// Gets the bitmask of allowed thread priorities.
166 u32 is_virtual_address_memory_enabled = 0; 184 u32 GetAllowedThreadPriorityMask() const {
185 return allowed_thread_priority_mask;
186 }
187
188 u32 IsVirtualMemoryEnabled() const {
189 return is_virtual_address_memory_enabled;
190 }
191
192 /// Whether this process is an AArch64 or AArch32 process.
193 bool Is64BitProcess() const {
194 return is_64bit_process;
195 }
196
197 /**
198 * Loads process-specifics configuration info with metadata provided
199 * by an executable.
200 *
201 * @param metadata The provided metadata to load process specific info.
202 */
203 void LoadFromMetadata(const FileSys::ProgramMetadata& metadata);
167 204
168 /** 205 /**
169 * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them 206 * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
@@ -200,18 +237,43 @@ public:
200 237
201 ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size); 238 ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
202 239
203 VMManager vm_manager;
204
205private: 240private:
206 explicit Process(KernelCore& kernel); 241 explicit Process(KernelCore& kernel);
207 ~Process() override; 242 ~Process() override;
208 243
244 /// Memory manager for this process.
245 Kernel::VMManager vm_manager;
246
209 /// Current status of the process 247 /// Current status of the process
210 ProcessStatus status; 248 ProcessStatus status;
211 249
212 /// The ID of this process 250 /// The ID of this process
213 u32 process_id = 0; 251 u32 process_id = 0;
214 252
253 /// Title ID corresponding to the process
254 u64 program_id;
255
256 /// Resource limit descriptor for this process
257 SharedPtr<ResourceLimit> resource_limit;
258
259 /// The process may only call SVCs which have the corresponding bit set.
260 std::bitset<0x80> svc_access_mask;
261 /// Maximum size of the handle table for the process.
262 u32 handle_table_size = 0x200;
263 /// Special memory ranges mapped into this processes address space. This is used to give
264 /// processes access to specific I/O regions and device memory.
265 boost::container::static_vector<AddressMapping, 8> address_mappings;
266 ProcessFlags flags;
267 /// Kernel compatibility version for this process
268 u16 kernel_version = 0;
269 /// The default CPU for this process, threads are scheduled on this cpu by default.
270 u8 ideal_processor = 0;
271 /// Bitmask of allowed CPUs that this process' threads can run on. TODO(Subv): Actually parse
272 /// this value from the process header.
273 u32 allowed_processor_mask = THREADPROCESSORID_DEFAULT_MASK;
274 u32 allowed_thread_priority_mask = 0xFFFFFFFF;
275 u32 is_virtual_address_memory_enabled = 0;
276
215 // Memory used to back the allocations in the regular heap. A single vector is used to cover 277 // Memory used to back the allocations in the regular heap. A single vector is used to cover
216 // the entire virtual address space extents that bound the allocations, including any holes. 278 // the entire virtual address space extents that bound the allocations, including any holes.
217 // This makes deallocation and reallocation of holes fast and keeps process memory contiguous 279 // This makes deallocation and reallocation of holes fast and keeps process memory contiguous
@@ -230,6 +292,11 @@ private:
230 /// This vector will grow as more pages are allocated for new threads. 292 /// This vector will grow as more pages are allocated for new threads.
231 std::vector<std::bitset<8>> tls_slots; 293 std::vector<std::bitset<8>> tls_slots;
232 294
295 /// Whether or not this process is AArch64, or AArch32.
296 /// By default, we currently assume this is true, unless otherwise
297 /// specified by metadata provided to the process during loading.
298 bool is_64bit_process = true;
299
233 std::string name; 300 std::string name;
234}; 301};
235 302
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index 69c812f16..1e82cfffb 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -17,7 +17,7 @@ namespace Kernel {
17 17
18std::mutex Scheduler::scheduler_mutex; 18std::mutex Scheduler::scheduler_mutex;
19 19
20Scheduler::Scheduler(Core::ARM_Interface* cpu_core) : cpu_core(cpu_core) {} 20Scheduler::Scheduler(Core::ARM_Interface& cpu_core) : cpu_core(cpu_core) {}
21 21
22Scheduler::~Scheduler() { 22Scheduler::~Scheduler() {
23 for (auto& thread : thread_list) { 23 for (auto& thread : thread_list) {
@@ -59,9 +59,9 @@ void Scheduler::SwitchContext(Thread* new_thread) {
59 // Save context for previous thread 59 // Save context for previous thread
60 if (previous_thread) { 60 if (previous_thread) {
61 previous_thread->last_running_ticks = CoreTiming::GetTicks(); 61 previous_thread->last_running_ticks = CoreTiming::GetTicks();
62 cpu_core->SaveContext(previous_thread->context); 62 cpu_core.SaveContext(previous_thread->context);
63 // Save the TPIDR_EL0 system register in case it was modified. 63 // Save the TPIDR_EL0 system register in case it was modified.
64 previous_thread->tpidr_el0 = cpu_core->GetTPIDR_EL0(); 64 previous_thread->tpidr_el0 = cpu_core.GetTPIDR_EL0();
65 65
66 if (previous_thread->status == ThreadStatus::Running) { 66 if (previous_thread->status == ThreadStatus::Running) {
67 // This is only the case when a reschedule is triggered without the current thread 67 // This is only the case when a reschedule is triggered without the current thread
@@ -88,13 +88,13 @@ void Scheduler::SwitchContext(Thread* new_thread) {
88 88
89 if (previous_process != current_thread->owner_process) { 89 if (previous_process != current_thread->owner_process) {
90 Core::CurrentProcess() = current_thread->owner_process; 90 Core::CurrentProcess() = current_thread->owner_process;
91 SetCurrentPageTable(&Core::CurrentProcess()->vm_manager.page_table); 91 SetCurrentPageTable(&Core::CurrentProcess()->VMManager().page_table);
92 } 92 }
93 93
94 cpu_core->LoadContext(new_thread->context); 94 cpu_core.LoadContext(new_thread->context);
95 cpu_core->SetTlsAddress(new_thread->GetTLSAddress()); 95 cpu_core.SetTlsAddress(new_thread->GetTLSAddress());
96 cpu_core->SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); 96 cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0());
97 cpu_core->ClearExclusiveState(); 97 cpu_core.ClearExclusiveState();
98 } else { 98 } else {
99 current_thread = nullptr; 99 current_thread = nullptr;
100 // Note: We do not reset the current process and current page table when idling because 100 // Note: We do not reset the current process and current page table when idling because
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
index 744990c9b..2c94641ec 100644
--- a/src/core/hle/kernel/scheduler.h
+++ b/src/core/hle/kernel/scheduler.h
@@ -19,7 +19,7 @@ namespace Kernel {
19 19
20class Scheduler final { 20class Scheduler final {
21public: 21public:
22 explicit Scheduler(Core::ARM_Interface* cpu_core); 22 explicit Scheduler(Core::ARM_Interface& cpu_core);
23 ~Scheduler(); 23 ~Scheduler();
24 24
25 /// Returns whether there are any threads that are ready to run. 25 /// Returns whether there are any threads that are ready to run.
@@ -72,7 +72,7 @@ private:
72 72
73 SharedPtr<Thread> current_thread = nullptr; 73 SharedPtr<Thread> current_thread = nullptr;
74 74
75 Core::ARM_Interface* cpu_core; 75 Core::ARM_Interface& cpu_core;
76 76
77 static std::mutex scheduler_mutex; 77 static std::mutex scheduler_mutex;
78}; 78};
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index abb1d09cd..d061e6155 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
@@ -34,11 +35,11 @@ SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, SharedPtr<Proce
34 35
35 // Refresh the address mappings for the current process. 36 // Refresh the address mappings for the current process.
36 if (Core::CurrentProcess() != nullptr) { 37 if (Core::CurrentProcess() != nullptr) {
37 Core::CurrentProcess()->vm_manager.RefreshMemoryBlockMappings( 38 Core::CurrentProcess()->VMManager().RefreshMemoryBlockMappings(
38 shared_memory->backing_block.get()); 39 shared_memory->backing_block.get());
39 } 40 }
40 } else { 41 } else {
41 auto& vm_manager = shared_memory->owner_process->vm_manager; 42 auto& vm_manager = shared_memory->owner_process->VMManager();
42 43
43 // The memory is already available and mapped in the owner process. 44 // The memory is already available and mapped in the owner process.
44 auto vma = vm_manager.FindVMA(address); 45 auto vma = vm_manager.FindVMA(address);
@@ -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()->VMManager().GetHeapRegionBaseAddress() + offset;
75 77
76 return shared_memory; 78 return shared_memory;
77} 79}
@@ -105,7 +107,7 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
105 VAddr target_address = address; 107 VAddr target_address = address;
106 108
107 // Map the memory block into the target process 109 // Map the memory block into the target process
108 auto result = target_process->vm_manager.MapMemoryBlock( 110 auto result = target_process->VMManager().MapMemoryBlock(
109 target_address, backing_block, backing_block_offset, size, MemoryState::Shared); 111 target_address, backing_block, backing_block_offset, size, MemoryState::Shared);
110 if (result.Failed()) { 112 if (result.Failed()) {
111 LOG_ERROR( 113 LOG_ERROR(
@@ -115,14 +117,14 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
115 return result.Code(); 117 return result.Code();
116 } 118 }
117 119
118 return target_process->vm_manager.ReprotectRange(target_address, size, 120 return target_process->VMManager().ReprotectRange(target_address, size,
119 ConvertPermissions(permissions)); 121 ConvertPermissions(permissions));
120} 122}
121 123
122ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) { 124ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) {
123 // TODO(Subv): Verify what happens if the application tries to unmap an address that is not 125 // TODO(Subv): Verify what happens if the application tries to unmap an address that is not
124 // mapped to a SharedMemory. 126 // mapped to a SharedMemory.
125 return target_process->vm_manager.UnmapRange(address, size); 127 return target_process->VMManager().UnmapRange(address, size);
126} 128}
127 129
128VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) { 130VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) {
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index c9d212a4c..1cdaa740a 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.VMManager().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->VMManager();
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->GetAllowedProcessorMask();
333 break; 335 break;
334 case GetInfoType::AllowedThreadPrioBitmask: 336 case GetInfoType::AllowedThreadPrioBitmask:
335 *result = Core::CurrentProcess()->allowed_thread_priority_mask; 337 *result = current_process->GetAllowedThreadPriorityMask();
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->IsVirtualMemoryEnabled();
375 break; 390 break;
376 case GetInfoType::TitleId: 391 case GetInfoType::TitleId:
377 *result = Core::CurrentProcess()->program_id; 392 *result = current_process->GetTitleID();
378 break; 393 break;
379 case GetInfoType::PrivilegedProcessId: 394 case GetInfoType::PrivilegedProcessId:
380 LOG_WARNING(Kernel_SVC, 395 LOG_WARNING(Kernel_SVC,
@@ -400,8 +415,36 @@ static ResultCode SetThreadActivity(Handle handle, u32 unknown) {
400} 415}
401 416
402/// Gets the thread context 417/// Gets the thread context
403static ResultCode GetThreadContext(Handle handle, VAddr addr) { 418static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
404 LOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, addr=0x{:X}", handle, addr); 419 LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle);
420
421 auto& kernel = Core::System::GetInstance().Kernel();
422 const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(handle);
423 if (!thread) {
424 return ERR_INVALID_HANDLE;
425 }
426
427 const auto current_process = Core::CurrentProcess();
428 if (thread->owner_process != current_process) {
429 return ERR_INVALID_HANDLE;
430 }
431
432 if (thread == GetCurrentThread()) {
433 return ERR_ALREADY_REGISTERED;
434 }
435
436 Core::ARM_Interface::ThreadContext ctx = thread->context;
437 // Mask away mode bits, interrupt bits, IL bit, and other reserved bits.
438 ctx.pstate &= 0xFF0FFE20;
439
440 // If 64-bit, we can just write the context registers directly and we're good.
441 // However, if 32-bit, we have to ensure some registers are zeroed out.
442 if (!current_process->Is64BitProcess()) {
443 std::fill(ctx.cpu_registers.begin() + 15, ctx.cpu_registers.end(), 0);
444 std::fill(ctx.vector_registers.begin() + 16, ctx.vector_registers.end(), u128{});
445 }
446
447 Memory::WriteBlock(thread_context, &ctx, sizeof(ctx));
405 return RESULT_SUCCESS; 448 return RESULT_SUCCESS;
406} 449}
407 450
@@ -429,8 +472,8 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
429 472
430 // Note: The kernel uses the current process's resource limit instead of 473 // Note: The kernel uses the current process's resource limit instead of
431 // the one from the thread owner's resource limit. 474 // the one from the thread owner's resource limit.
432 SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit; 475 const ResourceLimit& resource_limit = Core::CurrentProcess()->GetResourceLimit();
433 if (resource_limit->GetMaxResourceValue(ResourceType::Priority) > priority) { 476 if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) {
434 return ERR_NOT_AUTHORIZED; 477 return ERR_NOT_AUTHORIZED;
435 } 478 }
436 479
@@ -504,9 +547,9 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i
504 if (!process) { 547 if (!process) {
505 return ERR_INVALID_HANDLE; 548 return ERR_INVALID_HANDLE;
506 } 549 }
507 auto vma = process->vm_manager.FindVMA(addr); 550 auto vma = process->VMManager().FindVMA(addr);
508 memory_info->attributes = 0; 551 memory_info->attributes = 0;
509 if (vma == Core::CurrentProcess()->vm_manager.vma_map.end()) { 552 if (vma == Core::CurrentProcess()->VMManager().vma_map.end()) {
510 memory_info->base_address = 0; 553 memory_info->base_address = 0;
511 memory_info->permission = static_cast<u32>(VMAPermission::None); 554 memory_info->permission = static_cast<u32>(VMAPermission::None);
512 memory_info->size = 0; 555 memory_info->size = 0;
@@ -553,14 +596,14 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
553 return ERR_INVALID_THREAD_PRIORITY; 596 return ERR_INVALID_THREAD_PRIORITY;
554 } 597 }
555 598
556 SharedPtr<ResourceLimit>& resource_limit = Core::CurrentProcess()->resource_limit; 599 const ResourceLimit& resource_limit = Core::CurrentProcess()->GetResourceLimit();
557 if (resource_limit->GetMaxResourceValue(ResourceType::Priority) > priority) { 600 if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) {
558 return ERR_NOT_AUTHORIZED; 601 return ERR_NOT_AUTHORIZED;
559 } 602 }
560 603
561 if (processor_id == THREADPROCESSORID_DEFAULT) { 604 if (processor_id == THREADPROCESSORID_DEFAULT) {
562 // Set the target CPU to the one specified in the process' exheader. 605 // Set the target CPU to the one specified in the process' exheader.
563 processor_id = Core::CurrentProcess()->ideal_processor; 606 processor_id = Core::CurrentProcess()->GetDefaultProcessorID();
564 ASSERT(processor_id != THREADPROCESSORID_DEFAULT); 607 ASSERT(processor_id != THREADPROCESSORID_DEFAULT);
565 } 608 }
566 609
@@ -887,10 +930,10 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
887 } 930 }
888 931
889 if (core == static_cast<u32>(THREADPROCESSORID_DEFAULT)) { 932 if (core == static_cast<u32>(THREADPROCESSORID_DEFAULT)) {
890 ASSERT(thread->owner_process->ideal_processor != 933 ASSERT(thread->owner_process->GetDefaultProcessorID() !=
891 static_cast<u8>(THREADPROCESSORID_DEFAULT)); 934 static_cast<u8>(THREADPROCESSORID_DEFAULT));
892 // Set the target CPU to the one specified in the process' exheader. 935 // Set the target CPU to the one specified in the process' exheader.
893 core = thread->owner_process->ideal_processor; 936 core = thread->owner_process->GetDefaultProcessorID();
894 mask = 1ull << core; 937 mask = 1ull << core;
895 } 938 }
896 939
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index fea9ba5ea..22712e64f 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -64,6 +64,11 @@ void SvcWrap() {
64 FuncReturn(func(Param(0), (s32)Param(1)).raw); 64 FuncReturn(func(Param(0), (s32)Param(1)).raw);
65} 65}
66 66
67template <ResultCode func(u64, u32)>
68void SvcWrap() {
69 FuncReturn(func(Param(0), static_cast<u32>(Param(1))).raw);
70}
71
67template <ResultCode func(u64*, u64)> 72template <ResultCode func(u64*, u64)>
68void SvcWrap() { 73void SvcWrap() {
69 u64 param_1 = 0; 74 u64 param_1 = 0;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 315f65338..b5c16cfbb 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -259,11 +259,12 @@ void Thread::BoostPriority(u32 priority) {
259SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority, 259SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 priority,
260 Process& owner_process) { 260 Process& owner_process) {
261 // Setup page table so we can write to memory 261 // Setup page table so we can write to memory
262 SetCurrentPageTable(&owner_process.vm_manager.page_table); 262 SetCurrentPageTable(&owner_process.VMManager().page_table);
263 263
264 // Initialize new "main" thread 264 // Initialize new "main" thread
265 const VAddr stack_top = owner_process.VMManager().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/kernel/wait_object.h b/src/core/hle/kernel/wait_object.h
index 0bd97133c..f4367ee28 100644
--- a/src/core/hle/kernel/wait_object.h
+++ b/src/core/hle/kernel/wait_object.h
@@ -69,7 +69,7 @@ private:
69template <> 69template <>
70inline SharedPtr<WaitObject> DynamicObjectCast<WaitObject>(SharedPtr<Object> object) { 70inline SharedPtr<WaitObject> DynamicObjectCast<WaitObject>(SharedPtr<Object> object) {
71 if (object != nullptr && object->IsWaitable()) { 71 if (object != nullptr && object->IsWaitable()) {
72 return boost::static_pointer_cast<WaitObject>(std::move(object)); 72 return boost::static_pointer_cast<WaitObject>(object);
73 } 73 }
74 return nullptr; 74 return nullptr;
75} 75}
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 80ed4b152..6073f4ecd 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -10,6 +10,7 @@
10#include "common/alignment.h" 10#include "common/alignment.h"
11#include "common/common_funcs.h" 11#include "common/common_funcs.h"
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "core/core.h"
13#include "core/hle/ipc_helpers.h" 14#include "core/hle/ipc_helpers.h"
14#include "core/hle/kernel/event.h" 15#include "core/hle/kernel/event.h"
15#include "core/hle/kernel/hle_ipc.h" 16#include "core/hle/kernel/hle_ipc.h"
@@ -65,7 +66,7 @@ private:
65 void GetAudioRendererState(Kernel::HLERequestContext& ctx) { 66 void GetAudioRendererState(Kernel::HLERequestContext& ctx) {
66 IPC::ResponseBuilder rb{ctx, 3}; 67 IPC::ResponseBuilder rb{ctx, 3};
67 rb.Push(RESULT_SUCCESS); 68 rb.Push(RESULT_SUCCESS);
68 rb.Push<u32>(renderer->GetState()); 69 rb.Push<u32>(static_cast<u32>(renderer->GetStreamState()));
69 LOG_DEBUG(Service_Audio, "called"); 70 LOG_DEBUG(Service_Audio, "called");
70 } 71 }
71 72
diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp
index 6de7edf9e..2f15ac2a6 100644
--- a/src/core/hle/service/fatal/fatal.cpp
+++ b/src/core/hle/service/fatal/fatal.cpp
@@ -6,11 +6,11 @@
6#include <cstring> 6#include <cstring>
7#include <ctime> 7#include <ctime>
8#include <fmt/time.h> 8#include <fmt/time.h>
9#include "common/common_paths.h"
10#include "common/file_util.h" 9#include "common/file_util.h"
11#include "common/logging/log.h" 10#include "common/logging/log.h"
12#include "common/scm_rev.h" 11#include "common/scm_rev.h"
13#include "common/swap.h" 12#include "common/swap.h"
13#include "core/core.h"
14#include "core/hle/ipc_helpers.h" 14#include "core/hle/ipc_helpers.h"
15#include "core/hle/kernel/process.h" 15#include "core/hle/kernel/process.h"
16#include "core/hle/service/fatal/fatal.h" 16#include "core/hle/service/fatal/fatal.h"
@@ -51,7 +51,7 @@ enum class FatalType : u32 {
51}; 51};
52 52
53static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) { 53static void GenerateErrorReport(ResultCode error_code, const FatalInfo& info) {
54 const auto title_id = Core::CurrentProcess()->program_id; 54 const auto title_id = Core::CurrentProcess()->GetTitleID();
55 std::string crash_report = 55 std::string crash_report =
56 fmt::format("Yuzu {}-{} crash report\n" 56 fmt::format("Yuzu {}-{} crash report\n"
57 "Title ID: {:016x}\n" 57 "Title ID: {:016x}\n"
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index f8d2127d9..8c07a05c2 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/core.h"
6#include "core/hle/ipc_helpers.h" 7#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/event.h" 8#include "core/hle/kernel/event.h"
8#include "core/hle/service/hid/hid.h" 9#include "core/hle/service/hid/hid.h"
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index c1737defa..261ad539c 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.cpp
@@ -4,6 +4,7 @@
4 4
5#include <chrono> 5#include <chrono>
6#include <ctime> 6#include <ctime>
7#include "core/core.h"
7#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
8#include "core/hle/kernel/event.h" 9#include "core/hle/kernel/event.h"
9#include "core/hle/service/nim/nim.h" 10#include "core/hle/service/nim/nim.h"
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index 1069d103f..4b2f758a8 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -317,9 +317,9 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
317 317
318void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { 318void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
319 // Map backing memory for the font data 319 // Map backing memory for the font data
320 Core::CurrentProcess()->vm_manager.MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0, 320 Core::CurrentProcess()->VMManager().MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0,
321 SHARED_FONT_MEM_SIZE, 321 SHARED_FONT_MEM_SIZE,
322 Kernel::MemoryState::Shared); 322 Kernel::MemoryState::Shared);
323 323
324 // Create shared font memory object 324 // Create shared font memory object
325 auto& kernel = Core::System::GetInstance().Kernel(); 325 auto& kernel = Core::System::GetInstance().Kernel();
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp
index cdf328a26..98f6e4111 100644
--- a/src/core/hle/service/sm/controller.cpp
+++ b/src/core/hle/service/sm/controller.cpp
@@ -2,8 +2,11 @@
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 "common/assert.h"
5#include "common/logging/log.h" 6#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h" 7#include "core/hle/ipc_helpers.h"
8#include "core/hle/kernel/client_session.h"
9#include "core/hle/kernel/server_session.h"
7#include "core/hle/kernel/session.h" 10#include "core/hle/kernel/session.h"
8#include "core/hle/service/sm/controller.h" 11#include "core/hle/service/sm/controller.h"
9 12
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 2ee60f1ec..bbc02abcc 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -612,7 +612,7 @@ public:
612 {3000, nullptr, "ListDisplayModes"}, 612 {3000, nullptr, "ListDisplayModes"},
613 {3001, nullptr, "ListDisplayRgbRanges"}, 613 {3001, nullptr, "ListDisplayRgbRanges"},
614 {3002, nullptr, "ListDisplayContentTypes"}, 614 {3002, nullptr, "ListDisplayContentTypes"},
615 {3200, nullptr, "GetDisplayMode"}, 615 {3200, &ISystemDisplayService::GetDisplayMode, "GetDisplayMode"},
616 {3201, nullptr, "SetDisplayMode"}, 616 {3201, nullptr, "SetDisplayMode"},
617 {3202, nullptr, "GetDisplayUnderscan"}, 617 {3202, nullptr, "GetDisplayUnderscan"},
618 {3203, nullptr, "SetDisplayUnderscan"}, 618 {3203, nullptr, "SetDisplayUnderscan"},
@@ -663,6 +663,24 @@ private:
663 LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id, 663 LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id,
664 visibility); 664 visibility);
665 } 665 }
666
667 void GetDisplayMode(Kernel::HLERequestContext& ctx) {
668 IPC::ResponseBuilder rb{ctx, 6};
669 rb.Push(RESULT_SUCCESS);
670
671 if (Settings::values.use_docked_mode) {
672 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth));
673 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight));
674 } else {
675 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth));
676 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight));
677 }
678
679 rb.PushRaw<float>(60.0f);
680 rb.Push<u32>(0);
681
682 LOG_DEBUG(Service_VI, "called");
683 }
666}; 684};
667 685
668class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> { 686class IManagerDisplayService final : public ServiceFramework<IManagerDisplayService> {
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 2b8f78136..c1824b9c3 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
@@ -88,8 +86,7 @@ FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::Virtua
88 return FileType::Error; 86 return FileType::Error;
89} 87}
90 88
91ResultStatus AppLoader_DeconstructedRomDirectory::Load( 89ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process) {
92 Kernel::SharedPtr<Kernel::Process>& process) {
93 if (is_loaded) { 90 if (is_loaded) {
94 return ResultStatus::ErrorAlreadyLoaded; 91 return ResultStatus::ErrorAlreadyLoaded;
95 } 92 }
@@ -127,12 +124,16 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
127 metadata.Print(); 124 metadata.Print();
128 125
129 const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()}; 126 const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()};
130 if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit) { 127 if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit ||
128 arch_bits == FileSys::ProgramAddressSpaceType::Is32BitNoMap) {
131 return ResultStatus::Error32BitISA; 129 return ResultStatus::Error32BitISA;
132 } 130 }
133 131
132 process.LoadFromMetadata(metadata);
133
134 // Load NSO modules 134 // Load NSO modules
135 VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR}; 135 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
136 VAddr next_load_addr = base_address;
136 for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", 137 for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",
137 "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { 138 "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) {
138 const FileSys::VirtualFile module_file = dir->GetFile(module); 139 const FileSys::VirtualFile module_file = dir->GetFile(module);
@@ -145,13 +146,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
145 } 146 }
146 } 147 }
147 148
148 auto& kernel = Core::System::GetInstance().Kernel(); 149 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 150
156 // Find the RomFS by searching for a ".romfs" file in this directory 151 // Find the RomFS by searching for a ".romfs" file in this directory
157 const auto& files = dir->GetFiles(); 152 const auto& files = dir->GetFiles();
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h
index 8a0dc1b1e..d109ed2b5 100644
--- a/src/core/loader/deconstructed_rom_directory.h
+++ b/src/core/loader/deconstructed_rom_directory.h
@@ -7,7 +7,6 @@
7#include <string> 7#include <string>
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/file_sys/program_metadata.h" 9#include "core/file_sys/program_metadata.h"
10#include "core/hle/kernel/object.h"
11#include "core/loader/loader.h" 10#include "core/loader/loader.h"
12 11
13namespace Loader { 12namespace Loader {
@@ -38,7 +37,7 @@ public:
38 return IdentifyType(file); 37 return IdentifyType(file);
39 } 38 }
40 39
41 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; 40 ResultStatus Load(Kernel::Process& process) override;
42 41
43 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; 42 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
44 ResultStatus ReadIcon(std::vector<u8>& buffer) override; 43 ResultStatus ReadIcon(std::vector<u8>& buffer) override;
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 0e2af20b4..e67b49fc9 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;
@@ -387,7 +387,7 @@ FileType AppLoader_ELF::IdentifyType(const FileSys::VirtualFile& file) {
387 return FileType::Error; 387 return FileType::Error;
388} 388}
389 389
390ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) { 390ResultStatus AppLoader_ELF::Load(Kernel::Process& process) {
391 if (is_loaded) 391 if (is_loaded)
392 return ResultStatus::ErrorAlreadyLoaded; 392 return ResultStatus::ErrorAlreadyLoaded;
393 393
@@ -395,19 +395,13 @@ 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.VMManager().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 process.Run(codeset->entrypoint, 48, Memory::DEFAULT_STACK_SIZE);
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);
411 405
412 is_loaded = true; 406 is_loaded = true;
413 return ResultStatus::Success; 407 return ResultStatus::Success;
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index b8fb982d0..6af76441c 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -8,9 +8,6 @@
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/loader/loader.h" 9#include "core/loader/loader.h"
10 10
11////////////////////////////////////////////////////////////////////////////////////////////////////
12// Loader namespace
13
14namespace Loader { 11namespace Loader {
15 12
16/// Loads an ELF/AXF file 13/// Loads an ELF/AXF file
@@ -29,7 +26,7 @@ public:
29 return IdentifyType(file); 26 return IdentifyType(file);
30 } 27 }
31 28
32 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; 29 ResultStatus Load(Kernel::Process& process) override;
33}; 30};
34 31
35} // namespace Loader 32} // namespace Loader
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 843c4bb91..20e66109b 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -12,7 +12,6 @@
12#include <boost/optional.hpp> 12#include <boost/optional.hpp>
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "core/file_sys/vfs.h" 14#include "core/file_sys/vfs.h"
15#include "core/hle/kernel/object.h"
16 15
17namespace Kernel { 16namespace Kernel {
18struct AddressMapping; 17struct AddressMapping;
@@ -136,7 +135,7 @@ public:
136 * @param process The newly created process. 135 * @param process The newly created process.
137 * @return The status result of the operation. 136 * @return The status result of the operation.
138 */ 137 */
139 virtual ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) = 0; 138 virtual ResultStatus Load(Kernel::Process& process) = 0;
140 139
141 /** 140 /**
142 * Loads the system mode that this application needs. 141 * Loads the system mode that this application needs.
diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp
index 5d4380684..073fb9d2f 100644
--- a/src/core/loader/nax.cpp
+++ b/src/core/loader/nax.cpp
@@ -41,7 +41,7 @@ FileType AppLoader_NAX::GetFileType() {
41 return IdentifyTypeImpl(*nax); 41 return IdentifyTypeImpl(*nax);
42} 42}
43 43
44ResultStatus AppLoader_NAX::Load(Kernel::SharedPtr<Kernel::Process>& process) { 44ResultStatus AppLoader_NAX::Load(Kernel::Process& process) {
45 if (is_loaded) { 45 if (is_loaded) {
46 return ResultStatus::ErrorAlreadyLoaded; 46 return ResultStatus::ErrorAlreadyLoaded;
47 } 47 }
diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h
index 56605fe45..fc3c01876 100644
--- a/src/core/loader/nax.h
+++ b/src/core/loader/nax.h
@@ -33,7 +33,7 @@ public:
33 33
34 FileType GetFileType() override; 34 FileType GetFileType() override;
35 35
36 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; 36 ResultStatus Load(Kernel::Process& process) override;
37 37
38 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; 38 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
39 ResultStatus ReadProgramId(u64& out_program_id) override; 39 ResultStatus ReadProgramId(u64& out_program_id) override;
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp
index 6aaffae59..7e1b0d84f 100644
--- a/src/core/loader/nca.cpp
+++ b/src/core/loader/nca.cpp
@@ -30,7 +30,7 @@ FileType AppLoader_NCA::IdentifyType(const FileSys::VirtualFile& file) {
30 return FileType::Error; 30 return FileType::Error;
31} 31}
32 32
33ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) { 33ResultStatus AppLoader_NCA::Load(Kernel::Process& process) {
34 if (is_loaded) { 34 if (is_loaded) {
35 return ResultStatus::ErrorAlreadyLoaded; 35 return ResultStatus::ErrorAlreadyLoaded;
36 } 36 }
diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h
index 10be197c4..95d9b73a1 100644
--- a/src/core/loader/nca.h
+++ b/src/core/loader/nca.h
@@ -6,7 +6,6 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/file_sys/vfs.h" 8#include "core/file_sys/vfs.h"
9#include "core/hle/kernel/object.h"
10#include "core/loader/loader.h" 9#include "core/loader/loader.h"
11 10
12namespace FileSys { 11namespace FileSys {
@@ -34,7 +33,7 @@ public:
34 return IdentifyType(file); 33 return IdentifyType(file);
35 } 34 }
36 35
37 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; 36 ResultStatus Load(Kernel::Process& process) override;
38 37
39 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; 38 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
40 u64 ReadRomFSIVFCOffset() const override; 39 u64 ReadRomFSIVFCOffset() const override;
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index c49ec34ab..c10f826a4 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
@@ -175,23 +175,19 @@ bool AppLoader_NRO::LoadNro(FileSys::VirtualFile file, VAddr load_base) {
175 return true; 175 return true;
176} 176}
177 177
178ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) { 178ResultStatus AppLoader_NRO::Load(Kernel::Process& process) {
179 if (is_loaded) { 179 if (is_loaded) {
180 return ResultStatus::ErrorAlreadyLoaded; 180 return ResultStatus::ErrorAlreadyLoaded;
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.VMManager().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/nro.h b/src/core/loader/nro.h
index 96d2de305..04b46119a 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -6,7 +6,6 @@
6 6
7#include <string> 7#include <string>
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/hle/kernel/object.h"
10#include "core/loader/linker.h" 9#include "core/loader/linker.h"
11#include "core/loader/loader.h" 10#include "core/loader/loader.h"
12 11
@@ -33,7 +32,7 @@ public:
33 return IdentifyType(file); 32 return IdentifyType(file);
34 } 33 }
35 34
36 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; 35 ResultStatus Load(Kernel::Process& process) override;
37 36
38 ResultStatus ReadIcon(std::vector<u8>& buffer) override; 37 ResultStatus ReadIcon(std::vector<u8>& buffer) override;
39 ResultStatus ReadProgramId(u64& out_program_id) override; 38 ResultStatus ReadProgramId(u64& out_program_id) override;
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 78a4438c4..cbe2a3e53 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
@@ -153,21 +153,17 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base) {
153 return load_base + image_size; 153 return load_base + image_size;
154} 154}
155 155
156ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) { 156ResultStatus AppLoader_NSO::Load(Kernel::Process& process) {
157 if (is_loaded) { 157 if (is_loaded) {
158 return ResultStatus::ErrorAlreadyLoaded; 158 return ResultStatus::ErrorAlreadyLoaded;
159 } 159 }
160 160
161 // Load module 161 // Load module
162 LoadModule(file, Memory::PROCESS_IMAGE_VADDR); 162 const VAddr base_address = process.VMManager().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/loader/nso.h b/src/core/loader/nso.h
index aaeb1f2a9..7f142405b 100644
--- a/src/core/loader/nso.h
+++ b/src/core/loader/nso.h
@@ -4,9 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <string>
8#include "common/common_types.h" 7#include "common/common_types.h"
9#include "core/hle/kernel/object.h"
10#include "core/loader/linker.h" 8#include "core/loader/linker.h"
11#include "core/loader/loader.h" 9#include "core/loader/loader.h"
12 10
@@ -30,7 +28,7 @@ public:
30 28
31 static VAddr LoadModule(FileSys::VirtualFile file, VAddr load_base); 29 static VAddr LoadModule(FileSys::VirtualFile file, VAddr load_base);
32 30
33 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; 31 ResultStatus Load(Kernel::Process& process) override;
34}; 32};
35 33
36} // namespace Loader 34} // namespace Loader
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index 291a9876d..b7ba77ef4 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -10,8 +10,6 @@
10#include "core/file_sys/control_metadata.h" 10#include "core/file_sys/control_metadata.h"
11#include "core/file_sys/nca_metadata.h" 11#include "core/file_sys/nca_metadata.h"
12#include "core/file_sys/patch_manager.h" 12#include "core/file_sys/patch_manager.h"
13#include "core/file_sys/registered_cache.h"
14#include "core/file_sys/romfs.h"
15#include "core/file_sys/submission_package.h" 13#include "core/file_sys/submission_package.h"
16#include "core/hle/kernel/process.h" 14#include "core/hle/kernel/process.h"
17#include "core/loader/deconstructed_rom_directory.h" 15#include "core/loader/deconstructed_rom_directory.h"
@@ -62,7 +60,7 @@ FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& file) {
62 return FileType::Error; 60 return FileType::Error;
63} 61}
64 62
65ResultStatus AppLoader_NSP::Load(Kernel::SharedPtr<Kernel::Process>& process) { 63ResultStatus AppLoader_NSP::Load(Kernel::Process& process) {
66 if (is_loaded) { 64 if (is_loaded) {
67 return ResultStatus::ErrorAlreadyLoaded; 65 return ResultStatus::ErrorAlreadyLoaded;
68 } 66 }
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h
index 7ef810499..eac9b819a 100644
--- a/src/core/loader/nsp.h
+++ b/src/core/loader/nsp.h
@@ -35,7 +35,7 @@ public:
35 return IdentifyType(file); 35 return IdentifyType(file);
36 } 36 }
37 37
38 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; 38 ResultStatus Load(Kernel::Process& process) override;
39 39
40 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; 40 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
41 ResultStatus ReadProgramId(u64& out_program_id) override; 41 ResultStatus ReadProgramId(u64& out_program_id) override;
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index 16509229f..eda67a8c8 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -9,8 +9,6 @@
9#include "core/file_sys/content_archive.h" 9#include "core/file_sys/content_archive.h"
10#include "core/file_sys/control_metadata.h" 10#include "core/file_sys/control_metadata.h"
11#include "core/file_sys/patch_manager.h" 11#include "core/file_sys/patch_manager.h"
12#include "core/file_sys/romfs.h"
13#include "core/file_sys/submission_package.h"
14#include "core/hle/kernel/process.h" 12#include "core/hle/kernel/process.h"
15#include "core/loader/nca.h" 13#include "core/loader/nca.h"
16#include "core/loader/xci.h" 14#include "core/loader/xci.h"
@@ -46,7 +44,7 @@ FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& file) {
46 return FileType::Error; 44 return FileType::Error;
47} 45}
48 46
49ResultStatus AppLoader_XCI::Load(Kernel::SharedPtr<Kernel::Process>& process) { 47ResultStatus AppLoader_XCI::Load(Kernel::Process& process) {
50 if (is_loaded) { 48 if (is_loaded) {
51 return ResultStatus::ErrorAlreadyLoaded; 49 return ResultStatus::ErrorAlreadyLoaded;
52 } 50 }
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
index cc4287e17..17e47b658 100644
--- a/src/core/loader/xci.h
+++ b/src/core/loader/xci.h
@@ -35,7 +35,7 @@ public:
35 return IdentifyType(file); 35 return IdentifyType(file);
36 } 36 }
37 37
38 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; 38 ResultStatus Load(Kernel::Process& process) override;
39 39
40 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; 40 ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
41 ResultStatus ReadProgramId(u64& out_program_id) override; 41 ResultStatus ReadProgramId(u64& out_program_id) override;
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 316b46820..014298ed6 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;
@@ -105,7 +119,7 @@ void RemoveDebugHook(PageTable& page_table, VAddr base, u64 size, MemoryHookPoin
105static u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) { 119static u8* GetPointerFromVMA(const Kernel::Process& process, VAddr vaddr) {
106 u8* direct_pointer = nullptr; 120 u8* direct_pointer = nullptr;
107 121
108 auto& vm_manager = process.vm_manager; 122 auto& vm_manager = process.VMManager();
109 123
110 auto it = vm_manager.FindVMA(vaddr); 124 auto it = vm_manager.FindVMA(vaddr);
111 ASSERT(it != vm_manager.vma_map.end()); 125 ASSERT(it != vm_manager.vma_map.end());
@@ -200,7 +214,7 @@ void Write(const VAddr vaddr, const T data) {
200} 214}
201 215
202bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) { 216bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
203 auto& page_table = process.vm_manager.page_table; 217 const auto& page_table = process.VMManager().page_table;
204 218
205 const u8* page_pointer = page_table.pointers[vaddr >> PAGE_BITS]; 219 const u8* page_pointer = page_table.pointers[vaddr >> PAGE_BITS];
206 if (page_pointer) 220 if (page_pointer)
@@ -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()->VMManager();
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) {
@@ -371,7 +387,7 @@ u64 Read64(const VAddr addr) {
371 387
372void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer, 388void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
373 const std::size_t size) { 389 const std::size_t size) {
374 auto& page_table = process.vm_manager.page_table; 390 const auto& page_table = process.VMManager().page_table;
375 391
376 std::size_t remaining_size = size; 392 std::size_t remaining_size = size;
377 std::size_t page_index = src_addr >> PAGE_BITS; 393 std::size_t page_index = src_addr >> PAGE_BITS;
@@ -436,7 +452,7 @@ void Write64(const VAddr addr, const u64 data) {
436 452
437void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer, 453void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer,
438 const std::size_t size) { 454 const std::size_t size) {
439 auto& page_table = process.vm_manager.page_table; 455 const auto& page_table = process.VMManager().page_table;
440 std::size_t remaining_size = size; 456 std::size_t remaining_size = size;
441 std::size_t page_index = dest_addr >> PAGE_BITS; 457 std::size_t page_index = dest_addr >> PAGE_BITS;
442 std::size_t page_offset = dest_addr & PAGE_MASK; 458 std::size_t page_offset = dest_addr & PAGE_MASK;
@@ -482,7 +498,7 @@ void WriteBlock(const VAddr dest_addr, const void* src_buffer, const std::size_t
482} 498}
483 499
484void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) { 500void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) {
485 auto& page_table = process.vm_manager.page_table; 501 const auto& page_table = process.VMManager().page_table;
486 std::size_t remaining_size = size; 502 std::size_t remaining_size = size;
487 std::size_t page_index = dest_addr >> PAGE_BITS; 503 std::size_t page_index = dest_addr >> PAGE_BITS;
488 std::size_t page_offset = dest_addr & PAGE_MASK; 504 std::size_t page_offset = dest_addr & PAGE_MASK;
@@ -524,7 +540,7 @@ void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std:
524 540
525void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, 541void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
526 const std::size_t size) { 542 const std::size_t size) {
527 auto& page_table = process.vm_manager.page_table; 543 const auto& page_table = process.VMManager().page_table;
528 std::size_t remaining_size = size; 544 std::size_t remaining_size = size;
529 std::size_t page_index = src_addr >> PAGE_BITS; 545 std::size_t page_index = src_addr >> PAGE_BITS;
530 std::size_t page_offset = src_addr & PAGE_MASK; 546 std::size_t page_offset = src_addr & PAGE_MASK;
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..c0a57e71f 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"
@@ -14,11 +16,12 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
14 : mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) { 16 : mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) {
15 17
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()->VMManager().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 b81b0723d..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.
@@ -461,7 +462,11 @@ public:
461 u32 entry; 462 u32 entry;
462 } macros; 463 } macros;
463 464
464 INSERT_PADDING_WORDS(0x1B8); 465 INSERT_PADDING_WORDS(0x189);
466
467 u32 tfb_enabled;
468
469 INSERT_PADDING_WORDS(0x2E);
465 470
466 RenderTargetConfig rt[NumRenderTargets]; 471 RenderTargetConfig rt[NumRenderTargets];
467 472
@@ -594,7 +599,9 @@ public:
594 599
595 u32 depth_write_enabled; 600 u32 depth_write_enabled;
596 601
597 INSERT_PADDING_WORDS(0x7); 602 u32 alpha_test_enabled;
603
604 INSERT_PADDING_WORDS(0x6);
598 605
599 u32 d3d_cull_mode; 606 u32 d3d_cull_mode;
600 607
@@ -635,7 +642,11 @@ public:
635 642
636 u32 vb_element_base; 643 u32 vb_element_base;
637 644
638 INSERT_PADDING_WORDS(0x40); 645 INSERT_PADDING_WORDS(0x38);
646
647 float point_size;
648
649 INSERT_PADDING_WORDS(0x7);
639 650
640 u32 zeta_enable; 651 u32 zeta_enable;
641 652
@@ -977,6 +988,7 @@ private:
977 "Field " #field_name " has invalid position") 988 "Field " #field_name " has invalid position")
978 989
979ASSERT_REG_POSITION(macros, 0x45); 990ASSERT_REG_POSITION(macros, 0x45);
991ASSERT_REG_POSITION(tfb_enabled, 0x1D1);
980ASSERT_REG_POSITION(rt, 0x200); 992ASSERT_REG_POSITION(rt, 0x200);
981ASSERT_REG_POSITION(viewport_transform[0], 0x280); 993ASSERT_REG_POSITION(viewport_transform[0], 0x280);
982ASSERT_REG_POSITION(viewport, 0x300); 994ASSERT_REG_POSITION(viewport, 0x300);
@@ -996,6 +1008,7 @@ ASSERT_REG_POSITION(zeta_height, 0x48b);
996ASSERT_REG_POSITION(depth_test_enable, 0x4B3); 1008ASSERT_REG_POSITION(depth_test_enable, 0x4B3);
997ASSERT_REG_POSITION(independent_blend_enable, 0x4B9); 1009ASSERT_REG_POSITION(independent_blend_enable, 0x4B9);
998ASSERT_REG_POSITION(depth_write_enabled, 0x4BA); 1010ASSERT_REG_POSITION(depth_write_enabled, 0x4BA);
1011ASSERT_REG_POSITION(alpha_test_enabled, 0x4BB);
999ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2); 1012ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2);
1000ASSERT_REG_POSITION(depth_test_func, 0x4C3); 1013ASSERT_REG_POSITION(depth_test_func, 0x4C3);
1001ASSERT_REG_POSITION(blend, 0x4CF); 1014ASSERT_REG_POSITION(blend, 0x4CF);
@@ -1009,6 +1022,7 @@ ASSERT_REG_POSITION(stencil_front_func_mask, 0x4E6);
1009ASSERT_REG_POSITION(stencil_front_mask, 0x4E7); 1022ASSERT_REG_POSITION(stencil_front_mask, 0x4E7);
1010ASSERT_REG_POSITION(screen_y_control, 0x4EB); 1023ASSERT_REG_POSITION(screen_y_control, 0x4EB);
1011ASSERT_REG_POSITION(vb_element_base, 0x50D); 1024ASSERT_REG_POSITION(vb_element_base, 0x50D);
1025ASSERT_REG_POSITION(point_size, 0x546);
1012ASSERT_REG_POSITION(zeta_enable, 0x54E); 1026ASSERT_REG_POSITION(zeta_enable, 0x54E);
1013ASSERT_REG_POSITION(tsc, 0x557); 1027ASSERT_REG_POSITION(tsc, 0x557);
1014ASSERT_REG_POSITION(tic, 0x55D); 1028ASSERT_REG_POSITION(tic, 0x55D);
diff --git a/src/video_core/engines/maxwell_compute.cpp b/src/video_core/engines/maxwell_compute.cpp
index e4e5f9e5e..59e28b22d 100644
--- a/src/video_core/engines/maxwell_compute.cpp
+++ b/src/video_core/engines/maxwell_compute.cpp
@@ -2,12 +2,29 @@
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 "common/logging/log.h"
6#include "core/core.h"
5#include "video_core/engines/maxwell_compute.h" 7#include "video_core/engines/maxwell_compute.h"
6 8
7namespace Tegra { 9namespace Tegra {
8namespace Engines { 10namespace Engines {
9 11
10void MaxwellCompute::WriteReg(u32 method, u32 value) {} 12void MaxwellCompute::WriteReg(u32 method, u32 value) {
13 ASSERT_MSG(method < Regs::NUM_REGS,
14 "Invalid MaxwellCompute register, increase the size of the Regs structure");
15
16 regs.reg_array[method] = value;
17
18 switch (method) {
19 case MAXWELL_COMPUTE_REG_INDEX(compute): {
20 LOG_CRITICAL(HW_GPU, "Compute shaders are not implemented");
21 UNREACHABLE();
22 break;
23 }
24 default:
25 break;
26 }
27}
11 28
12} // namespace Engines 29} // namespace Engines
13} // namespace Tegra 30} // namespace Tegra
diff --git a/src/video_core/engines/maxwell_compute.h b/src/video_core/engines/maxwell_compute.h
index 2b3e4ced6..6ea934fb9 100644
--- a/src/video_core/engines/maxwell_compute.h
+++ b/src/video_core/engines/maxwell_compute.h
@@ -4,17 +4,53 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#include "common/assert.h"
9#include "common/bit_field.h"
10#include "common/common_funcs.h"
7#include "common/common_types.h" 11#include "common/common_types.h"
8 12
9namespace Tegra::Engines { 13namespace Tegra::Engines {
10 14
15#define MAXWELL_COMPUTE_REG_INDEX(field_name) \
16 (offsetof(Tegra::Engines::MaxwellCompute::Regs, field_name) / sizeof(u32))
17
11class MaxwellCompute final { 18class MaxwellCompute final {
12public: 19public:
13 MaxwellCompute() = default; 20 MaxwellCompute() = default;
14 ~MaxwellCompute() = default; 21 ~MaxwellCompute() = default;
15 22
23 struct Regs {
24 static constexpr std::size_t NUM_REGS = 0xCF8;
25
26 union {
27 struct {
28 INSERT_PADDING_WORDS(0x281);
29
30 union {
31 u32 compute_end;
32 BitField<0, 1, u32> unknown;
33 } compute;
34
35 INSERT_PADDING_WORDS(0xA76);
36 };
37 std::array<u32, NUM_REGS> reg_array;
38 };
39 } regs{};
40
41 static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32),
42 "MaxwellCompute Regs has wrong size");
43
16 /// Write the value to the register identified by method. 44 /// Write the value to the register identified by method.
17 void WriteReg(u32 method, u32 value); 45 void WriteReg(u32 method, u32 value);
18}; 46};
19 47
48#define ASSERT_REG_POSITION(field_name, position) \
49 static_assert(offsetof(MaxwellCompute::Regs, field_name) == position * 4, \
50 "Field " #field_name " has invalid position")
51
52ASSERT_REG_POSITION(compute, 0x281);
53
54#undef ASSERT_REG_POSITION
55
20} // namespace Tegra::Engines 56} // namespace Tegra::Engines
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 70fb54507..1fcd13f04 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -450,6 +450,9 @@ void RasterizerOpenGL::DrawArrays() {
450 SyncBlendState(); 450 SyncBlendState();
451 SyncLogicOpState(); 451 SyncLogicOpState();
452 SyncCullMode(); 452 SyncCullMode();
453 SyncAlphaTest();
454 SyncTransformFeedback();
455 SyncPointState();
453 456
454 // TODO(bunnei): Sync framebuffer_scale uniform here 457 // TODO(bunnei): Sync framebuffer_scale uniform here
455 // TODO(bunnei): Sync scissorbox uniform(s) here 458 // TODO(bunnei): Sync scissorbox uniform(s) here
@@ -883,4 +886,30 @@ void RasterizerOpenGL::SyncLogicOpState() {
883 state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation); 886 state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation);
884} 887}
885 888
889void RasterizerOpenGL::SyncAlphaTest() {
890 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
891
892 // TODO(Rodrigo): Alpha testing is a legacy OpenGL feature, but it can be
893 // implemented with a test+discard in fragment shaders.
894 if (regs.alpha_test_enabled != 0) {
895 LOG_CRITICAL(Render_OpenGL, "Alpha testing is not implemented");
896 UNREACHABLE();
897 }
898}
899
900void RasterizerOpenGL::SyncTransformFeedback() {
901 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
902
903 if (regs.tfb_enabled != 0) {
904 LOG_CRITICAL(Render_OpenGL, "Transform feedbacks are not implemented");
905 UNREACHABLE();
906 }
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
886} // 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 bf9560bdc..4c8ecbd1c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -158,6 +158,15 @@ private:
158 /// Syncs the LogicOp state to match the guest state 158 /// Syncs the LogicOp state to match the guest state
159 void SyncLogicOpState(); 159 void SyncLogicOpState();
160 160
161 /// Syncs the alpha test state to match the guest state
162 void SyncAlphaTest();
163
164 /// Syncs the transform feedback state to match the guest state
165 void SyncTransformFeedback();
166
167 /// Syncs the point state to match the guest state
168 void SyncPointState();
169
161 bool has_ARB_direct_state_access = false; 170 bool has_ARB_direct_state_access = false;
162 bool has_ARB_multi_bind = false; 171 bool has_ARB_multi_bind = false;
163 bool has_ARB_separate_shader_objects = false; 172 bool has_ARB_separate_shader_objects = false;
@@ -178,7 +187,7 @@ private:
178 OGLVertexArray> 187 OGLVertexArray>
179 vertex_array_cache; 188 vertex_array_cache;
180 189
181 std::array<SamplerInfo, GLShader::NumTextureSamplers> texture_samplers; 190 std::array<SamplerInfo, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_samplers;
182 191
183 static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024; 192 static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
184 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/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index 20ba6d4f6..3d5476e5d 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -13,47 +13,20 @@
13namespace Tegra::Texture { 13namespace Tegra::Texture {
14 14
15/** 15/**
16 * This table represents the internal swizzle of a gob,
17 * in format 16 bytes x 2 sector packing.
16 * Calculates the offset of an (x, y) position within a swizzled texture. 18 * Calculates the offset of an (x, y) position within a swizzled texture.
17 * Taken from the Tegra X1 TRM. 19 * Taken from the Tegra X1 Technical Reference Manual. pages 1187-1188
18 */ 20 */
19static u32 GetSwizzleOffset(u32 x, u32 y, u32 image_width, u32 bytes_per_pixel, u32 block_height) { 21template <std::size_t N, std::size_t M, u32 Align>
20 // Round up to the next gob
21 const u32 image_width_in_gobs{(image_width * bytes_per_pixel + 63) / 64};
22
23 u32 GOB_address = 0 + (y / (8 * block_height)) * 512 * block_height * image_width_in_gobs +
24 (x * bytes_per_pixel / 64) * 512 * block_height +
25 (y % (8 * block_height) / 8) * 512;
26 x *= bytes_per_pixel;
27 u32 address = GOB_address + ((x % 64) / 32) * 256 + ((y % 8) / 2) * 64 + ((x % 32) / 16) * 32 +
28 (y % 2) * 16 + (x % 16);
29
30 return address;
31}
32
33void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel,
34 u8* swizzled_data, u8* unswizzled_data, bool unswizzle, u32 block_height) {
35 u8* data_ptrs[2];
36 for (unsigned y = 0; y < height; ++y) {
37 for (unsigned x = 0; x < width; ++x) {
38 u32 swizzle_offset = GetSwizzleOffset(x, y, width, bytes_per_pixel, block_height);
39 u32 pixel_index = (x + y * width) * out_bytes_per_pixel;
40
41 data_ptrs[unswizzle] = swizzled_data + swizzle_offset;
42 data_ptrs[!unswizzle] = &unswizzled_data[pixel_index];
43
44 std::memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel);
45 }
46 }
47}
48
49template <std::size_t N, std::size_t M>
50struct alignas(64) SwizzleTable { 22struct alignas(64) SwizzleTable {
23 static_assert(M * Align == 64, "Swizzle Table does not align to GOB");
51 constexpr SwizzleTable() { 24 constexpr SwizzleTable() {
52 for (u32 y = 0; y < N; ++y) { 25 for (u32 y = 0; y < N; ++y) {
53 for (u32 x = 0; x < M; ++x) { 26 for (u32 x = 0; x < M; ++x) {
54 const u32 x2 = x * 16; 27 const u32 x2 = x * Align;
55 values[y][x] = static_cast<u16>(((x2 % 64) / 32) * 256 + ((y % 8) / 2) * 64 + 28 values[y][x] = static_cast<u16>(((x2 % 64) / 32) * 256 + ((y % 8) / 2) * 64 +
56 ((x2 % 32) / 16) * 32 + (y % 2) * 16); 29 ((x2 % 32) / 16) * 32 + (y % 2) * 16 + (x2 % 16));
57 } 30 }
58 } 31 }
59 } 32 }
@@ -63,24 +36,60 @@ struct alignas(64) SwizzleTable {
63 std::array<std::array<u16, M>, N> values{}; 36 std::array<std::array<u16, M>, N> values{};
64}; 37};
65 38
66constexpr auto swizzle_table = SwizzleTable<8, 4>(); 39constexpr auto legacy_swizzle_table = SwizzleTable<8, 64, 1>();
40constexpr auto fast_swizzle_table = SwizzleTable<8, 4, 16>();
67 41
68void FastSwizzleData(u32 width, u32 height, u32 bytes_per_pixel, u8* swizzled_data, 42static void LegacySwizzleData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel,
69 u8* unswizzled_data, bool unswizzle, u32 block_height) { 43 u8* swizzled_data, u8* unswizzled_data, bool unswizzle,
44 u32 block_height) {
45 std::array<u8*, 2> data_ptrs;
46 const std::size_t stride = width * bytes_per_pixel;
47 const std::size_t gobs_in_x = 64;
48 const std::size_t gobs_in_y = 8;
49 const std::size_t gobs_size = gobs_in_x * gobs_in_y;
50 const std::size_t image_width_in_gobs{(stride + gobs_in_x - 1) / gobs_in_x};
51 for (std::size_t y = 0; y < height; ++y) {
52 const std::size_t gob_y_address =
53 (y / (gobs_in_y * block_height)) * gobs_size * block_height * image_width_in_gobs +
54 (y % (gobs_in_y * block_height) / gobs_in_y) * gobs_size;
55 const auto& table = legacy_swizzle_table[y % gobs_in_y];
56 for (std::size_t x = 0; x < width; ++x) {
57 const std::size_t gob_address =
58 gob_y_address + (x * bytes_per_pixel / gobs_in_x) * gobs_size * block_height;
59 const std::size_t x2 = x * bytes_per_pixel;
60 const std::size_t swizzle_offset = gob_address + table[x2 % gobs_in_x];
61 const std::size_t pixel_index = (x + y * width) * out_bytes_per_pixel;
62
63 data_ptrs[unswizzle] = swizzled_data + swizzle_offset;
64 data_ptrs[!unswizzle] = unswizzled_data + pixel_index;
65
66 std::memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel);
67 }
68 }
69}
70
71static void FastSwizzleData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel,
72 u8* swizzled_data, u8* unswizzled_data, bool unswizzle,
73 u32 block_height) {
70 std::array<u8*, 2> data_ptrs; 74 std::array<u8*, 2> data_ptrs;
71 const std::size_t stride{width * bytes_per_pixel}; 75 const std::size_t stride{width * bytes_per_pixel};
72 const std::size_t image_width_in_gobs{(stride + 63) / 64}; 76 const std::size_t gobs_in_x = 64;
77 const std::size_t gobs_in_y = 8;
78 const std::size_t gobs_size = gobs_in_x * gobs_in_y;
79 const std::size_t image_width_in_gobs{(stride + gobs_in_x - 1) / gobs_in_x};
73 const std::size_t copy_size{16}; 80 const std::size_t copy_size{16};
74 for (std::size_t y = 0; y < height; ++y) { 81 for (std::size_t y = 0; y < height; ++y) {
75 const std::size_t initial_gob = 82 const std::size_t initial_gob =
76 (y / (8 * block_height)) * 512 * block_height * image_width_in_gobs + 83 (y / (gobs_in_y * block_height)) * gobs_size * block_height * image_width_in_gobs +
77 (y % (8 * block_height) / 8) * 512; 84 (y % (gobs_in_y * block_height) / gobs_in_y) * gobs_size;
78 const std::size_t pixel_base{y * width * bytes_per_pixel}; 85 const std::size_t pixel_base{y * width * out_bytes_per_pixel};
79 const auto& table = swizzle_table[y % 8]; 86 const auto& table = fast_swizzle_table[y % gobs_in_y];
80 for (std::size_t xb = 0; xb < stride; xb += copy_size) { 87 for (std::size_t xb = 0; xb < stride; xb += copy_size) {
81 const std::size_t gob_address{initial_gob + (xb / 64) * 512 * block_height}; 88 const std::size_t gob_address{initial_gob +
89 (xb / gobs_in_x) * gobs_size * block_height};
82 const std::size_t swizzle_offset{gob_address + table[(xb / 16) % 4]}; 90 const std::size_t swizzle_offset{gob_address + table[(xb / 16) % 4]};
83 const std::size_t pixel_index{xb + pixel_base}; 91 const std::size_t out_x = xb * out_bytes_per_pixel / bytes_per_pixel;
92 const std::size_t pixel_index{out_x + pixel_base};
84 data_ptrs[unswizzle] = swizzled_data + swizzle_offset; 93 data_ptrs[unswizzle] = swizzled_data + swizzle_offset;
85 data_ptrs[!unswizzle] = unswizzled_data + pixel_index; 94 data_ptrs[!unswizzle] = unswizzled_data + pixel_index;
86 std::memcpy(data_ptrs[0], data_ptrs[1], copy_size); 95 std::memcpy(data_ptrs[0], data_ptrs[1], copy_size);
@@ -88,6 +97,17 @@ void FastSwizzleData(u32 width, u32 height, u32 bytes_per_pixel, u8* swizzled_da
88 } 97 }
89} 98}
90 99
100void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_per_pixel,
101 u8* swizzled_data, u8* unswizzled_data, bool unswizzle, u32 block_height) {
102 if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % 16 == 0) {
103 FastSwizzleData(width, height, bytes_per_pixel, out_bytes_per_pixel, swizzled_data,
104 unswizzled_data, unswizzle, block_height);
105 } else {
106 LegacySwizzleData(width, height, bytes_per_pixel, out_bytes_per_pixel, swizzled_data,
107 unswizzled_data, unswizzle, block_height);
108 }
109}
110
91u32 BytesPerPixel(TextureFormat format) { 111u32 BytesPerPixel(TextureFormat format) {
92 switch (format) { 112 switch (format) {
93 case TextureFormat::DXT1: 113 case TextureFormat::DXT1:
@@ -134,13 +154,8 @@ u32 BytesPerPixel(TextureFormat format) {
134std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width, 154std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width,
135 u32 height, u32 block_height) { 155 u32 height, u32 block_height) {
136 std::vector<u8> unswizzled_data(width * height * bytes_per_pixel); 156 std::vector<u8> unswizzled_data(width * height * bytes_per_pixel);
137 if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % 16 == 0) { 157 CopySwizzledData(width / tile_size, height / tile_size, bytes_per_pixel, bytes_per_pixel,
138 FastSwizzleData(width / tile_size, height / tile_size, bytes_per_pixel, 158 Memory::GetPointer(address), unswizzled_data.data(), true, block_height);
139 Memory::GetPointer(address), unswizzled_data.data(), true, block_height);
140 } else {
141 CopySwizzledData(width / tile_size, height / tile_size, bytes_per_pixel, bytes_per_pixel,
142 Memory::GetPointer(address), unswizzled_data.data(), true, block_height);
143 }
144 return unswizzled_data; 159 return unswizzled_data;
145} 160}
146 161
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};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index cb37796fa..27015d02c 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -622,9 +622,9 @@ void GMainWindow::BootGame(const QString& filename) {
622 std::string title_name; 622 std::string title_name;
623 const auto res = Core::System::GetInstance().GetGameName(title_name); 623 const auto res = Core::System::GetInstance().GetGameName(title_name);
624 if (res != Loader::ResultStatus::Success) { 624 if (res != Loader::ResultStatus::Success) {
625 const u64 program_id = Core::System::GetInstance().CurrentProcess()->program_id; 625 const u64 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
626 626
627 const auto [nacp, icon_file] = FileSys::PatchManager(program_id).GetControlMetadata(); 627 const auto [nacp, icon_file] = FileSys::PatchManager(title_id).GetControlMetadata();
628 if (nacp != nullptr) 628 if (nacp != nullptr)
629 title_name = nacp->GetApplicationName(); 629 title_name = nacp->GetApplicationName();
630 630
@@ -756,11 +756,51 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
756 QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); 756 QDesktopServices::openUrl(QUrl::fromLocalFile(qpath));
757} 757}
758 758
759static std::size_t CalculateRomFSEntrySize(const FileSys::VirtualDir& dir, bool full) {
760 std::size_t out = 0;
761
762 for (const auto& subdir : dir->GetSubdirectories()) {
763 out += 1 + CalculateRomFSEntrySize(subdir, full);
764 }
765
766 return out + (full ? dir->GetFiles().size() : 0);
767}
768
769static bool RomFSRawCopy(QProgressDialog& dialog, const FileSys::VirtualDir& src,
770 const FileSys::VirtualDir& dest, std::size_t block_size, bool full) {
771 if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
772 return false;
773 if (dialog.wasCanceled())
774 return false;
775
776 if (full) {
777 for (const auto& file : src->GetFiles()) {
778 const auto out = VfsDirectoryCreateFileWrapper(dest, file->GetName());
779 if (!FileSys::VfsRawCopy(file, out, block_size))
780 return false;
781 dialog.setValue(dialog.value() + 1);
782 if (dialog.wasCanceled())
783 return false;
784 }
785 }
786
787 for (const auto& dir : src->GetSubdirectories()) {
788 const auto out = dest->CreateSubdirectory(dir->GetName());
789 if (!RomFSRawCopy(dialog, dir, out, block_size, full))
790 return false;
791 dialog.setValue(dialog.value() + 1);
792 if (dialog.wasCanceled())
793 return false;
794 }
795
796 return true;
797}
798
759void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path) { 799void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path) {
760 const auto path = fmt::format("{}{:016X}/romfs", 800 const auto path = fmt::format("{}{:016X}/romfs",
761 FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), program_id); 801 FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), program_id);
762 802
763 auto failed = [this, &path]() { 803 const auto failed = [this, &path] {
764 QMessageBox::warning(this, tr("RomFS Extraction Failed!"), 804 QMessageBox::warning(this, tr("RomFS Extraction Failed!"),
765 tr("There was an error copying the RomFS files or the user " 805 tr("There was an error copying the RomFS files or the user "
766 "cancelled the operation.")); 806 "cancelled the operation."));
@@ -808,53 +848,13 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
808 failed(); 848 failed();
809 849
810 const auto full = res == "Full"; 850 const auto full = res == "Full";
811 851 const auto entry_size = CalculateRomFSEntrySize(extracted, full);
812 const static std::function<size_t(const FileSys::VirtualDir&, bool)> calculate_entry_size =
813 [](const FileSys::VirtualDir& dir, bool full) {
814 size_t out = 0;
815 for (const auto& subdir : dir->GetSubdirectories())
816 out += 1 + calculate_entry_size(subdir, full);
817 return out + full ? dir->GetFiles().size() : 0;
818 };
819 const auto entry_size = calculate_entry_size(extracted, full);
820 852
821 QProgressDialog progress(tr("Extracting RomFS..."), tr("Cancel"), 0, entry_size, this); 853 QProgressDialog progress(tr("Extracting RomFS..."), tr("Cancel"), 0, entry_size, this);
822 progress.setWindowModality(Qt::WindowModal); 854 progress.setWindowModality(Qt::WindowModal);
823 progress.setMinimumDuration(100); 855 progress.setMinimumDuration(100);
824 856
825 const static std::function<bool(QProgressDialog&, const FileSys::VirtualDir&, 857 if (RomFSRawCopy(progress, extracted, out, 0x400000, full)) {
826 const FileSys::VirtualDir&, size_t, bool)>
827 qt_raw_copy = [](QProgressDialog& dialog, const FileSys::VirtualDir& src,
828 const FileSys::VirtualDir& dest, size_t block_size, bool full) {
829 if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
830 return false;
831 if (dialog.wasCanceled())
832 return false;
833
834 if (full) {
835 for (const auto& file : src->GetFiles()) {
836 const auto out = VfsDirectoryCreateFileWrapper(dest, file->GetName());
837 if (!FileSys::VfsRawCopy(file, out, block_size))
838 return false;
839 dialog.setValue(dialog.value() + 1);
840 if (dialog.wasCanceled())
841 return false;
842 }
843 }
844
845 for (const auto& dir : src->GetSubdirectories()) {
846 const auto out = dest->CreateSubdirectory(dir->GetName());
847 if (!qt_raw_copy(dialog, dir, out, block_size, full))
848 return false;
849 dialog.setValue(dialog.value() + 1);
850 if (dialog.wasCanceled())
851 return false;
852 }
853
854 return true;
855 };
856
857 if (qt_raw_copy(progress, extracted, out, 0x400000, full)) {
858 progress.close(); 858 progress.close();
859 QMessageBox::information(this, tr("RomFS Extraction Succeeded!"), 859 QMessageBox::information(this, tr("RomFS Extraction Succeeded!"),
860 tr("The operation completed successfully.")); 860 tr("The operation completed successfully."));
@@ -931,7 +931,7 @@ void GMainWindow::OnMenuInstallToNAND() {
931 } 931 }
932 932
933 const auto qt_raw_copy = [this](const FileSys::VirtualFile& src, 933 const auto qt_raw_copy = [this](const FileSys::VirtualFile& src,
934 const FileSys::VirtualFile& dest, size_t block_size) { 934 const FileSys::VirtualFile& dest, std::size_t block_size) {
935 if (src == nullptr || dest == nullptr) 935 if (src == nullptr || dest == nullptr)
936 return false; 936 return false;
937 if (!dest->Resize(src->GetSize())) 937 if (!dest->Resize(src->GetSize()))