summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt7
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp9
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h4
-rw-r--r--src/core/core.cpp50
-rw-r--r--src/core/core.h18
-rw-r--r--src/core/core_cpu.cpp14
-rw-r--r--src/core/core_cpu.h17
-rw-r--r--src/core/crypto/key_manager.cpp826
-rw-r--r--src/core/crypto/key_manager.h104
-rw-r--r--src/core/crypto/partition_data_manager.cpp593
-rw-r--r--src/core/crypto/partition_data_manager.h109
-rw-r--r--src/core/file_sys/bis_factory.cpp12
-rw-r--r--src/core/file_sys/bis_factory.h8
-rw-r--r--src/core/file_sys/content_archive.cpp2
-rw-r--r--src/core/file_sys/control_metadata.cpp13
-rw-r--r--src/core/file_sys/control_metadata.h1
-rw-r--r--src/core/file_sys/ips_layer.cpp6
-rw-r--r--src/core/file_sys/patch_manager.cpp27
-rw-r--r--src/core/file_sys/patch_manager.h5
-rw-r--r--src/core/file_sys/registered_cache.cpp14
-rw-r--r--src/core/file_sys/registered_cache.h12
-rw-r--r--src/core/file_sys/savedata_factory.cpp13
-rw-r--r--src/core/file_sys/sdmc_factory.cpp8
-rw-r--r--src/core/file_sys/sdmc_factory.h4
-rw-r--r--src/core/file_sys/vfs.h10
-rw-r--r--src/core/file_sys/vfs_types.h21
-rw-r--r--src/core/gdbstub/gdbstub.cpp6
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp2
-rw-r--r--src/core/hle/kernel/errors.h2
-rw-r--r--src/core/hle/kernel/kernel.cpp12
-rw-r--r--src/core/hle/kernel/kernel.h10
-rw-r--r--src/core/hle/kernel/object.cpp1
-rw-r--r--src/core/hle/kernel/object.h1
-rw-r--r--src/core/hle/kernel/process.cpp34
-rw-r--r--src/core/hle/kernel/process.h49
-rw-r--r--src/core/hle/kernel/scheduler.cpp8
-rw-r--r--src/core/hle/kernel/svc.cpp165
-rw-r--r--src/core/hle/kernel/svc.h4
-rw-r--r--src/core/hle/kernel/svc_wrap.h64
-rw-r--r--src/core/hle/kernel/thread.cpp29
-rw-r--r--src/core/hle/kernel/thread.h8
-rw-r--r--src/core/hle/kernel/vm_manager.cpp35
-rw-r--r--src/core/hle/kernel/vm_manager.h12
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp18
-rw-r--r--src/core/hle/service/audio/hwopus.cpp37
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp29
-rw-r--r--src/core/hle/service/filesystem/filesystem.h12
-rw-r--r--src/core/hle/service/ns/pl_u.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp20
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp72
-rw-r--r--src/core/hle/service/service.cpp4
-rw-r--r--src/core/hle/service/service.h3
-rw-r--r--src/core/hle/service/vi/vi.cpp50
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp22
-rw-r--r--src/core/loader/elf.cpp32
-rw-r--r--src/core/loader/loader.cpp3
-rw-r--r--src/core/loader/loader.h1
-rw-r--r--src/core/loader/nro.cpp29
-rw-r--r--src/core/loader/nro.h2
-rw-r--r--src/core/loader/nso.cpp42
-rw-r--r--src/core/loader/nso.h6
-rw-r--r--src/core/loader/nsp.cpp2
-rw-r--r--src/core/loader/nsp.h2
-rw-r--r--src/core/loader/xci.cpp2
-rw-r--r--src/core/loader/xci.h2
-rw-r--r--src/core/settings.h2
-rw-r--r--src/core/telemetry_session.cpp4
67 files changed, 2275 insertions, 472 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 1a9ec459f..4755ec822 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -18,6 +18,8 @@ add_library(core STATIC
18 crypto/encryption_layer.h 18 crypto/encryption_layer.h
19 crypto/key_manager.cpp 19 crypto/key_manager.cpp
20 crypto/key_manager.h 20 crypto/key_manager.h
21 crypto/partition_data_manager.cpp
22 crypto/partition_data_manager.h
21 crypto/ctr_encryption_layer.cpp 23 crypto/ctr_encryption_layer.cpp
22 crypto/ctr_encryption_layer.h 24 crypto/ctr_encryption_layer.h
23 crypto/xts_encryption_layer.cpp 25 crypto/xts_encryption_layer.cpp
@@ -70,6 +72,7 @@ add_library(core STATIC
70 file_sys/vfs_real.cpp 72 file_sys/vfs_real.cpp
71 file_sys/vfs_real.h 73 file_sys/vfs_real.h
72 file_sys/vfs_static.h 74 file_sys/vfs_static.h
75 file_sys/vfs_types.h
73 file_sys/vfs_vector.cpp 76 file_sys/vfs_vector.cpp
74 file_sys/vfs_vector.h 77 file_sys/vfs_vector.h
75 file_sys/xts_archive.cpp 78 file_sys/xts_archive.cpp
@@ -415,8 +418,8 @@ create_target_directory_groups(core)
415target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) 418target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
416target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static mbedtls opus unicorn open_source_archives) 419target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt lz4_static mbedtls opus unicorn open_source_archives)
417if (ENABLE_WEB_SERVICE) 420if (ENABLE_WEB_SERVICE)
418 add_definitions(-DENABLE_WEB_SERVICE) 421 target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE)
419 target_link_libraries(core PUBLIC json-headers web_service) 422 target_link_libraries(core PRIVATE web_service)
420endif() 423endif()
421 424
422if (ARCHITECTURE_x86_64) 425if (ARCHITECTURE_x86_64)
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 7e978cf7a..4d2491870 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -129,7 +129,7 @@ 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& current_process = Core::CurrentProcess(); 132 auto* current_process = Core::CurrentProcess();
133 auto** const page_table = current_process->VMManager().page_table.pointers.data(); 133 auto** const page_table = current_process->VMManager().page_table.pointers.data();
134 134
135 Dynarmic::A64::UserConfig config; 135 Dynarmic::A64::UserConfig config;
@@ -144,7 +144,7 @@ std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
144 144
145 // Multi-process state 145 // Multi-process state
146 config.processor_id = core_index; 146 config.processor_id = core_index;
147 config.global_monitor = &exclusive_monitor->monitor; 147 config.global_monitor = &exclusive_monitor.monitor;
148 148
149 // System registers 149 // System registers
150 config.tpidrro_el0 = &cb->tpidrro_el0; 150 config.tpidrro_el0 = &cb->tpidrro_el0;
@@ -171,10 +171,9 @@ void ARM_Dynarmic::Step() {
171 cb->InterpreterFallback(jit->GetPC(), 1); 171 cb->InterpreterFallback(jit->GetPC(), 1);
172} 172}
173 173
174ARM_Dynarmic::ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, 174ARM_Dynarmic::ARM_Dynarmic(ExclusiveMonitor& exclusive_monitor, std::size_t core_index)
175 std::size_t core_index)
176 : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), core_index{core_index}, 175 : cb(std::make_unique<ARM_Dynarmic_Callbacks>(*this)), core_index{core_index},
177 exclusive_monitor{std::dynamic_pointer_cast<DynarmicExclusiveMonitor>(exclusive_monitor)} { 176 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {
178 ThreadContext ctx{}; 177 ThreadContext ctx{};
179 inner_unicorn.SaveContext(ctx); 178 inner_unicorn.SaveContext(ctx);
180 PageTableChanged(); 179 PageTableChanged();
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index 4ee92ee27..512bf8ce9 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -23,7 +23,7 @@ class DynarmicExclusiveMonitor;
23 23
24class ARM_Dynarmic final : public ARM_Interface { 24class ARM_Dynarmic final : public ARM_Interface {
25public: 25public:
26 ARM_Dynarmic(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, std::size_t core_index); 26 ARM_Dynarmic(ExclusiveMonitor& exclusive_monitor, std::size_t core_index);
27 ~ARM_Dynarmic(); 27 ~ARM_Dynarmic();
28 28
29 void MapBackingMemory(VAddr address, std::size_t size, u8* memory, 29 void MapBackingMemory(VAddr address, std::size_t size, u8* memory,
@@ -62,7 +62,7 @@ private:
62 ARM_Unicorn inner_unicorn; 62 ARM_Unicorn inner_unicorn;
63 63
64 std::size_t core_index; 64 std::size_t core_index;
65 std::shared_ptr<DynarmicExclusiveMonitor> exclusive_monitor; 65 DynarmicExclusiveMonitor& exclusive_monitor;
66 66
67 Memory::PageTable* current_page_table = nullptr; 67 Memory::PageTable* current_page_table = nullptr;
68}; 68};
diff --git a/src/core/core.cpp b/src/core/core.cpp
index b6acfb3e4..3c57a62ec 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -71,9 +71,9 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
71} 71}
72 72
73/// Runs a CPU core while the system is powered on 73/// Runs a CPU core while the system is powered on
74void RunCpuCore(std::shared_ptr<Cpu> cpu_state) { 74void RunCpuCore(Cpu& cpu_state) {
75 while (Core::System::GetInstance().IsPoweredOn()) { 75 while (Core::System::GetInstance().IsPoweredOn()) {
76 cpu_state->RunLoop(true); 76 cpu_state.RunLoop(true);
77 } 77 }
78} 78}
79} // Anonymous namespace 79} // Anonymous namespace
@@ -95,7 +95,7 @@ struct System::Impl {
95 status = ResultStatus::Success; 95 status = ResultStatus::Success;
96 96
97 // Update thread_to_cpu in case Core 0 is run from a different host thread 97 // Update thread_to_cpu in case Core 0 is run from a different host thread
98 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0]; 98 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0].get();
99 99
100 if (GDBStub::IsServerEnabled()) { 100 if (GDBStub::IsServerEnabled()) {
101 GDBStub::HandlePacket(); 101 GDBStub::HandlePacket();
@@ -136,18 +136,19 @@ struct System::Impl {
136 if (virtual_filesystem == nullptr) 136 if (virtual_filesystem == nullptr)
137 virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); 137 virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
138 138
139 kernel.MakeCurrentProcess(Kernel::Process::Create(kernel, "main")); 139 auto main_process = Kernel::Process::Create(kernel, "main");
140 kernel.MakeCurrentProcess(main_process.get());
140 141
141 cpu_barrier = std::make_shared<CpuBarrier>(); 142 cpu_barrier = std::make_unique<CpuBarrier>();
142 cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size()); 143 cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size());
143 for (std::size_t index = 0; index < cpu_cores.size(); ++index) { 144 for (std::size_t index = 0; index < cpu_cores.size(); ++index) {
144 cpu_cores[index] = std::make_shared<Cpu>(cpu_exclusive_monitor, cpu_barrier, index); 145 cpu_cores[index] = std::make_unique<Cpu>(*cpu_exclusive_monitor, *cpu_barrier, index);
145 } 146 }
146 147
147 telemetry_session = std::make_unique<Core::TelemetrySession>(); 148 telemetry_session = std::make_unique<Core::TelemetrySession>();
148 service_manager = std::make_shared<Service::SM::ServiceManager>(); 149 service_manager = std::make_shared<Service::SM::ServiceManager>();
149 150
150 Service::Init(service_manager, virtual_filesystem); 151 Service::Init(service_manager, *virtual_filesystem);
151 GDBStub::Init(); 152 GDBStub::Init();
152 153
153 renderer = VideoCore::CreateRenderer(emu_window); 154 renderer = VideoCore::CreateRenderer(emu_window);
@@ -159,12 +160,12 @@ struct System::Impl {
159 160
160 // Create threads for CPU cores 1-3, and build thread_to_cpu map 161 // Create threads for CPU cores 1-3, and build thread_to_cpu map
161 // CPU core 0 is run on the main thread 162 // CPU core 0 is run on the main thread
162 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0]; 163 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0].get();
163 if (Settings::values.use_multi_core) { 164 if (Settings::values.use_multi_core) {
164 for (std::size_t index = 0; index < cpu_core_threads.size(); ++index) { 165 for (std::size_t index = 0; index < cpu_core_threads.size(); ++index) {
165 cpu_core_threads[index] = 166 cpu_core_threads[index] =
166 std::make_unique<std::thread>(RunCpuCore, cpu_cores[index + 1]); 167 std::make_unique<std::thread>(RunCpuCore, std::ref(*cpu_cores[index + 1]));
167 thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1]; 168 thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1].get();
168 } 169 }
169 } 170 }
170 171
@@ -244,6 +245,7 @@ struct System::Impl {
244 for (auto& cpu_core : cpu_cores) { 245 for (auto& cpu_core : cpu_cores) {
245 cpu_core.reset(); 246 cpu_core.reset();
246 } 247 }
248 cpu_exclusive_monitor.reset();
247 cpu_barrier.reset(); 249 cpu_barrier.reset();
248 250
249 // Shutdown kernel and core timing 251 // Shutdown kernel and core timing
@@ -281,9 +283,9 @@ struct System::Impl {
281 std::unique_ptr<VideoCore::RendererBase> renderer; 283 std::unique_ptr<VideoCore::RendererBase> renderer;
282 std::unique_ptr<Tegra::GPU> gpu_core; 284 std::unique_ptr<Tegra::GPU> gpu_core;
283 std::shared_ptr<Tegra::DebugContext> debug_context; 285 std::shared_ptr<Tegra::DebugContext> debug_context;
284 std::shared_ptr<ExclusiveMonitor> cpu_exclusive_monitor; 286 std::unique_ptr<ExclusiveMonitor> cpu_exclusive_monitor;
285 std::shared_ptr<CpuBarrier> cpu_barrier; 287 std::unique_ptr<CpuBarrier> cpu_barrier;
286 std::array<std::shared_ptr<Cpu>, NUM_CPU_CORES> cpu_cores; 288 std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cpu_cores;
287 std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads; 289 std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads;
288 std::size_t active_core{}; ///< Active core, only used in single thread mode 290 std::size_t active_core{}; ///< Active core, only used in single thread mode
289 291
@@ -297,7 +299,7 @@ struct System::Impl {
297 std::string status_details = ""; 299 std::string status_details = "";
298 300
299 /// Map of guest threads to CPU cores 301 /// Map of guest threads to CPU cores
300 std::map<std::thread::id, std::shared_ptr<Cpu>> thread_to_cpu; 302 std::map<std::thread::id, Cpu*> thread_to_cpu;
301 303
302 Core::PerfStats perf_stats; 304 Core::PerfStats perf_stats;
303 Core::FrameLimiter frame_limiter; 305 Core::FrameLimiter frame_limiter;
@@ -353,19 +355,22 @@ std::size_t System::CurrentCoreIndex() {
353} 355}
354 356
355Kernel::Scheduler& System::CurrentScheduler() { 357Kernel::Scheduler& System::CurrentScheduler() {
356 return *CurrentCpuCore().Scheduler(); 358 return CurrentCpuCore().Scheduler();
357} 359}
358 360
359const std::shared_ptr<Kernel::Scheduler>& System::Scheduler(std::size_t core_index) { 361Kernel::Scheduler& System::Scheduler(std::size_t core_index) {
360 ASSERT(core_index < NUM_CPU_CORES); 362 return CpuCore(core_index).Scheduler();
361 return impl->cpu_cores[core_index]->Scheduler(); 363}
364
365const Kernel::Scheduler& System::Scheduler(std::size_t core_index) const {
366 return CpuCore(core_index).Scheduler();
362} 367}
363 368
364Kernel::SharedPtr<Kernel::Process>& System::CurrentProcess() { 369Kernel::Process* System::CurrentProcess() {
365 return impl->kernel.CurrentProcess(); 370 return impl->kernel.CurrentProcess();
366} 371}
367 372
368const Kernel::SharedPtr<Kernel::Process>& System::CurrentProcess() const { 373const Kernel::Process* System::CurrentProcess() const {
369 return impl->kernel.CurrentProcess(); 374 return impl->kernel.CurrentProcess();
370} 375}
371 376
@@ -379,6 +384,11 @@ Cpu& System::CpuCore(std::size_t core_index) {
379 return *impl->cpu_cores[core_index]; 384 return *impl->cpu_cores[core_index];
380} 385}
381 386
387const Cpu& System::CpuCore(std::size_t core_index) const {
388 ASSERT(core_index < NUM_CPU_CORES);
389 return *impl->cpu_cores[core_index];
390}
391
382ExclusiveMonitor& System::Monitor() { 392ExclusiveMonitor& System::Monitor() {
383 return *impl->cpu_exclusive_monitor; 393 return *impl->cpu_exclusive_monitor;
384} 394}
diff --git a/src/core/core.h b/src/core/core.h
index f9a3e97e3..173be45f8 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -156,6 +156,9 @@ public:
156 /// Gets a CPU interface to the CPU core with the specified index 156 /// Gets a CPU interface to the CPU core with the specified index
157 Cpu& CpuCore(std::size_t core_index); 157 Cpu& CpuCore(std::size_t core_index);
158 158
159 /// Gets a CPU interface to the CPU core with the specified index
160 const Cpu& CpuCore(std::size_t core_index) const;
161
159 /// Gets the exclusive monitor 162 /// Gets the exclusive monitor
160 ExclusiveMonitor& Monitor(); 163 ExclusiveMonitor& Monitor();
161 164
@@ -172,13 +175,16 @@ public:
172 const VideoCore::RendererBase& Renderer() const; 175 const VideoCore::RendererBase& Renderer() const;
173 176
174 /// Gets the scheduler for the CPU core with the specified index 177 /// Gets the scheduler for the CPU core with the specified index
175 const std::shared_ptr<Kernel::Scheduler>& Scheduler(std::size_t core_index); 178 Kernel::Scheduler& Scheduler(std::size_t core_index);
179
180 /// Gets the scheduler for the CPU core with the specified index
181 const Kernel::Scheduler& Scheduler(std::size_t core_index) const;
176 182
177 /// Provides a reference to the current process 183 /// Provides a pointer to the current process
178 Kernel::SharedPtr<Kernel::Process>& CurrentProcess(); 184 Kernel::Process* CurrentProcess();
179 185
180 /// Provides a constant reference to the current process. 186 /// Provides a constant pointer to the current process.
181 const Kernel::SharedPtr<Kernel::Process>& CurrentProcess() const; 187 const Kernel::Process* CurrentProcess() const;
182 188
183 /// Provides a reference to the kernel instance. 189 /// Provides a reference to the kernel instance.
184 Kernel::KernelCore& Kernel(); 190 Kernel::KernelCore& Kernel();
@@ -246,7 +252,7 @@ inline TelemetrySession& Telemetry() {
246 return System::GetInstance().TelemetrySession(); 252 return System::GetInstance().TelemetrySession();
247} 253}
248 254
249inline Kernel::SharedPtr<Kernel::Process>& CurrentProcess() { 255inline Kernel::Process* CurrentProcess() {
250 return System::GetInstance().CurrentProcess(); 256 return System::GetInstance().CurrentProcess();
251} 257}
252 258
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp
index 265f8ed9c..fffda8a99 100644
--- a/src/core/core_cpu.cpp
+++ b/src/core/core_cpu.cpp
@@ -49,10 +49,8 @@ bool CpuBarrier::Rendezvous() {
49 return false; 49 return false;
50} 50}
51 51
52Cpu::Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, 52Cpu::Cpu(ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier, std::size_t core_index)
53 std::shared_ptr<CpuBarrier> cpu_barrier, std::size_t core_index) 53 : cpu_barrier{cpu_barrier}, core_index{core_index} {
54 : cpu_barrier{std::move(cpu_barrier)}, core_index{core_index} {
55
56 if (Settings::values.use_cpu_jit) { 54 if (Settings::values.use_cpu_jit) {
57#ifdef ARCHITECTURE_x86_64 55#ifdef ARCHITECTURE_x86_64
58 arm_interface = std::make_unique<ARM_Dynarmic>(exclusive_monitor, core_index); 56 arm_interface = std::make_unique<ARM_Dynarmic>(exclusive_monitor, core_index);
@@ -64,15 +62,15 @@ Cpu::Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor,
64 arm_interface = std::make_unique<ARM_Unicorn>(); 62 arm_interface = std::make_unique<ARM_Unicorn>();
65 } 63 }
66 64
67 scheduler = std::make_shared<Kernel::Scheduler>(*arm_interface); 65 scheduler = std::make_unique<Kernel::Scheduler>(*arm_interface);
68} 66}
69 67
70Cpu::~Cpu() = default; 68Cpu::~Cpu() = default;
71 69
72std::shared_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) { 70std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_cores) {
73 if (Settings::values.use_cpu_jit) { 71 if (Settings::values.use_cpu_jit) {
74#ifdef ARCHITECTURE_x86_64 72#ifdef ARCHITECTURE_x86_64
75 return std::make_shared<DynarmicExclusiveMonitor>(num_cores); 73 return std::make_unique<DynarmicExclusiveMonitor>(num_cores);
76#else 74#else
77 return nullptr; // TODO(merry): Passthrough exclusive monitor 75 return nullptr; // TODO(merry): Passthrough exclusive monitor
78#endif 76#endif
@@ -83,7 +81,7 @@ std::shared_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(std::size_t num_core
83 81
84void Cpu::RunLoop(bool tight_loop) { 82void Cpu::RunLoop(bool tight_loop) {
85 // Wait for all other CPU cores to complete the previous slice, such that they run in lock-step 83 // Wait for all other CPU cores to complete the previous slice, such that they run in lock-step
86 if (!cpu_barrier->Rendezvous()) { 84 if (!cpu_barrier.Rendezvous()) {
87 // If rendezvous failed, session has been killed 85 // If rendezvous failed, session has been killed
88 return; 86 return;
89 } 87 }
diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h
index ee7e04abc..1d2bdc6cd 100644
--- a/src/core/core_cpu.h
+++ b/src/core/core_cpu.h
@@ -41,8 +41,7 @@ private:
41 41
42class Cpu { 42class Cpu {
43public: 43public:
44 Cpu(std::shared_ptr<ExclusiveMonitor> exclusive_monitor, 44 Cpu(ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier, std::size_t core_index);
45 std::shared_ptr<CpuBarrier> cpu_barrier, std::size_t core_index);
46 ~Cpu(); 45 ~Cpu();
47 46
48 void RunLoop(bool tight_loop = true); 47 void RunLoop(bool tight_loop = true);
@@ -59,8 +58,12 @@ public:
59 return *arm_interface; 58 return *arm_interface;
60 } 59 }
61 60
62 const std::shared_ptr<Kernel::Scheduler>& Scheduler() const { 61 Kernel::Scheduler& Scheduler() {
63 return scheduler; 62 return *scheduler;
63 }
64
65 const Kernel::Scheduler& Scheduler() const {
66 return *scheduler;
64 } 67 }
65 68
66 bool IsMainCore() const { 69 bool IsMainCore() const {
@@ -71,14 +74,14 @@ public:
71 return core_index; 74 return core_index;
72 } 75 }
73 76
74 static std::shared_ptr<ExclusiveMonitor> MakeExclusiveMonitor(std::size_t num_cores); 77 static std::unique_ptr<ExclusiveMonitor> MakeExclusiveMonitor(std::size_t num_cores);
75 78
76private: 79private:
77 void Reschedule(); 80 void Reschedule();
78 81
79 std::unique_ptr<ARM_Interface> arm_interface; 82 std::unique_ptr<ARM_Interface> arm_interface;
80 std::shared_ptr<CpuBarrier> cpu_barrier; 83 CpuBarrier& cpu_barrier;
81 std::shared_ptr<Kernel::Scheduler> scheduler; 84 std::unique_ptr<Kernel::Scheduler> scheduler;
82 85
83 std::atomic<bool> reschedule_pending = false; 86 std::atomic<bool> reschedule_pending = false;
84 std::size_t core_index; 87 std::size_t core_index;
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index bf3a70944..fd0786068 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -4,23 +4,56 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <array> 6#include <array>
7#include <bitset>
8#include <cctype>
7#include <fstream> 9#include <fstream>
8#include <locale> 10#include <locale>
11#include <map>
9#include <sstream> 12#include <sstream>
10#include <string_view> 13#include <string_view>
11#include <tuple> 14#include <tuple>
12#include <vector> 15#include <vector>
16#include <mbedtls/bignum.h>
17#include <mbedtls/cipher.h>
18#include <mbedtls/cmac.h>
19#include <mbedtls/sha256.h>
20#include "common/common_funcs.h"
13#include "common/common_paths.h" 21#include "common/common_paths.h"
14#include "common/file_util.h" 22#include "common/file_util.h"
15#include "common/hex_util.h" 23#include "common/hex_util.h"
16#include "common/logging/log.h" 24#include "common/logging/log.h"
17#include "core/crypto/aes_util.h" 25#include "core/crypto/aes_util.h"
18#include "core/crypto/key_manager.h" 26#include "core/crypto/key_manager.h"
27#include "core/crypto/partition_data_manager.h"
28#include "core/file_sys/content_archive.h"
29#include "core/file_sys/nca_metadata.h"
30#include "core/file_sys/partition_filesystem.h"
31#include "core/file_sys/registered_cache.h"
32#include "core/hle/service/filesystem/filesystem.h"
19#include "core/loader/loader.h" 33#include "core/loader/loader.h"
20#include "core/settings.h" 34#include "core/settings.h"
21 35
22namespace Core::Crypto { 36namespace Core::Crypto {
23 37
38constexpr u64 CURRENT_CRYPTO_REVISION = 0x5;
39
40using namespace Common;
41
42const std::array<SHA256Hash, 2> eticket_source_hashes{
43 "B71DB271DC338DF380AA2C4335EF8873B1AFD408E80B3582D8719FC81C5E511C"_array32, // eticket_rsa_kek_source
44 "E8965A187D30E57869F562D04383C996DE487BBA5761363D2D4D32391866A85C"_array32, // eticket_rsa_kekek_source
45};
46
47const std::map<std::pair<S128KeyType, u64>, std::string> KEYS_VARIABLE_LENGTH{
48 {{S128KeyType::Master, 0}, "master_key_"},
49 {{S128KeyType::Package1, 0}, "package1_key_"},
50 {{S128KeyType::Package2, 0}, "package2_key_"},
51 {{S128KeyType::Titlekek, 0}, "titlekek_"},
52 {{S128KeyType::Source, static_cast<u64>(SourceKeyType::Keyblob)}, "keyblob_key_source_"},
53 {{S128KeyType::Keyblob, 0}, "keyblob_key_"},
54 {{S128KeyType::KeyblobMAC, 0}, "keyblob_mac_key_"},
55};
56
24Key128 GenerateKeyEncryptionKey(Key128 source, Key128 master, Key128 kek_seed, Key128 key_seed) { 57Key128 GenerateKeyEncryptionKey(Key128 source, Key128 master, Key128 kek_seed, Key128 key_seed) {
25 Key128 out{}; 58 Key128 out{};
26 59
@@ -37,57 +70,136 @@ Key128 GenerateKeyEncryptionKey(Key128 source, Key128 master, Key128 kek_seed, K
37 return out; 70 return out;
38} 71}
39 72
73Key128 DeriveKeyblobKey(const Key128& sbk, const Key128& tsec, Key128 source) {
74 AESCipher<Key128> sbk_cipher(sbk, Mode::ECB);
75 AESCipher<Key128> tsec_cipher(tsec, Mode::ECB);
76 tsec_cipher.Transcode(source.data(), source.size(), source.data(), Op::Decrypt);
77 sbk_cipher.Transcode(source.data(), source.size(), source.data(), Op::Decrypt);
78 return source;
79}
80
81Key128 DeriveMasterKey(const std::array<u8, 0x90>& keyblob, const Key128& master_source) {
82 Key128 master_root;
83 std::memcpy(master_root.data(), keyblob.data(), sizeof(Key128));
84
85 AESCipher<Key128> master_cipher(master_root, Mode::ECB);
86
87 Key128 master{};
88 master_cipher.Transcode(master_source.data(), master_source.size(), master.data(), Op::Decrypt);
89 return master;
90}
91
92std::array<u8, 144> DecryptKeyblob(const std::array<u8, 176>& encrypted_keyblob,
93 const Key128& key) {
94 std::array<u8, 0x90> keyblob;
95 AESCipher<Key128> cipher(key, Mode::CTR);
96 cipher.SetIV(std::vector<u8>(encrypted_keyblob.data() + 0x10, encrypted_keyblob.data() + 0x20));
97 cipher.Transcode(encrypted_keyblob.data() + 0x20, keyblob.size(), keyblob.data(), Op::Decrypt);
98 return keyblob;
99}
100
101void KeyManager::DeriveGeneralPurposeKeys(std::size_t crypto_revision) {
102 const auto kek_generation_source =
103 GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration));
104 const auto key_generation_source =
105 GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration));
106
107 if (HasKey(S128KeyType::Master, crypto_revision)) {
108 for (auto kak_type :
109 {KeyAreaKeyType::Application, KeyAreaKeyType::Ocean, KeyAreaKeyType::System}) {
110 if (HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
111 static_cast<u64>(kak_type))) {
112 const auto source =
113 GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
114 static_cast<u64>(kak_type));
115 const auto kek =
116 GenerateKeyEncryptionKey(source, GetKey(S128KeyType::Master, crypto_revision),
117 kek_generation_source, key_generation_source);
118 SetKey(S128KeyType::KeyArea, kek, crypto_revision, static_cast<u64>(kak_type));
119 }
120 }
121
122 AESCipher<Key128> master_cipher(GetKey(S128KeyType::Master, crypto_revision), Mode::ECB);
123 for (auto key_type : {SourceKeyType::Titlekek, SourceKeyType::Package2}) {
124 if (HasKey(S128KeyType::Source, static_cast<u64>(key_type))) {
125 Key128 key{};
126 master_cipher.Transcode(
127 GetKey(S128KeyType::Source, static_cast<u64>(key_type)).data(), key.size(),
128 key.data(), Op::Decrypt);
129 SetKey(key_type == SourceKeyType::Titlekek ? S128KeyType::Titlekek
130 : S128KeyType::Package2,
131 key, crypto_revision);
132 }
133 }
134 }
135}
136
137Key128 DeriveKeyblobMACKey(const Key128& keyblob_key, const Key128& mac_source) {
138 AESCipher<Key128> mac_cipher(keyblob_key, Mode::ECB);
139 Key128 mac_key{};
140 mac_cipher.Transcode(mac_source.data(), mac_key.size(), mac_key.data(), Op::Decrypt);
141 return mac_key;
142}
143
40boost::optional<Key128> DeriveSDSeed() { 144boost::optional<Key128> DeriveSDSeed() {
41 const FileUtil::IOFile save_43(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + 145 const FileUtil::IOFile save_43(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
42 "/system/save/8000000000000043", 146 "/system/save/8000000000000043",
43 "rb+"); 147 "rb+");
44 if (!save_43.IsOpen()) 148 if (!save_43.IsOpen())
45 return boost::none; 149 return boost::none;
150
46 const FileUtil::IOFile sd_private( 151 const FileUtil::IOFile sd_private(
47 FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) + "/Nintendo/Contents/private", "rb+"); 152 FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) + "/Nintendo/Contents/private", "rb+");
48 if (!sd_private.IsOpen()) 153 if (!sd_private.IsOpen())
49 return boost::none; 154 return boost::none;
50 155
51 sd_private.Seek(0, SEEK_SET);
52 std::array<u8, 0x10> private_seed{}; 156 std::array<u8, 0x10> private_seed{};
53 if (sd_private.ReadBytes(private_seed.data(), private_seed.size()) != 0x10) 157 if (sd_private.ReadBytes(private_seed.data(), private_seed.size()) != private_seed.size()) {
54 return boost::none; 158 return boost::none;
159 }
55 160
56 std::array<u8, 0x10> buffer{}; 161 std::array<u8, 0x10> buffer{};
57 std::size_t offset = 0; 162 std::size_t offset = 0;
58 for (; offset + 0x10 < save_43.GetSize(); ++offset) { 163 for (; offset + 0x10 < save_43.GetSize(); ++offset) {
59 save_43.Seek(offset, SEEK_SET); 164 if (!save_43.Seek(offset, SEEK_SET)) {
165 return boost::none;
166 }
167
60 save_43.ReadBytes(buffer.data(), buffer.size()); 168 save_43.ReadBytes(buffer.data(), buffer.size());
61 if (buffer == private_seed) 169 if (buffer == private_seed) {
62 break; 170 break;
171 }
63 } 172 }
64 173
65 if (offset + 0x10 >= save_43.GetSize()) 174 if (!save_43.Seek(offset + 0x10, SEEK_SET)) {
66 return boost::none; 175 return boost::none;
176 }
67 177
68 Key128 seed{}; 178 Key128 seed{};
69 save_43.Seek(offset + 0x10, SEEK_SET); 179 if (save_43.ReadBytes(seed.data(), seed.size()) != seed.size()) {
70 save_43.ReadBytes(seed.data(), seed.size()); 180 return boost::none;
181 }
71 return seed; 182 return seed;
72} 183}
73 184
74Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, const KeyManager& keys) { 185Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& keys) {
75 if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKEK))) 186 if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek)))
76 return Loader::ResultStatus::ErrorMissingSDKEKSource; 187 return Loader::ResultStatus::ErrorMissingSDKEKSource;
77 if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKEKGeneration))) 188 if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration)))
78 return Loader::ResultStatus::ErrorMissingAESKEKGenerationSource; 189 return Loader::ResultStatus::ErrorMissingAESKEKGenerationSource;
79 if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration))) 190 if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration)))
80 return Loader::ResultStatus::ErrorMissingAESKeyGenerationSource; 191 return Loader::ResultStatus::ErrorMissingAESKeyGenerationSource;
81 192
82 const auto sd_kek_source = 193 const auto sd_kek_source =
83 keys.GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKEK)); 194 keys.GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek));
84 const auto aes_kek_gen = 195 const auto aes_kek_gen =
85 keys.GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKEKGeneration)); 196 keys.GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration));
86 const auto aes_key_gen = 197 const auto aes_key_gen =
87 keys.GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration)); 198 keys.GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration));
88 const auto master_00 = keys.GetKey(S128KeyType::Master); 199 const auto master_00 = keys.GetKey(S128KeyType::Master);
89 const auto sd_kek = 200 const auto sd_kek =
90 GenerateKeyEncryptionKey(sd_kek_source, master_00, aes_kek_gen, aes_key_gen); 201 GenerateKeyEncryptionKey(sd_kek_source, master_00, aes_kek_gen, aes_key_gen);
202 keys.SetKey(S128KeyType::SDKek, sd_kek);
91 203
92 if (!keys.HasKey(S128KeyType::SDSeed)) 204 if (!keys.HasKey(S128KeyType::SDSeed))
93 return Loader::ResultStatus::ErrorMissingSDSeed; 205 return Loader::ResultStatus::ErrorMissingSDSeed;
@@ -118,9 +230,147 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, const KeyManag
118 return source; ///< Return unaltered source to satisfy output requirement. 230 return source; ///< Return unaltered source to satisfy output requirement.
119 }); 231 });
120 232
233 keys.SetKey(S256KeyType::SDKey, sd_keys[0], static_cast<u64>(SDKeyType::Save));
234 keys.SetKey(S256KeyType::SDKey, sd_keys[1], static_cast<u64>(SDKeyType::NCA));
235
121 return Loader::ResultStatus::Success; 236 return Loader::ResultStatus::Success;
122} 237}
123 238
239std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save) {
240 if (!ticket_save.IsOpen())
241 return {};
242
243 std::vector<u8> buffer(ticket_save.GetSize());
244 if (ticket_save.ReadBytes(buffer.data(), buffer.size()) != buffer.size()) {
245 return {};
246 }
247
248 std::vector<TicketRaw> out;
249 u32 magic{};
250 for (std::size_t offset = 0; offset + 0x4 < buffer.size(); ++offset) {
251 if (buffer[offset] == 0x4 && buffer[offset + 1] == 0x0 && buffer[offset + 2] == 0x1 &&
252 buffer[offset + 3] == 0x0) {
253 out.emplace_back();
254 auto& next = out.back();
255 std::memcpy(&next, buffer.data() + offset, sizeof(TicketRaw));
256 offset += next.size();
257 }
258 }
259
260 return out;
261}
262
263template <size_t size>
264static std::array<u8, size> operator^(const std::array<u8, size>& lhs,
265 const std::array<u8, size>& rhs) {
266 std::array<u8, size> out{};
267 std::transform(lhs.begin(), lhs.end(), rhs.begin(), out.begin(), std::bit_xor<>());
268 return out;
269}
270
271template <size_t target_size, size_t in_size>
272static std::array<u8, target_size> MGF1(const std::array<u8, in_size>& seed) {
273 // Avoids truncation overflow within the loop below.
274 static_assert(target_size <= 0xFF);
275
276 std::array<u8, in_size + 4> seed_exp{};
277 std::memcpy(seed_exp.data(), seed.data(), in_size);
278
279 std::vector<u8> out;
280 size_t i = 0;
281 while (out.size() < target_size) {
282 out.resize(out.size() + 0x20);
283 seed_exp[in_size + 3] = static_cast<u8>(i);
284 mbedtls_sha256(seed_exp.data(), seed_exp.size(), out.data() + out.size() - 0x20, 0);
285 ++i;
286 }
287
288 std::array<u8, target_size> target;
289 std::memcpy(target.data(), out.data(), target_size);
290 return target;
291}
292
293template <size_t size>
294static boost::optional<u64> FindTicketOffset(const std::array<u8, size>& data) {
295 u64 offset = 0;
296 for (size_t i = 0x20; i < data.size() - 0x10; ++i) {
297 if (data[i] == 0x1) {
298 offset = i + 1;
299 break;
300 } else if (data[i] != 0x0) {
301 return boost::none;
302 }
303 }
304
305 return offset;
306}
307
308boost::optional<std::pair<Key128, Key128>> ParseTicket(const TicketRaw& ticket,
309 const RSAKeyPair<2048>& key) {
310 u32 cert_authority;
311 std::memcpy(&cert_authority, ticket.data() + 0x140, sizeof(cert_authority));
312 if (cert_authority == 0)
313 return boost::none;
314 if (cert_authority != Common::MakeMagic('R', 'o', 'o', 't')) {
315 LOG_INFO(Crypto,
316 "Attempting to parse ticket with non-standard certificate authority {:08X}.",
317 cert_authority);
318 }
319
320 Key128 rights_id;
321 std::memcpy(rights_id.data(), ticket.data() + 0x2A0, sizeof(Key128));
322
323 if (rights_id == Key128{})
324 return boost::none;
325
326 Key128 key_temp{};
327
328 if (!std::any_of(ticket.begin() + 0x190, ticket.begin() + 0x280, [](u8 b) { return b != 0; })) {
329 std::memcpy(key_temp.data(), ticket.data() + 0x180, key_temp.size());
330 return std::make_pair(rights_id, key_temp);
331 }
332
333 mbedtls_mpi D; // RSA Private Exponent
334 mbedtls_mpi N; // RSA Modulus
335 mbedtls_mpi S; // Input
336 mbedtls_mpi M; // Output
337
338 mbedtls_mpi_init(&D);
339 mbedtls_mpi_init(&N);
340 mbedtls_mpi_init(&S);
341 mbedtls_mpi_init(&M);
342
343 mbedtls_mpi_read_binary(&D, key.decryption_key.data(), key.decryption_key.size());
344 mbedtls_mpi_read_binary(&N, key.modulus.data(), key.modulus.size());
345 mbedtls_mpi_read_binary(&S, ticket.data() + 0x180, 0x100);
346
347 mbedtls_mpi_exp_mod(&M, &S, &D, &N, nullptr);
348
349 std::array<u8, 0x100> rsa_step;
350 mbedtls_mpi_write_binary(&M, rsa_step.data(), rsa_step.size());
351
352 u8 m_0 = rsa_step[0];
353 std::array<u8, 0x20> m_1;
354 std::memcpy(m_1.data(), rsa_step.data() + 0x01, m_1.size());
355 std::array<u8, 0xDF> m_2;
356 std::memcpy(m_2.data(), rsa_step.data() + 0x21, m_2.size());
357
358 if (m_0 != 0)
359 return boost::none;
360
361 m_1 = m_1 ^ MGF1<0x20>(m_2);
362 m_2 = m_2 ^ MGF1<0xDF>(m_1);
363
364 const auto offset = FindTicketOffset(m_2);
365 if (offset == boost::none)
366 return boost::none;
367 ASSERT(offset.get() > 0);
368
369 std::memcpy(key_temp.data(), m_2.data() + offset.get(), key_temp.size());
370
371 return std::make_pair(rights_id, key_temp);
372}
373
124KeyManager::KeyManager() { 374KeyManager::KeyManager() {
125 // Initialize keys 375 // Initialize keys
126 const std::string hactool_keys_dir = FileUtil::GetHactoolConfigurationPath(); 376 const std::string hactool_keys_dir = FileUtil::GetHactoolConfigurationPath();
@@ -137,6 +387,15 @@ KeyManager::KeyManager() {
137 387
138 AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "title.keys", true); 388 AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "title.keys", true);
139 AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, "title.keys_autogenerated", true); 389 AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, "title.keys_autogenerated", true);
390 AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "console.keys", false);
391 AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, "console.keys_autogenerated", false);
392}
393
394static bool ValidCryptoRevisionString(std::string_view base, size_t begin, size_t length) {
395 if (base.size() < begin + length)
396 return false;
397 return std::all_of(base.begin() + begin, base.begin() + begin + length,
398 [](u8 c) { return std::isdigit(c); });
140} 399}
141 400
142void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) { 401void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
@@ -158,6 +417,9 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
158 out[0].erase(std::remove(out[0].begin(), out[0].end(), ' '), out[0].end()); 417 out[0].erase(std::remove(out[0].begin(), out[0].end(), ' '), out[0].end());
159 out[1].erase(std::remove(out[1].begin(), out[1].end(), ' '), out[1].end()); 418 out[1].erase(std::remove(out[1].begin(), out[1].end(), ' '), out[1].end());
160 419
420 if (out[0].compare(0, 1, "#") == 0)
421 continue;
422
161 if (is_title_keys) { 423 if (is_title_keys) {
162 auto rights_id_raw = Common::HexStringToArray<16>(out[0]); 424 auto rights_id_raw = Common::HexStringToArray<16>(out[0]);
163 u128 rights_id{}; 425 u128 rights_id{};
@@ -174,6 +436,50 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
174 const auto index = s256_file_id.at(out[0]); 436 const auto index = s256_file_id.at(out[0]);
175 Key256 key = Common::HexStringToArray<32>(out[1]); 437 Key256 key = Common::HexStringToArray<32>(out[1]);
176 s256_keys[{index.type, index.field1, index.field2}] = key; 438 s256_keys[{index.type, index.field1, index.field2}] = key;
439 } else if (out[0].compare(0, 8, "keyblob_") == 0 &&
440 out[0].compare(0, 9, "keyblob_k") != 0) {
441 if (!ValidCryptoRevisionString(out[0], 8, 2))
442 continue;
443
444 const auto index = std::stoul(out[0].substr(8, 2), nullptr, 16);
445 keyblobs[index] = Common::HexStringToArray<0x90>(out[1]);
446 } else if (out[0].compare(0, 18, "encrypted_keyblob_") == 0) {
447 if (!ValidCryptoRevisionString(out[0], 18, 2))
448 continue;
449
450 const auto index = std::stoul(out[0].substr(18, 2), nullptr, 16);
451 encrypted_keyblobs[index] = Common::HexStringToArray<0xB0>(out[1]);
452 } else {
453 for (const auto& kv : KEYS_VARIABLE_LENGTH) {
454 if (!ValidCryptoRevisionString(out[0], kv.second.size(), 2))
455 continue;
456 if (out[0].compare(0, kv.second.size(), kv.second) == 0) {
457 const auto index =
458 std::stoul(out[0].substr(kv.second.size(), 2), nullptr, 16);
459 const auto sub = kv.first.second;
460 if (sub == 0) {
461 s128_keys[{kv.first.first, index, 0}] =
462 Common::HexStringToArray<16>(out[1]);
463 } else {
464 s128_keys[{kv.first.first, kv.first.second, index}] =
465 Common::HexStringToArray<16>(out[1]);
466 }
467
468 break;
469 }
470 }
471
472 static constexpr std::array<const char*, 3> kak_names = {
473 "key_area_key_application_", "key_area_key_ocean_", "key_area_key_system_"};
474 for (size_t j = 0; j < kak_names.size(); ++j) {
475 const auto& match = kak_names[j];
476 if (out[0].compare(0, std::strlen(match), match) == 0) {
477 const auto index =
478 std::stoul(out[0].substr(std::strlen(match), 2), nullptr, 16);
479 s128_keys[{S128KeyType::KeyArea, index, j}] =
480 Common::HexStringToArray<16>(out[1]);
481 }
482 }
177 } 483 }
178 } 484 }
179 } 485 }
@@ -187,6 +493,28 @@ void KeyManager::AttemptLoadKeyFile(const std::string& dir1, const std::string&
187 LoadFromFile(dir2 + DIR_SEP + filename, title); 493 LoadFromFile(dir2 + DIR_SEP + filename, title);
188} 494}
189 495
496bool KeyManager::BaseDeriveNecessary() const {
497 const auto check_key_existence = [this](auto key_type, u64 index1 = 0, u64 index2 = 0) {
498 return !HasKey(key_type, index1, index2);
499 };
500
501 if (check_key_existence(S256KeyType::Header))
502 return true;
503
504 for (size_t i = 0; i < CURRENT_CRYPTO_REVISION; ++i) {
505 if (check_key_existence(S128KeyType::Master, i) ||
506 check_key_existence(S128KeyType::KeyArea, i,
507 static_cast<u64>(KeyAreaKeyType::Application)) ||
508 check_key_existence(S128KeyType::KeyArea, i, static_cast<u64>(KeyAreaKeyType::Ocean)) ||
509 check_key_existence(S128KeyType::KeyArea, i,
510 static_cast<u64>(KeyAreaKeyType::System)) ||
511 check_key_existence(S128KeyType::Titlekek, i))
512 return true;
513 }
514
515 return false;
516}
517
190bool KeyManager::HasKey(S128KeyType id, u64 field1, u64 field2) const { 518bool KeyManager::HasKey(S128KeyType id, u64 field1, u64 field2) const {
191 return s128_keys.find({id, field1, field2}) != s128_keys.end(); 519 return s128_keys.find({id, field1, field2}) != s128_keys.end();
192} 520}
@@ -207,13 +535,30 @@ Key256 KeyManager::GetKey(S256KeyType id, u64 field1, u64 field2) const {
207 return s256_keys.at({id, field1, field2}); 535 return s256_keys.at({id, field1, field2});
208} 536}
209 537
210template <std::size_t Size> 538Key256 KeyManager::GetBISKey(u8 partition_id) const {
211void KeyManager::WriteKeyToFile(bool title_key, std::string_view keyname, 539 Key256 out{};
540
541 for (const auto& bis_type : {BISKeyType::Crypto, BISKeyType::Tweak}) {
542 if (HasKey(S128KeyType::BIS, partition_id, static_cast<u64>(bis_type))) {
543 std::memcpy(
544 out.data() + sizeof(Key128) * static_cast<u64>(bis_type),
545 s128_keys.at({S128KeyType::BIS, partition_id, static_cast<u64>(bis_type)}).data(),
546 sizeof(Key128));
547 }
548 }
549
550 return out;
551}
552
553template <size_t Size>
554void KeyManager::WriteKeyToFile(KeyCategory category, std::string_view keyname,
212 const std::array<u8, Size>& key) { 555 const std::array<u8, Size>& key) {
213 const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir); 556 const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir);
214 std::string filename = "title.keys_autogenerated"; 557 std::string filename = "title.keys_autogenerated";
215 if (!title_key) 558 if (category == KeyCategory::Standard)
216 filename = dev_mode ? "dev.keys_autogenerated" : "prod.keys_autogenerated"; 559 filename = dev_mode ? "dev.keys_autogenerated" : "prod.keys_autogenerated";
560 else if (category == KeyCategory::Console)
561 filename = "console.keys_autogenerated";
217 const auto add_info_text = !FileUtil::Exists(yuzu_keys_dir + DIR_SEP + filename); 562 const auto add_info_text = !FileUtil::Exists(yuzu_keys_dir + DIR_SEP + filename);
218 FileUtil::CreateFullPath(yuzu_keys_dir + DIR_SEP + filename); 563 FileUtil::CreateFullPath(yuzu_keys_dir + DIR_SEP + filename);
219 std::ofstream file(yuzu_keys_dir + DIR_SEP + filename, std::ios::app); 564 std::ofstream file(yuzu_keys_dir + DIR_SEP + filename, std::ios::app);
@@ -227,7 +572,7 @@ void KeyManager::WriteKeyToFile(bool title_key, std::string_view keyname,
227 } 572 }
228 573
229 file << fmt::format("\n{} = {}", keyname, Common::HexArrayToString(key)); 574 file << fmt::format("\n{} = {}", keyname, Common::HexArrayToString(key));
230 AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, filename, title_key); 575 AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, filename, category == KeyCategory::Title);
231} 576}
232 577
233void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) { 578void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
@@ -237,8 +582,15 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
237 Key128 rights_id; 582 Key128 rights_id;
238 std::memcpy(rights_id.data(), &field2, sizeof(u64)); 583 std::memcpy(rights_id.data(), &field2, sizeof(u64));
239 std::memcpy(rights_id.data() + sizeof(u64), &field1, sizeof(u64)); 584 std::memcpy(rights_id.data() + sizeof(u64), &field1, sizeof(u64));
240 WriteKeyToFile(true, Common::HexArrayToString(rights_id), key); 585 WriteKeyToFile(KeyCategory::Title, Common::HexArrayToString(rights_id), key);
241 } 586 }
587
588 auto category = KeyCategory::Standard;
589 if (id == S128KeyType::Keyblob || id == S128KeyType::KeyblobMAC || id == S128KeyType::TSEC ||
590 id == S128KeyType::SecureBoot || id == S128KeyType::SDSeed || id == S128KeyType::BIS) {
591 category = KeyCategory::Console;
592 }
593
242 const auto iter2 = std::find_if( 594 const auto iter2 = std::find_if(
243 s128_file_id.begin(), s128_file_id.end(), 595 s128_file_id.begin(), s128_file_id.end(),
244 [&id, &field1, &field2](const std::pair<std::string, KeyIndex<S128KeyType>> elem) { 596 [&id, &field1, &field2](const std::pair<std::string, KeyIndex<S128KeyType>> elem) {
@@ -246,7 +598,30 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
246 std::tie(id, field1, field2); 598 std::tie(id, field1, field2);
247 }); 599 });
248 if (iter2 != s128_file_id.end()) 600 if (iter2 != s128_file_id.end())
249 WriteKeyToFile(false, iter2->first, key); 601 WriteKeyToFile(category, iter2->first, key);
602
603 // Variable cases
604 if (id == S128KeyType::KeyArea) {
605 static constexpr std::array<const char*, 3> kak_names = {"key_area_key_application_{:02X}",
606 "key_area_key_ocean_{:02X}",
607 "key_area_key_system_{:02X}"};
608 WriteKeyToFile(category, fmt::format(kak_names.at(field2), field1), key);
609 } else if (id == S128KeyType::Master) {
610 WriteKeyToFile(category, fmt::format("master_key_{:02X}", field1), key);
611 } else if (id == S128KeyType::Package1) {
612 WriteKeyToFile(category, fmt::format("package1_key_{:02X}", field1), key);
613 } else if (id == S128KeyType::Package2) {
614 WriteKeyToFile(category, fmt::format("package2_key_{:02X}", field1), key);
615 } else if (id == S128KeyType::Titlekek) {
616 WriteKeyToFile(category, fmt::format("titlekek_{:02X}", field1), key);
617 } else if (id == S128KeyType::Keyblob) {
618 WriteKeyToFile(category, fmt::format("keyblob_key_{:02X}", field1), key);
619 } else if (id == S128KeyType::KeyblobMAC) {
620 WriteKeyToFile(category, fmt::format("keyblob_mac_key_{:02X}", field1), key);
621 } else if (id == S128KeyType::Source && field1 == static_cast<u64>(SourceKeyType::Keyblob)) {
622 WriteKeyToFile(category, fmt::format("keyblob_key_source_{:02X}", field2), key);
623 }
624
250 s128_keys[{id, field1, field2}] = key; 625 s128_keys[{id, field1, field2}] = key;
251} 626}
252 627
@@ -260,7 +635,7 @@ void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) {
260 std::tie(id, field1, field2); 635 std::tie(id, field1, field2);
261 }); 636 });
262 if (iter != s256_file_id.end()) 637 if (iter != s256_file_id.end())
263 WriteKeyToFile(false, iter->first, key); 638 WriteKeyToFile(KeyCategory::Standard, iter->first, key);
264 s256_keys[{id, field1, field2}] = key; 639 s256_keys[{id, field1, field2}] = key;
265} 640}
266 641
@@ -290,59 +665,388 @@ void KeyManager::DeriveSDSeedLazy() {
290 SetKey(S128KeyType::SDSeed, res.get()); 665 SetKey(S128KeyType::SDSeed, res.get());
291} 666}
292 667
668static Key128 CalculateCMAC(const u8* source, size_t size, const Key128& key) {
669 Key128 out{};
670
671 mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), key.data(),
672 key.size() * 8, source, size, out.data());
673 return out;
674}
675
676void KeyManager::DeriveBase() {
677 if (!BaseDeriveNecessary())
678 return;
679
680 if (!HasKey(S128KeyType::SecureBoot) || !HasKey(S128KeyType::TSEC))
681 return;
682
683 const auto has_bis = [this](u64 id) {
684 return HasKey(S128KeyType::BIS, id, static_cast<u64>(BISKeyType::Crypto)) &&
685 HasKey(S128KeyType::BIS, id, static_cast<u64>(BISKeyType::Tweak));
686 };
687
688 const auto copy_bis = [this](u64 id_from, u64 id_to) {
689 SetKey(S128KeyType::BIS,
690 GetKey(S128KeyType::BIS, id_from, static_cast<u64>(BISKeyType::Crypto)), id_to,
691 static_cast<u64>(BISKeyType::Crypto));
692
693 SetKey(S128KeyType::BIS,
694 GetKey(S128KeyType::BIS, id_from, static_cast<u64>(BISKeyType::Tweak)), id_to,
695 static_cast<u64>(BISKeyType::Tweak));
696 };
697
698 if (has_bis(2) && !has_bis(3))
699 copy_bis(2, 3);
700 else if (has_bis(3) && !has_bis(2))
701 copy_bis(3, 2);
702
703 std::bitset<32> revisions(0xFFFFFFFF);
704 for (size_t i = 0; i < revisions.size(); ++i) {
705 if (!HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::Keyblob), i) ||
706 encrypted_keyblobs[i] == std::array<u8, 0xB0>{}) {
707 revisions.reset(i);
708 }
709 }
710
711 if (!revisions.any())
712 return;
713
714 const auto sbk = GetKey(S128KeyType::SecureBoot);
715 const auto tsec = GetKey(S128KeyType::TSEC);
716 const auto master_source = GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::Master));
717
718 for (size_t i = 0; i < revisions.size(); ++i) {
719 if (!revisions[i])
720 continue;
721
722 // Derive keyblob key
723 const auto key = DeriveKeyblobKey(
724 sbk, tsec, GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::Keyblob), i));
725
726 SetKey(S128KeyType::Keyblob, key, i);
727
728 // Derive keyblob MAC key
729 if (!HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC)))
730 continue;
731
732 const auto mac_key = DeriveKeyblobMACKey(
733 key, GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC)));
734 SetKey(S128KeyType::KeyblobMAC, mac_key, i);
735
736 Key128 cmac = CalculateCMAC(encrypted_keyblobs[i].data() + 0x10, 0xA0, mac_key);
737 if (std::memcmp(cmac.data(), encrypted_keyblobs[i].data(), cmac.size()) != 0)
738 continue;
739
740 // Decrypt keyblob
741 if (keyblobs[i] == std::array<u8, 0x90>{}) {
742 keyblobs[i] = DecryptKeyblob(encrypted_keyblobs[i], key);
743 WriteKeyToFile<0x90>(KeyCategory::Console, fmt::format("keyblob_{:02X}", i),
744 keyblobs[i]);
745 }
746
747 Key128 package1;
748 std::memcpy(package1.data(), keyblobs[i].data() + 0x80, sizeof(Key128));
749 SetKey(S128KeyType::Package1, package1, i);
750
751 // Derive master key
752 if (HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::Master))) {
753 SetKey(S128KeyType::Master,
754 DeriveMasterKey(keyblobs[i], GetKey(S128KeyType::Source,
755 static_cast<u64>(SourceKeyType::Master))),
756 i);
757 }
758 }
759
760 revisions.set();
761 for (size_t i = 0; i < revisions.size(); ++i) {
762 if (!HasKey(S128KeyType::Master, i))
763 revisions.reset(i);
764 }
765
766 if (!revisions.any())
767 return;
768
769 for (size_t i = 0; i < revisions.size(); ++i) {
770 if (!revisions[i])
771 continue;
772
773 // Derive general purpose keys
774 DeriveGeneralPurposeKeys(i);
775 }
776
777 if (HasKey(S128KeyType::Master, 0) &&
778 HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration)) &&
779 HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration)) &&
780 HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::HeaderKek)) &&
781 HasKey(S256KeyType::HeaderSource)) {
782 const auto header_kek = GenerateKeyEncryptionKey(
783 GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::HeaderKek)),
784 GetKey(S128KeyType::Master, 0),
785 GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration)),
786 GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration)));
787 SetKey(S128KeyType::HeaderKek, header_kek);
788
789 AESCipher<Key128> header_cipher(header_kek, Mode::ECB);
790 Key256 out = GetKey(S256KeyType::HeaderSource);
791 header_cipher.Transcode(out.data(), out.size(), out.data(), Op::Decrypt);
792 SetKey(S256KeyType::Header, out);
793 }
794}
795
796void KeyManager::DeriveETicket(PartitionDataManager& data) {
797 // ETicket keys
798 const auto es = Service::FileSystem::GetUnionContents()->GetEntry(
799 0x0100000000000033, FileSys::ContentRecordType::Program);
800
801 if (es == nullptr)
802 return;
803
804 const auto exefs = es->GetExeFS();
805 if (exefs == nullptr)
806 return;
807
808 const auto main = exefs->GetFile("main");
809 if (main == nullptr)
810 return;
811
812 const auto bytes = main->ReadAllBytes();
813
814 const auto eticket_kek = FindKeyFromHex16(bytes, eticket_source_hashes[0]);
815 const auto eticket_kekek = FindKeyFromHex16(bytes, eticket_source_hashes[1]);
816
817 const auto seed3 = data.GetRSAKekSeed3();
818 const auto mask0 = data.GetRSAKekMask0();
819
820 if (eticket_kek != Key128{})
821 SetKey(S128KeyType::Source, eticket_kek, static_cast<size_t>(SourceKeyType::ETicketKek));
822 if (eticket_kekek != Key128{}) {
823 SetKey(S128KeyType::Source, eticket_kekek,
824 static_cast<size_t>(SourceKeyType::ETicketKekek));
825 }
826 if (seed3 != Key128{})
827 SetKey(S128KeyType::RSAKek, seed3, static_cast<size_t>(RSAKekType::Seed3));
828 if (mask0 != Key128{})
829 SetKey(S128KeyType::RSAKek, mask0, static_cast<size_t>(RSAKekType::Mask0));
830 if (eticket_kek == Key128{} || eticket_kekek == Key128{} || seed3 == Key128{} ||
831 mask0 == Key128{}) {
832 return;
833 }
834
835 Key128 rsa_oaep_kek{};
836 std::transform(seed3.begin(), seed3.end(), mask0.begin(), rsa_oaep_kek.begin(),
837 std::bit_xor<>());
838
839 if (rsa_oaep_kek == Key128{})
840 return;
841
842 SetKey(S128KeyType::Source, rsa_oaep_kek,
843 static_cast<u64>(SourceKeyType::RSAOaepKekGeneration));
844
845 Key128 temp_kek{};
846 Key128 temp_kekek{};
847 Key128 eticket_final{};
848
849 // Derive ETicket RSA Kek
850 AESCipher<Key128> es_master(GetKey(S128KeyType::Master), Mode::ECB);
851 es_master.Transcode(rsa_oaep_kek.data(), rsa_oaep_kek.size(), temp_kek.data(), Op::Decrypt);
852 AESCipher<Key128> es_kekek(temp_kek, Mode::ECB);
853 es_kekek.Transcode(eticket_kekek.data(), eticket_kekek.size(), temp_kekek.data(), Op::Decrypt);
854 AESCipher<Key128> es_kek(temp_kekek, Mode::ECB);
855 es_kek.Transcode(eticket_kek.data(), eticket_kek.size(), eticket_final.data(), Op::Decrypt);
856
857 if (eticket_final == Key128{})
858 return;
859
860 SetKey(S128KeyType::ETicketRSAKek, eticket_final);
861
862 // Titlekeys
863 data.DecryptProdInfo(GetBISKey(0));
864
865 const auto eticket_extended_kek = data.GetETicketExtendedKek();
866
867 std::vector<u8> extended_iv(0x10);
868 std::memcpy(extended_iv.data(), eticket_extended_kek.data(), extended_iv.size());
869 std::array<u8, 0x230> extended_dec{};
870 AESCipher<Key128> rsa_1(eticket_final, Mode::CTR);
871 rsa_1.SetIV(extended_iv);
872 rsa_1.Transcode(eticket_extended_kek.data() + 0x10, eticket_extended_kek.size() - 0x10,
873 extended_dec.data(), Op::Decrypt);
874
875 RSAKeyPair<2048> rsa_key{};
876 std::memcpy(rsa_key.decryption_key.data(), extended_dec.data(), rsa_key.decryption_key.size());
877 std::memcpy(rsa_key.modulus.data(), extended_dec.data() + 0x100, rsa_key.modulus.size());
878 std::memcpy(rsa_key.exponent.data(), extended_dec.data() + 0x200, rsa_key.exponent.size());
879
880 const FileUtil::IOFile save1(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
881 "/system/save/80000000000000e1",
882 "rb+");
883 const FileUtil::IOFile save2(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) +
884 "/system/save/80000000000000e2",
885 "rb+");
886
887 const auto blob2 = GetTicketblob(save2);
888 auto res = GetTicketblob(save1);
889 res.insert(res.end(), blob2.begin(), blob2.end());
890
891 for (const auto& raw : res) {
892 const auto pair = ParseTicket(raw, rsa_key);
893 if (pair == boost::none)
894 continue;
895 const auto& [rid, key] = pair.value();
896 u128 rights_id;
897 std::memcpy(rights_id.data(), rid.data(), rid.size());
898 SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
899 }
900}
901
902void KeyManager::SetKeyWrapped(S128KeyType id, Key128 key, u64 field1, u64 field2) {
903 if (key == Key128{})
904 return;
905 SetKey(id, key, field1, field2);
906}
907
908void KeyManager::SetKeyWrapped(S256KeyType id, Key256 key, u64 field1, u64 field2) {
909 if (key == Key256{})
910 return;
911 SetKey(id, key, field1, field2);
912}
913
914void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) {
915 if (!BaseDeriveNecessary())
916 return;
917
918 if (!data.HasBoot0())
919 return;
920
921 for (size_t i = 0; i < encrypted_keyblobs.size(); ++i) {
922 if (encrypted_keyblobs[i] != std::array<u8, 0xB0>{})
923 continue;
924 encrypted_keyblobs[i] = data.GetEncryptedKeyblob(i);
925 WriteKeyToFile<0xB0>(KeyCategory::Console, fmt::format("encrypted_keyblob_{:02X}", i),
926 encrypted_keyblobs[i]);
927 }
928
929 SetKeyWrapped(S128KeyType::Source, data.GetPackage2KeySource(),
930 static_cast<u64>(SourceKeyType::Package2));
931 SetKeyWrapped(S128KeyType::Source, data.GetAESKekGenerationSource(),
932 static_cast<u64>(SourceKeyType::AESKekGeneration));
933 SetKeyWrapped(S128KeyType::Source, data.GetTitlekekSource(),
934 static_cast<u64>(SourceKeyType::Titlekek));
935 SetKeyWrapped(S128KeyType::Source, data.GetMasterKeySource(),
936 static_cast<u64>(SourceKeyType::Master));
937 SetKeyWrapped(S128KeyType::Source, data.GetKeyblobMACKeySource(),
938 static_cast<u64>(SourceKeyType::KeyblobMAC));
939
940 for (size_t i = 0; i < PartitionDataManager::MAX_KEYBLOB_SOURCE_HASH; ++i) {
941 SetKeyWrapped(S128KeyType::Source, data.GetKeyblobKeySource(i),
942 static_cast<u64>(SourceKeyType::Keyblob), i);
943 }
944
945 if (data.HasFuses())
946 SetKeyWrapped(S128KeyType::SecureBoot, data.GetSecureBootKey());
947
948 DeriveBase();
949
950 Key128 latest_master{};
951 for (s8 i = 0x1F; i >= 0; --i) {
952 if (GetKey(S128KeyType::Master, static_cast<u8>(i)) != Key128{}) {
953 latest_master = GetKey(S128KeyType::Master, static_cast<u8>(i));
954 break;
955 }
956 }
957
958 const auto masters = data.GetTZMasterKeys(latest_master);
959 for (size_t i = 0; i < masters.size(); ++i) {
960 if (masters[i] != Key128{} && !HasKey(S128KeyType::Master, i))
961 SetKey(S128KeyType::Master, masters[i], i);
962 }
963
964 DeriveBase();
965
966 if (!data.HasPackage2())
967 return;
968
969 std::array<Key128, 0x20> package2_keys{};
970 for (size_t i = 0; i < package2_keys.size(); ++i) {
971 if (HasKey(S128KeyType::Package2, i))
972 package2_keys[i] = GetKey(S128KeyType::Package2, i);
973 }
974 data.DecryptPackage2(package2_keys, Package2Type::NormalMain);
975
976 SetKeyWrapped(S128KeyType::Source, data.GetKeyAreaKeyApplicationSource(),
977 static_cast<u64>(SourceKeyType::KeyAreaKey),
978 static_cast<u64>(KeyAreaKeyType::Application));
979 SetKeyWrapped(S128KeyType::Source, data.GetKeyAreaKeyOceanSource(),
980 static_cast<u64>(SourceKeyType::KeyAreaKey),
981 static_cast<u64>(KeyAreaKeyType::Ocean));
982 SetKeyWrapped(S128KeyType::Source, data.GetKeyAreaKeySystemSource(),
983 static_cast<u64>(SourceKeyType::KeyAreaKey),
984 static_cast<u64>(KeyAreaKeyType::System));
985 SetKeyWrapped(S128KeyType::Source, data.GetSDKekSource(),
986 static_cast<u64>(SourceKeyType::SDKek));
987 SetKeyWrapped(S256KeyType::SDKeySource, data.GetSDSaveKeySource(),
988 static_cast<u64>(SDKeyType::Save));
989 SetKeyWrapped(S256KeyType::SDKeySource, data.GetSDNCAKeySource(),
990 static_cast<u64>(SDKeyType::NCA));
991 SetKeyWrapped(S128KeyType::Source, data.GetHeaderKekSource(),
992 static_cast<u64>(SourceKeyType::HeaderKek));
993 SetKeyWrapped(S256KeyType::HeaderSource, data.GetHeaderKeySource());
994 SetKeyWrapped(S128KeyType::Source, data.GetAESKeyGenerationSource(),
995 static_cast<u64>(SourceKeyType::AESKeyGeneration));
996
997 DeriveBase();
998}
999
293const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = { 1000const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = {
294 {"master_key_00", {S128KeyType::Master, 0, 0}},
295 {"master_key_01", {S128KeyType::Master, 1, 0}},
296 {"master_key_02", {S128KeyType::Master, 2, 0}},
297 {"master_key_03", {S128KeyType::Master, 3, 0}},
298 {"master_key_04", {S128KeyType::Master, 4, 0}},
299 {"package1_key_00", {S128KeyType::Package1, 0, 0}},
300 {"package1_key_01", {S128KeyType::Package1, 1, 0}},
301 {"package1_key_02", {S128KeyType::Package1, 2, 0}},
302 {"package1_key_03", {S128KeyType::Package1, 3, 0}},
303 {"package1_key_04", {S128KeyType::Package1, 4, 0}},
304 {"package2_key_00", {S128KeyType::Package2, 0, 0}},
305 {"package2_key_01", {S128KeyType::Package2, 1, 0}},
306 {"package2_key_02", {S128KeyType::Package2, 2, 0}},
307 {"package2_key_03", {S128KeyType::Package2, 3, 0}},
308 {"package2_key_04", {S128KeyType::Package2, 4, 0}},
309 {"titlekek_00", {S128KeyType::Titlekek, 0, 0}},
310 {"titlekek_01", {S128KeyType::Titlekek, 1, 0}},
311 {"titlekek_02", {S128KeyType::Titlekek, 2, 0}},
312 {"titlekek_03", {S128KeyType::Titlekek, 3, 0}},
313 {"titlekek_04", {S128KeyType::Titlekek, 4, 0}},
314 {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}}, 1001 {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}},
315 {"key_area_key_application_00", 1002 {"eticket_rsa_kek_source",
316 {S128KeyType::KeyArea, 0, static_cast<u64>(KeyAreaKeyType::Application)}}, 1003 {S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKek), 0}},
317 {"key_area_key_application_01", 1004 {"eticket_rsa_kekek_source",
318 {S128KeyType::KeyArea, 1, static_cast<u64>(KeyAreaKeyType::Application)}}, 1005 {S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKekek), 0}},
319 {"key_area_key_application_02", 1006 {"rsa_kek_mask_0", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Mask0), 0}},
320 {S128KeyType::KeyArea, 2, static_cast<u64>(KeyAreaKeyType::Application)}}, 1007 {"rsa_kek_seed_3", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Seed3), 0}},
321 {"key_area_key_application_03", 1008 {"rsa_oaep_kek_generation_source",
322 {S128KeyType::KeyArea, 3, static_cast<u64>(KeyAreaKeyType::Application)}}, 1009 {S128KeyType::Source, static_cast<u64>(SourceKeyType::RSAOaepKekGeneration), 0}},
323 {"key_area_key_application_04", 1010 {"sd_card_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek), 0}},
324 {S128KeyType::KeyArea, 4, static_cast<u64>(KeyAreaKeyType::Application)}},
325 {"key_area_key_ocean_00", {S128KeyType::KeyArea, 0, static_cast<u64>(KeyAreaKeyType::Ocean)}},
326 {"key_area_key_ocean_01", {S128KeyType::KeyArea, 1, static_cast<u64>(KeyAreaKeyType::Ocean)}},
327 {"key_area_key_ocean_02", {S128KeyType::KeyArea, 2, static_cast<u64>(KeyAreaKeyType::Ocean)}},
328 {"key_area_key_ocean_03", {S128KeyType::KeyArea, 3, static_cast<u64>(KeyAreaKeyType::Ocean)}},
329 {"key_area_key_ocean_04", {S128KeyType::KeyArea, 4, static_cast<u64>(KeyAreaKeyType::Ocean)}},
330 {"key_area_key_system_00", {S128KeyType::KeyArea, 0, static_cast<u64>(KeyAreaKeyType::System)}},
331 {"key_area_key_system_01", {S128KeyType::KeyArea, 1, static_cast<u64>(KeyAreaKeyType::System)}},
332 {"key_area_key_system_02", {S128KeyType::KeyArea, 2, static_cast<u64>(KeyAreaKeyType::System)}},
333 {"key_area_key_system_03", {S128KeyType::KeyArea, 3, static_cast<u64>(KeyAreaKeyType::System)}},
334 {"key_area_key_system_04", {S128KeyType::KeyArea, 4, static_cast<u64>(KeyAreaKeyType::System)}},
335 {"sd_card_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKEK), 0}},
336 {"aes_kek_generation_source", 1011 {"aes_kek_generation_source",
337 {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKEKGeneration), 0}}, 1012 {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration), 0}},
338 {"aes_key_generation_source", 1013 {"aes_key_generation_source",
339 {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration), 0}}, 1014 {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration), 0}},
1015 {"package2_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Package2), 0}},
1016 {"master_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Master), 0}},
1017 {"header_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::HeaderKek), 0}},
1018 {"key_area_key_application_source",
1019 {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
1020 static_cast<u64>(KeyAreaKeyType::Application)}},
1021 {"key_area_key_ocean_source",
1022 {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
1023 static_cast<u64>(KeyAreaKeyType::Ocean)}},
1024 {"key_area_key_system_source",
1025 {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
1026 static_cast<u64>(KeyAreaKeyType::System)}},
1027 {"titlekek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Titlekek), 0}},
1028 {"keyblob_mac_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC)}},
1029 {"tsec_key", {S128KeyType::TSEC, 0, 0}},
1030 {"secure_boot_key", {S128KeyType::SecureBoot, 0, 0}},
340 {"sd_seed", {S128KeyType::SDSeed, 0, 0}}, 1031 {"sd_seed", {S128KeyType::SDSeed, 0, 0}},
1032 {"bis_key_0_crypt", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Crypto)}},
1033 {"bis_key_0_tweak", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Tweak)}},
1034 {"bis_key_1_crypt", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Crypto)}},
1035 {"bis_key_1_tweak", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Tweak)}},
1036 {"bis_key_2_crypt", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Crypto)}},
1037 {"bis_key_2_tweak", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Tweak)}},
1038 {"bis_key_3_crypt", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Crypto)}},
1039 {"bis_key_3_tweak", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Tweak)}},
1040 {"header_kek", {S128KeyType::HeaderKek, 0, 0}},
1041 {"sd_card_kek", {S128KeyType::SDKek, 0, 0}},
341}; 1042};
342 1043
343const boost::container::flat_map<std::string, KeyIndex<S256KeyType>> KeyManager::s256_file_id = { 1044const boost::container::flat_map<std::string, KeyIndex<S256KeyType>> KeyManager::s256_file_id = {
344 {"header_key", {S256KeyType::Header, 0, 0}}, 1045 {"header_key", {S256KeyType::Header, 0, 0}},
345 {"sd_card_save_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save), 0}}, 1046 {"sd_card_save_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save), 0}},
346 {"sd_card_nca_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA), 0}}, 1047 {"sd_card_nca_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA), 0}},
1048 {"header_key_source", {S256KeyType::HeaderSource, 0, 0}},
1049 {"sd_card_save_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::Save), 0}},
1050 {"sd_card_nca_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::NCA), 0}},
347}; 1051};
348} // namespace Core::Crypto 1052} // namespace Core::Crypto
diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h
index 978eec8dc..cccb3c0ae 100644
--- a/src/core/crypto/key_manager.h
+++ b/src/core/crypto/key_manager.h
@@ -5,11 +5,18 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <map>
8#include <string> 9#include <string>
9#include <boost/container/flat_map.hpp> 10#include <boost/container/flat_map.hpp>
10#include <boost/optional.hpp> 11#include <boost/optional.hpp>
11#include <fmt/format.h> 12#include <fmt/format.h>
12#include "common/common_types.h" 13#include "common/common_types.h"
14#include "core/crypto/partition_data_manager.h"
15#include "core/file_sys/vfs_types.h"
16
17namespace FileUtil {
18class IOFile;
19}
13 20
14namespace Loader { 21namespace Loader {
15enum class ResultStatus : u16; 22enum class ResultStatus : u16;
@@ -22,13 +29,30 @@ constexpr u64 TICKET_FILE_TITLEKEY_OFFSET = 0x180;
22using Key128 = std::array<u8, 0x10>; 29using Key128 = std::array<u8, 0x10>;
23using Key256 = std::array<u8, 0x20>; 30using Key256 = std::array<u8, 0x20>;
24using SHA256Hash = std::array<u8, 0x20>; 31using SHA256Hash = std::array<u8, 0x20>;
32using TicketRaw = std::array<u8, 0x400>;
25 33
26static_assert(sizeof(Key128) == 16, "Key128 must be 128 bytes big."); 34static_assert(sizeof(Key128) == 16, "Key128 must be 128 bytes big.");
27static_assert(sizeof(Key256) == 32, "Key128 must be 128 bytes big."); 35static_assert(sizeof(Key256) == 32, "Key256 must be 256 bytes big.");
36
37template <size_t bit_size, size_t byte_size = (bit_size >> 3)>
38struct RSAKeyPair {
39 std::array<u8, byte_size> encryption_key;
40 std::array<u8, byte_size> decryption_key;
41 std::array<u8, byte_size> modulus;
42 std::array<u8, 4> exponent;
43};
44
45enum class KeyCategory : u8 {
46 Standard,
47 Title,
48 Console,
49};
28 50
29enum class S256KeyType : u64 { 51enum class S256KeyType : u64 {
30 Header, // 52 SDKey, // f1=SDKeyType
31 SDKeySource, // f1=SDKeyType 53 Header, //
54 SDKeySource, // f1=SDKeyType
55 HeaderSource, //
32}; 56};
33 57
34enum class S128KeyType : u64 { 58enum class S128KeyType : u64 {
@@ -41,6 +65,14 @@ enum class S128KeyType : u64 {
41 SDSeed, // 65 SDSeed, //
42 Titlekey, // f1=rights id LSB f2=rights id MSB 66 Titlekey, // f1=rights id LSB f2=rights id MSB
43 Source, // f1=source type, f2= sub id 67 Source, // f1=source type, f2= sub id
68 Keyblob, // f1=crypto revision
69 KeyblobMAC, // f1=crypto revision
70 TSEC, //
71 SecureBoot, //
72 BIS, // f1=partition (0-3), f2=type {crypt, tweak}
73 HeaderKek, //
74 SDKek, //
75 RSAKek, //
44}; 76};
45 77
46enum class KeyAreaKeyType : u8 { 78enum class KeyAreaKeyType : u8 {
@@ -50,9 +82,19 @@ enum class KeyAreaKeyType : u8 {
50}; 82};
51 83
52enum class SourceKeyType : u8 { 84enum class SourceKeyType : u8 {
53 SDKEK, 85 SDKek, //
54 AESKEKGeneration, 86 AESKekGeneration, //
55 AESKeyGeneration, 87 AESKeyGeneration, //
88 RSAOaepKekGeneration, //
89 Master, //
90 Keyblob, // f2=crypto revision
91 KeyAreaKey, // f2=KeyAreaKeyType
92 Titlekek, //
93 Package2, //
94 HeaderKek, //
95 KeyblobMAC, //
96 ETicketKek, //
97 ETicketKekek, //
56}; 98};
57 99
58enum class SDKeyType : u8 { 100enum class SDKeyType : u8 {
@@ -60,6 +102,16 @@ enum class SDKeyType : u8 {
60 NCA, 102 NCA,
61}; 103};
62 104
105enum class BISKeyType : u8 {
106 Crypto,
107 Tweak,
108};
109
110enum class RSAKekType : u8 {
111 Mask0,
112 Seed3,
113};
114
63template <typename KeyType> 115template <typename KeyType>
64struct KeyIndex { 116struct KeyIndex {
65 KeyType type; 117 KeyType type;
@@ -91,6 +143,8 @@ public:
91 Key128 GetKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0) const; 143 Key128 GetKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0) const;
92 Key256 GetKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0) const; 144 Key256 GetKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0) const;
93 145
146 Key256 GetBISKey(u8 partition_id) const;
147
94 void SetKey(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0); 148 void SetKey(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0);
95 void SetKey(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0); 149 void SetKey(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0);
96 150
@@ -100,23 +154,51 @@ public:
100 // 8*43 and the private file to exist. 154 // 8*43 and the private file to exist.
101 void DeriveSDSeedLazy(); 155 void DeriveSDSeedLazy();
102 156
157 bool BaseDeriveNecessary() const;
158 void DeriveBase();
159 void DeriveETicket(PartitionDataManager& data);
160
161 void PopulateFromPartitionData(PartitionDataManager& data);
162
103private: 163private:
104 boost::container::flat_map<KeyIndex<S128KeyType>, Key128> s128_keys; 164 std::map<KeyIndex<S128KeyType>, Key128> s128_keys;
105 boost::container::flat_map<KeyIndex<S256KeyType>, Key256> s256_keys; 165 std::map<KeyIndex<S256KeyType>, Key256> s256_keys;
166
167 std::array<std::array<u8, 0xB0>, 0x20> encrypted_keyblobs{};
168 std::array<std::array<u8, 0x90>, 0x20> keyblobs{};
106 169
107 bool dev_mode; 170 bool dev_mode;
108 void LoadFromFile(const std::string& filename, bool is_title_keys); 171 void LoadFromFile(const std::string& filename, bool is_title_keys);
109 void AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2, 172 void AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2,
110 const std::string& filename, bool title); 173 const std::string& filename, bool title);
111 template <std::size_t Size> 174 template <size_t Size>
112 void WriteKeyToFile(bool title_key, std::string_view keyname, const std::array<u8, Size>& key); 175 void WriteKeyToFile(KeyCategory category, std::string_view keyname,
176 const std::array<u8, Size>& key);
177
178 void DeriveGeneralPurposeKeys(std::size_t crypto_revision);
179
180 void SetKeyWrapped(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0);
181 void SetKeyWrapped(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0);
113 182
114 static const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> s128_file_id; 183 static const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> s128_file_id;
115 static const boost::container::flat_map<std::string, KeyIndex<S256KeyType>> s256_file_id; 184 static const boost::container::flat_map<std::string, KeyIndex<S256KeyType>> s256_file_id;
116}; 185};
117 186
118Key128 GenerateKeyEncryptionKey(Key128 source, Key128 master, Key128 kek_seed, Key128 key_seed); 187Key128 GenerateKeyEncryptionKey(Key128 source, Key128 master, Key128 kek_seed, Key128 key_seed);
188Key128 DeriveKeyblobKey(const Key128& sbk, const Key128& tsec, Key128 source);
189Key128 DeriveKeyblobMACKey(const Key128& keyblob_key, const Key128& mac_source);
190Key128 DeriveMasterKey(const std::array<u8, 0x90>& keyblob, const Key128& master_source);
191std::array<u8, 0x90> DecryptKeyblob(const std::array<u8, 0xB0>& encrypted_keyblob,
192 const Key128& key);
193
119boost::optional<Key128> DeriveSDSeed(); 194boost::optional<Key128> DeriveSDSeed();
120Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, const KeyManager& keys); 195Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& keys);
196
197std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save);
198
199// Returns a pair of {rights_id, titlekey}. Fails if the ticket has no certificate authority (offset
200// 0x140-0x144 is zero)
201boost::optional<std::pair<Key128, Key128>> ParseTicket(
202 const TicketRaw& ticket, const RSAKeyPair<2048>& eticket_extended_key);
121 203
122} // namespace Core::Crypto 204} // namespace Core::Crypto
diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp
new file mode 100644
index 000000000..25cee1f3a
--- /dev/null
+++ b/src/core/crypto/partition_data_manager.cpp
@@ -0,0 +1,593 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5// NOTE TO FUTURE MAINTAINERS:
6// When a new version of switch cryptography is released,
7// hash the new keyblob source and master key and add the hashes to
8// the arrays below.
9
10#include <algorithm>
11#include <array>
12#include <cctype>
13#include <cstring>
14#include <mbedtls/sha256.h>
15#include "common/assert.h"
16#include "common/common_funcs.h"
17#include "common/common_types.h"
18#include "common/hex_util.h"
19#include "common/logging/log.h"
20#include "common/string_util.h"
21#include "common/swap.h"
22#include "core/crypto/key_manager.h"
23#include "core/crypto/partition_data_manager.h"
24#include "core/crypto/xts_encryption_layer.h"
25#include "core/file_sys/vfs.h"
26#include "core/file_sys/vfs_offset.h"
27
28using namespace Common;
29
30namespace Core::Crypto {
31
32struct Package2Header {
33 std::array<u8, 0x100> signature;
34 Key128 header_ctr;
35 std::array<Key128, 4> section_ctr;
36 u32_le magic;
37 u32_le base_offset;
38 INSERT_PADDING_BYTES(4);
39 u8 version_max;
40 u8 version_min;
41 INSERT_PADDING_BYTES(2);
42 std::array<u32_le, 4> section_size;
43 std::array<u32_le, 4> section_offset;
44 std::array<SHA256Hash, 4> section_hash;
45};
46static_assert(sizeof(Package2Header) == 0x200, "Package2Header has incorrect size.");
47
48struct INIHeader {
49 u32_le magic;
50 u32_le size;
51 u32_le process_count;
52 INSERT_PADDING_BYTES(4);
53};
54static_assert(sizeof(INIHeader) == 0x10, "INIHeader has incorrect size.");
55
56struct SectionHeader {
57 u32_le offset;
58 u32_le size_decompressed;
59 u32_le size_compressed;
60 u32_le attribute;
61};
62static_assert(sizeof(SectionHeader) == 0x10, "SectionHeader has incorrect size.");
63
64struct KIPHeader {
65 u32_le magic;
66 std::array<char, 12> name;
67 u64_le title_id;
68 u32_le category;
69 u8 priority;
70 u8 core;
71 INSERT_PADDING_BYTES(1);
72 u8 flags;
73 std::array<SectionHeader, 6> sections;
74 std::array<u32, 0x20> capabilities;
75};
76static_assert(sizeof(KIPHeader) == 0x100, "KIPHeader has incorrect size.");
77
78const std::array<SHA256Hash, 0x10> source_hashes{
79 "B24BD293259DBC7AC5D63F88E60C59792498E6FC5443402C7FFE87EE8B61A3F0"_array32, // keyblob_mac_key_source
80 "7944862A3A5C31C6720595EFD302245ABD1B54CCDCF33000557681E65C5664A4"_array32, // master_key_source
81 "21E2DF100FC9E094DB51B47B9B1D6E94ED379DB8B547955BEF8FE08D8DD35603"_array32, // package2_key_source
82 "FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"_array32, // aes_kek_generation_source
83 "FBD10056999EDC7ACDB96098E47E2C3606230270D23281E671F0F389FC5BC585"_array32, // aes_key_generation_source
84 "C48B619827986C7F4E3081D59DB2B460C84312650E9A8E6B458E53E8CBCA4E87"_array32, // titlekek_source
85 "04AD66143C726B2A139FB6B21128B46F56C553B2B3887110304298D8D0092D9E"_array32, // key_area_key_application_source
86 "FD434000C8FF2B26F8E9A9D2D2C12F6BE5773CBB9DC86300E1BD99F8EA33A417"_array32, // key_area_key_ocean_source
87 "1F17B1FD51AD1C2379B58F152CA4912EC2106441E51722F38700D5937A1162F7"_array32, // key_area_key_system_source
88 "6B2ED877C2C52334AC51E59ABFA7EC457F4A7D01E46291E9F2EAA45F011D24B7"_array32, // sd_card_kek_source
89 "D482743563D3EA5DCDC3B74E97C9AC8A342164FA041A1DC80F17F6D31E4BC01C"_array32, // sd_card_save_key_source
90 "2E751CECF7D93A2B957BD5FFCB082FD038CC2853219DD3092C6DAB9838F5A7CC"_array32, // sd_card_nca_key_source
91 "1888CAED5551B3EDE01499E87CE0D86827F80820EFB275921055AA4E2ABDFFC2"_array32, // header_kek_source
92 "8F783E46852DF6BE0BA4E19273C4ADBAEE16380043E1B8C418C4089A8BD64AA6"_array32, // header_key_source
93 "D1757E52F1AE55FA882EC690BC6F954AC46A83DC22F277F8806BD55577C6EED7"_array32, // rsa_kek_seed3
94 "FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"_array32, // rsa_kek_mask0
95};
96
97const std::array<SHA256Hash, 0x20> keyblob_source_hashes{
98 "8A06FE274AC491436791FDB388BCDD3AB9943BD4DEF8094418CDAC150FD73786"_array32, // keyblob_key_source_00
99 "2D5CAEB2521FEF70B47E17D6D0F11F8CE2C1E442A979AD8035832C4E9FBCCC4B"_array32, // keyblob_key_source_01
100 "61C5005E713BAE780641683AF43E5F5C0E03671117F702F401282847D2FC6064"_array32, // keyblob_key_source_02
101 "8E9795928E1C4428E1B78F0BE724D7294D6934689C11B190943923B9D5B85903"_array32, // keyblob_key_source_03
102 "95FA33AF95AFF9D9B61D164655B32710ED8D615D46C7D6CC3CC70481B686B402"_array32, // keyblob_key_source_04
103 "3F5BE7B3C8B1ABD8C10B4B703D44766BA08730562C172A4FE0D6B866B3E2DB3E"_array32, // keyblob_key_source_05
104 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_06
105 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_07
106
107 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_08
108 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_09
109 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0A
110 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0B
111 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0C
112 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0D
113 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0E
114 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0F
115
116 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_10
117 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_11
118 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_12
119 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_13
120 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_14
121 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_15
122 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_16
123 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_17
124
125 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_18
126 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_19
127 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1A
128 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1B
129 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1C
130 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1D
131 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1E
132 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1F
133};
134
135const std::array<SHA256Hash, 0x20> master_key_hashes{
136 "0EE359BE3C864BB0782E1D70A718A0342C551EED28C369754F9C4F691BECF7CA"_array32, // master_key_00
137 "4FE707B7E4ABDAF727C894AAF13B1351BFE2AC90D875F73B2E20FA94B9CC661E"_array32, // master_key_01
138 "79277C0237A2252EC3DFAC1F7C359C2B3D121E9DB15BB9AB4C2B4408D2F3AE09"_array32, // master_key_02
139 "4F36C565D13325F65EE134073C6A578FFCB0008E02D69400836844EAB7432754"_array32, // master_key_03
140 "75FF1D95D26113550EE6FCC20ACB58E97EDEB3A2FF52543ED5AEC63BDCC3DA50"_array32, // master_key_04
141 "EBE2BCD6704673EC0F88A187BB2AD9F1CC82B718C389425941BDC194DC46B0DD"_array32, // master_key_05
142 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_06
143 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_07
144
145 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_08
146 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_09
147 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0A
148 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0B
149 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0C
150 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0D
151 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0E
152 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0F
153
154 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_10
155 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_11
156 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_12
157 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_13
158 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_14
159 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_15
160 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_16
161 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_17
162
163 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_18
164 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_19
165 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1A
166 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1B
167 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1C
168 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1D
169 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1E
170 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1F
171};
172
173static std::vector<u8> DecompressBLZ(const std::vector<u8>& in) {
174 const auto data_size = in.size() - 0xC;
175
176 u32 compressed_size{};
177 u32 init_index{};
178 u32 additional_size{};
179 std::memcpy(&compressed_size, in.data() + data_size, sizeof(u32));
180 std::memcpy(&init_index, in.data() + data_size + 0x4, sizeof(u32));
181 std::memcpy(&additional_size, in.data() + data_size + 0x8, sizeof(u32));
182
183 std::vector<u8> out(in.size() + additional_size);
184
185 if (compressed_size == in.size())
186 std::memcpy(out.data(), in.data() + in.size() - compressed_size, compressed_size);
187 else
188 std::memcpy(out.data(), in.data(), compressed_size);
189
190 auto index = in.size() - init_index;
191 auto out_index = out.size();
192
193 while (out_index > 0) {
194 --index;
195 auto control = in[index];
196 for (size_t i = 0; i < 8; ++i) {
197 if ((control & 0x80) > 0) {
198 ASSERT(index >= 2);
199 index -= 2;
200 u64 segment_offset = in[index] | in[index + 1] << 8;
201 u64 segment_size = ((segment_offset >> 12) & 0xF) + 3;
202 segment_offset &= 0xFFF;
203 segment_offset += 3;
204
205 if (out_index < segment_size)
206 segment_size = out_index;
207
208 ASSERT(out_index >= segment_size);
209
210 out_index -= segment_size;
211
212 for (size_t j = 0; j < segment_size; ++j) {
213 ASSERT(out_index + j + segment_offset < out.size());
214 out[out_index + j] = out[out_index + j + segment_offset];
215 }
216 } else {
217 ASSERT(out_index >= 1);
218 --out_index;
219 --index;
220 out[out_index] = in[index];
221 }
222
223 control <<= 1;
224 if (out_index == 0)
225 return out;
226 }
227 }
228
229 return out;
230}
231
232static u8 CalculateMaxKeyblobSourceHash() {
233 for (s8 i = 0x1F; i >= 0; --i) {
234 if (keyblob_source_hashes[i] != SHA256Hash{})
235 return static_cast<u8>(i + 1);
236 }
237
238 return 0;
239}
240
241const u8 PartitionDataManager::MAX_KEYBLOB_SOURCE_HASH = CalculateMaxKeyblobSourceHash();
242
243template <size_t key_size = 0x10>
244std::array<u8, key_size> FindKeyFromHex(const std::vector<u8>& binary,
245 const std::array<u8, 0x20>& hash) {
246 if (binary.size() < key_size)
247 return {};
248
249 std::array<u8, 0x20> temp{};
250 for (size_t i = 0; i < binary.size() - key_size; ++i) {
251 mbedtls_sha256(binary.data() + i, key_size, temp.data(), 0);
252
253 if (temp != hash)
254 continue;
255
256 std::array<u8, key_size> out{};
257 std::memcpy(out.data(), binary.data() + i, key_size);
258 return out;
259 }
260
261 return {};
262}
263
264std::array<u8, 16> FindKeyFromHex16(const std::vector<u8>& binary, std::array<u8, 32> hash) {
265 return FindKeyFromHex<0x10>(binary, hash);
266}
267
268static std::array<Key128, 0x20> FindEncryptedMasterKeyFromHex(const std::vector<u8>& binary,
269 const Key128& key) {
270 if (binary.size() < 0x10)
271 return {};
272
273 SHA256Hash temp{};
274 Key128 dec_temp{};
275 std::array<Key128, 0x20> out{};
276 AESCipher<Key128> cipher(key, Mode::ECB);
277 for (size_t i = 0; i < binary.size() - 0x10; ++i) {
278 cipher.Transcode(binary.data() + i, dec_temp.size(), dec_temp.data(), Op::Decrypt);
279 mbedtls_sha256(dec_temp.data(), dec_temp.size(), temp.data(), 0);
280
281 for (size_t k = 0; k < out.size(); ++k) {
282 if (temp == master_key_hashes[k]) {
283 out[k] = dec_temp;
284 break;
285 }
286 }
287 }
288
289 return out;
290}
291
292FileSys::VirtualFile FindFileInDirWithNames(const FileSys::VirtualDir& dir,
293 const std::string& name) {
294 auto upper = name;
295 std::transform(upper.begin(), upper.end(), upper.begin(), [](u8 c) { return std::toupper(c); });
296 for (const auto& fname : {name, name + ".bin", upper, upper + ".BIN"}) {
297 if (dir->GetFile(fname) != nullptr)
298 return dir->GetFile(fname);
299 }
300
301 return nullptr;
302}
303
304PartitionDataManager::PartitionDataManager(const FileSys::VirtualDir& sysdata_dir)
305 : boot0(FindFileInDirWithNames(sysdata_dir, "BOOT0")),
306 fuses(FindFileInDirWithNames(sysdata_dir, "fuses")),
307 kfuses(FindFileInDirWithNames(sysdata_dir, "kfuses")),
308 package2({
309 FindFileInDirWithNames(sysdata_dir, "BCPKG2-1-Normal-Main"),
310 FindFileInDirWithNames(sysdata_dir, "BCPKG2-2-Normal-Sub"),
311 FindFileInDirWithNames(sysdata_dir, "BCPKG2-3-SafeMode-Main"),
312 FindFileInDirWithNames(sysdata_dir, "BCPKG2-4-SafeMode-Sub"),
313 FindFileInDirWithNames(sysdata_dir, "BCPKG2-5-Repair-Main"),
314 FindFileInDirWithNames(sysdata_dir, "BCPKG2-6-Repair-Sub"),
315 }),
316 prodinfo(FindFileInDirWithNames(sysdata_dir, "PRODINFO")),
317 secure_monitor(FindFileInDirWithNames(sysdata_dir, "secmon")),
318 package1_decrypted(FindFileInDirWithNames(sysdata_dir, "pkg1_decr")),
319 secure_monitor_bytes(secure_monitor == nullptr ? std::vector<u8>{}
320 : secure_monitor->ReadAllBytes()),
321 package1_decrypted_bytes(package1_decrypted == nullptr ? std::vector<u8>{}
322 : package1_decrypted->ReadAllBytes()) {
323}
324
325PartitionDataManager::~PartitionDataManager() = default;
326
327bool PartitionDataManager::HasBoot0() const {
328 return boot0 != nullptr;
329}
330
331FileSys::VirtualFile PartitionDataManager::GetBoot0Raw() const {
332 return boot0;
333}
334
335PartitionDataManager::EncryptedKeyBlob PartitionDataManager::GetEncryptedKeyblob(
336 std::size_t index) const {
337 if (HasBoot0() && index < NUM_ENCRYPTED_KEYBLOBS)
338 return GetEncryptedKeyblobs()[index];
339 return {};
340}
341
342PartitionDataManager::EncryptedKeyBlobs PartitionDataManager::GetEncryptedKeyblobs() const {
343 if (!HasBoot0())
344 return {};
345
346 EncryptedKeyBlobs out{};
347 for (size_t i = 0; i < out.size(); ++i)
348 boot0->Read(out[i].data(), out[i].size(), 0x180000 + i * 0x200);
349 return out;
350}
351
352std::vector<u8> PartitionDataManager::GetSecureMonitor() const {
353 return secure_monitor_bytes;
354}
355
356std::array<u8, 16> PartitionDataManager::GetPackage2KeySource() const {
357 return FindKeyFromHex(secure_monitor_bytes, source_hashes[2]);
358}
359
360std::array<u8, 16> PartitionDataManager::GetAESKekGenerationSource() const {
361 return FindKeyFromHex(secure_monitor_bytes, source_hashes[3]);
362}
363
364std::array<u8, 16> PartitionDataManager::GetTitlekekSource() const {
365 return FindKeyFromHex(secure_monitor_bytes, source_hashes[5]);
366}
367
368std::array<std::array<u8, 16>, 32> PartitionDataManager::GetTZMasterKeys(
369 std::array<u8, 0x10> master_key) const {
370 return FindEncryptedMasterKeyFromHex(secure_monitor_bytes, master_key);
371}
372
373std::array<u8, 16> PartitionDataManager::GetRSAKekSeed3() const {
374 return FindKeyFromHex(secure_monitor_bytes, source_hashes[14]);
375}
376
377std::array<u8, 16> PartitionDataManager::GetRSAKekMask0() const {
378 return FindKeyFromHex(secure_monitor_bytes, source_hashes[15]);
379}
380
381std::vector<u8> PartitionDataManager::GetPackage1Decrypted() const {
382 return package1_decrypted_bytes;
383}
384
385std::array<u8, 16> PartitionDataManager::GetMasterKeySource() const {
386 return FindKeyFromHex(package1_decrypted_bytes, source_hashes[1]);
387}
388
389std::array<u8, 16> PartitionDataManager::GetKeyblobMACKeySource() const {
390 return FindKeyFromHex(package1_decrypted_bytes, source_hashes[0]);
391}
392
393std::array<u8, 16> PartitionDataManager::GetKeyblobKeySource(std::size_t revision) const {
394 if (keyblob_source_hashes[revision] == SHA256Hash{}) {
395 LOG_WARNING(Crypto,
396 "No keyblob source hash for crypto revision {:02X}! Cannot derive keys...",
397 revision);
398 }
399 return FindKeyFromHex(package1_decrypted_bytes, keyblob_source_hashes[revision]);
400}
401
402bool PartitionDataManager::HasFuses() const {
403 return fuses != nullptr;
404}
405
406FileSys::VirtualFile PartitionDataManager::GetFusesRaw() const {
407 return fuses;
408}
409
410std::array<u8, 16> PartitionDataManager::GetSecureBootKey() const {
411 if (!HasFuses())
412 return {};
413 Key128 out{};
414 fuses->Read(out.data(), out.size(), 0xA4);
415 return out;
416}
417
418bool PartitionDataManager::HasKFuses() const {
419 return kfuses != nullptr;
420}
421
422FileSys::VirtualFile PartitionDataManager::GetKFusesRaw() const {
423 return kfuses;
424}
425
426bool PartitionDataManager::HasPackage2(Package2Type type) const {
427 return package2.at(static_cast<size_t>(type)) != nullptr;
428}
429
430FileSys::VirtualFile PartitionDataManager::GetPackage2Raw(Package2Type type) const {
431 return package2.at(static_cast<size_t>(type));
432}
433
434bool AttemptDecrypt(const std::array<u8, 16>& key, Package2Header& header) {
435
436 const std::vector<u8> iv(header.header_ctr.begin(), header.header_ctr.end());
437 Package2Header temp = header;
438 AESCipher<Key128> cipher(key, Mode::CTR);
439 cipher.SetIV(iv);
440 cipher.Transcode(&temp.header_ctr, sizeof(Package2Header) - 0x100, &temp.header_ctr,
441 Op::Decrypt);
442 if (temp.magic == Common::MakeMagic('P', 'K', '2', '1')) {
443 header = temp;
444 return true;
445 }
446
447 return false;
448}
449
450void PartitionDataManager::DecryptPackage2(const std::array<Key128, 0x20>& package2_keys,
451 Package2Type type) {
452 FileSys::VirtualFile file = std::make_shared<FileSys::OffsetVfsFile>(
453 package2[static_cast<size_t>(type)],
454 package2[static_cast<size_t>(type)]->GetSize() - 0x4000, 0x4000);
455
456 Package2Header header{};
457 if (file->ReadObject(&header) != sizeof(Package2Header))
458 return;
459
460 std::size_t revision = 0xFF;
461 if (header.magic != Common::MakeMagic('P', 'K', '2', '1')) {
462 for (std::size_t i = 0; i < package2_keys.size(); ++i) {
463 if (AttemptDecrypt(package2_keys[i], header)) {
464 revision = i;
465 }
466 }
467 }
468
469 if (header.magic != Common::MakeMagic('P', 'K', '2', '1'))
470 return;
471
472 const auto a = std::make_shared<FileSys::OffsetVfsFile>(
473 file, header.section_size[1], header.section_size[0] + sizeof(Package2Header));
474
475 auto c = a->ReadAllBytes();
476
477 AESCipher<Key128> cipher(package2_keys[revision], Mode::CTR);
478 cipher.SetIV({header.section_ctr[1].begin(), header.section_ctr[1].end()});
479 cipher.Transcode(c.data(), c.size(), c.data(), Op::Decrypt);
480
481 INIHeader ini;
482 std::memcpy(&ini, c.data(), sizeof(INIHeader));
483 if (ini.magic != Common::MakeMagic('I', 'N', 'I', '1'))
484 return;
485
486 u64 offset = sizeof(INIHeader);
487 for (size_t i = 0; i < ini.process_count; ++i) {
488 KIPHeader kip;
489 std::memcpy(&kip, c.data() + offset, sizeof(KIPHeader));
490 if (kip.magic != Common::MakeMagic('K', 'I', 'P', '1'))
491 return;
492
493 const auto name =
494 Common::StringFromFixedZeroTerminatedBuffer(kip.name.data(), kip.name.size());
495
496 if (name != "FS" && name != "spl") {
497 offset += sizeof(KIPHeader) + kip.sections[0].size_compressed +
498 kip.sections[1].size_compressed + kip.sections[2].size_compressed;
499 continue;
500 }
501
502 const u64 initial_offset = sizeof(KIPHeader) + offset;
503 const auto text_begin = c.cbegin() + initial_offset;
504 const auto text_end = text_begin + kip.sections[0].size_compressed;
505 const std::vector<u8> text = DecompressBLZ({text_begin, text_end});
506
507 const auto rodata_end = text_end + kip.sections[1].size_compressed;
508 const std::vector<u8> rodata = DecompressBLZ({text_end, rodata_end});
509
510 const auto data_end = rodata_end + kip.sections[2].size_compressed;
511 const std::vector<u8> data = DecompressBLZ({rodata_end, data_end});
512
513 std::vector<u8> out;
514 out.reserve(text.size() + rodata.size() + data.size());
515 out.insert(out.end(), text.begin(), text.end());
516 out.insert(out.end(), rodata.begin(), rodata.end());
517 out.insert(out.end(), data.begin(), data.end());
518
519 offset += sizeof(KIPHeader) + out.size();
520
521 if (name == "FS")
522 package2_fs[static_cast<size_t>(type)] = std::move(out);
523 else if (name == "spl")
524 package2_spl[static_cast<size_t>(type)] = std::move(out);
525 }
526}
527
528const std::vector<u8>& PartitionDataManager::GetPackage2FSDecompressed(Package2Type type) const {
529 return package2_fs.at(static_cast<size_t>(type));
530}
531
532std::array<u8, 16> PartitionDataManager::GetKeyAreaKeyApplicationSource(Package2Type type) const {
533 return FindKeyFromHex(package2_fs.at(static_cast<size_t>(type)), source_hashes[6]);
534}
535
536std::array<u8, 16> PartitionDataManager::GetKeyAreaKeyOceanSource(Package2Type type) const {
537 return FindKeyFromHex(package2_fs.at(static_cast<size_t>(type)), source_hashes[7]);
538}
539
540std::array<u8, 16> PartitionDataManager::GetKeyAreaKeySystemSource(Package2Type type) const {
541 return FindKeyFromHex(package2_fs.at(static_cast<size_t>(type)), source_hashes[8]);
542}
543
544std::array<u8, 16> PartitionDataManager::GetSDKekSource(Package2Type type) const {
545 return FindKeyFromHex(package2_fs.at(static_cast<size_t>(type)), source_hashes[9]);
546}
547
548std::array<u8, 32> PartitionDataManager::GetSDSaveKeySource(Package2Type type) const {
549 return FindKeyFromHex<0x20>(package2_fs.at(static_cast<size_t>(type)), source_hashes[10]);
550}
551
552std::array<u8, 32> PartitionDataManager::GetSDNCAKeySource(Package2Type type) const {
553 return FindKeyFromHex<0x20>(package2_fs.at(static_cast<size_t>(type)), source_hashes[11]);
554}
555
556std::array<u8, 16> PartitionDataManager::GetHeaderKekSource(Package2Type type) const {
557 return FindKeyFromHex(package2_fs.at(static_cast<size_t>(type)), source_hashes[12]);
558}
559
560std::array<u8, 32> PartitionDataManager::GetHeaderKeySource(Package2Type type) const {
561 return FindKeyFromHex<0x20>(package2_fs.at(static_cast<size_t>(type)), source_hashes[13]);
562}
563
564const std::vector<u8>& PartitionDataManager::GetPackage2SPLDecompressed(Package2Type type) const {
565 return package2_spl.at(static_cast<size_t>(type));
566}
567
568std::array<u8, 16> PartitionDataManager::GetAESKeyGenerationSource(Package2Type type) const {
569 return FindKeyFromHex(package2_spl.at(static_cast<size_t>(type)), source_hashes[4]);
570}
571
572bool PartitionDataManager::HasProdInfo() const {
573 return prodinfo != nullptr;
574}
575
576FileSys::VirtualFile PartitionDataManager::GetProdInfoRaw() const {
577 return prodinfo;
578}
579
580void PartitionDataManager::DecryptProdInfo(std::array<u8, 0x20> bis_key) {
581 if (prodinfo == nullptr)
582 return;
583
584 prodinfo_decrypted = std::make_shared<XTSEncryptionLayer>(prodinfo, bis_key);
585}
586
587std::array<u8, 576> PartitionDataManager::GetETicketExtendedKek() const {
588 std::array<u8, 0x240> out{};
589 if (prodinfo_decrypted != nullptr)
590 prodinfo_decrypted->Read(out.data(), out.size(), 0x3890);
591 return out;
592}
593} // namespace Core::Crypto
diff --git a/src/core/crypto/partition_data_manager.h b/src/core/crypto/partition_data_manager.h
new file mode 100644
index 000000000..0ad007c72
--- /dev/null
+++ b/src/core/crypto/partition_data_manager.h
@@ -0,0 +1,109 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <vector>
8#include "common/common_types.h"
9#include "core/file_sys/vfs_types.h"
10
11namespace Core::Crypto {
12
13enum class Package2Type {
14 NormalMain,
15 NormalSub,
16 SafeModeMain,
17 SafeModeSub,
18 RepairMain,
19 RepairSub,
20};
21
22class PartitionDataManager {
23public:
24 static const u8 MAX_KEYBLOB_SOURCE_HASH;
25 static constexpr std::size_t NUM_ENCRYPTED_KEYBLOBS = 32;
26 static constexpr std::size_t ENCRYPTED_KEYBLOB_SIZE = 0xB0;
27
28 using EncryptedKeyBlob = std::array<u8, ENCRYPTED_KEYBLOB_SIZE>;
29 using EncryptedKeyBlobs = std::array<EncryptedKeyBlob, NUM_ENCRYPTED_KEYBLOBS>;
30
31 explicit PartitionDataManager(const FileSys::VirtualDir& sysdata_dir);
32 ~PartitionDataManager();
33
34 // BOOT0
35 bool HasBoot0() const;
36 FileSys::VirtualFile GetBoot0Raw() const;
37 EncryptedKeyBlob GetEncryptedKeyblob(std::size_t index) const;
38 EncryptedKeyBlobs GetEncryptedKeyblobs() const;
39 std::vector<u8> GetSecureMonitor() const;
40 std::array<u8, 0x10> GetPackage2KeySource() const;
41 std::array<u8, 0x10> GetAESKekGenerationSource() const;
42 std::array<u8, 0x10> GetTitlekekSource() const;
43 std::array<std::array<u8, 0x10>, 0x20> GetTZMasterKeys(std::array<u8, 0x10> master_key) const;
44 std::array<u8, 0x10> GetRSAKekSeed3() const;
45 std::array<u8, 0x10> GetRSAKekMask0() const;
46 std::vector<u8> GetPackage1Decrypted() const;
47 std::array<u8, 0x10> GetMasterKeySource() const;
48 std::array<u8, 0x10> GetKeyblobMACKeySource() const;
49 std::array<u8, 0x10> GetKeyblobKeySource(std::size_t revision) const;
50
51 // Fuses
52 bool HasFuses() const;
53 FileSys::VirtualFile GetFusesRaw() const;
54 std::array<u8, 0x10> GetSecureBootKey() const;
55
56 // K-Fuses
57 bool HasKFuses() const;
58 FileSys::VirtualFile GetKFusesRaw() const;
59
60 // Package2
61 bool HasPackage2(Package2Type type = Package2Type::NormalMain) const;
62 FileSys::VirtualFile GetPackage2Raw(Package2Type type = Package2Type::NormalMain) const;
63 void DecryptPackage2(const std::array<std::array<u8, 16>, 0x20>& package2_keys,
64 Package2Type type);
65 const std::vector<u8>& GetPackage2FSDecompressed(
66 Package2Type type = Package2Type::NormalMain) const;
67 std::array<u8, 0x10> GetKeyAreaKeyApplicationSource(
68 Package2Type type = Package2Type::NormalMain) const;
69 std::array<u8, 0x10> GetKeyAreaKeyOceanSource(
70 Package2Type type = Package2Type::NormalMain) const;
71 std::array<u8, 0x10> GetKeyAreaKeySystemSource(
72 Package2Type type = Package2Type::NormalMain) const;
73 std::array<u8, 0x10> GetSDKekSource(Package2Type type = Package2Type::NormalMain) const;
74 std::array<u8, 0x20> GetSDSaveKeySource(Package2Type type = Package2Type::NormalMain) const;
75 std::array<u8, 0x20> GetSDNCAKeySource(Package2Type type = Package2Type::NormalMain) const;
76 std::array<u8, 0x10> GetHeaderKekSource(Package2Type type = Package2Type::NormalMain) const;
77 std::array<u8, 0x20> GetHeaderKeySource(Package2Type type = Package2Type::NormalMain) const;
78 const std::vector<u8>& GetPackage2SPLDecompressed(
79 Package2Type type = Package2Type::NormalMain) const;
80 std::array<u8, 0x10> GetAESKeyGenerationSource(
81 Package2Type type = Package2Type::NormalMain) const;
82
83 // PRODINFO
84 bool HasProdInfo() const;
85 FileSys::VirtualFile GetProdInfoRaw() const;
86 void DecryptProdInfo(std::array<u8, 0x20> bis_key);
87 std::array<u8, 0x240> GetETicketExtendedKek() const;
88
89private:
90 FileSys::VirtualFile boot0;
91 FileSys::VirtualFile fuses;
92 FileSys::VirtualFile kfuses;
93 std::array<FileSys::VirtualFile, 6> package2;
94 FileSys::VirtualFile prodinfo;
95 FileSys::VirtualFile secure_monitor;
96 FileSys::VirtualFile package1_decrypted;
97
98 // Processed
99 std::array<FileSys::VirtualFile, 6> package2_decrypted;
100 FileSys::VirtualFile prodinfo_decrypted;
101 std::vector<u8> secure_monitor_bytes;
102 std::vector<u8> package1_decrypted_bytes;
103 std::array<std::vector<u8>, 6> package2_fs;
104 std::array<std::vector<u8>, 6> package2_spl;
105};
106
107std::array<u8, 0x10> FindKeyFromHex16(const std::vector<u8>& binary, std::array<u8, 0x20> hash);
108
109} // namespace Core::Crypto
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp
index 6102ef476..76a2b7e86 100644
--- a/src/core/file_sys/bis_factory.cpp
+++ b/src/core/file_sys/bis_factory.cpp
@@ -10,19 +10,19 @@ namespace FileSys {
10 10
11BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_) 11BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_)
12 : nand_root(std::move(nand_root_)), load_root(std::move(load_root_)), 12 : nand_root(std::move(nand_root_)), load_root(std::move(load_root_)),
13 sysnand_cache(std::make_shared<RegisteredCache>( 13 sysnand_cache(std::make_unique<RegisteredCache>(
14 GetOrCreateDirectoryRelative(nand_root, "/system/Contents/registered"))), 14 GetOrCreateDirectoryRelative(nand_root, "/system/Contents/registered"))),
15 usrnand_cache(std::make_shared<RegisteredCache>( 15 usrnand_cache(std::make_unique<RegisteredCache>(
16 GetOrCreateDirectoryRelative(nand_root, "/user/Contents/registered"))) {} 16 GetOrCreateDirectoryRelative(nand_root, "/user/Contents/registered"))) {}
17 17
18BISFactory::~BISFactory() = default; 18BISFactory::~BISFactory() = default;
19 19
20std::shared_ptr<RegisteredCache> BISFactory::GetSystemNANDContents() const { 20RegisteredCache* BISFactory::GetSystemNANDContents() const {
21 return sysnand_cache; 21 return sysnand_cache.get();
22} 22}
23 23
24std::shared_ptr<RegisteredCache> BISFactory::GetUserNANDContents() const { 24RegisteredCache* BISFactory::GetUserNANDContents() const {
25 return usrnand_cache; 25 return usrnand_cache.get();
26} 26}
27 27
28VirtualDir BISFactory::GetModificationLoadRoot(u64 title_id) const { 28VirtualDir BISFactory::GetModificationLoadRoot(u64 title_id) const {
diff --git a/src/core/file_sys/bis_factory.h b/src/core/file_sys/bis_factory.h
index c352e0925..364d309bd 100644
--- a/src/core/file_sys/bis_factory.h
+++ b/src/core/file_sys/bis_factory.h
@@ -20,8 +20,8 @@ public:
20 explicit BISFactory(VirtualDir nand_root, VirtualDir load_root); 20 explicit BISFactory(VirtualDir nand_root, VirtualDir load_root);
21 ~BISFactory(); 21 ~BISFactory();
22 22
23 std::shared_ptr<RegisteredCache> GetSystemNANDContents() const; 23 RegisteredCache* GetSystemNANDContents() const;
24 std::shared_ptr<RegisteredCache> GetUserNANDContents() const; 24 RegisteredCache* GetUserNANDContents() const;
25 25
26 VirtualDir GetModificationLoadRoot(u64 title_id) const; 26 VirtualDir GetModificationLoadRoot(u64 title_id) const;
27 27
@@ -29,8 +29,8 @@ private:
29 VirtualDir nand_root; 29 VirtualDir nand_root;
30 VirtualDir load_root; 30 VirtualDir load_root;
31 31
32 std::shared_ptr<RegisteredCache> sysnand_cache; 32 std::unique_ptr<RegisteredCache> sysnand_cache;
33 std::shared_ptr<RegisteredCache> usrnand_cache; 33 std::unique_ptr<RegisteredCache> usrnand_cache;
34}; 34};
35 35
36} // namespace FileSys 36} // namespace FileSys
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index aa1b3c17d..6dcec7816 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -133,7 +133,7 @@ boost::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType ty
133 static_cast<u8>(type)); 133 static_cast<u8>(type));
134 u128 out_128{}; 134 u128 out_128{};
135 memcpy(out_128.data(), out.data(), 16); 135 memcpy(out_128.data(), out.data(), 16);
136 LOG_DEBUG(Crypto, "called with crypto_rev={:02X}, kak_index={:02X}, key={:016X}{:016X}", 136 LOG_TRACE(Crypto, "called with crypto_rev={:02X}, kak_index={:02X}, key={:016X}{:016X}",
137 master_key_id, header.key_index, out_128[1], out_128[0]); 137 master_key_id, header.key_index, out_128[1], out_128[0]);
138 138
139 return out; 139 return out;
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index 5b1177a03..a012c2be9 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -17,11 +17,13 @@ const std::array<const char*, 15> LANGUAGE_NAMES = {
17}; 17};
18 18
19std::string LanguageEntry::GetApplicationName() const { 19std::string LanguageEntry::GetApplicationName() const {
20 return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), 0x200); 20 return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(),
21 application_name.size());
21} 22}
22 23
23std::string LanguageEntry::GetDeveloperName() const { 24std::string LanguageEntry::GetDeveloperName() const {
24 return Common::StringFromFixedZeroTerminatedBuffer(developer_name.data(), 0x100); 25 return Common::StringFromFixedZeroTerminatedBuffer(developer_name.data(),
26 developer_name.size());
25} 27}
26 28
27NACP::NACP(VirtualFile file) : raw(std::make_unique<RawNACP>()) { 29NACP::NACP(VirtualFile file) : raw(std::make_unique<RawNACP>()) {
@@ -56,7 +58,12 @@ u64 NACP::GetTitleId() const {
56 return raw->title_id; 58 return raw->title_id;
57} 59}
58 60
61u64 NACP::GetDLCBaseTitleId() const {
62 return raw->dlc_base_title_id;
63}
64
59std::string NACP::GetVersionString() const { 65std::string NACP::GetVersionString() const {
60 return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(), 0x10); 66 return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(),
67 raw->version_string.size());
61} 68}
62} // namespace FileSys 69} // namespace FileSys
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index 43d6f0719..141f7e056 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -79,6 +79,7 @@ public:
79 std::string GetApplicationName(Language language = Language::Default) const; 79 std::string GetApplicationName(Language language = Language::Default) const;
80 std::string GetDeveloperName(Language language = Language::Default) const; 80 std::string GetDeveloperName(Language language = Language::Default) const;
81 u64 GetTitleId() const; 81 u64 GetTitleId() const;
82 u64 GetDLCBaseTitleId() const;
82 std::string GetVersionString() const; 83 std::string GetVersionString() const;
83 84
84private: 85private:
diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp
index 6c072d0a3..554eae9bc 100644
--- a/src/core/file_sys/ips_layer.cpp
+++ b/src/core/file_sys/ips_layer.cpp
@@ -107,12 +107,12 @@ VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) {
107 return nullptr; 107 return nullptr;
108 108
109 if (real_offset + rle_size > in_data.size()) 109 if (real_offset + rle_size > in_data.size())
110 rle_size = in_data.size() - real_offset; 110 rle_size = static_cast<u16>(in_data.size() - real_offset);
111 std::memset(in_data.data() + real_offset, data.get(), rle_size); 111 std::memset(in_data.data() + real_offset, data.get(), rle_size);
112 } else { // Standard Patch 112 } else { // Standard Patch
113 auto read = data_size; 113 auto read = data_size;
114 if (real_offset + read > in_data.size()) 114 if (real_offset + read > in_data.size())
115 read = in_data.size() - real_offset; 115 read = static_cast<u16>(in_data.size() - real_offset);
116 if (ips->Read(in_data.data() + real_offset, read, offset) != data_size) 116 if (ips->Read(in_data.data() + real_offset, read, offset) != data_size)
117 return nullptr; 117 return nullptr;
118 offset += data_size; 118 offset += data_size;
@@ -265,7 +265,7 @@ void IPSwitchCompiler::Parse() {
265 if (patch_line.length() < 11) 265 if (patch_line.length() < 11)
266 break; 266 break;
267 auto offset = std::stoul(patch_line.substr(0, 8), nullptr, 16); 267 auto offset = std::stoul(patch_line.substr(0, 8), nullptr, 16);
268 offset += offset_shift; 268 offset += static_cast<unsigned long>(offset_shift);
269 269
270 std::vector<u8> replace; 270 std::vector<u8> replace;
271 // 9 - first char of replacement val 271 // 9 - first char of replacement val
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index b14d7cb0a..0117cb0bf 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -214,8 +214,14 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t
214 214
215VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, ContentRecordType type, 215VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, ContentRecordType type,
216 VirtualFile update_raw) const { 216 VirtualFile update_raw) const {
217 LOG_INFO(Loader, "Patching RomFS for title_id={:016X}, type={:02X}", title_id, 217 const auto log_string = fmt::format("Patching RomFS for title_id={:016X}, type={:02X}",
218 static_cast<u8>(type)); 218 title_id, static_cast<u8>(type))
219 .c_str();
220
221 if (type == ContentRecordType::Program)
222 LOG_INFO(Loader, log_string);
223 else
224 LOG_DEBUG(Loader, log_string);
219 225
220 if (romfs == nullptr) 226 if (romfs == nullptr)
221 return romfs; 227 return romfs;
@@ -345,23 +351,22 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
345 return out; 351 return out;
346} 352}
347 353
348std::pair<std::shared_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const { 354std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const {
349 const auto& installed{Service::FileSystem::GetUnionContents()}; 355 const auto installed{Service::FileSystem::GetUnionContents()};
350 356
351 const auto base_control_nca = installed->GetEntry(title_id, ContentRecordType::Control); 357 const auto base_control_nca = installed->GetEntry(title_id, ContentRecordType::Control);
352 if (base_control_nca == nullptr) 358 if (base_control_nca == nullptr)
353 return {}; 359 return {};
354 360
355 return ParseControlNCA(base_control_nca); 361 return ParseControlNCA(*base_control_nca);
356} 362}
357 363
358std::pair<std::shared_ptr<NACP>, VirtualFile> PatchManager::ParseControlNCA( 364std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::ParseControlNCA(const NCA& nca) const {
359 const std::shared_ptr<NCA>& nca) const { 365 const auto base_romfs = nca.GetRomFS();
360 const auto base_romfs = nca->GetRomFS();
361 if (base_romfs == nullptr) 366 if (base_romfs == nullptr)
362 return {}; 367 return {};
363 368
364 const auto romfs = PatchRomFS(base_romfs, nca->GetBaseIVFCOffset(), ContentRecordType::Control); 369 const auto romfs = PatchRomFS(base_romfs, nca.GetBaseIVFCOffset(), ContentRecordType::Control);
365 if (romfs == nullptr) 370 if (romfs == nullptr)
366 return {}; 371 return {};
367 372
@@ -373,7 +378,7 @@ std::pair<std::shared_ptr<NACP>, VirtualFile> PatchManager::ParseControlNCA(
373 if (nacp_file == nullptr) 378 if (nacp_file == nullptr)
374 nacp_file = extracted->GetFile("Control.nacp"); 379 nacp_file = extracted->GetFile("Control.nacp");
375 380
376 const auto nacp = nacp_file == nullptr ? nullptr : std::make_shared<NACP>(nacp_file); 381 auto nacp = nacp_file == nullptr ? nullptr : std::make_unique<NACP>(nacp_file);
377 382
378 VirtualFile icon_file; 383 VirtualFile icon_file;
379 for (const auto& language : FileSys::LANGUAGE_NAMES) { 384 for (const auto& language : FileSys::LANGUAGE_NAMES) {
@@ -382,6 +387,6 @@ std::pair<std::shared_ptr<NACP>, VirtualFile> PatchManager::ParseControlNCA(
382 break; 387 break;
383 } 388 }
384 389
385 return {nacp, icon_file}; 390 return {std::move(nacp), icon_file};
386} 391}
387} // namespace FileSys 392} // namespace FileSys
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index eb6fc4607..7d168837f 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -57,11 +57,10 @@ public:
57 57
58 // Given title_id of the program, attempts to get the control data of the update and parse it, 58 // Given title_id of the program, attempts to get the control data of the update and parse it,
59 // falling back to the base control data. 59 // falling back to the base control data.
60 std::pair<std::shared_ptr<NACP>, VirtualFile> GetControlMetadata() const; 60 std::pair<std::unique_ptr<NACP>, VirtualFile> GetControlMetadata() const;
61 61
62 // Version of GetControlMetadata that takes an arbitrary NCA 62 // Version of GetControlMetadata that takes an arbitrary NCA
63 std::pair<std::shared_ptr<NACP>, VirtualFile> ParseControlNCA( 63 std::pair<std::unique_ptr<NACP>, VirtualFile> ParseControlNCA(const NCA& nca) const;
64 const std::shared_ptr<NCA>& nca) const;
65 64
66private: 65private:
67 u64 title_id; 66 u64 title_id;
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index e9b040689..1febb398e 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -308,14 +308,14 @@ VirtualFile RegisteredCache::GetEntryRaw(RegisteredCacheEntry entry) const {
308 return GetEntryRaw(entry.title_id, entry.type); 308 return GetEntryRaw(entry.title_id, entry.type);
309} 309}
310 310
311std::shared_ptr<NCA> RegisteredCache::GetEntry(u64 title_id, ContentRecordType type) const { 311std::unique_ptr<NCA> RegisteredCache::GetEntry(u64 title_id, ContentRecordType type) const {
312 const auto raw = GetEntryRaw(title_id, type); 312 const auto raw = GetEntryRaw(title_id, type);
313 if (raw == nullptr) 313 if (raw == nullptr)
314 return nullptr; 314 return nullptr;
315 return std::make_shared<NCA>(raw); 315 return std::make_unique<NCA>(raw);
316} 316}
317 317
318std::shared_ptr<NCA> RegisteredCache::GetEntry(RegisteredCacheEntry entry) const { 318std::unique_ptr<NCA> RegisteredCache::GetEntry(RegisteredCacheEntry entry) const {
319 return GetEntry(entry.title_id, entry.type); 319 return GetEntry(entry.title_id, entry.type);
320} 320}
321 321
@@ -516,7 +516,7 @@ bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) {
516 }) != yuzu_meta.end(); 516 }) != yuzu_meta.end();
517} 517}
518 518
519RegisteredCacheUnion::RegisteredCacheUnion(std::vector<std::shared_ptr<RegisteredCache>> caches) 519RegisteredCacheUnion::RegisteredCacheUnion(std::vector<RegisteredCache*> caches)
520 : caches(std::move(caches)) {} 520 : caches(std::move(caches)) {}
521 521
522void RegisteredCacheUnion::Refresh() { 522void RegisteredCacheUnion::Refresh() {
@@ -572,14 +572,14 @@ VirtualFile RegisteredCacheUnion::GetEntryRaw(RegisteredCacheEntry entry) const
572 return GetEntryRaw(entry.title_id, entry.type); 572 return GetEntryRaw(entry.title_id, entry.type);
573} 573}
574 574
575std::shared_ptr<NCA> RegisteredCacheUnion::GetEntry(u64 title_id, ContentRecordType type) const { 575std::unique_ptr<NCA> RegisteredCacheUnion::GetEntry(u64 title_id, ContentRecordType type) const {
576 const auto raw = GetEntryRaw(title_id, type); 576 const auto raw = GetEntryRaw(title_id, type);
577 if (raw == nullptr) 577 if (raw == nullptr)
578 return nullptr; 578 return nullptr;
579 return std::make_shared<NCA>(raw); 579 return std::make_unique<NCA>(raw);
580} 580}
581 581
582std::shared_ptr<NCA> RegisteredCacheUnion::GetEntry(RegisteredCacheEntry entry) const { 582std::unique_ptr<NCA> RegisteredCacheUnion::GetEntry(RegisteredCacheEntry entry) const {
583 return GetEntry(entry.title_id, entry.type); 583 return GetEntry(entry.title_id, entry.type);
584} 584}
585 585
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index c0cd59fc5..5ddacba47 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -88,8 +88,8 @@ public:
88 VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const; 88 VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const;
89 VirtualFile GetEntryRaw(RegisteredCacheEntry entry) const; 89 VirtualFile GetEntryRaw(RegisteredCacheEntry entry) const;
90 90
91 std::shared_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const; 91 std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const;
92 std::shared_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const; 92 std::unique_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const;
93 93
94 std::vector<RegisteredCacheEntry> ListEntries() const; 94 std::vector<RegisteredCacheEntry> ListEntries() const;
95 // If a parameter is not boost::none, it will be filtered for from all entries. 95 // If a parameter is not boost::none, it will be filtered for from all entries.
@@ -142,7 +142,7 @@ private:
142// Combines multiple RegisteredCaches (i.e. SysNAND, UserNAND, SDMC) into one interface. 142// Combines multiple RegisteredCaches (i.e. SysNAND, UserNAND, SDMC) into one interface.
143class RegisteredCacheUnion { 143class RegisteredCacheUnion {
144public: 144public:
145 explicit RegisteredCacheUnion(std::vector<std::shared_ptr<RegisteredCache>> caches); 145 explicit RegisteredCacheUnion(std::vector<RegisteredCache*> caches);
146 146
147 void Refresh(); 147 void Refresh();
148 148
@@ -157,8 +157,8 @@ public:
157 VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const; 157 VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const;
158 VirtualFile GetEntryRaw(RegisteredCacheEntry entry) const; 158 VirtualFile GetEntryRaw(RegisteredCacheEntry entry) const;
159 159
160 std::shared_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const; 160 std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const;
161 std::shared_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const; 161 std::unique_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const;
162 162
163 std::vector<RegisteredCacheEntry> ListEntries() const; 163 std::vector<RegisteredCacheEntry> ListEntries() const;
164 // If a parameter is not boost::none, it will be filtered for from all entries. 164 // If a parameter is not boost::none, it will be filtered for from all entries.
@@ -168,7 +168,7 @@ public:
168 boost::optional<u64> title_id = boost::none) const; 168 boost::optional<u64> title_id = boost::none) const;
169 169
170private: 170private:
171 std::vector<std::shared_ptr<RegisteredCache>> caches; 171 std::vector<RegisteredCache*> caches;
172}; 172};
173 173
174} // namespace FileSys 174} // namespace FileSys
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index 47f2ab9e0..ef1aaebbb 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -51,6 +51,13 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescr
51 meta.title_id); 51 meta.title_id);
52 } 52 }
53 53
54 if (meta.type == SaveDataType::DeviceSaveData && meta.user_id != u128{0, 0}) {
55 LOG_WARNING(Service_FS,
56 "Possibly incorrect SaveDataDescriptor, type is DeviceSaveData but user_id is "
57 "non-zero ({:016X}{:016X})",
58 meta.user_id[1], meta.user_id[0]);
59 }
60
54 std::string save_directory = 61 std::string save_directory =
55 GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id); 62 GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id);
56 63
@@ -92,6 +99,9 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
92 case SaveDataSpaceId::NandUser: 99 case SaveDataSpaceId::NandUser:
93 out = "/user/"; 100 out = "/user/";
94 break; 101 break;
102 case SaveDataSpaceId::TemporaryStorage:
103 out = "/temp/";
104 break;
95 default: 105 default:
96 ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space)); 106 ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
97 } 107 }
@@ -100,10 +110,11 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
100 case SaveDataType::SystemSaveData: 110 case SaveDataType::SystemSaveData:
101 return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]); 111 return fmt::format("{}save/{:016X}/{:016X}{:016X}", out, save_id, user_id[1], user_id[0]);
102 case SaveDataType::SaveData: 112 case SaveDataType::SaveData:
113 case SaveDataType::DeviceSaveData:
103 return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0], 114 return fmt::format("{}save/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
104 title_id); 115 title_id);
105 case SaveDataType::TemporaryStorage: 116 case SaveDataType::TemporaryStorage:
106 return fmt::format("{}temp/{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0], 117 return fmt::format("{}{:016X}/{:016X}{:016X}/{:016X}", out, 0, user_id[1], user_id[0],
107 title_id); 118 title_id);
108 default: 119 default:
109 ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type)); 120 ASSERT_MSG(false, "Unrecognized SaveDataType: {:02X}", static_cast<u8>(type));
diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp
index d66a9c9a4..bd3a57058 100644
--- a/src/core/file_sys/sdmc_factory.cpp
+++ b/src/core/file_sys/sdmc_factory.cpp
@@ -10,10 +10,10 @@
10namespace FileSys { 10namespace FileSys {
11 11
12SDMCFactory::SDMCFactory(VirtualDir dir_) 12SDMCFactory::SDMCFactory(VirtualDir dir_)
13 : dir(std::move(dir_)), contents(std::make_shared<RegisteredCache>( 13 : dir(std::move(dir_)), contents(std::make_unique<RegisteredCache>(
14 GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/registered"), 14 GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/registered"),
15 [](const VirtualFile& file, const NcaID& id) { 15 [](const VirtualFile& file, const NcaID& id) {
16 return std::make_shared<NAX>(file, id)->GetDecrypted(); 16 return NAX{file, id}.GetDecrypted();
17 })) {} 17 })) {}
18 18
19SDMCFactory::~SDMCFactory() = default; 19SDMCFactory::~SDMCFactory() = default;
@@ -22,8 +22,8 @@ ResultVal<VirtualDir> SDMCFactory::Open() {
22 return MakeResult<VirtualDir>(dir); 22 return MakeResult<VirtualDir>(dir);
23} 23}
24 24
25std::shared_ptr<RegisteredCache> SDMCFactory::GetSDMCContents() const { 25RegisteredCache* SDMCFactory::GetSDMCContents() const {
26 return contents; 26 return contents.get();
27} 27}
28 28
29} // namespace FileSys 29} // namespace FileSys
diff --git a/src/core/file_sys/sdmc_factory.h b/src/core/file_sys/sdmc_factory.h
index ea12149de..42794ba5b 100644
--- a/src/core/file_sys/sdmc_factory.h
+++ b/src/core/file_sys/sdmc_factory.h
@@ -19,12 +19,12 @@ public:
19 ~SDMCFactory(); 19 ~SDMCFactory();
20 20
21 ResultVal<VirtualDir> Open(); 21 ResultVal<VirtualDir> Open();
22 std::shared_ptr<RegisteredCache> GetSDMCContents() const; 22 RegisteredCache* GetSDMCContents() const;
23 23
24private: 24private:
25 VirtualDir dir; 25 VirtualDir dir;
26 26
27 std::shared_ptr<RegisteredCache> contents; 27 std::unique_ptr<RegisteredCache> contents;
28}; 28};
29 29
30} // namespace FileSys 30} // namespace FileSys
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h
index 270291631..7f0d520ca 100644
--- a/src/core/file_sys/vfs.h
+++ b/src/core/file_sys/vfs.h
@@ -12,20 +12,12 @@
12#include <vector> 12#include <vector>
13#include <boost/optional.hpp> 13#include <boost/optional.hpp>
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "core/file_sys/vfs_types.h"
15 16
16namespace FileSys { 17namespace FileSys {
17 18
18class VfsDirectory;
19class VfsFile;
20class VfsFilesystem;
21
22enum class Mode : u32; 19enum class Mode : u32;
23 20
24// Convenience typedefs to use Vfs* interfaces
25using VirtualFilesystem = std::shared_ptr<VfsFilesystem>;
26using VirtualDir = std::shared_ptr<VfsDirectory>;
27using VirtualFile = std::shared_ptr<VfsFile>;
28
29// An enumeration representing what can be at the end of a path in a VfsFilesystem 21// An enumeration representing what can be at the end of a path in a VfsFilesystem
30enum class VfsEntryType { 22enum class VfsEntryType {
31 None, 23 None,
diff --git a/src/core/file_sys/vfs_types.h b/src/core/file_sys/vfs_types.h
new file mode 100644
index 000000000..6215ed7af
--- /dev/null
+++ b/src/core/file_sys/vfs_types.h
@@ -0,0 +1,21 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8
9namespace FileSys {
10
11class VfsDirectory;
12class VfsFile;
13class VfsFilesystem;
14
15// Declarations for Vfs* pointer types
16
17using VirtualDir = std::shared_ptr<VfsDirectory>;
18using VirtualFile = std::shared_ptr<VfsFile>;
19using VirtualFilesystem = std::shared_ptr<VfsFilesystem>;
20
21} // namespace FileSys
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index e961ef121..bdcc889e0 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -207,7 +207,7 @@ void RegisterModule(std::string name, VAddr beg, VAddr end, bool add_elf_ext) {
207 207
208static Kernel::Thread* FindThreadById(int id) { 208static Kernel::Thread* FindThreadById(int id) {
209 for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { 209 for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) {
210 const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); 210 const auto& threads = Core::System::GetInstance().Scheduler(core).GetThreadList();
211 for (auto& thread : threads) { 211 for (auto& thread : threads) {
212 if (thread->GetThreadID() == static_cast<u32>(id)) { 212 if (thread->GetThreadID() == static_cast<u32>(id)) {
213 current_core = core; 213 current_core = core;
@@ -597,7 +597,7 @@ static void HandleQuery() {
597 } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) { 597 } else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) {
598 std::string val = "m"; 598 std::string val = "m";
599 for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { 599 for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) {
600 const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); 600 const auto& threads = Core::System::GetInstance().Scheduler(core).GetThreadList();
601 for (const auto& thread : threads) { 601 for (const auto& thread : threads) {
602 val += fmt::format("{:x}", thread->GetThreadID()); 602 val += fmt::format("{:x}", thread->GetThreadID());
603 val += ","; 603 val += ",";
@@ -612,7 +612,7 @@ static void HandleQuery() {
612 buffer += "l<?xml version=\"1.0\"?>"; 612 buffer += "l<?xml version=\"1.0\"?>";
613 buffer += "<threads>"; 613 buffer += "<threads>";
614 for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { 614 for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) {
615 const auto& threads = Core::System::GetInstance().Scheduler(core)->GetThreadList(); 615 const auto& threads = Core::System::GetInstance().Scheduler(core).GetThreadList();
616 for (const auto& thread : threads) { 616 for (const auto& thread : threads) {
617 buffer += 617 buffer +=
618 fmt::format(R"*(<thread id="{:x}" core="{:d}" name="Thread {:x}"></thread>)*", 618 fmt::format(R"*(<thread id="{:x}" core="{:d}" name="Thread {:x}"></thread>)*",
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index ebf193930..57157beb4 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -39,7 +39,7 @@ static std::vector<SharedPtr<Thread>> GetThreadsWaitingOnAddress(VAddr address)
39 std::vector<SharedPtr<Thread>>& waiting_threads, 39 std::vector<SharedPtr<Thread>>& waiting_threads,
40 VAddr arb_addr) { 40 VAddr arb_addr) {
41 const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); 41 const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
42 const auto& thread_list = scheduler->GetThreadList(); 42 const auto& thread_list = scheduler.GetThreadList();
43 43
44 for (const auto& thread : thread_list) { 44 for (const auto& thread : thread_list) {
45 if (thread->GetArbiterWaitAddress() == arb_addr) 45 if (thread->GetArbiterWaitAddress() == arb_addr)
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h
index e5fa67ae8..885259618 100644
--- a/src/core/hle/kernel/errors.h
+++ b/src/core/hle/kernel/errors.h
@@ -22,6 +22,7 @@ enum {
22 HandleTableFull = 105, 22 HandleTableFull = 105,
23 InvalidMemoryState = 106, 23 InvalidMemoryState = 106,
24 InvalidMemoryPermissions = 108, 24 InvalidMemoryPermissions = 108,
25 InvalidMemoryRange = 110,
25 InvalidThreadPriority = 112, 26 InvalidThreadPriority = 112,
26 InvalidProcessorId = 113, 27 InvalidProcessorId = 113,
27 InvalidHandle = 114, 28 InvalidHandle = 114,
@@ -56,6 +57,7 @@ constexpr ResultCode ERR_INVALID_ADDRESS(ErrorModule::Kernel, ErrCodes::InvalidA
56constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState); 57constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState);
57constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel, 58constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel,
58 ErrCodes::InvalidMemoryPermissions); 59 ErrCodes::InvalidMemoryPermissions);
60constexpr ResultCode ERR_INVALID_MEMORY_RANGE(ErrorModule::Kernel, ErrCodes::InvalidMemoryRange);
59constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); 61constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle);
60constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); 62constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
61constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize); 63constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize);
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 98eb74298..bd680adfe 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -116,7 +116,7 @@ struct KernelCore::Impl {
116 next_thread_id = 1; 116 next_thread_id = 1;
117 117
118 process_list.clear(); 118 process_list.clear();
119 current_process.reset(); 119 current_process = nullptr;
120 120
121 handle_table.Clear(); 121 handle_table.Clear();
122 resource_limits.fill(nullptr); 122 resource_limits.fill(nullptr);
@@ -207,7 +207,7 @@ struct KernelCore::Impl {
207 207
208 // Lists all processes that exist in the current session. 208 // Lists all processes that exist in the current session.
209 std::vector<SharedPtr<Process>> process_list; 209 std::vector<SharedPtr<Process>> process_list;
210 SharedPtr<Process> current_process; 210 Process* current_process = nullptr;
211 211
212 Kernel::HandleTable handle_table; 212 Kernel::HandleTable handle_table;
213 std::array<SharedPtr<ResourceLimit>, 4> resource_limits; 213 std::array<SharedPtr<ResourceLimit>, 4> resource_limits;
@@ -266,15 +266,15 @@ void KernelCore::AppendNewProcess(SharedPtr<Process> process) {
266 impl->process_list.push_back(std::move(process)); 266 impl->process_list.push_back(std::move(process));
267} 267}
268 268
269void KernelCore::MakeCurrentProcess(SharedPtr<Process> process) { 269void KernelCore::MakeCurrentProcess(Process* process) {
270 impl->current_process = std::move(process); 270 impl->current_process = process;
271} 271}
272 272
273SharedPtr<Process>& KernelCore::CurrentProcess() { 273Process* KernelCore::CurrentProcess() {
274 return impl->current_process; 274 return impl->current_process;
275} 275}
276 276
277const SharedPtr<Process>& KernelCore::CurrentProcess() const { 277const Process* KernelCore::CurrentProcess() const {
278 return impl->current_process; 278 return impl->current_process;
279} 279}
280 280
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index c0771ecf0..41554821f 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -66,13 +66,13 @@ public:
66 void AppendNewProcess(SharedPtr<Process> process); 66 void AppendNewProcess(SharedPtr<Process> process);
67 67
68 /// Makes the given process the new current process. 68 /// Makes the given process the new current process.
69 void MakeCurrentProcess(SharedPtr<Process> process); 69 void MakeCurrentProcess(Process* process);
70 70
71 /// Retrieves a reference to the current process. 71 /// Retrieves a pointer to the current process.
72 SharedPtr<Process>& CurrentProcess(); 72 Process* CurrentProcess();
73 73
74 /// Retrieves a const reference to the current process. 74 /// Retrieves a const pointer to the current process.
75 const SharedPtr<Process>& CurrentProcess() const; 75 const Process* CurrentProcess() const;
76 76
77 /// Adds a port to the named port table 77 /// Adds a port to the named port table
78 void AddNamedPort(std::string name, SharedPtr<ClientPort> port); 78 void AddNamedPort(std::string name, SharedPtr<ClientPort> port);
diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp
index d51562d92..d87a62bb9 100644
--- a/src/core/hle/kernel/object.cpp
+++ b/src/core/hle/kernel/object.cpp
@@ -25,7 +25,6 @@ bool Object::IsWaitable() const {
25 case HandleType::Process: 25 case HandleType::Process:
26 case HandleType::AddressArbiter: 26 case HandleType::AddressArbiter:
27 case HandleType::ResourceLimit: 27 case HandleType::ResourceLimit:
28 case HandleType::CodeSet:
29 case HandleType::ClientPort: 28 case HandleType::ClientPort:
30 case HandleType::ClientSession: 29 case HandleType::ClientSession:
31 return false; 30 return false;
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h
index 9eb72315c..c9f4d0bb3 100644
--- a/src/core/hle/kernel/object.h
+++ b/src/core/hle/kernel/object.h
@@ -26,7 +26,6 @@ enum class HandleType : u32 {
26 AddressArbiter, 26 AddressArbiter,
27 Timer, 27 Timer,
28 ResourceLimit, 28 ResourceLimit,
29 CodeSet,
30 ClientPort, 29 ClientPort,
31 ServerPort, 30 ServerPort,
32 ClientSession, 31 ClientSession,
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index fb0027a71..073dd5a7d 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -20,13 +20,7 @@
20 20
21namespace Kernel { 21namespace Kernel {
22 22
23SharedPtr<CodeSet> CodeSet::Create(KernelCore& kernel, std::string name) { 23CodeSet::CodeSet() = default;
24 SharedPtr<CodeSet> codeset(new CodeSet(kernel));
25 codeset->name = std::move(name);
26 return codeset;
27}
28
29CodeSet::CodeSet(KernelCore& kernel) : Object{kernel} {}
30CodeSet::~CodeSet() = default; 24CodeSet::~CodeSet() = default;
31 25
32SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) { 26SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) {
@@ -159,11 +153,11 @@ void Process::PrepareForTermination() {
159 } 153 }
160 }; 154 };
161 155
162 auto& system = Core::System::GetInstance(); 156 const auto& system = Core::System::GetInstance();
163 stop_threads(system.Scheduler(0)->GetThreadList()); 157 stop_threads(system.Scheduler(0).GetThreadList());
164 stop_threads(system.Scheduler(1)->GetThreadList()); 158 stop_threads(system.Scheduler(1).GetThreadList());
165 stop_threads(system.Scheduler(2)->GetThreadList()); 159 stop_threads(system.Scheduler(2).GetThreadList());
166 stop_threads(system.Scheduler(3)->GetThreadList()); 160 stop_threads(system.Scheduler(3).GetThreadList());
167} 161}
168 162
169/** 163/**
@@ -224,20 +218,20 @@ void Process::FreeTLSSlot(VAddr tls_address) {
224 tls_slots[tls_page].reset(tls_slot); 218 tls_slots[tls_page].reset(tls_slot);
225} 219}
226 220
227void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) { 221void Process::LoadModule(CodeSet module_, VAddr base_addr) {
228 const auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, 222 const auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
229 MemoryState memory_state) { 223 MemoryState memory_state) {
230 auto vma = vm_manager 224 const auto vma = vm_manager
231 .MapMemoryBlock(segment.addr + base_addr, module_->memory, segment.offset, 225 .MapMemoryBlock(segment.addr + base_addr, module_.memory,
232 segment.size, memory_state) 226 segment.offset, segment.size, memory_state)
233 .Unwrap(); 227 .Unwrap();
234 vm_manager.Reprotect(vma, permissions); 228 vm_manager.Reprotect(vma, permissions);
235 }; 229 };
236 230
237 // Map CodeSet segments 231 // Map CodeSet segments
238 MapSegment(module_->CodeSegment(), VMAPermission::ReadExecute, MemoryState::CodeStatic); 232 MapSegment(module_.CodeSegment(), VMAPermission::ReadExecute, MemoryState::CodeStatic);
239 MapSegment(module_->RODataSegment(), VMAPermission::Read, MemoryState::CodeMutable); 233 MapSegment(module_.RODataSegment(), VMAPermission::Read, MemoryState::CodeMutable);
240 MapSegment(module_->DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable); 234 MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable);
241} 235}
242 236
243ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { 237ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 590e0c73d..f2816943a 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -24,6 +24,7 @@ class ProgramMetadata;
24namespace Kernel { 24namespace Kernel {
25 25
26class KernelCore; 26class KernelCore;
27class ResourceLimit;
27 28
28struct AddressMapping { 29struct AddressMapping {
29 // Address and size must be page-aligned 30 // Address and size must be page-aligned
@@ -57,30 +58,33 @@ union ProcessFlags {
57 BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000). 58 BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000).
58}; 59};
59 60
60enum class ProcessStatus { Created, Running, Exited }; 61/**
61 62 * Indicates the status of a Process instance.
62class ResourceLimit; 63 *
64 * @note These match the values as used by kernel,
65 * so new entries should only be added if RE
66 * shows that a new value has been introduced.
67 */
68enum class ProcessStatus {
69 Created,
70 CreatedWithDebuggerAttached,
71 Running,
72 WaitingForDebuggerToAttach,
73 DebuggerAttached,
74 Exiting,
75 Exited,
76 DebugBreak,
77};
63 78
64struct CodeSet final : public Object { 79struct CodeSet final {
65 struct Segment { 80 struct Segment {
66 std::size_t offset = 0; 81 std::size_t offset = 0;
67 VAddr addr = 0; 82 VAddr addr = 0;
68 u32 size = 0; 83 u32 size = 0;
69 }; 84 };
70 85
71 static SharedPtr<CodeSet> Create(KernelCore& kernel, std::string name); 86 explicit CodeSet();
72 87 ~CodeSet();
73 std::string GetTypeName() const override {
74 return "CodeSet";
75 }
76 std::string GetName() const override {
77 return name;
78 }
79
80 static const HandleType HANDLE_TYPE = HandleType::CodeSet;
81 HandleType GetHandleType() const override {
82 return HANDLE_TYPE;
83 }
84 88
85 Segment& CodeSegment() { 89 Segment& CodeSegment() {
86 return segments[0]; 90 return segments[0];
@@ -109,14 +113,7 @@ struct CodeSet final : public Object {
109 std::shared_ptr<std::vector<u8>> memory; 113 std::shared_ptr<std::vector<u8>> memory;
110 114
111 std::array<Segment, 3> segments; 115 std::array<Segment, 3> segments;
112 VAddr entrypoint; 116 VAddr entrypoint = 0;
113
114 /// Name of the process
115 std::string name;
116
117private:
118 explicit CodeSet(KernelCore& kernel);
119 ~CodeSet() override;
120}; 117};
121 118
122class Process final : public Object { 119class Process final : public Object {
@@ -219,7 +216,7 @@ public:
219 */ 216 */
220 void PrepareForTermination(); 217 void PrepareForTermination();
221 218
222 void LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr); 219 void LoadModule(CodeSet module_, VAddr base_addr);
223 220
224 /////////////////////////////////////////////////////////////////////////////////////////////// 221 ///////////////////////////////////////////////////////////////////////////////////////////////
225 // Memory Management 222 // Memory Management
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index cfd6e1bad..1342c597e 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -9,7 +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/core_timing.h" 12#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/process.h" 13#include "core/hle/kernel/process.h"
14#include "core/hle/kernel/scheduler.h" 14#include "core/hle/kernel/scheduler.h"
15 15
@@ -78,16 +78,16 @@ void Scheduler::SwitchContext(Thread* new_thread) {
78 // Cancel any outstanding wakeup events for this thread 78 // Cancel any outstanding wakeup events for this thread
79 new_thread->CancelWakeupTimer(); 79 new_thread->CancelWakeupTimer();
80 80
81 auto previous_process = Core::CurrentProcess(); 81 auto* const previous_process = Core::CurrentProcess();
82 82
83 current_thread = new_thread; 83 current_thread = new_thread;
84 84
85 ready_queue.remove(new_thread->GetPriority(), new_thread); 85 ready_queue.remove(new_thread->GetPriority(), new_thread);
86 new_thread->SetStatus(ThreadStatus::Running); 86 new_thread->SetStatus(ThreadStatus::Running);
87 87
88 const auto thread_owner_process = current_thread->GetOwnerProcess(); 88 auto* const thread_owner_process = current_thread->GetOwnerProcess();
89 if (previous_process != thread_owner_process) { 89 if (previous_process != thread_owner_process) {
90 Core::CurrentProcess() = thread_owner_process; 90 Core::System::GetInstance().Kernel().MakeCurrentProcess(thread_owner_process);
91 SetCurrentPageTable(&Core::CurrentProcess()->VMManager().page_table); 91 SetCurrentPageTable(&Core::CurrentProcess()->VMManager().page_table);
92 } 92 }
93 93
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index b488b508d..d08b84bde 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -39,6 +39,73 @@ namespace {
39constexpr bool Is4KBAligned(VAddr address) { 39constexpr bool Is4KBAligned(VAddr address) {
40 return (address & 0xFFF) == 0; 40 return (address & 0xFFF) == 0;
41} 41}
42
43// Checks if address + size is greater than the given address
44// This can return false if the size causes an overflow of a 64-bit type
45// or if the given size is zero.
46constexpr bool IsValidAddressRange(VAddr address, u64 size) {
47 return address + size > address;
48}
49
50// Checks if a given address range lies within a larger address range.
51constexpr bool IsInsideAddressRange(VAddr address, u64 size, VAddr address_range_begin,
52 VAddr address_range_end) {
53 const VAddr end_address = address + size - 1;
54 return address_range_begin <= address && end_address <= address_range_end - 1;
55}
56
57bool IsInsideAddressSpace(const VMManager& vm, VAddr address, u64 size) {
58 return IsInsideAddressRange(address, size, vm.GetAddressSpaceBaseAddress(),
59 vm.GetAddressSpaceEndAddress());
60}
61
62bool IsInsideNewMapRegion(const VMManager& vm, VAddr address, u64 size) {
63 return IsInsideAddressRange(address, size, vm.GetNewMapRegionBaseAddress(),
64 vm.GetNewMapRegionEndAddress());
65}
66
67// Helper function that performs the common sanity checks for svcMapMemory
68// and svcUnmapMemory. This is doable, as both functions perform their sanitizing
69// in the same order.
70ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_addr, VAddr src_addr,
71 u64 size) {
72 if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) {
73 return ERR_INVALID_ADDRESS;
74 }
75
76 if (size == 0 || !Is4KBAligned(size)) {
77 return ERR_INVALID_SIZE;
78 }
79
80 if (!IsValidAddressRange(dst_addr, size)) {
81 return ERR_INVALID_ADDRESS_STATE;
82 }
83
84 if (!IsValidAddressRange(src_addr, size)) {
85 return ERR_INVALID_ADDRESS_STATE;
86 }
87
88 if (!IsInsideAddressSpace(vm_manager, src_addr, size)) {
89 return ERR_INVALID_ADDRESS_STATE;
90 }
91
92 if (!IsInsideNewMapRegion(vm_manager, dst_addr, size)) {
93 return ERR_INVALID_MEMORY_RANGE;
94 }
95
96 const VAddr dst_end_address = dst_addr + size;
97 if (dst_end_address > vm_manager.GetHeapRegionBaseAddress() &&
98 vm_manager.GetHeapRegionEndAddress() > dst_addr) {
99 return ERR_INVALID_MEMORY_RANGE;
100 }
101
102 if (dst_end_address > vm_manager.GetMapRegionBaseAddress() &&
103 vm_manager.GetMapRegionEndAddress() > dst_addr) {
104 return ERR_INVALID_MEMORY_RANGE;
105 }
106
107 return RESULT_SUCCESS;
108}
42} // Anonymous namespace 109} // Anonymous namespace
43 110
44/// Set the process heap to a given Size. It can both extend and shrink the heap. 111/// Set the process heap to a given Size. It can both extend and shrink the heap.
@@ -69,15 +136,15 @@ static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
69 LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, 136 LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
70 src_addr, size); 137 src_addr, size);
71 138
72 if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) { 139 auto* const current_process = Core::CurrentProcess();
73 return ERR_INVALID_ADDRESS; 140 const auto& vm_manager = current_process->VMManager();
74 }
75 141
76 if (size == 0 || !Is4KBAligned(size)) { 142 const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size);
77 return ERR_INVALID_SIZE; 143 if (result != RESULT_SUCCESS) {
144 return result;
78 } 145 }
79 146
80 return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size); 147 return current_process->MirrorMemory(dst_addr, src_addr, size);
81} 148}
82 149
83/// Unmaps a region that was previously mapped with svcMapMemory 150/// Unmaps a region that was previously mapped with svcMapMemory
@@ -85,15 +152,15 @@ static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
85 LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr, 152 LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
86 src_addr, size); 153 src_addr, size);
87 154
88 if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) { 155 auto* const current_process = Core::CurrentProcess();
89 return ERR_INVALID_ADDRESS; 156 const auto& vm_manager = current_process->VMManager();
90 }
91 157
92 if (size == 0 || !Is4KBAligned(size)) { 158 const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size);
93 return ERR_INVALID_SIZE; 159 if (result != RESULT_SUCCESS) {
160 return result;
94 } 161 }
95 162
96 return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size); 163 return current_process->UnmapMemory(dst_addr, src_addr, size);
97} 164}
98 165
99/// Connect to an OS service given the port name, returns the handle to the port to out 166/// Connect to an OS service given the port name, returns the handle to the port to out
@@ -303,15 +370,15 @@ static ResultCode ArbitrateUnlock(VAddr mutex_addr) {
303 370
304struct BreakReason { 371struct BreakReason {
305 union { 372 union {
306 u64 raw; 373 u32 raw;
307 BitField<31, 1, u64> dont_kill_application; 374 BitField<31, 1, u32> signal_debugger;
308 }; 375 };
309}; 376};
310 377
311/// Break program execution 378/// Break program execution
312static void Break(u64 reason, u64 info1, u64 info2) { 379static void Break(u32 reason, u64 info1, u64 info2) {
313 BreakReason break_reason{reason}; 380 BreakReason break_reason{reason};
314 if (break_reason.dont_kill_application) { 381 if (break_reason.signal_debugger) {
315 LOG_ERROR( 382 LOG_ERROR(
316 Debug_Emulated, 383 Debug_Emulated,
317 "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", 384 "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
@@ -322,6 +389,12 @@ static void Break(u64 reason, u64 info1, u64 info2) {
322 "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}", 389 "Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
323 reason, info1, info2); 390 reason, info1, info2);
324 ASSERT(false); 391 ASSERT(false);
392
393 Core::CurrentProcess()->PrepareForTermination();
394
395 // Kill the current thread
396 GetCurrentThread()->Stop();
397 Core::System::GetInstance().PrepareReschedule();
325 } 398 }
326} 399}
327 400
@@ -341,7 +414,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
341 LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id, 414 LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
342 info_sub_id, handle); 415 info_sub_id, handle);
343 416
344 const auto& current_process = Core::CurrentProcess(); 417 const auto* current_process = Core::CurrentProcess();
345 const auto& vm_manager = current_process->VMManager(); 418 const auto& vm_manager = current_process->VMManager();
346 419
347 switch (static_cast<GetInfoType>(info_id)) { 420 switch (static_cast<GetInfoType>(info_id)) {
@@ -375,25 +448,12 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
375 case GetInfoType::RandomEntropy: 448 case GetInfoType::RandomEntropy:
376 *result = 0; 449 *result = 0;
377 break; 450 break;
378 case GetInfoType::AddressSpaceBaseAddr: 451 case GetInfoType::ASLRRegionBaseAddr:
379 *result = vm_manager.GetCodeRegionBaseAddress(); 452 *result = vm_manager.GetASLRRegionBaseAddress();
380 break; 453 break;
381 case GetInfoType::AddressSpaceSize: { 454 case GetInfoType::ASLRRegionSize:
382 const u64 width = vm_manager.GetAddressSpaceWidth(); 455 *result = vm_manager.GetASLRRegionSize();
383
384 switch (width) {
385 case 32:
386 *result = 0xFFE00000;
387 break;
388 case 36:
389 *result = 0xFF8000000;
390 break;
391 case 39:
392 *result = 0x7FF8000000;
393 break;
394 }
395 break; 456 break;
396 }
397 case GetInfoType::NewMapRegionBaseAddr: 457 case GetInfoType::NewMapRegionBaseAddr:
398 *result = vm_manager.GetNewMapRegionBaseAddress(); 458 *result = vm_manager.GetNewMapRegionBaseAddress();
399 break; 459 break;
@@ -439,7 +499,7 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
439 return ERR_INVALID_HANDLE; 499 return ERR_INVALID_HANDLE;
440 } 500 }
441 501
442 const auto current_process = Core::CurrentProcess(); 502 const auto* current_process = Core::CurrentProcess();
443 if (thread->GetOwnerProcess() != current_process) { 503 if (thread->GetOwnerProcess() != current_process) {
444 return ERR_INVALID_HANDLE; 504 return ERR_INVALID_HANDLE;
445 } 505 }
@@ -531,7 +591,7 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s
531 return ERR_INVALID_HANDLE; 591 return ERR_INVALID_HANDLE;
532 } 592 }
533 593
534 return shared_memory->Map(Core::CurrentProcess().get(), addr, permissions_type, 594 return shared_memory->Map(Core::CurrentProcess(), addr, permissions_type,
535 MemoryPermission::DontCare); 595 MemoryPermission::DontCare);
536} 596}
537 597
@@ -550,7 +610,7 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64
550 auto& kernel = Core::System::GetInstance().Kernel(); 610 auto& kernel = Core::System::GetInstance().Kernel();
551 auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle); 611 auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle);
552 612
553 return shared_memory->Unmap(Core::CurrentProcess().get(), addr); 613 return shared_memory->Unmap(Core::CurrentProcess(), addr);
554} 614}
555 615
556/// Query process memory 616/// Query process memory
@@ -588,7 +648,7 @@ static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, VAdd
588 648
589/// Exits the current process 649/// Exits the current process
590static void ExitProcess() { 650static void ExitProcess() {
591 auto& current_process = Core::CurrentProcess(); 651 auto* current_process = Core::CurrentProcess();
592 652
593 LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID()); 653 LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID());
594 ASSERT_MSG(current_process->GetStatus() == ProcessStatus::Running, 654 ASSERT_MSG(current_process->GetStatus() == ProcessStatus::Running,
@@ -636,7 +696,7 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
636 auto& kernel = Core::System::GetInstance().Kernel(); 696 auto& kernel = Core::System::GetInstance().Kernel();
637 CASCADE_RESULT(SharedPtr<Thread> thread, 697 CASCADE_RESULT(SharedPtr<Thread> thread,
638 Thread::Create(kernel, name, entry_point, priority, arg, processor_id, stack_top, 698 Thread::Create(kernel, name, entry_point, priority, arg, processor_id, stack_top,
639 Core::CurrentProcess())); 699 *Core::CurrentProcess()));
640 const auto new_guest_handle = kernel.HandleTable().Create(thread); 700 const auto new_guest_handle = kernel.HandleTable().Create(thread);
641 if (new_guest_handle.Failed()) { 701 if (new_guest_handle.Failed()) {
642 return new_guest_handle.Code(); 702 return new_guest_handle.Code();
@@ -736,7 +796,7 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
736 std::vector<SharedPtr<Thread>>& waiting_threads, 796 std::vector<SharedPtr<Thread>>& waiting_threads,
737 VAddr condvar_addr) { 797 VAddr condvar_addr) {
738 const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); 798 const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
739 const auto& thread_list = scheduler->GetThreadList(); 799 const auto& thread_list = scheduler.GetThreadList();
740 800
741 for (const auto& thread : thread_list) { 801 for (const auto& thread : thread_list) {
742 if (thread->GetCondVarWaitAddress() == condvar_addr) 802 if (thread->GetCondVarWaitAddress() == condvar_addr)
@@ -1025,6 +1085,29 @@ static ResultCode ClearEvent(Handle handle) {
1025 return RESULT_SUCCESS; 1085 return RESULT_SUCCESS;
1026} 1086}
1027 1087
1088static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) {
1089 LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, type);
1090
1091 // This function currently only allows retrieving a process' status.
1092 enum class InfoType {
1093 Status,
1094 };
1095
1096 const auto& kernel = Core::System::GetInstance().Kernel();
1097 const auto process = kernel.HandleTable().Get<Process>(process_handle);
1098 if (!process) {
1099 return ERR_INVALID_HANDLE;
1100 }
1101
1102 const auto info_type = static_cast<InfoType>(type);
1103 if (info_type != InfoType::Status) {
1104 return ERR_INVALID_ENUM_VALUE;
1105 }
1106
1107 *out = static_cast<u64>(process->GetStatus());
1108 return RESULT_SUCCESS;
1109}
1110
1028namespace { 1111namespace {
1029struct FunctionDef { 1112struct FunctionDef {
1030 using Func = void(); 1113 using Func = void();
@@ -1160,7 +1243,7 @@ static const FunctionDef SVC_Table[] = {
1160 {0x79, nullptr, "CreateProcess"}, 1243 {0x79, nullptr, "CreateProcess"},
1161 {0x7A, nullptr, "StartProcess"}, 1244 {0x7A, nullptr, "StartProcess"},
1162 {0x7B, nullptr, "TerminateProcess"}, 1245 {0x7B, nullptr, "TerminateProcess"},
1163 {0x7C, nullptr, "GetProcessInfo"}, 1246 {0x7C, SvcWrap<GetProcessInfo>, "GetProcessInfo"},
1164 {0x7D, nullptr, "CreateResourceLimit"}, 1247 {0x7D, nullptr, "CreateResourceLimit"},
1165 {0x7E, nullptr, "SetResourceLimitLimitValue"}, 1248 {0x7E, nullptr, "SetResourceLimitLimitValue"},
1166 {0x7F, nullptr, "CallSecureMonitor"}, 1249 {0x7F, nullptr, "CallSecureMonitor"},
diff --git a/src/core/hle/kernel/svc.h b/src/core/hle/kernel/svc.h
index 70148c4fe..554a5e328 100644
--- a/src/core/hle/kernel/svc.h
+++ b/src/core/hle/kernel/svc.h
@@ -41,8 +41,8 @@ enum class GetInfoType : u64 {
41 RandomEntropy = 11, 41 RandomEntropy = 11,
42 PerformanceCounter = 0xF0000002, 42 PerformanceCounter = 0xF0000002,
43 // 2.0.0+ 43 // 2.0.0+
44 AddressSpaceBaseAddr = 12, 44 ASLRRegionBaseAddr = 12,
45 AddressSpaceSize = 13, 45 ASLRRegionSize = 13,
46 NewMapRegionBaseAddr = 14, 46 NewMapRegionBaseAddr = 14,
47 NewMapRegionSize = 15, 47 NewMapRegionSize = 15,
48 // 3.0.0+ 48 // 3.0.0+
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index 22712e64f..b09753c80 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -35,18 +35,18 @@ void SvcWrap() {
35 35
36template <ResultCode func(u32)> 36template <ResultCode func(u32)>
37void SvcWrap() { 37void SvcWrap() {
38 FuncReturn(func((u32)Param(0)).raw); 38 FuncReturn(func(static_cast<u32>(Param(0))).raw);
39} 39}
40 40
41template <ResultCode func(u32, u32)> 41template <ResultCode func(u32, u32)>
42void SvcWrap() { 42void SvcWrap() {
43 FuncReturn(func((u32)Param(0), (u32)Param(1)).raw); 43 FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1))).raw);
44} 44}
45 45
46template <ResultCode func(u32*, u32)> 46template <ResultCode func(u32*, u32)>
47void SvcWrap() { 47void SvcWrap() {
48 u32 param_1 = 0; 48 u32 param_1 = 0;
49 u32 retval = func(&param_1, (u32)Param(1)).raw; 49 u32 retval = func(&param_1, static_cast<u32>(Param(1))).raw;
50 Core::CurrentArmInterface().SetReg(1, param_1); 50 Core::CurrentArmInterface().SetReg(1, param_1);
51 FuncReturn(retval); 51 FuncReturn(retval);
52} 52}
@@ -61,7 +61,7 @@ void SvcWrap() {
61 61
62template <ResultCode func(u64, s32)> 62template <ResultCode func(u64, s32)>
63void SvcWrap() { 63void SvcWrap() {
64 FuncReturn(func(Param(0), (s32)Param(1)).raw); 64 FuncReturn(func(Param(0), static_cast<s32>(Param(1))).raw);
65} 65}
66 66
67template <ResultCode func(u64, u32)> 67template <ResultCode func(u64, u32)>
@@ -77,21 +77,29 @@ void SvcWrap() {
77 FuncReturn(retval); 77 FuncReturn(retval);
78} 78}
79 79
80template <ResultCode func(u64*, u32, u32)>
81void SvcWrap() {
82 u64 param_1 = 0;
83 u32 retval = func(&param_1, static_cast<u32>(Param(1)), static_cast<u32>(Param(2))).raw;
84 Core::CurrentArmInterface().SetReg(1, param_1);
85 FuncReturn(retval);
86}
87
80template <ResultCode func(u32, u64)> 88template <ResultCode func(u32, u64)>
81void SvcWrap() { 89void SvcWrap() {
82 FuncReturn(func((u32)(Param(0) & 0xFFFFFFFF), Param(1)).raw); 90 FuncReturn(func(static_cast<u32>(Param(0)), Param(1)).raw);
83} 91}
84 92
85template <ResultCode func(u32, u32, u64)> 93template <ResultCode func(u32, u32, u64)>
86void SvcWrap() { 94void SvcWrap() {
87 FuncReturn(func((u32)(Param(0) & 0xFFFFFFFF), (u32)(Param(1) & 0xFFFFFFFF), Param(2)).raw); 95 FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1)), Param(2)).raw);
88} 96}
89 97
90template <ResultCode func(u32, u32*, u64*)> 98template <ResultCode func(u32, u32*, u64*)>
91void SvcWrap() { 99void SvcWrap() {
92 u32 param_1 = 0; 100 u32 param_1 = 0;
93 u64 param_2 = 0; 101 u64 param_2 = 0;
94 ResultCode retval = func((u32)(Param(2) & 0xFFFFFFFF), &param_1, &param_2); 102 ResultCode retval = func(static_cast<u32>(Param(2)), &param_1, &param_2);
95 Core::CurrentArmInterface().SetReg(1, param_1); 103 Core::CurrentArmInterface().SetReg(1, param_1);
96 Core::CurrentArmInterface().SetReg(2, param_2); 104 Core::CurrentArmInterface().SetReg(2, param_2);
97 FuncReturn(retval.raw); 105 FuncReturn(retval.raw);
@@ -100,12 +108,12 @@ void SvcWrap() {
100template <ResultCode func(u64, u64, u32, u32)> 108template <ResultCode func(u64, u64, u32, u32)>
101void SvcWrap() { 109void SvcWrap() {
102 FuncReturn( 110 FuncReturn(
103 func(Param(0), Param(1), (u32)(Param(3) & 0xFFFFFFFF), (u32)(Param(3) & 0xFFFFFFFF)).raw); 111 func(Param(0), Param(1), static_cast<u32>(Param(3)), static_cast<u32>(Param(3))).raw);
104} 112}
105 113
106template <ResultCode func(u32, u64, u32)> 114template <ResultCode func(u32, u64, u32)>
107void SvcWrap() { 115void SvcWrap() {
108 FuncReturn(func((u32)Param(0), Param(1), (u32)Param(2)).raw); 116 FuncReturn(func(static_cast<u32>(Param(0)), Param(1), static_cast<u32>(Param(2))).raw);
109} 117}
110 118
111template <ResultCode func(u64, u64, u64)> 119template <ResultCode func(u64, u64, u64)>
@@ -115,25 +123,28 @@ void SvcWrap() {
115 123
116template <ResultCode func(u32, u64, u64, u32)> 124template <ResultCode func(u32, u64, u64, u32)>
117void SvcWrap() { 125void SvcWrap() {
118 FuncReturn(func((u32)Param(0), Param(1), Param(2), (u32)Param(3)).raw); 126 FuncReturn(
127 func(static_cast<u32>(Param(0)), Param(1), Param(2), static_cast<u32>(Param(3))).raw);
119} 128}
120 129
121template <ResultCode func(u32, u64, u64)> 130template <ResultCode func(u32, u64, u64)>
122void SvcWrap() { 131void SvcWrap() {
123 FuncReturn(func((u32)Param(0), Param(1), Param(2)).raw); 132 FuncReturn(func(static_cast<u32>(Param(0)), Param(1), Param(2)).raw);
124} 133}
125 134
126template <ResultCode func(u32*, u64, u64, s64)> 135template <ResultCode func(u32*, u64, u64, s64)>
127void SvcWrap() { 136void SvcWrap() {
128 u32 param_1 = 0; 137 u32 param_1 = 0;
129 ResultCode retval = func(&param_1, Param(1), (u32)(Param(2) & 0xFFFFFFFF), (s64)Param(3)); 138 ResultCode retval =
139 func(&param_1, Param(1), static_cast<u32>(Param(2)), static_cast<s64>(Param(3)));
130 Core::CurrentArmInterface().SetReg(1, param_1); 140 Core::CurrentArmInterface().SetReg(1, param_1);
131 FuncReturn(retval.raw); 141 FuncReturn(retval.raw);
132} 142}
133 143
134template <ResultCode func(u64, u64, u32, s64)> 144template <ResultCode func(u64, u64, u32, s64)>
135void SvcWrap() { 145void SvcWrap() {
136 FuncReturn(func(Param(0), Param(1), (u32)Param(2), (s64)Param(3)).raw); 146 FuncReturn(
147 func(Param(0), Param(1), static_cast<u32>(Param(2)), static_cast<s64>(Param(3))).raw);
137} 148}
138 149
139template <ResultCode func(u64*, u64, u64, u64)> 150template <ResultCode func(u64*, u64, u64, u64)>
@@ -147,9 +158,9 @@ void SvcWrap() {
147template <ResultCode func(u32*, u64, u64, u64, u32, s32)> 158template <ResultCode func(u32*, u64, u64, u64, u32, s32)>
148void SvcWrap() { 159void SvcWrap() {
149 u32 param_1 = 0; 160 u32 param_1 = 0;
150 u32 retval = 161 u32 retval = func(&param_1, Param(1), Param(2), Param(3), static_cast<u32>(Param(4)),
151 func(&param_1, Param(1), Param(2), Param(3), (u32)Param(4), (s32)(Param(5) & 0xFFFFFFFF)) 162 static_cast<s32>(Param(5)))
152 .raw; 163 .raw;
153 Core::CurrentArmInterface().SetReg(1, param_1); 164 Core::CurrentArmInterface().SetReg(1, param_1);
154 FuncReturn(retval); 165 FuncReturn(retval);
155} 166}
@@ -172,7 +183,7 @@ void SvcWrap() {
172template <ResultCode func(u32*, u64, u64, u32)> 183template <ResultCode func(u32*, u64, u64, u32)>
173void SvcWrap() { 184void SvcWrap() {
174 u32 param_1 = 0; 185 u32 param_1 = 0;
175 u32 retval = func(&param_1, Param(1), Param(2), (u32)(Param(3) & 0xFFFFFFFF)).raw; 186 u32 retval = func(&param_1, Param(1), Param(2), static_cast<u32>(Param(3))).raw;
176 Core::CurrentArmInterface().SetReg(1, param_1); 187 Core::CurrentArmInterface().SetReg(1, param_1);
177 FuncReturn(retval); 188 FuncReturn(retval);
178} 189}
@@ -181,22 +192,22 @@ template <ResultCode func(Handle*, u64, u32, u32)>
181void SvcWrap() { 192void SvcWrap() {
182 u32 param_1 = 0; 193 u32 param_1 = 0;
183 u32 retval = 194 u32 retval =
184 func(&param_1, Param(1), (u32)(Param(2) & 0xFFFFFFFF), (u32)(Param(3) & 0xFFFFFFFF)).raw; 195 func(&param_1, Param(1), static_cast<u32>(Param(2)), static_cast<u32>(Param(3))).raw;
185 Core::CurrentArmInterface().SetReg(1, param_1); 196 Core::CurrentArmInterface().SetReg(1, param_1);
186 FuncReturn(retval); 197 FuncReturn(retval);
187} 198}
188 199
189template <ResultCode func(u64, u32, s32, s64)> 200template <ResultCode func(u64, u32, s32, s64)>
190void SvcWrap() { 201void SvcWrap() {
191 FuncReturn( 202 FuncReturn(func(Param(0), static_cast<u32>(Param(1)), static_cast<s32>(Param(2)),
192 func(Param(0), (u32)(Param(1) & 0xFFFFFFFF), (s32)(Param(2) & 0xFFFFFFFF), (s64)Param(3)) 203 static_cast<s64>(Param(3)))
193 .raw); 204 .raw);
194} 205}
195 206
196template <ResultCode func(u64, u32, s32, s32)> 207template <ResultCode func(u64, u32, s32, s32)>
197void SvcWrap() { 208void SvcWrap() {
198 FuncReturn(func(Param(0), (u32)(Param(1) & 0xFFFFFFFF), (s32)(Param(2) & 0xFFFFFFFF), 209 FuncReturn(func(Param(0), static_cast<u32>(Param(1)), static_cast<s32>(Param(2)),
199 (s32)(Param(3) & 0xFFFFFFFF)) 210 static_cast<s32>(Param(3)))
200 .raw); 211 .raw);
201} 212}
202 213
@@ -226,7 +237,7 @@ void SvcWrap() {
226 237
227template <void func(s64)> 238template <void func(s64)>
228void SvcWrap() { 239void SvcWrap() {
229 func((s64)Param(0)); 240 func(static_cast<s64>(Param(0)));
230} 241}
231 242
232template <void func(u64, u64 len)> 243template <void func(u64, u64 len)>
@@ -239,4 +250,9 @@ void SvcWrap() {
239 func(Param(0), Param(1), Param(2)); 250 func(Param(0), Param(1), Param(2));
240} 251}
241 252
253template <void func(u32, u64, u64)>
254void SvcWrap() {
255 func(static_cast<u32>(Param(0)), Param(1), Param(2));
256}
257
242} // namespace Kernel 258} // namespace Kernel
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 8e514cf9a..35ec98c1a 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -97,7 +97,7 @@ void Thread::CancelWakeupTimer() {
97static boost::optional<s32> GetNextProcessorId(u64 mask) { 97static boost::optional<s32> GetNextProcessorId(u64 mask) {
98 for (s32 index = 0; index < Core::NUM_CPU_CORES; ++index) { 98 for (s32 index = 0; index < Core::NUM_CPU_CORES; ++index) {
99 if (mask & (1ULL << index)) { 99 if (mask & (1ULL << index)) {
100 if (!Core::System::GetInstance().Scheduler(index)->GetCurrentThread()) { 100 if (!Core::System::GetInstance().Scheduler(index).GetCurrentThread()) {
101 // Core is enabled and not running any threads, use this one 101 // Core is enabled and not running any threads, use this one
102 return index; 102 return index;
103 } 103 }
@@ -147,14 +147,14 @@ void Thread::ResumeFromWait() {
147 new_processor_id = processor_id; 147 new_processor_id = processor_id;
148 } 148 }
149 if (ideal_core != -1 && 149 if (ideal_core != -1 &&
150 Core::System::GetInstance().Scheduler(ideal_core)->GetCurrentThread() == nullptr) { 150 Core::System::GetInstance().Scheduler(ideal_core).GetCurrentThread() == nullptr) {
151 new_processor_id = ideal_core; 151 new_processor_id = ideal_core;
152 } 152 }
153 153
154 ASSERT(*new_processor_id < 4); 154 ASSERT(*new_processor_id < 4);
155 155
156 // Add thread to new core's scheduler 156 // Add thread to new core's scheduler
157 auto& next_scheduler = Core::System::GetInstance().Scheduler(*new_processor_id); 157 auto* next_scheduler = &Core::System::GetInstance().Scheduler(*new_processor_id);
158 158
159 if (*new_processor_id != processor_id) { 159 if (*new_processor_id != processor_id) {
160 // Remove thread from previous core's scheduler 160 // Remove thread from previous core's scheduler
@@ -169,7 +169,7 @@ void Thread::ResumeFromWait() {
169 next_scheduler->ScheduleThread(this, current_priority); 169 next_scheduler->ScheduleThread(this, current_priority);
170 170
171 // Change thread's scheduler 171 // Change thread's scheduler
172 scheduler = next_scheduler.get(); 172 scheduler = next_scheduler;
173 173
174 Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); 174 Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule();
175} 175}
@@ -183,18 +183,15 @@ void Thread::ResumeFromWait() {
183 */ 183 */
184static void ResetThreadContext(Core::ARM_Interface::ThreadContext& context, VAddr stack_top, 184static void ResetThreadContext(Core::ARM_Interface::ThreadContext& context, VAddr stack_top,
185 VAddr entry_point, u64 arg) { 185 VAddr entry_point, u64 arg) {
186 memset(&context, 0, sizeof(Core::ARM_Interface::ThreadContext)); 186 context = {};
187
188 context.cpu_registers[0] = arg; 187 context.cpu_registers[0] = arg;
189 context.pc = entry_point; 188 context.pc = entry_point;
190 context.sp = stack_top; 189 context.sp = stack_top;
191 context.pstate = 0;
192 context.fpcr = 0;
193} 190}
194 191
195ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name, VAddr entry_point, 192ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name, VAddr entry_point,
196 u32 priority, u64 arg, s32 processor_id, 193 u32 priority, u64 arg, s32 processor_id,
197 VAddr stack_top, SharedPtr<Process> owner_process) { 194 VAddr stack_top, Process& owner_process) {
198 // Check if priority is in ranged. Lowest priority -> highest priority id. 195 // Check if priority is in ranged. Lowest priority -> highest priority id.
199 if (priority > THREADPRIO_LOWEST) { 196 if (priority > THREADPRIO_LOWEST) {
200 LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); 197 LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
@@ -208,7 +205,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
208 205
209 // TODO(yuriks): Other checks, returning 0xD9001BEA 206 // TODO(yuriks): Other checks, returning 0xD9001BEA
210 207
211 if (!Memory::IsValidVirtualAddress(*owner_process, entry_point)) { 208 if (!Memory::IsValidVirtualAddress(owner_process, entry_point)) {
212 LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point); 209 LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point);
213 // TODO (bunnei): Find the correct error code to use here 210 // TODO (bunnei): Find the correct error code to use here
214 return ResultCode(-1); 211 return ResultCode(-1);
@@ -232,8 +229,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name
232 thread->wait_handle = 0; 229 thread->wait_handle = 0;
233 thread->name = std::move(name); 230 thread->name = std::move(name);
234 thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap(); 231 thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap();
235 thread->owner_process = owner_process; 232 thread->owner_process = &owner_process;
236 thread->scheduler = Core::System::GetInstance().Scheduler(processor_id).get(); 233 thread->scheduler = &Core::System::GetInstance().Scheduler(processor_id);
237 thread->scheduler->AddThread(thread, priority); 234 thread->scheduler->AddThread(thread, priority);
238 thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread); 235 thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread);
239 236
@@ -264,7 +261,7 @@ SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 pri
264 // Initialize new "main" thread 261 // Initialize new "main" thread
265 const VAddr stack_top = owner_process.VMManager().GetTLSIORegionEndAddress(); 262 const VAddr stack_top = owner_process.VMManager().GetTLSIORegionEndAddress();
266 auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0, 263 auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0,
267 stack_top, &owner_process); 264 stack_top, owner_process);
268 265
269 SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); 266 SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
270 267
@@ -378,14 +375,14 @@ void Thread::ChangeCore(u32 core, u64 mask) {
378 new_processor_id = processor_id; 375 new_processor_id = processor_id;
379 } 376 }
380 if (ideal_core != -1 && 377 if (ideal_core != -1 &&
381 Core::System::GetInstance().Scheduler(ideal_core)->GetCurrentThread() == nullptr) { 378 Core::System::GetInstance().Scheduler(ideal_core).GetCurrentThread() == nullptr) {
382 new_processor_id = ideal_core; 379 new_processor_id = ideal_core;
383 } 380 }
384 381
385 ASSERT(*new_processor_id < 4); 382 ASSERT(*new_processor_id < 4);
386 383
387 // Add thread to new core's scheduler 384 // Add thread to new core's scheduler
388 auto& next_scheduler = Core::System::GetInstance().Scheduler(*new_processor_id); 385 auto* next_scheduler = &Core::System::GetInstance().Scheduler(*new_processor_id);
389 386
390 if (*new_processor_id != processor_id) { 387 if (*new_processor_id != processor_id) {
391 // Remove thread from previous core's scheduler 388 // Remove thread from previous core's scheduler
@@ -400,7 +397,7 @@ void Thread::ChangeCore(u32 core, u64 mask) {
400 next_scheduler->ScheduleThread(this, current_priority); 397 next_scheduler->ScheduleThread(this, current_priority);
401 398
402 // Change thread's scheduler 399 // Change thread's scheduler
403 scheduler = next_scheduler.get(); 400 scheduler = next_scheduler;
404 401
405 Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); 402 Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule();
406} 403}
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index c6ffbd28c..f4d7bd235 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -89,7 +89,7 @@ public:
89 static ResultVal<SharedPtr<Thread>> Create(KernelCore& kernel, std::string name, 89 static ResultVal<SharedPtr<Thread>> Create(KernelCore& kernel, std::string name,
90 VAddr entry_point, u32 priority, u64 arg, 90 VAddr entry_point, u32 priority, u64 arg,
91 s32 processor_id, VAddr stack_top, 91 s32 processor_id, VAddr stack_top,
92 SharedPtr<Process> owner_process); 92 Process& owner_process);
93 93
94 std::string GetName() const override { 94 std::string GetName() const override {
95 return name; 95 return name;
@@ -262,11 +262,11 @@ public:
262 return processor_id; 262 return processor_id;
263 } 263 }
264 264
265 SharedPtr<Process>& GetOwnerProcess() { 265 Process* GetOwnerProcess() {
266 return owner_process; 266 return owner_process;
267 } 267 }
268 268
269 const SharedPtr<Process>& GetOwnerProcess() const { 269 const Process* GetOwnerProcess() const {
270 return owner_process; 270 return owner_process;
271 } 271 }
272 272
@@ -386,7 +386,7 @@ private:
386 u64 tpidr_el0 = 0; ///< TPIDR_EL0 read/write system register. 386 u64 tpidr_el0 = 0; ///< TPIDR_EL0 read/write system register.
387 387
388 /// Process that owns this thread 388 /// Process that owns this thread
389 SharedPtr<Process> owner_process; 389 Process* owner_process;
390 390
391 /// Objects that the thread is waiting on, in the same order as they were 391 /// Objects that the thread is waiting on, in the same order as they were
392 /// passed to WaitSynchronization1/N. 392 /// passed to WaitSynchronization1/N.
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index e412309fd..1e28ccbda 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -393,30 +393,35 @@ void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType ty
393 393
394 switch (type) { 394 switch (type) {
395 case FileSys::ProgramAddressSpaceType::Is32Bit: 395 case FileSys::ProgramAddressSpaceType::Is32Bit:
396 case FileSys::ProgramAddressSpaceType::Is32BitNoMap:
396 address_space_width = 32; 397 address_space_width = 32;
397 code_region_base = 0x200000; 398 code_region_base = 0x200000;
398 code_region_end = code_region_base + 0x3FE00000; 399 code_region_end = code_region_base + 0x3FE00000;
399 map_region_size = 0x40000000; 400 aslr_region_base = 0x200000;
400 heap_region_size = 0x40000000; 401 aslr_region_end = aslr_region_base + 0xFFE00000;
402 if (type == FileSys::ProgramAddressSpaceType::Is32Bit) {
403 map_region_size = 0x40000000;
404 heap_region_size = 0x40000000;
405 } else {
406 map_region_size = 0;
407 heap_region_size = 0x80000000;
408 }
401 break; 409 break;
402 case FileSys::ProgramAddressSpaceType::Is36Bit: 410 case FileSys::ProgramAddressSpaceType::Is36Bit:
403 address_space_width = 36; 411 address_space_width = 36;
404 code_region_base = 0x8000000; 412 code_region_base = 0x8000000;
405 code_region_end = code_region_base + 0x78000000; 413 code_region_end = code_region_base + 0x78000000;
414 aslr_region_base = 0x8000000;
415 aslr_region_end = aslr_region_base + 0xFF8000000;
406 map_region_size = 0x180000000; 416 map_region_size = 0x180000000;
407 heap_region_size = 0x180000000; 417 heap_region_size = 0x180000000;
408 break; 418 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: 419 case FileSys::ProgramAddressSpaceType::Is39Bit:
417 address_space_width = 39; 420 address_space_width = 39;
418 code_region_base = 0x8000000; 421 code_region_base = 0x8000000;
419 code_region_end = code_region_base + 0x80000000; 422 code_region_end = code_region_base + 0x80000000;
423 aslr_region_base = 0x8000000;
424 aslr_region_end = aslr_region_base + 0x7FF8000000;
420 map_region_size = 0x1000000000; 425 map_region_size = 0x1000000000;
421 heap_region_size = 0x180000000; 426 heap_region_size = 0x180000000;
422 new_map_region_size = 0x80000000; 427 new_map_region_size = 0x80000000;
@@ -490,6 +495,18 @@ u64 VMManager::GetAddressSpaceWidth() const {
490 return address_space_width; 495 return address_space_width;
491} 496}
492 497
498VAddr VMManager::GetASLRRegionBaseAddress() const {
499 return aslr_region_base;
500}
501
502VAddr VMManager::GetASLRRegionEndAddress() const {
503 return aslr_region_end;
504}
505
506u64 VMManager::GetASLRRegionSize() const {
507 return aslr_region_end - aslr_region_base;
508}
509
493VAddr VMManager::GetCodeRegionBaseAddress() const { 510VAddr VMManager::GetCodeRegionBaseAddress() const {
494 return code_region_base; 511 return code_region_base;
495} 512}
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 015559a64..4accde6b3 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -205,6 +205,15 @@ public:
205 /// Gets the address space width in bits. 205 /// Gets the address space width in bits.
206 u64 GetAddressSpaceWidth() const; 206 u64 GetAddressSpaceWidth() const;
207 207
208 /// Gets the base address of the ASLR region.
209 VAddr GetASLRRegionBaseAddress() const;
210
211 /// Gets the end address of the ASLR region.
212 VAddr GetASLRRegionEndAddress() const;
213
214 /// Gets the size of the ASLR region
215 u64 GetASLRRegionSize() const;
216
208 /// Gets the base address of the code region. 217 /// Gets the base address of the code region.
209 VAddr GetCodeRegionBaseAddress() const; 218 VAddr GetCodeRegionBaseAddress() const;
210 219
@@ -306,6 +315,9 @@ private:
306 VAddr address_space_base = 0; 315 VAddr address_space_base = 0;
307 VAddr address_space_end = 0; 316 VAddr address_space_end = 0;
308 317
318 VAddr aslr_region_base = 0;
319 VAddr aslr_region_end = 0;
320
309 VAddr code_region_base = 0; 321 VAddr code_region_base = 0;
310 VAddr code_region_end = 0; 322 VAddr code_region_end = 0;
311 323
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index 0ecfb5af1..518161bf7 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -7,8 +7,10 @@
7#include <vector> 7#include <vector>
8#include "common/logging/log.h" 8#include "common/logging/log.h"
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/nca_metadata.h" 11#include "core/file_sys/nca_metadata.h"
11#include "core/file_sys/partition_filesystem.h" 12#include "core/file_sys/partition_filesystem.h"
13#include "core/file_sys/patch_manager.h"
12#include "core/file_sys/registered_cache.h" 14#include "core/file_sys/registered_cache.h"
13#include "core/hle/ipc_helpers.h" 15#include "core/hle/ipc_helpers.h"
14#include "core/hle/kernel/process.h" 16#include "core/hle/kernel/process.h"
@@ -19,7 +21,7 @@
19namespace Service::AOC { 21namespace Service::AOC {
20 22
21constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; 23constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
22constexpr u64 DLC_BASE_TO_AOC_ID_MASK = 0x1000; 24constexpr u64 DLC_BASE_TO_AOC_ID = 0x1000;
23 25
24static bool CheckAOCTitleIDMatchesBase(u64 base, u64 aoc) { 26static bool CheckAOCTitleIDMatchesBase(u64 base, u64 aoc) {
25 return (aoc & DLC_BASE_TITLE_ID_MASK) == base; 27 return (aoc & DLC_BASE_TITLE_ID_MASK) == base;
@@ -97,14 +99,24 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
97 99
98 ctx.WriteBuffer(out); 100 ctx.WriteBuffer(out);
99 101
100 IPC::ResponseBuilder rb{ctx, 2}; 102 IPC::ResponseBuilder rb{ctx, 3};
101 rb.Push(RESULT_SUCCESS); 103 rb.Push(RESULT_SUCCESS);
104 rb.Push(count);
102} 105}
103 106
104void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) { 107void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {
105 IPC::ResponseBuilder rb{ctx, 4}; 108 IPC::ResponseBuilder rb{ctx, 4};
106 rb.Push(RESULT_SUCCESS); 109 rb.Push(RESULT_SUCCESS);
107 rb.Push(Core::System::GetInstance().CurrentProcess()->GetTitleID() | DLC_BASE_TO_AOC_ID_MASK); 110 const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
111 FileSys::PatchManager pm{title_id};
112
113 const auto res = pm.GetControlMetadata();
114 if (res.first == nullptr) {
115 rb.Push(title_id + DLC_BASE_TO_AOC_ID);
116 return;
117 }
118
119 rb.Push(res.first->GetDLCBaseTitleId());
108} 120}
109 121
110void AOC_U::PrepareAddOnContent(Kernel::HLERequestContext& ctx) { 122void AOC_U::PrepareAddOnContent(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index fc6067e59..7168c6a10 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -2,8 +2,10 @@
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 <chrono>
5#include <cstring> 6#include <cstring>
6#include <memory> 7#include <memory>
8#include <optional>
7#include <vector> 9#include <vector>
8 10
9#include <opus.h> 11#include <opus.h>
@@ -33,7 +35,8 @@ public:
33 {1, nullptr, "SetContext"}, 35 {1, nullptr, "SetContext"},
34 {2, nullptr, "DecodeInterleavedForMultiStream"}, 36 {2, nullptr, "DecodeInterleavedForMultiStream"},
35 {3, nullptr, "SetContextForMultiStream"}, 37 {3, nullptr, "SetContextForMultiStream"},
36 {4, nullptr, "Unknown4"}, 38 {4, &IHardwareOpusDecoderManager::DecodeInterleavedWithPerformance,
39 "DecodeInterleavedWithPerformance"},
37 {5, nullptr, "Unknown5"}, 40 {5, nullptr, "Unknown5"},
38 {6, nullptr, "Unknown6"}, 41 {6, nullptr, "Unknown6"},
39 {7, nullptr, "Unknown7"}, 42 {7, nullptr, "Unknown7"},
@@ -59,8 +62,31 @@ private:
59 ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16)); 62 ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16));
60 } 63 }
61 64
62 bool Decoder_DecodeInterleaved(u32& consumed, u32& sample_count, const std::vector<u8>& input, 65 void DecodeInterleavedWithPerformance(Kernel::HLERequestContext& ctx) {
63 std::vector<opus_int16>& output) { 66 u32 consumed = 0;
67 u32 sample_count = 0;
68 u64 performance = 0;
69 std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16));
70 if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples,
71 performance)) {
72 IPC::ResponseBuilder rb{ctx, 2};
73 // TODO(ogniK): Use correct error code
74 rb.Push(ResultCode(-1));
75 return;
76 }
77 IPC::ResponseBuilder rb{ctx, 6};
78 rb.Push(RESULT_SUCCESS);
79 rb.Push<u32>(consumed);
80 rb.Push<u64>(performance);
81 rb.Push<u32>(sample_count);
82 ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16));
83 }
84
85 bool Decoder_DecodeInterleaved(
86 u32& consumed, u32& sample_count, const std::vector<u8>& input,
87 std::vector<opus_int16>& output,
88 std::optional<std::reference_wrapper<u64>> performance_time = std::nullopt) {
89 const auto start_time = std::chrono::high_resolution_clock::now();
64 std::size_t raw_output_sz = output.size() * sizeof(opus_int16); 90 std::size_t raw_output_sz = output.size() * sizeof(opus_int16);
65 if (sizeof(OpusHeader) > input.size()) 91 if (sizeof(OpusHeader) > input.size())
66 return false; 92 return false;
@@ -80,8 +106,13 @@ private:
80 (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)), 0); 106 (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)), 0);
81 if (out_sample_count < 0) 107 if (out_sample_count < 0)
82 return false; 108 return false;
109 const auto end_time = std::chrono::high_resolution_clock::now() - start_time;
83 sample_count = out_sample_count; 110 sample_count = out_sample_count;
84 consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz); 111 consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz);
112 if (performance_time.has_value()) {
113 performance_time->get() =
114 std::chrono::duration_cast<std::chrono::milliseconds>(end_time).count();
115 }
85 return true; 116 return true;
86 } 117 }
87 118
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 439e62d27..e32a7c48e 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -319,13 +319,12 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() {
319 return sdmc_factory->Open(); 319 return sdmc_factory->Open();
320} 320}
321 321
322std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() { 322std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() {
323 return std::make_shared<FileSys::RegisteredCacheUnion>( 323 return std::make_unique<FileSys::RegisteredCacheUnion>(std::vector<FileSys::RegisteredCache*>{
324 std::vector<std::shared_ptr<FileSys::RegisteredCache>>{ 324 GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()});
325 GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()});
326} 325}
327 326
328std::shared_ptr<FileSys::RegisteredCache> GetSystemNANDContents() { 327FileSys::RegisteredCache* GetSystemNANDContents() {
329 LOG_TRACE(Service_FS, "Opening System NAND Contents"); 328 LOG_TRACE(Service_FS, "Opening System NAND Contents");
330 329
331 if (bis_factory == nullptr) 330 if (bis_factory == nullptr)
@@ -334,7 +333,7 @@ std::shared_ptr<FileSys::RegisteredCache> GetSystemNANDContents() {
334 return bis_factory->GetSystemNANDContents(); 333 return bis_factory->GetSystemNANDContents();
335} 334}
336 335
337std::shared_ptr<FileSys::RegisteredCache> GetUserNANDContents() { 336FileSys::RegisteredCache* GetUserNANDContents() {
338 LOG_TRACE(Service_FS, "Opening User NAND Contents"); 337 LOG_TRACE(Service_FS, "Opening User NAND Contents");
339 338
340 if (bis_factory == nullptr) 339 if (bis_factory == nullptr)
@@ -343,7 +342,7 @@ std::shared_ptr<FileSys::RegisteredCache> GetUserNANDContents() {
343 return bis_factory->GetUserNANDContents(); 342 return bis_factory->GetUserNANDContents();
344} 343}
345 344
346std::shared_ptr<FileSys::RegisteredCache> GetSDMCContents() { 345FileSys::RegisteredCache* GetSDMCContents() {
347 LOG_TRACE(Service_FS, "Opening SDMC Contents"); 346 LOG_TRACE(Service_FS, "Opening SDMC Contents");
348 347
349 if (sdmc_factory == nullptr) 348 if (sdmc_factory == nullptr)
@@ -361,19 +360,19 @@ FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) {
361 return bis_factory->GetModificationLoadRoot(title_id); 360 return bis_factory->GetModificationLoadRoot(title_id);
362} 361}
363 362
364void CreateFactories(const FileSys::VirtualFilesystem& vfs, bool overwrite) { 363void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
365 if (overwrite) { 364 if (overwrite) {
366 bis_factory = nullptr; 365 bis_factory = nullptr;
367 save_data_factory = nullptr; 366 save_data_factory = nullptr;
368 sdmc_factory = nullptr; 367 sdmc_factory = nullptr;
369 } 368 }
370 369
371 auto nand_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), 370 auto nand_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir),
372 FileSys::Mode::ReadWrite); 371 FileSys::Mode::ReadWrite);
373 auto sd_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), 372 auto sd_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir),
374 FileSys::Mode::ReadWrite); 373 FileSys::Mode::ReadWrite);
375 auto load_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), 374 auto load_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir),
376 FileSys::Mode::ReadWrite); 375 FileSys::Mode::ReadWrite);
377 376
378 if (bis_factory == nullptr) 377 if (bis_factory == nullptr)
379 bis_factory = std::make_unique<FileSys::BISFactory>(nand_directory, load_directory); 378 bis_factory = std::make_unique<FileSys::BISFactory>(nand_directory, load_directory);
@@ -383,7 +382,7 @@ void CreateFactories(const FileSys::VirtualFilesystem& vfs, bool overwrite) {
383 sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory)); 382 sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory));
384} 383}
385 384
386void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::VirtualFilesystem& vfs) { 385void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs) {
387 romfs_factory = nullptr; 386 romfs_factory = nullptr;
388 CreateFactories(vfs, false); 387 CreateFactories(vfs, false);
389 std::make_shared<FSP_LDR>()->InstallAsService(service_manager); 388 std::make_shared<FSP_LDR>()->InstallAsService(service_manager);
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 53b01bb01..6ca5c5636 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -47,19 +47,19 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
47 FileSys::SaveDataDescriptor save_struct); 47 FileSys::SaveDataDescriptor save_struct);
48ResultVal<FileSys::VirtualDir> OpenSDMC(); 48ResultVal<FileSys::VirtualDir> OpenSDMC();
49 49
50std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents(); 50std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents();
51 51
52std::shared_ptr<FileSys::RegisteredCache> GetSystemNANDContents(); 52FileSys::RegisteredCache* GetSystemNANDContents();
53std::shared_ptr<FileSys::RegisteredCache> GetUserNANDContents(); 53FileSys::RegisteredCache* GetUserNANDContents();
54std::shared_ptr<FileSys::RegisteredCache> GetSDMCContents(); 54FileSys::RegisteredCache* GetSDMCContents();
55 55
56FileSys::VirtualDir GetModificationLoadRoot(u64 title_id); 56FileSys::VirtualDir GetModificationLoadRoot(u64 title_id);
57 57
58// Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function 58// Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function
59// above is called. 59// above is called.
60void CreateFactories(const FileSys::VirtualFilesystem& vfs, bool overwrite = true); 60void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true);
61 61
62void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::VirtualFilesystem& vfs); 62void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs);
63 63
64// A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of 64// A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of
65// pointers and booleans. This makes using a VfsDirectory with switch services much easier and 65// pointers and booleans. This makes using a VfsDirectory with switch services much easier and
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index 4b2f758a8..44accecb7 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -161,7 +161,7 @@ PL_U::PL_U() : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} {
161 }; 161 };
162 RegisterHandlers(functions); 162 RegisterHandlers(functions);
163 // Attempt to load shared font data from disk 163 // Attempt to load shared font data from disk
164 const auto nand = FileSystem::GetSystemNANDContents(); 164 const auto* nand = FileSystem::GetSystemNANDContents();
165 std::size_t offset = 0; 165 std::size_t offset = 0;
166 // Rebuild shared fonts from data ncas 166 // Rebuild shared fonts from data ncas
167 if (nand->HasEntry(static_cast<u64>(FontArchives::Standard), 167 if (nand->HasEntry(static_cast<u64>(FontArchives::Standard),
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index 7555bbe7d..c41ef7058 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -15,6 +15,11 @@
15#include "video_core/renderer_base.h" 15#include "video_core/renderer_base.h"
16 16
17namespace Service::Nvidia::Devices { 17namespace Service::Nvidia::Devices {
18namespace NvErrCodes {
19enum {
20 InvalidNmapHandle = -22,
21};
22}
18 23
19nvhost_as_gpu::nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {} 24nvhost_as_gpu::nvhost_as_gpu(std::shared_ptr<nvmap> nvmap_dev) : nvmap_dev(std::move(nvmap_dev)) {}
20nvhost_as_gpu::~nvhost_as_gpu() = default; 25nvhost_as_gpu::~nvhost_as_gpu() = default;
@@ -79,14 +84,16 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)
79 std::memcpy(entries.data(), input.data(), input.size()); 84 std::memcpy(entries.data(), input.data(), input.size());
80 85
81 auto& gpu = Core::System::GetInstance().GPU(); 86 auto& gpu = Core::System::GetInstance().GPU();
82
83 for (const auto& entry : entries) { 87 for (const auto& entry : entries) {
84 LOG_WARNING(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}", 88 LOG_WARNING(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}",
85 entry.offset, entry.nvmap_handle, entry.pages); 89 entry.offset, entry.nvmap_handle, entry.pages);
86 Tegra::GPUVAddr offset = static_cast<Tegra::GPUVAddr>(entry.offset) << 0x10; 90 Tegra::GPUVAddr offset = static_cast<Tegra::GPUVAddr>(entry.offset) << 0x10;
87
88 auto object = nvmap_dev->GetObject(entry.nvmap_handle); 91 auto object = nvmap_dev->GetObject(entry.nvmap_handle);
89 ASSERT(object); 92 if (!object) {
93 LOG_CRITICAL(Service_NVDRV, "nvmap {} is an invalid handle!", entry.nvmap_handle);
94 std::memcpy(output.data(), entries.data(), output.size());
95 return static_cast<u32>(NvErrCodes::InvalidNmapHandle);
96 }
90 97
91 ASSERT(object->status == nvmap::Object::Status::Allocated); 98 ASSERT(object->status == nvmap::Object::Status::Allocated);
92 99
@@ -167,10 +174,11 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou
167 auto& system_instance = Core::System::GetInstance(); 174 auto& system_instance = Core::System::GetInstance();
168 175
169 // Remove this memory region from the rasterizer cache. 176 // Remove this memory region from the rasterizer cache.
170 system_instance.Renderer().Rasterizer().FlushAndInvalidateRegion(params.offset,
171 itr->second.size);
172
173 auto& gpu = system_instance.GPU(); 177 auto& gpu = system_instance.GPU();
178 auto cpu_addr = gpu.MemoryManager().GpuToCpuAddress(params.offset);
179 ASSERT(cpu_addr);
180 system_instance.Renderer().Rasterizer().FlushAndInvalidateRegion(*cpu_addr, itr->second.size);
181
174 params.offset = gpu.MemoryManager().UnmapBuffer(params.offset, itr->second.size); 182 params.offset = gpu.MemoryManager().UnmapBuffer(params.offset, itr->second.size);
175 183
176 buffer_mappings.erase(itr->second.offset); 184 buffer_mappings.erase(itr->second.offset);
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index a2287cc1b..43651d8a6 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -11,6 +11,13 @@
11 11
12namespace Service::Nvidia::Devices { 12namespace Service::Nvidia::Devices {
13 13
14namespace NvErrCodes {
15enum {
16 OperationNotPermitted = -1,
17 InvalidValue = -22,
18};
19}
20
14nvmap::nvmap() = default; 21nvmap::nvmap() = default;
15nvmap::~nvmap() = default; 22nvmap::~nvmap() = default;
16 23
@@ -44,7 +51,11 @@ u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& o
44u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { 51u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
45 IocCreateParams params; 52 IocCreateParams params;
46 std::memcpy(&params, input.data(), sizeof(params)); 53 std::memcpy(&params, input.data(), sizeof(params));
54 LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size);
47 55
56 if (!params.size) {
57 return static_cast<u32>(NvErrCodes::InvalidValue);
58 }
48 // Create a new nvmap object and obtain a handle to it. 59 // Create a new nvmap object and obtain a handle to it.
49 auto object = std::make_shared<Object>(); 60 auto object = std::make_shared<Object>();
50 object->id = next_id++; 61 object->id = next_id++;
@@ -55,8 +66,6 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
55 u32 handle = next_handle++; 66 u32 handle = next_handle++;
56 handles[handle] = std::move(object); 67 handles[handle] = std::move(object);
57 68
58 LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size);
59
60 params.handle = handle; 69 params.handle = handle;
61 70
62 std::memcpy(output.data(), &params, sizeof(params)); 71 std::memcpy(output.data(), &params, sizeof(params));
@@ -66,9 +75,29 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
66u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { 75u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
67 IocAllocParams params; 76 IocAllocParams params;
68 std::memcpy(&params, input.data(), sizeof(params)); 77 std::memcpy(&params, input.data(), sizeof(params));
78 LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr);
79
80 if (!params.handle) {
81 return static_cast<u32>(NvErrCodes::InvalidValue);
82 }
83
84 if ((params.align - 1) & params.align) {
85 return static_cast<u32>(NvErrCodes::InvalidValue);
86 }
87
88 const u32 min_alignment = 0x1000;
89 if (params.align < min_alignment) {
90 params.align = min_alignment;
91 }
69 92
70 auto object = GetObject(params.handle); 93 auto object = GetObject(params.handle);
71 ASSERT(object); 94 if (!object) {
95 return static_cast<u32>(NvErrCodes::InvalidValue);
96 }
97
98 if (object->status == Object::Status::Allocated) {
99 return static_cast<u32>(NvErrCodes::OperationNotPermitted);
100 }
72 101
73 object->flags = params.flags; 102 object->flags = params.flags;
74 object->align = params.align; 103 object->align = params.align;
@@ -76,8 +105,6 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
76 object->addr = params.addr; 105 object->addr = params.addr;
77 object->status = Object::Status::Allocated; 106 object->status = Object::Status::Allocated;
78 107
79 LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr);
80
81 std::memcpy(output.data(), &params, sizeof(params)); 108 std::memcpy(output.data(), &params, sizeof(params));
82 return 0; 109 return 0;
83} 110}
@@ -88,8 +115,14 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
88 115
89 LOG_WARNING(Service_NVDRV, "called"); 116 LOG_WARNING(Service_NVDRV, "called");
90 117
118 if (!params.handle) {
119 return static_cast<u32>(NvErrCodes::InvalidValue);
120 }
121
91 auto object = GetObject(params.handle); 122 auto object = GetObject(params.handle);
92 ASSERT(object); 123 if (!object) {
124 return static_cast<u32>(NvErrCodes::OperationNotPermitted);
125 }
93 126
94 params.id = object->id; 127 params.id = object->id;
95 128
@@ -105,7 +138,14 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
105 138
106 auto itr = std::find_if(handles.begin(), handles.end(), 139 auto itr = std::find_if(handles.begin(), handles.end(),
107 [&](const auto& entry) { return entry.second->id == params.id; }); 140 [&](const auto& entry) { return entry.second->id == params.id; });
108 ASSERT(itr != handles.end()); 141 if (itr == handles.end()) {
142 return static_cast<u32>(NvErrCodes::InvalidValue);
143 }
144
145 auto& object = itr->second;
146 if (object->status != Object::Status::Allocated) {
147 return static_cast<u32>(NvErrCodes::InvalidValue);
148 }
109 149
110 itr->second->refcount++; 150 itr->second->refcount++;
111 151
@@ -125,8 +165,13 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
125 LOG_WARNING(Service_NVDRV, "(STUBBED) called type={}", params.param); 165 LOG_WARNING(Service_NVDRV, "(STUBBED) called type={}", params.param);
126 166
127 auto object = GetObject(params.handle); 167 auto object = GetObject(params.handle);
128 ASSERT(object); 168 if (!object) {
129 ASSERT(object->status == Object::Status::Allocated); 169 return static_cast<u32>(NvErrCodes::InvalidValue);
170 }
171
172 if (object->status != Object::Status::Allocated) {
173 return static_cast<u32>(NvErrCodes::OperationNotPermitted);
174 }
130 175
131 switch (static_cast<ParamTypes>(params.param)) { 176 switch (static_cast<ParamTypes>(params.param)) {
132 case ParamTypes::Size: 177 case ParamTypes::Size:
@@ -163,9 +208,12 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
163 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 208 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
164 209
165 auto itr = handles.find(params.handle); 210 auto itr = handles.find(params.handle);
166 ASSERT(itr != handles.end()); 211 if (itr == handles.end()) {
167 212 return static_cast<u32>(NvErrCodes::InvalidValue);
168 ASSERT(itr->second->refcount > 0); 213 }
214 if (!itr->second->refcount) {
215 return static_cast<u32>(NvErrCodes::InvalidValue);
216 }
169 217
170 itr->second->refcount--; 218 itr->second->refcount--;
171 219
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 62f049660..a225cb4cb 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -197,7 +197,7 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
197// Module interface 197// Module interface
198 198
199/// Initialize ServiceManager 199/// Initialize ServiceManager
200void Init(std::shared_ptr<SM::ServiceManager>& sm, const FileSys::VirtualFilesystem& rfs) { 200void Init(std::shared_ptr<SM::ServiceManager>& sm, FileSys::VfsFilesystem& vfs) {
201 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it 201 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
202 // here and pass it into the respective InstallInterfaces functions. 202 // here and pass it into the respective InstallInterfaces functions.
203 auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(); 203 auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>();
@@ -220,7 +220,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, const FileSys::VirtualFilesys
220 EUPLD::InstallInterfaces(*sm); 220 EUPLD::InstallInterfaces(*sm);
221 Fatal::InstallInterfaces(*sm); 221 Fatal::InstallInterfaces(*sm);
222 FGM::InstallInterfaces(*sm); 222 FGM::InstallInterfaces(*sm);
223 FileSystem::InstallInterfaces(*sm, rfs); 223 FileSystem::InstallInterfaces(*sm, vfs);
224 Friend::InstallInterfaces(*sm); 224 Friend::InstallInterfaces(*sm);
225 GRC::InstallInterfaces(*sm); 225 GRC::InstallInterfaces(*sm);
226 HID::InstallInterfaces(*sm); 226 HID::InstallInterfaces(*sm);
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 2fc57a82e..98483ecf1 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -180,8 +180,7 @@ private:
180}; 180};
181 181
182/// Initialize ServiceManager 182/// Initialize ServiceManager
183void Init(std::shared_ptr<SM::ServiceManager>& sm, 183void Init(std::shared_ptr<SM::ServiceManager>& sm, FileSys::VfsFilesystem& vfs);
184 const std::shared_ptr<FileSys::VfsFilesystem>& vfs);
185 184
186/// Shutdown ServiceManager 185/// Shutdown ServiceManager
187void Shutdown(); 186void Shutdown();
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index bbc02abcc..184537daa 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -968,6 +968,54 @@ private:
968 rb.PushCopyObjects(vsync_event); 968 rb.PushCopyObjects(vsync_event);
969 } 969 }
970 970
971 enum class ConvertedScaleMode : u64 {
972 None = 0, // VI seems to name this as "Unknown" but lots of games pass it, assume it's no
973 // scaling/default
974 Freeze = 1,
975 ScaleToWindow = 2,
976 Crop = 3,
977 NoCrop = 4,
978 };
979
980 // This struct is different, currently it's 1:1 but this might change in the future.
981 enum class NintendoScaleMode : u32 {
982 None = 0,
983 Freeze = 1,
984 ScaleToWindow = 2,
985 Crop = 3,
986 NoCrop = 4,
987 };
988
989 void ConvertScalingMode(Kernel::HLERequestContext& ctx) {
990 IPC::RequestParser rp{ctx};
991 auto mode = rp.PopEnum<NintendoScaleMode>();
992 LOG_DEBUG(Service_VI, "called mode={}", static_cast<u32>(mode));
993
994 IPC::ResponseBuilder rb{ctx, 4};
995 rb.Push(RESULT_SUCCESS);
996 switch (mode) {
997 case NintendoScaleMode::None:
998 rb.PushEnum(ConvertedScaleMode::None);
999 break;
1000 case NintendoScaleMode::Freeze:
1001 rb.PushEnum(ConvertedScaleMode::Freeze);
1002 break;
1003 case NintendoScaleMode::ScaleToWindow:
1004 rb.PushEnum(ConvertedScaleMode::ScaleToWindow);
1005 break;
1006 case NintendoScaleMode::Crop:
1007 rb.PushEnum(ConvertedScaleMode::Crop);
1008 break;
1009 case NintendoScaleMode::NoCrop:
1010 rb.PushEnum(ConvertedScaleMode::NoCrop);
1011 break;
1012 default:
1013 UNIMPLEMENTED_MSG("Unknown scaling mode {}", static_cast<u32>(mode));
1014 rb.PushEnum(ConvertedScaleMode::None);
1015 break;
1016 }
1017 }
1018
971 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; 1019 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
972}; 1020};
973 1021
@@ -991,7 +1039,7 @@ IApplicationDisplayService::IApplicationDisplayService(
991 {2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"}, 1039 {2030, &IApplicationDisplayService::CreateStrayLayer, "CreateStrayLayer"},
992 {2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"}, 1040 {2031, &IApplicationDisplayService::DestroyStrayLayer, "DestroyStrayLayer"},
993 {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"}, 1041 {2101, &IApplicationDisplayService::SetLayerScalingMode, "SetLayerScalingMode"},
994 {2102, nullptr, "ConvertScalingMode"}, 1042 {2102, &IApplicationDisplayService::ConvertScalingMode, "ConvertScalingMode"},
995 {2450, nullptr, "GetIndirectLayerImageMap"}, 1043 {2450, nullptr, "GetIndirectLayerImageMap"},
996 {2451, nullptr, "GetIndirectLayerImageCropMap"}, 1044 {2451, nullptr, "GetIndirectLayerImageCropMap"},
997 {2460, nullptr, "GetIndirectLayerImageRequiredMemoryInfo"}, 1045 {2460, nullptr, "GetIndirectLayerImageRequiredMemoryInfo"},
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 951fd8257..8518dddcb 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -139,14 +139,22 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process)
139 for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", 139 for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",
140 "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { 140 "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) {
141 const FileSys::VirtualFile module_file = dir->GetFile(module); 141 const FileSys::VirtualFile module_file = dir->GetFile(module);
142 if (module_file != nullptr) { 142 if (module_file == nullptr) {
143 const VAddr load_addr = next_load_addr; 143 continue;
144 next_load_addr = AppLoader_NSO::LoadModule(module_file, load_addr,
145 std::strcmp(module, "rtld") == 0, pm);
146 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr);
147 // Register module with GDBStub
148 GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false);
149 } 144 }
145
146 const VAddr load_addr = next_load_addr;
147 const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
148 const auto tentative_next_load_addr =
149 AppLoader_NSO::LoadModule(*module_file, load_addr, should_pass_arguments, pm);
150 if (!tentative_next_load_addr) {
151 return ResultStatus::ErrorLoadingNSO;
152 }
153
154 next_load_addr = *tentative_next_load_addr;
155 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr);
156 // Register module with GDBStub
157 GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false);
150 } 158 }
151 159
152 process.Run(base_address, metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()); 160 process.Run(base_address, metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize());
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index e67b49fc9..6057c7f26 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -9,16 +9,11 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/file_util.h" 10#include "common/file_util.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "core/core.h"
13#include "core/hle/kernel/kernel.h"
14#include "core/hle/kernel/process.h" 12#include "core/hle/kernel/process.h"
15#include "core/hle/kernel/vm_manager.h" 13#include "core/hle/kernel/vm_manager.h"
16#include "core/loader/elf.h" 14#include "core/loader/elf.h"
17#include "core/memory.h" 15#include "core/memory.h"
18 16
19using Kernel::CodeSet;
20using Kernel::SharedPtr;
21
22//////////////////////////////////////////////////////////////////////////////////////////////////// 17////////////////////////////////////////////////////////////////////////////////////////////////////
23// ELF Header Constants 18// ELF Header Constants
24 19
@@ -211,7 +206,7 @@ public:
211 u32 GetFlags() const { 206 u32 GetFlags() const {
212 return (u32)(header->e_flags); 207 return (u32)(header->e_flags);
213 } 208 }
214 SharedPtr<CodeSet> LoadInto(VAddr vaddr); 209 Kernel::CodeSet LoadInto(VAddr vaddr);
215 210
216 int GetNumSegments() const { 211 int GetNumSegments() const {
217 return (int)(header->e_phnum); 212 return (int)(header->e_phnum);
@@ -274,7 +269,7 @@ const char* ElfReader::GetSectionName(int section) const {
274 return nullptr; 269 return nullptr;
275} 270}
276 271
277SharedPtr<CodeSet> ElfReader::LoadInto(VAddr vaddr) { 272Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) {
278 LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx); 273 LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx);
279 274
280 // Should we relocate? 275 // Should we relocate?
@@ -302,8 +297,7 @@ SharedPtr<CodeSet> ElfReader::LoadInto(VAddr vaddr) {
302 std::vector<u8> program_image(total_image_size); 297 std::vector<u8> program_image(total_image_size);
303 std::size_t current_image_position = 0; 298 std::size_t current_image_position = 0;
304 299
305 auto& kernel = Core::System::GetInstance().Kernel(); 300 Kernel::CodeSet codeset;
306 SharedPtr<CodeSet> codeset = CodeSet::Create(kernel, "");
307 301
308 for (unsigned int i = 0; i < header->e_phnum; ++i) { 302 for (unsigned int i = 0; i < header->e_phnum; ++i) {
309 const Elf32_Phdr* p = &segments[i]; 303 const Elf32_Phdr* p = &segments[i];
@@ -311,14 +305,14 @@ SharedPtr<CodeSet> ElfReader::LoadInto(VAddr vaddr) {
311 p->p_vaddr, p->p_filesz, p->p_memsz); 305 p->p_vaddr, p->p_filesz, p->p_memsz);
312 306
313 if (p->p_type == PT_LOAD) { 307 if (p->p_type == PT_LOAD) {
314 CodeSet::Segment* codeset_segment; 308 Kernel::CodeSet::Segment* codeset_segment;
315 u32 permission_flags = p->p_flags & (PF_R | PF_W | PF_X); 309 u32 permission_flags = p->p_flags & (PF_R | PF_W | PF_X);
316 if (permission_flags == (PF_R | PF_X)) { 310 if (permission_flags == (PF_R | PF_X)) {
317 codeset_segment = &codeset->CodeSegment(); 311 codeset_segment = &codeset.CodeSegment();
318 } else if (permission_flags == (PF_R)) { 312 } else if (permission_flags == (PF_R)) {
319 codeset_segment = &codeset->RODataSegment(); 313 codeset_segment = &codeset.RODataSegment();
320 } else if (permission_flags == (PF_R | PF_W)) { 314 } else if (permission_flags == (PF_R | PF_W)) {
321 codeset_segment = &codeset->DataSegment(); 315 codeset_segment = &codeset.DataSegment();
322 } else { 316 } else {
323 LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id {} with flags {:X}", i, 317 LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id {} with flags {:X}", i,
324 p->p_flags); 318 p->p_flags);
@@ -345,8 +339,8 @@ SharedPtr<CodeSet> ElfReader::LoadInto(VAddr vaddr) {
345 } 339 }
346 } 340 }
347 341
348 codeset->entrypoint = base_addr + header->e_entry; 342 codeset.entrypoint = base_addr + header->e_entry;
349 codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); 343 codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image));
350 344
351 LOG_DEBUG(Loader, "Done loading."); 345 LOG_DEBUG(Loader, "Done loading.");
352 346
@@ -397,11 +391,11 @@ ResultStatus AppLoader_ELF::Load(Kernel::Process& process) {
397 391
398 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); 392 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
399 ElfReader elf_reader(&buffer[0]); 393 ElfReader elf_reader(&buffer[0]);
400 SharedPtr<CodeSet> codeset = elf_reader.LoadInto(base_address); 394 Kernel::CodeSet codeset = elf_reader.LoadInto(base_address);
401 codeset->name = file->GetName(); 395 const VAddr entry_point = codeset.entrypoint;
402 396
403 process.LoadModule(codeset, codeset->entrypoint); 397 process.LoadModule(std::move(codeset), entry_point);
404 process.Run(codeset->entrypoint, 48, Memory::DEFAULT_STACK_SIZE); 398 process.Run(entry_point, 48, Memory::DEFAULT_STACK_SIZE);
405 399
406 is_loaded = true; 400 is_loaded = true;
407 return ResultStatus::Success; 401 return ResultStatus::Success;
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 91659ec17..9cd0b0ccd 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -93,7 +93,7 @@ std::string GetFileTypeString(FileType type) {
93 return "unknown"; 93 return "unknown";
94} 94}
95 95
96constexpr std::array<const char*, 59> RESULT_MESSAGES{ 96constexpr std::array<const char*, 60> RESULT_MESSAGES{
97 "The operation completed successfully.", 97 "The operation completed successfully.",
98 "The loader requested to load is already loaded.", 98 "The loader requested to load is already loaded.",
99 "The operation is not implemented.", 99 "The operation is not implemented.",
@@ -128,6 +128,7 @@ constexpr std::array<const char*, 59> RESULT_MESSAGES{
128 "The RomFS could not be found.", 128 "The RomFS could not be found.",
129 "The ELF file has incorrect size as determined by the header.", 129 "The ELF file has incorrect size as determined by the header.",
130 "There was a general error loading the NRO into emulated memory.", 130 "There was a general error loading the NRO into emulated memory.",
131 "There was a general error loading the NSO into emulated memory.",
131 "There is no icon available.", 132 "There is no icon available.",
132 "There is no control data available.", 133 "There is no control data available.",
133 "The NAX file has a bad header.", 134 "The NAX file has a bad header.",
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 0e0333db5..e562b3a04 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -90,6 +90,7 @@ enum class ResultStatus : u16 {
90 ErrorNoRomFS, 90 ErrorNoRomFS,
91 ErrorIncorrectELFFileSize, 91 ErrorIncorrectELFFileSize,
92 ErrorLoadingNRO, 92 ErrorLoadingNRO,
93 ErrorLoadingNSO,
93 ErrorNoIcon, 94 ErrorNoIcon,
94 ErrorNoControl, 95 ErrorNoControl,
95 ErrorBadNAXHeader, 96 ErrorBadNAXHeader,
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 25dd3f04e..243b499f2 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -14,7 +14,6 @@
14#include "core/file_sys/control_metadata.h" 14#include "core/file_sys/control_metadata.h"
15#include "core/file_sys/vfs_offset.h" 15#include "core/file_sys/vfs_offset.h"
16#include "core/gdbstub/gdbstub.h" 16#include "core/gdbstub/gdbstub.h"
17#include "core/hle/kernel/kernel.h"
18#include "core/hle/kernel/process.h" 17#include "core/hle/kernel/process.h"
19#include "core/hle/kernel/vm_manager.h" 18#include "core/hle/kernel/vm_manager.h"
20#include "core/loader/nro.h" 19#include "core/loader/nro.h"
@@ -128,10 +127,10 @@ static constexpr u32 PageAlignSize(u32 size) {
128 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; 127 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
129} 128}
130 129
131bool AppLoader_NRO::LoadNro(FileSys::VirtualFile file, VAddr load_base) { 130bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) {
132 // Read NSO header 131 // Read NSO header
133 NroHeader nro_header{}; 132 NroHeader nro_header{};
134 if (sizeof(NroHeader) != file->ReadObject(&nro_header)) { 133 if (sizeof(NroHeader) != file.ReadObject(&nro_header)) {
135 return {}; 134 return {};
136 } 135 }
137 if (nro_header.magic != Common::MakeMagic('N', 'R', 'O', '0')) { 136 if (nro_header.magic != Common::MakeMagic('N', 'R', 'O', '0')) {
@@ -139,22 +138,21 @@ bool AppLoader_NRO::LoadNro(FileSys::VirtualFile file, VAddr load_base) {
139 } 138 }
140 139
141 // Build program image 140 // Build program image
142 auto& kernel = Core::System::GetInstance().Kernel(); 141 std::vector<u8> program_image = file.ReadBytes(PageAlignSize(nro_header.file_size));
143 Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(kernel, "");
144 std::vector<u8> program_image = file->ReadBytes(PageAlignSize(nro_header.file_size));
145 if (program_image.size() != PageAlignSize(nro_header.file_size)) { 142 if (program_image.size() != PageAlignSize(nro_header.file_size)) {
146 return {}; 143 return {};
147 } 144 }
148 145
146 Kernel::CodeSet codeset;
149 for (std::size_t i = 0; i < nro_header.segments.size(); ++i) { 147 for (std::size_t i = 0; i < nro_header.segments.size(); ++i) {
150 codeset->segments[i].addr = nro_header.segments[i].offset; 148 codeset.segments[i].addr = nro_header.segments[i].offset;
151 codeset->segments[i].offset = nro_header.segments[i].offset; 149 codeset.segments[i].offset = nro_header.segments[i].offset;
152 codeset->segments[i].size = PageAlignSize(nro_header.segments[i].size); 150 codeset.segments[i].size = PageAlignSize(nro_header.segments[i].size);
153 } 151 }
154 152
155 if (!Settings::values.program_args.empty()) { 153 if (!Settings::values.program_args.empty()) {
156 const auto arg_data = Settings::values.program_args; 154 const auto arg_data = Settings::values.program_args;
157 codeset->DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE; 155 codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
158 NSOArgumentHeader args_header{ 156 NSOArgumentHeader args_header{
159 NSO_ARGUMENT_DATA_ALLOCATION_SIZE, static_cast<u32_le>(arg_data.size()), {}}; 157 NSO_ARGUMENT_DATA_ALLOCATION_SIZE, static_cast<u32_le>(arg_data.size()), {}};
160 const auto end_offset = program_image.size(); 158 const auto end_offset = program_image.size();
@@ -176,16 +174,15 @@ bool AppLoader_NRO::LoadNro(FileSys::VirtualFile file, VAddr load_base) {
176 // Resize program image to include .bss section and page align each section 174 // Resize program image to include .bss section and page align each section
177 bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset); 175 bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset);
178 } 176 }
179 codeset->DataSegment().size += bss_size; 177 codeset.DataSegment().size += bss_size;
180 program_image.resize(static_cast<u32>(program_image.size()) + bss_size); 178 program_image.resize(static_cast<u32>(program_image.size()) + bss_size);
181 179
182 // Load codeset for current process 180 // Load codeset for current process
183 codeset->name = file->GetName(); 181 codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image));
184 codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); 182 Core::CurrentProcess()->LoadModule(std::move(codeset), load_base);
185 Core::CurrentProcess()->LoadModule(codeset, load_base);
186 183
187 // Register module with GDBStub 184 // Register module with GDBStub
188 GDBStub::RegisterModule(codeset->name, load_base, load_base); 185 GDBStub::RegisterModule(file.GetName(), load_base, load_base);
189 186
190 return true; 187 return true;
191} 188}
@@ -198,7 +195,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::Process& process) {
198 // Load NRO 195 // Load NRO
199 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); 196 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
200 197
201 if (!LoadNro(file, base_address)) { 198 if (!LoadNro(*file, base_address)) {
202 return ResultStatus::ErrorLoadingNRO; 199 return ResultStatus::ErrorLoadingNRO;
203 } 200 }
204 201
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index 04b46119a..50ee5a78a 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -41,7 +41,7 @@ public:
41 bool IsRomFSUpdatable() const override; 41 bool IsRomFSUpdatable() const override;
42 42
43private: 43private:
44 bool LoadNro(FileSys::VirtualFile file, VAddr load_base); 44 bool LoadNro(const FileSys::VfsFile& file, VAddr load_base);
45 45
46 std::vector<u8> icon_data; 46 std::vector<u8> icon_data;
47 std::unique_ptr<FileSys::NACP> nacp; 47 std::unique_ptr<FileSys::NACP> nacp;
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 28c6dd9b7..68efca5c0 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -12,7 +12,6 @@
12#include "core/core.h" 12#include "core/core.h"
13#include "core/file_sys/patch_manager.h" 13#include "core/file_sys/patch_manager.h"
14#include "core/gdbstub/gdbstub.h" 14#include "core/gdbstub/gdbstub.h"
15#include "core/hle/kernel/kernel.h"
16#include "core/hle/kernel/process.h" 15#include "core/hle/kernel/process.h"
17#include "core/hle/kernel/vm_manager.h" 16#include "core/hle/kernel/vm_manager.h"
18#include "core/loader/nso.h" 17#include "core/loader/nso.h"
@@ -94,42 +93,38 @@ static constexpr u32 PageAlignSize(u32 size) {
94 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; 93 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
95} 94}
96 95
97VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base, 96std::optional<VAddr> AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAddr load_base,
98 bool should_pass_arguments, 97 bool should_pass_arguments,
99 boost::optional<FileSys::PatchManager> pm) { 98 std::optional<FileSys::PatchManager> pm) {
100 if (file == nullptr) 99 if (file.GetSize() < sizeof(NsoHeader))
101 return {};
102
103 if (file->GetSize() < sizeof(NsoHeader))
104 return {}; 100 return {};
105 101
106 NsoHeader nso_header{}; 102 NsoHeader nso_header{};
107 if (sizeof(NsoHeader) != file->ReadObject(&nso_header)) 103 if (sizeof(NsoHeader) != file.ReadObject(&nso_header))
108 return {}; 104 return {};
109 105
110 if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0')) 106 if (nso_header.magic != Common::MakeMagic('N', 'S', 'O', '0'))
111 return {}; 107 return {};
112 108
113 // Build program image 109 // Build program image
114 auto& kernel = Core::System::GetInstance().Kernel(); 110 Kernel::CodeSet codeset;
115 Kernel::SharedPtr<Kernel::CodeSet> codeset = Kernel::CodeSet::Create(kernel, "");
116 std::vector<u8> program_image; 111 std::vector<u8> program_image;
117 for (std::size_t i = 0; i < nso_header.segments.size(); ++i) { 112 for (std::size_t i = 0; i < nso_header.segments.size(); ++i) {
118 std::vector<u8> data = 113 std::vector<u8> data =
119 file->ReadBytes(nso_header.segments_compressed_size[i], nso_header.segments[i].offset); 114 file.ReadBytes(nso_header.segments_compressed_size[i], nso_header.segments[i].offset);
120 if (nso_header.IsSegmentCompressed(i)) { 115 if (nso_header.IsSegmentCompressed(i)) {
121 data = DecompressSegment(data, nso_header.segments[i]); 116 data = DecompressSegment(data, nso_header.segments[i]);
122 } 117 }
123 program_image.resize(nso_header.segments[i].location); 118 program_image.resize(nso_header.segments[i].location);
124 program_image.insert(program_image.end(), data.begin(), data.end()); 119 program_image.insert(program_image.end(), data.begin(), data.end());
125 codeset->segments[i].addr = nso_header.segments[i].location; 120 codeset.segments[i].addr = nso_header.segments[i].location;
126 codeset->segments[i].offset = nso_header.segments[i].location; 121 codeset.segments[i].offset = nso_header.segments[i].location;
127 codeset->segments[i].size = PageAlignSize(static_cast<u32>(data.size())); 122 codeset.segments[i].size = PageAlignSize(static_cast<u32>(data.size()));
128 } 123 }
129 124
130 if (should_pass_arguments && !Settings::values.program_args.empty()) { 125 if (should_pass_arguments && !Settings::values.program_args.empty()) {
131 const auto arg_data = Settings::values.program_args; 126 const auto arg_data = Settings::values.program_args;
132 codeset->DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE; 127 codeset.DataSegment().size += NSO_ARGUMENT_DATA_ALLOCATION_SIZE;
133 NSOArgumentHeader args_header{ 128 NSOArgumentHeader args_header{
134 NSO_ARGUMENT_DATA_ALLOCATION_SIZE, static_cast<u32_le>(arg_data.size()), {}}; 129 NSO_ARGUMENT_DATA_ALLOCATION_SIZE, static_cast<u32_le>(arg_data.size()), {}};
135 const auto end_offset = program_image.size(); 130 const auto end_offset = program_image.size();
@@ -154,12 +149,12 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base,
154 // Resize program image to include .bss section and page align each section 149 // Resize program image to include .bss section and page align each section
155 bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset); 150 bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset);
156 } 151 }
157 codeset->DataSegment().size += bss_size; 152 codeset.DataSegment().size += bss_size;
158 const u32 image_size{PageAlignSize(static_cast<u32>(program_image.size()) + bss_size)}; 153 const u32 image_size{PageAlignSize(static_cast<u32>(program_image.size()) + bss_size)};
159 program_image.resize(image_size); 154 program_image.resize(image_size);
160 155
161 // Apply patches if necessary 156 // Apply patches if necessary
162 if (pm != boost::none && pm->HasNSOPatch(nso_header.build_id)) { 157 if (pm && pm->HasNSOPatch(nso_header.build_id)) {
163 std::vector<u8> pi_header(program_image.size() + 0x100); 158 std::vector<u8> pi_header(program_image.size() + 0x100);
164 std::memcpy(pi_header.data(), &nso_header, sizeof(NsoHeader)); 159 std::memcpy(pi_header.data(), &nso_header, sizeof(NsoHeader));
165 std::memcpy(pi_header.data() + 0x100, program_image.data(), program_image.size()); 160 std::memcpy(pi_header.data() + 0x100, program_image.data(), program_image.size());
@@ -170,12 +165,11 @@ VAddr AppLoader_NSO::LoadModule(FileSys::VirtualFile file, VAddr load_base,
170 } 165 }
171 166
172 // Load codeset for current process 167 // Load codeset for current process
173 codeset->name = file->GetName(); 168 codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image));
174 codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image)); 169 Core::CurrentProcess()->LoadModule(std::move(codeset), load_base);
175 Core::CurrentProcess()->LoadModule(codeset, load_base);
176 170
177 // Register module with GDBStub 171 // Register module with GDBStub
178 GDBStub::RegisterModule(codeset->name, load_base, load_base); 172 GDBStub::RegisterModule(file.GetName(), load_base, load_base);
179 173
180 return load_base + image_size; 174 return load_base + image_size;
181} 175}
@@ -187,7 +181,9 @@ ResultStatus AppLoader_NSO::Load(Kernel::Process& process) {
187 181
188 // Load module 182 // Load module
189 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); 183 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
190 LoadModule(file, base_address, true); 184 if (!LoadModule(*file, base_address, true)) {
185 return ResultStatus::ErrorLoadingNSO;
186 }
191 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); 187 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address);
192 188
193 process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); 189 process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h
index 70ab3b718..433306139 100644
--- a/src/core/loader/nso.h
+++ b/src/core/loader/nso.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <optional>
7#include "common/common_types.h" 8#include "common/common_types.h"
8#include "core/file_sys/patch_manager.h" 9#include "core/file_sys/patch_manager.h"
9#include "core/loader/linker.h" 10#include "core/loader/linker.h"
@@ -36,8 +37,9 @@ public:
36 return IdentifyType(file); 37 return IdentifyType(file);
37 } 38 }
38 39
39 static VAddr LoadModule(FileSys::VirtualFile file, VAddr load_base, bool should_pass_arguments, 40 static std::optional<VAddr> LoadModule(const FileSys::VfsFile& file, VAddr load_base,
40 boost::optional<FileSys::PatchManager> pm = boost::none); 41 bool should_pass_arguments,
42 std::optional<FileSys::PatchManager> pm = {});
41 43
42 ResultStatus Load(Kernel::Process& process) override; 44 ResultStatus Load(Kernel::Process& process) override;
43}; 45};
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index 5534ce01c..13e57848d 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -35,7 +35,7 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file)
35 return; 35 return;
36 36
37 std::tie(nacp_file, icon_file) = 37 std::tie(nacp_file, icon_file) =
38 FileSys::PatchManager(nsp->GetProgramTitleID()).ParseControlNCA(control_nca); 38 FileSys::PatchManager(nsp->GetProgramTitleID()).ParseControlNCA(*control_nca);
39} 39}
40 40
41AppLoader_NSP::~AppLoader_NSP() = default; 41AppLoader_NSP::~AppLoader_NSP() = default;
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h
index b006594a6..db91cd01e 100644
--- a/src/core/loader/nsp.h
+++ b/src/core/loader/nsp.h
@@ -49,7 +49,7 @@ private:
49 std::unique_ptr<AppLoader> secondary_loader; 49 std::unique_ptr<AppLoader> secondary_loader;
50 50
51 FileSys::VirtualFile icon_file; 51 FileSys::VirtualFile icon_file;
52 std::shared_ptr<FileSys::NACP> nacp_file; 52 std::unique_ptr<FileSys::NACP> nacp_file;
53 u64 title_id; 53 u64 title_id;
54}; 54};
55 55
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index ee5452eb9..7a619acb4 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -30,7 +30,7 @@ AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file)
30 return; 30 return;
31 31
32 std::tie(nacp_file, icon_file) = 32 std::tie(nacp_file, icon_file) =
33 FileSys::PatchManager(xci->GetProgramTitleID()).ParseControlNCA(control_nca); 33 FileSys::PatchManager(xci->GetProgramTitleID()).ParseControlNCA(*control_nca);
34} 34}
35 35
36AppLoader_XCI::~AppLoader_XCI() = default; 36AppLoader_XCI::~AppLoader_XCI() = default;
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
index 770ed1437..46f8dfc9e 100644
--- a/src/core/loader/xci.h
+++ b/src/core/loader/xci.h
@@ -49,7 +49,7 @@ private:
49 std::unique_ptr<AppLoader_NCA> nca_loader; 49 std::unique_ptr<AppLoader_NCA> nca_loader;
50 50
51 FileSys::VirtualFile icon_file; 51 FileSys::VirtualFile icon_file;
52 std::shared_ptr<FileSys::NACP> nacp_file; 52 std::unique_ptr<FileSys::NACP> nacp_file;
53}; 53};
54 54
55} // namespace Loader 55} // namespace Loader
diff --git a/src/core/settings.h b/src/core/settings.h
index 83b9a04c8..8f2da01c8 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -136,7 +136,7 @@ struct Values {
136 float resolution_factor; 136 float resolution_factor;
137 bool use_frame_limit; 137 bool use_frame_limit;
138 u16 frame_limit; 138 u16 frame_limit;
139 bool use_accurate_framebuffers; 139 bool use_accurate_gpu_emulation;
140 140
141 float bg_red; 141 float bg_red;
142 float bg_green; 142 float bg_green;
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 7b04792b5..0de13edd3 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -163,8 +163,8 @@ TelemetrySession::TelemetrySession() {
163 AddField(Telemetry::FieldType::UserConfig, "Renderer_UseFrameLimit", 163 AddField(Telemetry::FieldType::UserConfig, "Renderer_UseFrameLimit",
164 Settings::values.use_frame_limit); 164 Settings::values.use_frame_limit);
165 AddField(Telemetry::FieldType::UserConfig, "Renderer_FrameLimit", Settings::values.frame_limit); 165 AddField(Telemetry::FieldType::UserConfig, "Renderer_FrameLimit", Settings::values.frame_limit);
166 AddField(Telemetry::FieldType::UserConfig, "Renderer_UseAccurateFramebuffers", 166 AddField(Telemetry::FieldType::UserConfig, "Renderer_UseAccurateGpuEmulation",
167 Settings::values.use_accurate_framebuffers); 167 Settings::values.use_accurate_gpu_emulation);
168 AddField(Telemetry::FieldType::UserConfig, "System_UseDockedMode", 168 AddField(Telemetry::FieldType::UserConfig, "System_UseDockedMode",
169 Settings::values.use_docked_mode); 169 Settings::values.use_docked_mode);
170} 170}