summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt16
-rw-r--r--src/core/core.cpp136
-rw-r--r--src/core/core.h5
-rw-r--r--src/core/cpu_core_manager.cpp142
-rw-r--r--src/core/cpu_core_manager.h59
-rw-r--r--src/core/crypto/key_manager.cpp3
-rw-r--r--src/core/file_sys/bis_factory.cpp9
-rw-r--r--src/core/file_sys/bis_factory.h4
-rw-r--r--src/core/file_sys/card_image.cpp2
-rw-r--r--src/core/file_sys/card_image.h16
-rw-r--r--src/core/file_sys/content_archive.cpp5
-rw-r--r--src/core/file_sys/content_archive.h3
-rw-r--r--src/core/file_sys/control_metadata.cpp30
-rw-r--r--src/core/file_sys/control_metadata.h1
-rw-r--r--src/core/file_sys/errors.h25
-rw-r--r--src/core/file_sys/patch_manager.cpp81
-rw-r--r--src/core/file_sys/registered_cache.cpp108
-rw-r--r--src/core/file_sys/registered_cache.h13
-rw-r--r--src/core/file_sys/romfs_factory.cpp2
-rw-r--r--src/core/file_sys/savedata_factory.cpp32
-rw-r--r--src/core/file_sys/savedata_factory.h3
-rw-r--r--src/core/file_sys/submission_package.cpp2
-rw-r--r--src/core/file_sys/submission_package.h2
-rw-r--r--src/core/file_sys/vfs.cpp46
-rw-r--r--src/core/file_sys/vfs.h20
-rw-r--r--src/core/frontend/applets/software_keyboard.cpp29
-rw-r--r--src/core/frontend/applets/software_keyboard.h54
-rw-r--r--src/core/frontend/input.h7
-rw-r--r--src/core/gdbstub/gdbstub.cpp123
-rw-r--r--src/core/hle/kernel/errors.h74
-rw-r--r--src/core/hle/kernel/handle_table.cpp16
-rw-r--r--src/core/hle/kernel/handle_table.h16
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp29
-rw-r--r--src/core/hle/kernel/hle_ipc.h12
-rw-r--r--src/core/hle/kernel/kernel.cpp79
-rw-r--r--src/core/hle/kernel/kernel.h6
-rw-r--r--src/core/hle/kernel/object.cpp3
-rw-r--r--src/core/hle/kernel/object.h9
-rw-r--r--src/core/hle/kernel/process.cpp91
-rw-r--r--src/core/hle/kernel/process.h33
-rw-r--r--src/core/hle/kernel/readable_event.cpp (renamed from src/core/hle/kernel/event.cpp)27
-rw-r--r--src/core/hle/kernel/readable_event.h55
-rw-r--r--src/core/hle/kernel/resource_limit.cpp75
-rw-r--r--src/core/hle/kernel/resource_limit.h102
-rw-r--r--src/core/hle/kernel/shared_memory.cpp22
-rw-r--r--src/core/hle/kernel/shared_memory.h48
-rw-r--r--src/core/hle/kernel/svc.cpp718
-rw-r--r--src/core/hle/kernel/svc_wrap.h26
-rw-r--r--src/core/hle/kernel/thread.cpp48
-rw-r--r--src/core/hle/kernel/thread.h2
-rw-r--r--src/core/hle/kernel/vm_manager.cpp82
-rw-r--r--src/core/hle/kernel/vm_manager.h16
-rw-r--r--src/core/hle/kernel/writable_event.cpp52
-rw-r--r--src/core/hle/kernel/writable_event.h (renamed from src/core/hle/kernel/event.h)35
-rw-r--r--src/core/hle/result.h2
-rw-r--r--src/core/hle/service/acc/acc.cpp28
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp28
-rw-r--r--src/core/hle/service/acc/profile_manager.h27
-rw-r--r--src/core/hle/service/am/am.cpp567
-rw-r--r--src/core/hle/service/am/am.h46
-rw-r--r--src/core/hle/service/am/applet_ae.cpp66
-rw-r--r--src/core/hle/service/am/applet_oe.cpp27
-rw-r--r--src/core/hle/service/am/applets/applets.cpp114
-rw-r--r--src/core/hle/service/am/applets/applets.h109
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.cpp161
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.h74
-rw-r--r--src/core/hle/service/am/applets/stub_applet.cpp70
-rw-r--r--src/core/hle/service/am/applets/stub_applet.h24
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp20
-rw-r--r--src/core/hle/service/aoc/aoc_u.h6
-rw-r--r--src/core/hle/service/apm/interface.cpp16
-rw-r--r--src/core/hle/service/arp/arp.cpp4
-rw-r--r--src/core/hle/service/audio/audout_u.cpp48
-rw-r--r--src/core/hle/service/audio/audout_u.h3
-rw-r--r--src/core/hle/service/audio/audren_u.cpp102
-rw-r--r--src/core/hle/service/audio/hwopus.cpp48
-rw-r--r--src/core/hle/service/bcat/module.cpp3
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp43
-rw-r--r--src/core/hle/service/btm/btm.cpp121
-rw-r--r--src/core/hle/service/erpt/erpt.cpp12
-rw-r--r--src/core/hle/service/fgm/fgm.cpp4
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp57
-rw-r--r--src/core/hle/service/filesystem/filesystem.h16
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp196
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h1
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp43
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.h41
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp20
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.h7
-rw-r--r--src/core/hle/service/hid/controllers/mouse.cpp25
-rw-r--r--src/core/hle/service/hid/controllers/mouse.h9
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp529
-rw-r--r--src/core/hle/service/hid/controllers/npad.h56
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp13
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h12
-rw-r--r--src/core/hle/service/hid/hid.cpp133
-rw-r--r--src/core/hle/service/hid/irs.cpp54
-rw-r--r--src/core/hle/service/lbl/lbl.cpp12
-rw-r--r--src/core/hle/service/ldn/ldn.cpp12
-rw-r--r--src/core/hle/service/ldr/ldr.cpp392
-rw-r--r--src/core/hle/service/lm/lm.cpp17
-rw-r--r--src/core/hle/service/mm/mm_u.cpp14
-rw-r--r--src/core/hle/service/nfc/nfc.cpp24
-rw-r--r--src/core/hle/service/nfp/nfp.cpp52
-rw-r--r--src/core/hle/service/nfp/nfp.h7
-rw-r--r--src/core/hle/service/nifm/nifm.cpp43
-rw-r--r--src/core/hle/service/nim/nim.cpp43
-rw-r--r--src/core/hle/service/ns/ns.cpp72
-rw-r--r--src/core/hle/service/ns/pl_u.cpp18
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp20
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp25
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp16
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp33
-rw-r--r--src/core/hle/service/nvdrv/interface.h9
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp24
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h11
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp13
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h11
-rw-r--r--src/core/hle/service/pctl/module.cpp8
-rw-r--r--src/core/hle/service/pm/pm.cpp4
-rw-r--r--src/core/hle/service/psc/psc.cpp4
-rw-r--r--src/core/hle/service/service.cpp4
-rw-r--r--src/core/hle/service/set/set.cpp52
-rw-r--r--src/core/hle/service/set/set.h1
-rw-r--r--src/core/hle/service/set/set_sys.cpp8
-rw-r--r--src/core/hle/service/sm/controller.cpp11
-rw-r--r--src/core/hle/service/sm/sm.cpp58
-rw-r--r--src/core/hle/service/sm/sm.h3
-rw-r--r--src/core/hle/service/spl/module.cpp13
-rw-r--r--src/core/hle/service/spl/module.h4
-rw-r--r--src/core/hle/service/ssl/ssl.cpp2
-rw-r--r--src/core/hle/service/time/interface.cpp5
-rw-r--r--src/core/hle/service/time/time.cpp170
-rw-r--r--src/core/hle/service/time/time.h20
-rw-r--r--src/core/hle/service/usb/usb.cpp6
-rw-r--r--src/core/hle/service/vi/vi.cpp99
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp3
-rw-r--r--src/core/loader/nro.cpp27
-rw-r--r--src/core/loader/nro.h8
-rw-r--r--src/core/loader/nso.cpp10
-rw-r--r--src/core/loader/nso.h8
-rw-r--r--src/core/settings.cpp50
-rw-r--r--src/core/settings.h322
148 files changed, 5625 insertions, 1793 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 2d61e2f2c..882c9ab59 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -12,6 +12,8 @@ add_library(core STATIC
12 core_timing.h 12 core_timing.h
13 core_timing_util.cpp 13 core_timing_util.cpp
14 core_timing_util.h 14 core_timing_util.h
15 cpu_core_manager.cpp
16 cpu_core_manager.h
15 crypto/aes_util.cpp 17 crypto/aes_util.cpp
16 crypto/aes_util.h 18 crypto/aes_util.h
17 crypto/encryption_layer.cpp 19 crypto/encryption_layer.cpp
@@ -81,6 +83,8 @@ add_library(core STATIC
81 file_sys/vfs_vector.h 83 file_sys/vfs_vector.h
82 file_sys/xts_archive.cpp 84 file_sys/xts_archive.cpp
83 file_sys/xts_archive.h 85 file_sys/xts_archive.h
86 frontend/applets/software_keyboard.cpp
87 frontend/applets/software_keyboard.h
84 frontend/emu_window.cpp 88 frontend/emu_window.cpp
85 frontend/emu_window.h 89 frontend/emu_window.h
86 frontend/framebuffer_layout.cpp 90 frontend/framebuffer_layout.cpp
@@ -97,8 +101,6 @@ add_library(core STATIC
97 hle/kernel/client_session.cpp 101 hle/kernel/client_session.cpp
98 hle/kernel/client_session.h 102 hle/kernel/client_session.h
99 hle/kernel/errors.h 103 hle/kernel/errors.h
100 hle/kernel/event.cpp
101 hle/kernel/event.h
102 hle/kernel/handle_table.cpp 104 hle/kernel/handle_table.cpp
103 hle/kernel/handle_table.h 105 hle/kernel/handle_table.h
104 hle/kernel/hle_ipc.cpp 106 hle/kernel/hle_ipc.cpp
@@ -111,6 +113,8 @@ add_library(core STATIC
111 hle/kernel/object.h 113 hle/kernel/object.h
112 hle/kernel/process.cpp 114 hle/kernel/process.cpp
113 hle/kernel/process.h 115 hle/kernel/process.h
116 hle/kernel/readable_event.cpp
117 hle/kernel/readable_event.h
114 hle/kernel/resource_limit.cpp 118 hle/kernel/resource_limit.cpp
115 hle/kernel/resource_limit.h 119 hle/kernel/resource_limit.h
116 hle/kernel/scheduler.cpp 120 hle/kernel/scheduler.cpp
@@ -133,6 +137,8 @@ add_library(core STATIC
133 hle/kernel/vm_manager.h 137 hle/kernel/vm_manager.h
134 hle/kernel/wait_object.cpp 138 hle/kernel/wait_object.cpp
135 hle/kernel/wait_object.h 139 hle/kernel/wait_object.h
140 hle/kernel/writable_event.cpp
141 hle/kernel/writable_event.h
136 hle/lock.cpp 142 hle/lock.cpp
137 hle/lock.h 143 hle/lock.h
138 hle/result.h 144 hle/result.h
@@ -154,6 +160,12 @@ add_library(core STATIC
154 hle/service/am/applet_ae.h 160 hle/service/am/applet_ae.h
155 hle/service/am/applet_oe.cpp 161 hle/service/am/applet_oe.cpp
156 hle/service/am/applet_oe.h 162 hle/service/am/applet_oe.h
163 hle/service/am/applets/applets.cpp
164 hle/service/am/applets/applets.h
165 hle/service/am/applets/software_keyboard.cpp
166 hle/service/am/applets/software_keyboard.h
167 hle/service/am/applets/stub_applet.cpp
168 hle/service/am/applets/stub_applet.h
157 hle/service/am/idle.cpp 169 hle/service/am/idle.cpp
158 hle/service/am/idle.h 170 hle/service/am/idle.h
159 hle/service/am/omm.cpp 171 hle/service/am/omm.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 6d5b5a2d0..795fabc65 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -14,6 +14,7 @@
14#include "core/core.h" 14#include "core/core.h"
15#include "core/core_cpu.h" 15#include "core/core_cpu.h"
16#include "core/core_timing.h" 16#include "core/core_timing.h"
17#include "core/cpu_core_manager.h"
17#include "core/file_sys/mode.h" 18#include "core/file_sys/mode.h"
18#include "core/file_sys/vfs_concat.h" 19#include "core/file_sys/vfs_concat.h"
19#include "core/file_sys/vfs_real.h" 20#include "core/file_sys/vfs_real.h"
@@ -23,12 +24,13 @@
23#include "core/hle/kernel/process.h" 24#include "core/hle/kernel/process.h"
24#include "core/hle/kernel/scheduler.h" 25#include "core/hle/kernel/scheduler.h"
25#include "core/hle/kernel/thread.h" 26#include "core/hle/kernel/thread.h"
27#include "core/hle/service/am/applets/software_keyboard.h"
26#include "core/hle/service/service.h" 28#include "core/hle/service/service.h"
27#include "core/hle/service/sm/sm.h" 29#include "core/hle/service/sm/sm.h"
28#include "core/loader/loader.h" 30#include "core/loader/loader.h"
29#include "core/perf_stats.h" 31#include "core/perf_stats.h"
30#include "core/settings.h"
31#include "core/telemetry_session.h" 32#include "core/telemetry_session.h"
33#include "frontend/applets/software_keyboard.h"
32#include "video_core/debug_utils/debug_utils.h" 34#include "video_core/debug_utils/debug_utils.h"
33#include "video_core/gpu.h" 35#include "video_core/gpu.h"
34#include "video_core/renderer_base.h" 36#include "video_core/renderer_base.h"
@@ -69,64 +71,22 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
69 71
70 return vfs->OpenFile(path, FileSys::Mode::Read); 72 return vfs->OpenFile(path, FileSys::Mode::Read);
71} 73}
72
73/// Runs a CPU core while the system is powered on
74void RunCpuCore(Cpu& cpu_state) {
75 while (Core::System::GetInstance().IsPoweredOn()) {
76 cpu_state.RunLoop(true);
77 }
78}
79} // Anonymous namespace 74} // Anonymous namespace
80 75
81struct System::Impl { 76struct System::Impl {
82 Cpu& CurrentCpuCore() { 77 Cpu& CurrentCpuCore() {
83 if (Settings::values.use_multi_core) { 78 return cpu_core_manager.GetCurrentCore();
84 const auto& search = thread_to_cpu.find(std::this_thread::get_id());
85 ASSERT(search != thread_to_cpu.end());
86 ASSERT(search->second);
87 return *search->second;
88 }
89
90 // Otherwise, use single-threaded mode active_core variable
91 return *cpu_cores[active_core];
92 } 79 }
93 80
94 ResultStatus RunLoop(bool tight_loop) { 81 ResultStatus RunLoop(bool tight_loop) {
95 status = ResultStatus::Success; 82 status = ResultStatus::Success;
96 83
97 // Update thread_to_cpu in case Core 0 is run from a different host thread 84 cpu_core_manager.RunLoop(tight_loop);
98 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0].get();
99
100 if (GDBStub::IsServerEnabled()) {
101 GDBStub::HandlePacket();
102
103 // If the loop is halted and we want to step, use a tiny (1) number of instructions to
104 // execute. Otherwise, get out of the loop function.
105 if (GDBStub::GetCpuHaltFlag()) {
106 if (GDBStub::GetCpuStepFlag()) {
107 tight_loop = false;
108 } else {
109 return ResultStatus::Success;
110 }
111 }
112 }
113
114 for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
115 cpu_cores[active_core]->RunLoop(tight_loop);
116 if (Settings::values.use_multi_core) {
117 // Cores 1-3 are run on other threads in this mode
118 break;
119 }
120 }
121
122 if (GDBStub::IsServerEnabled()) {
123 GDBStub::SetCpuStepFlag(false);
124 }
125 85
126 return status; 86 return status;
127 } 87 }
128 88
129 ResultStatus Init(Frontend::EmuWindow& emu_window) { 89 ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
130 LOG_DEBUG(HW_Memory, "initialized OK"); 90 LOG_DEBUG(HW_Memory, "initialized OK");
131 91
132 CoreTiming::Init(); 92 CoreTiming::Init();
@@ -136,15 +96,13 @@ struct System::Impl {
136 if (virtual_filesystem == nullptr) 96 if (virtual_filesystem == nullptr)
137 virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); 97 virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
138 98
99 /// Create default implementations of applets if one is not provided.
100 if (software_keyboard == nullptr)
101 software_keyboard = std::make_unique<Core::Frontend::DefaultSoftwareKeyboardApplet>();
102
139 auto main_process = Kernel::Process::Create(kernel, "main"); 103 auto main_process = Kernel::Process::Create(kernel, "main");
140 kernel.MakeCurrentProcess(main_process.get()); 104 kernel.MakeCurrentProcess(main_process.get());
141 105
142 cpu_barrier = std::make_unique<CpuBarrier>();
143 cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size());
144 for (std::size_t index = 0; index < cpu_cores.size(); ++index) {
145 cpu_cores[index] = std::make_unique<Cpu>(*cpu_exclusive_monitor, *cpu_barrier, index);
146 }
147
148 telemetry_session = std::make_unique<Core::TelemetrySession>(); 106 telemetry_session = std::make_unique<Core::TelemetrySession>();
149 service_manager = std::make_shared<Service::SM::ServiceManager>(); 107 service_manager = std::make_shared<Service::SM::ServiceManager>();
150 108
@@ -158,17 +116,8 @@ struct System::Impl {
158 116
159 gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer()); 117 gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer());
160 118
161 // Create threads for CPU cores 1-3, and build thread_to_cpu map 119 cpu_core_manager.Initialize(system);
162 // CPU core 0 is run on the main thread 120 is_powered_on = true;
163 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0].get();
164 if (Settings::values.use_multi_core) {
165 for (std::size_t index = 0; index < cpu_core_threads.size(); ++index) {
166 cpu_core_threads[index] =
167 std::make_unique<std::thread>(RunCpuCore, std::ref(*cpu_cores[index + 1]));
168 thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1].get();
169 }
170 }
171
172 LOG_DEBUG(Core, "Initialized OK"); 121 LOG_DEBUG(Core, "Initialized OK");
173 122
174 // Reset counters and set time origin to current frame 123 // Reset counters and set time origin to current frame
@@ -178,7 +127,8 @@ struct System::Impl {
178 return ResultStatus::Success; 127 return ResultStatus::Success;
179 } 128 }
180 129
181 ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { 130 ResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
131 const std::string& filepath) {
182 app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); 132 app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath));
183 133
184 if (!app_loader) { 134 if (!app_loader) {
@@ -195,7 +145,7 @@ struct System::Impl {
195 return ResultStatus::ErrorSystemMode; 145 return ResultStatus::ErrorSystemMode;
196 } 146 }
197 147
198 ResultStatus init_result{Init(emu_window)}; 148 ResultStatus init_result{Init(system, emu_window)};
199 if (init_result != ResultStatus::Success) { 149 if (init_result != ResultStatus::Success) {
200 LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", 150 LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
201 static_cast<int>(init_result)); 151 static_cast<int>(init_result));
@@ -225,6 +175,8 @@ struct System::Impl {
225 Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime", 175 Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime",
226 perf_results.frametime * 1000.0); 176 perf_results.frametime * 1000.0);
227 177
178 is_powered_on = false;
179
228 // Shutdown emulation session 180 // Shutdown emulation session
229 renderer.reset(); 181 renderer.reset();
230 GDBStub::Shutdown(); 182 GDBStub::Shutdown();
@@ -234,19 +186,7 @@ struct System::Impl {
234 gpu_core.reset(); 186 gpu_core.reset();
235 187
236 // Close all CPU/threading state 188 // Close all CPU/threading state
237 cpu_barrier->NotifyEnd(); 189 cpu_core_manager.Shutdown();
238 if (Settings::values.use_multi_core) {
239 for (auto& thread : cpu_core_threads) {
240 thread->join();
241 thread.reset();
242 }
243 }
244 thread_to_cpu.clear();
245 for (auto& cpu_core : cpu_cores) {
246 cpu_core.reset();
247 }
248 cpu_exclusive_monitor.reset();
249 cpu_barrier.reset();
250 190
251 // Shutdown kernel and core timing 191 // Shutdown kernel and core timing
252 kernel.Shutdown(); 192 kernel.Shutdown();
@@ -283,11 +223,11 @@ struct System::Impl {
283 std::unique_ptr<VideoCore::RendererBase> renderer; 223 std::unique_ptr<VideoCore::RendererBase> renderer;
284 std::unique_ptr<Tegra::GPU> gpu_core; 224 std::unique_ptr<Tegra::GPU> gpu_core;
285 std::shared_ptr<Tegra::DebugContext> debug_context; 225 std::shared_ptr<Tegra::DebugContext> debug_context;
286 std::unique_ptr<ExclusiveMonitor> cpu_exclusive_monitor; 226 CpuCoreManager cpu_core_manager;
287 std::unique_ptr<CpuBarrier> cpu_barrier; 227 bool is_powered_on = false;
288 std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cpu_cores; 228
289 std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads; 229 /// Frontend applets
290 std::size_t active_core{}; ///< Active core, only used in single thread mode 230 std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard;
291 231
292 /// Service manager 232 /// Service manager
293 std::shared_ptr<Service::SM::ServiceManager> service_manager; 233 std::shared_ptr<Service::SM::ServiceManager> service_manager;
@@ -298,9 +238,6 @@ struct System::Impl {
298 ResultStatus status = ResultStatus::Success; 238 ResultStatus status = ResultStatus::Success;
299 std::string status_details = ""; 239 std::string status_details = "";
300 240
301 /// Map of guest threads to CPU cores
302 std::map<std::thread::id, Cpu*> thread_to_cpu;
303
304 Core::PerfStats perf_stats; 241 Core::PerfStats perf_stats;
305 Core::FrameLimiter frame_limiter; 242 Core::FrameLimiter frame_limiter;
306}; 243};
@@ -325,17 +262,15 @@ System::ResultStatus System::SingleStep() {
325} 262}
326 263
327void System::InvalidateCpuInstructionCaches() { 264void System::InvalidateCpuInstructionCaches() {
328 for (auto& cpu : impl->cpu_cores) { 265 impl->cpu_core_manager.InvalidateAllInstructionCaches();
329 cpu->ArmInterface().ClearInstructionCache();
330 }
331} 266}
332 267
333System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { 268System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
334 return impl->Load(emu_window, filepath); 269 return impl->Load(*this, emu_window, filepath);
335} 270}
336 271
337bool System::IsPoweredOn() const { 272bool System::IsPoweredOn() const {
338 return impl->cpu_barrier && impl->cpu_barrier->IsAlive(); 273 return impl->is_powered_on;
339} 274}
340 275
341void System::PrepareReschedule() { 276void System::PrepareReschedule() {
@@ -399,21 +334,20 @@ const ARM_Interface& System::ArmInterface(std::size_t core_index) const {
399} 334}
400 335
401Cpu& System::CpuCore(std::size_t core_index) { 336Cpu& System::CpuCore(std::size_t core_index) {
402 ASSERT(core_index < NUM_CPU_CORES); 337 return impl->cpu_core_manager.GetCore(core_index);
403 return *impl->cpu_cores[core_index];
404} 338}
405 339
406const Cpu& System::CpuCore(std::size_t core_index) const { 340const Cpu& System::CpuCore(std::size_t core_index) const {
407 ASSERT(core_index < NUM_CPU_CORES); 341 ASSERT(core_index < NUM_CPU_CORES);
408 return *impl->cpu_cores[core_index]; 342 return impl->cpu_core_manager.GetCore(core_index);
409} 343}
410 344
411ExclusiveMonitor& System::Monitor() { 345ExclusiveMonitor& System::Monitor() {
412 return *impl->cpu_exclusive_monitor; 346 return impl->cpu_core_manager.GetExclusiveMonitor();
413} 347}
414 348
415const ExclusiveMonitor& System::Monitor() const { 349const ExclusiveMonitor& System::Monitor() const {
416 return *impl->cpu_exclusive_monitor; 350 return impl->cpu_core_manager.GetExclusiveMonitor();
417} 351}
418 352
419Tegra::GPU& System::GPU() { 353Tegra::GPU& System::GPU() {
@@ -488,8 +422,16 @@ std::shared_ptr<FileSys::VfsFilesystem> System::GetFilesystem() const {
488 return impl->virtual_filesystem; 422 return impl->virtual_filesystem;
489} 423}
490 424
425void System::SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet) {
426 impl->software_keyboard = std::move(applet);
427}
428
429const Core::Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() const {
430 return *impl->software_keyboard;
431}
432
491System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { 433System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
492 return impl->Init(emu_window); 434 return impl->Init(*this, emu_window);
493} 435}
494 436
495void System::Shutdown() { 437void System::Shutdown() {
diff --git a/src/core/core.h b/src/core/core.h
index cfacceb81..be71bd437 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -13,6 +13,7 @@
13 13
14namespace Core::Frontend { 14namespace Core::Frontend {
15class EmuWindow; 15class EmuWindow;
16class SoftwareKeyboardApplet;
16} // namespace Core::Frontend 17} // namespace Core::Frontend
17 18
18namespace FileSys { 19namespace FileSys {
@@ -236,6 +237,10 @@ public:
236 237
237 std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const; 238 std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const;
238 239
240 void SetSoftwareKeyboard(std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> applet);
241
242 const Core::Frontend::SoftwareKeyboardApplet& GetSoftwareKeyboard() const;
243
239private: 244private:
240 System(); 245 System();
241 246
diff --git a/src/core/cpu_core_manager.cpp b/src/core/cpu_core_manager.cpp
new file mode 100644
index 000000000..769a6fefa
--- /dev/null
+++ b/src/core/cpu_core_manager.cpp
@@ -0,0 +1,142 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/assert.h"
6#include "core/arm/exclusive_monitor.h"
7#include "core/core.h"
8#include "core/core_cpu.h"
9#include "core/cpu_core_manager.h"
10#include "core/gdbstub/gdbstub.h"
11#include "core/settings.h"
12
13namespace Core {
14namespace {
15void RunCpuCore(const System& system, Cpu& cpu_state) {
16 while (system.IsPoweredOn()) {
17 cpu_state.RunLoop(true);
18 }
19}
20} // Anonymous namespace
21
22CpuCoreManager::CpuCoreManager() = default;
23CpuCoreManager::~CpuCoreManager() = default;
24
25void CpuCoreManager::Initialize(System& system) {
26 barrier = std::make_unique<CpuBarrier>();
27 exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size());
28
29 for (std::size_t index = 0; index < cores.size(); ++index) {
30 cores[index] = std::make_unique<Cpu>(*exclusive_monitor, *barrier, index);
31 }
32
33 // Create threads for CPU cores 1-3, and build thread_to_cpu map
34 // CPU core 0 is run on the main thread
35 thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
36 if (!Settings::values.use_multi_core) {
37 return;
38 }
39
40 for (std::size_t index = 0; index < core_threads.size(); ++index) {
41 core_threads[index] = std::make_unique<std::thread>(RunCpuCore, std::cref(system),
42 std::ref(*cores[index + 1]));
43 thread_to_cpu[core_threads[index]->get_id()] = cores[index + 1].get();
44 }
45}
46
47void CpuCoreManager::Shutdown() {
48 barrier->NotifyEnd();
49 if (Settings::values.use_multi_core) {
50 for (auto& thread : core_threads) {
51 thread->join();
52 thread.reset();
53 }
54 }
55
56 thread_to_cpu.clear();
57 for (auto& cpu_core : cores) {
58 cpu_core.reset();
59 }
60
61 exclusive_monitor.reset();
62 barrier.reset();
63}
64
65Cpu& CpuCoreManager::GetCore(std::size_t index) {
66 return *cores.at(index);
67}
68
69const Cpu& CpuCoreManager::GetCore(std::size_t index) const {
70 return *cores.at(index);
71}
72
73ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() {
74 return *exclusive_monitor;
75}
76
77const ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() const {
78 return *exclusive_monitor;
79}
80
81Cpu& CpuCoreManager::GetCurrentCore() {
82 if (Settings::values.use_multi_core) {
83 const auto& search = thread_to_cpu.find(std::this_thread::get_id());
84 ASSERT(search != thread_to_cpu.end());
85 ASSERT(search->second);
86 return *search->second;
87 }
88
89 // Otherwise, use single-threaded mode active_core variable
90 return *cores[active_core];
91}
92
93const Cpu& CpuCoreManager::GetCurrentCore() const {
94 if (Settings::values.use_multi_core) {
95 const auto& search = thread_to_cpu.find(std::this_thread::get_id());
96 ASSERT(search != thread_to_cpu.end());
97 ASSERT(search->second);
98 return *search->second;
99 }
100
101 // Otherwise, use single-threaded mode active_core variable
102 return *cores[active_core];
103}
104
105void CpuCoreManager::RunLoop(bool tight_loop) {
106 // Update thread_to_cpu in case Core 0 is run from a different host thread
107 thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
108
109 if (GDBStub::IsServerEnabled()) {
110 GDBStub::HandlePacket();
111
112 // If the loop is halted and we want to step, use a tiny (1) number of instructions to
113 // execute. Otherwise, get out of the loop function.
114 if (GDBStub::GetCpuHaltFlag()) {
115 if (GDBStub::GetCpuStepFlag()) {
116 tight_loop = false;
117 } else {
118 return;
119 }
120 }
121 }
122
123 for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
124 cores[active_core]->RunLoop(tight_loop);
125 if (Settings::values.use_multi_core) {
126 // Cores 1-3 are run on other threads in this mode
127 break;
128 }
129 }
130
131 if (GDBStub::IsServerEnabled()) {
132 GDBStub::SetCpuStepFlag(false);
133 }
134}
135
136void CpuCoreManager::InvalidateAllInstructionCaches() {
137 for (auto& cpu : cores) {
138 cpu->ArmInterface().ClearInstructionCache();
139 }
140}
141
142} // namespace Core
diff --git a/src/core/cpu_core_manager.h b/src/core/cpu_core_manager.h
new file mode 100644
index 000000000..a4d70ec56
--- /dev/null
+++ b/src/core/cpu_core_manager.h
@@ -0,0 +1,59 @@
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 <array>
8#include <map>
9#include <memory>
10#include <thread>
11
12namespace Core {
13
14class Cpu;
15class CpuBarrier;
16class ExclusiveMonitor;
17class System;
18
19class CpuCoreManager {
20public:
21 CpuCoreManager();
22 CpuCoreManager(const CpuCoreManager&) = delete;
23 CpuCoreManager(CpuCoreManager&&) = delete;
24
25 ~CpuCoreManager();
26
27 CpuCoreManager& operator=(const CpuCoreManager&) = delete;
28 CpuCoreManager& operator=(CpuCoreManager&&) = delete;
29
30 void Initialize(System& system);
31 void Shutdown();
32
33 Cpu& GetCore(std::size_t index);
34 const Cpu& GetCore(std::size_t index) const;
35
36 Cpu& GetCurrentCore();
37 const Cpu& GetCurrentCore() const;
38
39 ExclusiveMonitor& GetExclusiveMonitor();
40 const ExclusiveMonitor& GetExclusiveMonitor() const;
41
42 void RunLoop(bool tight_loop);
43
44 void InvalidateAllInstructionCaches();
45
46private:
47 static constexpr std::size_t NUM_CPU_CORES = 4;
48
49 std::unique_ptr<ExclusiveMonitor> exclusive_monitor;
50 std::unique_ptr<CpuBarrier> barrier;
51 std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cores;
52 std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> core_threads;
53 std::size_t active_core{}; ///< Active core, only used in single thread mode
54
55 /// Map of guest threads to CPU cores
56 std::map<std::thread::id, Cpu*> thread_to_cpu;
57};
58
59} // namespace Core
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index 904afa039..ca12fb4ab 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -246,7 +246,6 @@ std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save) {
246 } 246 }
247 247
248 std::vector<TicketRaw> out; 248 std::vector<TicketRaw> out;
249 u32 magic{};
250 for (std::size_t offset = 0; offset + 0x4 < buffer.size(); ++offset) { 249 for (std::size_t offset = 0; offset + 0x4 < buffer.size(); ++offset) {
251 if (buffer[offset] == 0x4 && buffer[offset + 1] == 0x0 && buffer[offset + 2] == 0x1 && 250 if (buffer[offset] == 0x4 && buffer[offset + 1] == 0x0 && buffer[offset + 2] == 0x1 &&
252 buffer[offset + 3] == 0x0) { 251 buffer[offset + 3] == 0x0) {
@@ -794,7 +793,7 @@ void KeyManager::DeriveBase() {
794 793
795void KeyManager::DeriveETicket(PartitionDataManager& data) { 794void KeyManager::DeriveETicket(PartitionDataManager& data) {
796 // ETicket keys 795 // ETicket keys
797 const auto es = Service::FileSystem::GetUnionContents()->GetEntry( 796 const auto es = Service::FileSystem::GetUnionContents().GetEntry(
798 0x0100000000000033, FileSys::ContentRecordType::Program); 797 0x0100000000000033, FileSys::ContentRecordType::Program);
799 798
800 if (es == nullptr) 799 if (es == nullptr)
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp
index 76a2b7e86..e29f70b3a 100644
--- a/src/core/file_sys/bis_factory.cpp
+++ b/src/core/file_sys/bis_factory.cpp
@@ -8,8 +8,9 @@
8 8
9namespace FileSys { 9namespace FileSys {
10 10
11BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_) 11BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir dump_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 dump_root(std::move(dump_root_)),
13 sysnand_cache(std::make_unique<RegisteredCache>( 14 sysnand_cache(std::make_unique<RegisteredCache>(
14 GetOrCreateDirectoryRelative(nand_root, "/system/Contents/registered"))), 15 GetOrCreateDirectoryRelative(nand_root, "/system/Contents/registered"))),
15 usrnand_cache(std::make_unique<RegisteredCache>( 16 usrnand_cache(std::make_unique<RegisteredCache>(
@@ -32,4 +33,10 @@ VirtualDir BISFactory::GetModificationLoadRoot(u64 title_id) const {
32 return GetOrCreateDirectoryRelative(load_root, fmt::format("/{:016X}", title_id)); 33 return GetOrCreateDirectoryRelative(load_root, fmt::format("/{:016X}", title_id));
33} 34}
34 35
36VirtualDir BISFactory::GetModificationDumpRoot(u64 title_id) const {
37 if (title_id == 0)
38 return nullptr;
39 return GetOrCreateDirectoryRelative(dump_root, fmt::format("/{:016X}", title_id));
40}
41
35} // namespace FileSys 42} // namespace FileSys
diff --git a/src/core/file_sys/bis_factory.h b/src/core/file_sys/bis_factory.h
index 364d309bd..453c11ad2 100644
--- a/src/core/file_sys/bis_factory.h
+++ b/src/core/file_sys/bis_factory.h
@@ -17,17 +17,19 @@ class RegisteredCache;
17/// registered caches. 17/// registered caches.
18class BISFactory { 18class BISFactory {
19public: 19public:
20 explicit BISFactory(VirtualDir nand_root, VirtualDir load_root); 20 explicit BISFactory(VirtualDir nand_root, VirtualDir load_root, VirtualDir dump_root);
21 ~BISFactory(); 21 ~BISFactory();
22 22
23 RegisteredCache* GetSystemNANDContents() const; 23 RegisteredCache* GetSystemNANDContents() const;
24 RegisteredCache* GetUserNANDContents() const; 24 RegisteredCache* GetUserNANDContents() const;
25 25
26 VirtualDir GetModificationLoadRoot(u64 title_id) const; 26 VirtualDir GetModificationLoadRoot(u64 title_id) const;
27 VirtualDir GetModificationDumpRoot(u64 title_id) const;
27 28
28private: 29private:
29 VirtualDir nand_root; 30 VirtualDir nand_root;
30 VirtualDir load_root; 31 VirtualDir load_root;
32 VirtualDir dump_root;
31 33
32 std::unique_ptr<RegisteredCache> sysnand_cache; 34 std::unique_ptr<RegisteredCache> sysnand_cache;
33 std::unique_ptr<RegisteredCache> usrnand_cache; 35 std::unique_ptr<RegisteredCache> usrnand_cache;
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp
index 1ece55731..2c145bd09 100644
--- a/src/core/file_sys/card_image.cpp
+++ b/src/core/file_sys/card_image.cpp
@@ -176,7 +176,7 @@ Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
176 for (const VirtualFile& file : partitions[static_cast<std::size_t>(part)]->GetFiles()) { 176 for (const VirtualFile& file : partitions[static_cast<std::size_t>(part)]->GetFiles()) {
177 if (file->GetExtension() != "nca") 177 if (file->GetExtension() != "nca")
178 continue; 178 continue;
179 auto nca = std::make_shared<NCA>(file); 179 auto nca = std::make_shared<NCA>(file, nullptr, 0, keys);
180 // TODO(DarkLordZach): Add proper Rev1+ Support 180 // TODO(DarkLordZach): Add proper Rev1+ Support
181 if (nca->IsUpdate()) 181 if (nca->IsUpdate())
182 continue; 182 continue;
diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h
index 8f62571cf..a350496f7 100644
--- a/src/core/file_sys/card_image.h
+++ b/src/core/file_sys/card_image.h
@@ -9,6 +9,7 @@
9#include <vector> 9#include <vector>
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/swap.h" 11#include "common/swap.h"
12#include "core/crypto/key_manager.h"
12#include "core/file_sys/vfs.h" 13#include "core/file_sys/vfs.h"
13 14
14namespace Loader { 15namespace Loader {
@@ -31,7 +32,18 @@ enum class GamecardSize : u8 {
31}; 32};
32 33
33struct GamecardInfo { 34struct GamecardInfo {
34 std::array<u8, 0x70> data; 35 u64_le firmware_version;
36 u32_le access_control_flags;
37 u32_le read_wait_time1;
38 u32_le read_wait_time2;
39 u32_le write_wait_time1;
40 u32_le write_wait_time2;
41 u32_le firmware_mode;
42 u32_le cup_version;
43 std::array<u8, 4> reserved1;
44 u64_le update_partition_hash;
45 u64_le cup_id;
46 std::array<u8, 0x38> reserved2;
35}; 47};
36static_assert(sizeof(GamecardInfo) == 0x70, "GamecardInfo has incorrect size."); 48static_assert(sizeof(GamecardInfo) == 0x70, "GamecardInfo has incorrect size.");
37 49
@@ -107,5 +119,7 @@ private:
107 std::shared_ptr<NSP> secure_partition; 119 std::shared_ptr<NSP> secure_partition;
108 std::shared_ptr<NCA> program; 120 std::shared_ptr<NCA> program;
109 std::vector<std::shared_ptr<NCA>> ncas; 121 std::vector<std::shared_ptr<NCA>> ncas;
122
123 Core::Crypto::KeyManager keys;
110}; 124};
111} // namespace FileSys 125} // namespace FileSys
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index b46fe893c..19b6f8600 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -101,8 +101,9 @@ static bool IsValidNCA(const NCAHeader& header) {
101 return header.magic == Common::MakeMagic('N', 'C', 'A', '3'); 101 return header.magic == Common::MakeMagic('N', 'C', 'A', '3');
102} 102}
103 103
104NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset) 104NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset,
105 : file(std::move(file_)), bktr_base_romfs(std::move(bktr_base_romfs_)) { 105 Core::Crypto::KeyManager keys_)
106 : file(std::move(file_)), bktr_base_romfs(std::move(bktr_base_romfs_)), keys(std::move(keys_)) {
106 if (file == nullptr) { 107 if (file == nullptr) {
107 status = Loader::ResultStatus::ErrorNullFile; 108 status = Loader::ResultStatus::ErrorNullFile;
108 return; 109 return;
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index 4bba55607..99294cbb4 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -79,7 +79,8 @@ inline bool IsDirectoryExeFS(const std::shared_ptr<VfsDirectory>& pfs) {
79class NCA : public ReadOnlyVfsDirectory { 79class NCA : public ReadOnlyVfsDirectory {
80public: 80public:
81 explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr, 81 explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr,
82 u64 bktr_base_ivfc_offset = 0); 82 u64 bktr_base_ivfc_offset = 0,
83 Core::Crypto::KeyManager keys = Core::Crypto::KeyManager());
83 ~NCA() override; 84 ~NCA() override;
84 85
85 Loader::ResultStatus GetStatus() const; 86 Loader::ResultStatus GetStatus() const;
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index a012c2be9..e065e592f 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -8,13 +8,23 @@
8 8
9namespace FileSys { 9namespace FileSys {
10 10
11const std::array<const char*, 15> LANGUAGE_NAMES = { 11const std::array<const char*, 15> LANGUAGE_NAMES{{
12 "AmericanEnglish", "BritishEnglish", "Japanese", 12 "AmericanEnglish",
13 "French", "German", "LatinAmericanSpanish", 13 "BritishEnglish",
14 "Spanish", "Italian", "Dutch", 14 "Japanese",
15 "CanadianFrench", "Portugese", "Russian", 15 "French",
16 "Korean", "Taiwanese", "Chinese", 16 "German",
17}; 17 "LatinAmericanSpanish",
18 "Spanish",
19 "Italian",
20 "Dutch",
21 "CanadianFrench",
22 "Portuguese",
23 "Russian",
24 "Korean",
25 "Taiwanese",
26 "Chinese",
27}};
18 28
19std::string LanguageEntry::GetApplicationName() const { 29std::string LanguageEntry::GetApplicationName() const {
20 return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), 30 return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(),
@@ -66,4 +76,10 @@ std::string NACP::GetVersionString() const {
66 return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(), 76 return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(),
67 raw->version_string.size()); 77 raw->version_string.size());
68} 78}
79
80std::vector<u8> NACP::GetRawBytes() const {
81 std::vector<u8> out(sizeof(RawNACP));
82 std::memcpy(out.data(), raw.get(), sizeof(RawNACP));
83 return out;
84}
69} // namespace FileSys 85} // namespace FileSys
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index 141f7e056..bfaad46b4 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -81,6 +81,7 @@ public:
81 u64 GetTitleId() const; 81 u64 GetTitleId() const;
82 u64 GetDLCBaseTitleId() const; 82 u64 GetDLCBaseTitleId() const;
83 std::string GetVersionString() const; 83 std::string GetVersionString() const;
84 std::vector<u8> GetRawBytes() const;
84 85
85private: 86private:
86 std::unique_ptr<RawNACP> raw; 87 std::unique_ptr<RawNACP> raw;
diff --git a/src/core/file_sys/errors.h b/src/core/file_sys/errors.h
index fea0593c7..e4a4ee4ab 100644
--- a/src/core/file_sys/errors.h
+++ b/src/core/file_sys/errors.h
@@ -8,25 +8,10 @@
8 8
9namespace FileSys { 9namespace FileSys {
10 10
11namespace ErrCodes { 11constexpr ResultCode ERROR_PATH_NOT_FOUND{ErrorModule::FS, 1};
12enum { 12constexpr ResultCode ERROR_ENTITY_NOT_FOUND{ErrorModule::FS, 1002};
13 NotFound = 1, 13constexpr ResultCode ERROR_SD_CARD_NOT_FOUND{ErrorModule::FS, 2001};
14 TitleNotFound = 1002, 14constexpr ResultCode ERROR_INVALID_OFFSET{ErrorModule::FS, 6061};
15 SdCardNotFound = 2001, 15constexpr ResultCode ERROR_INVALID_SIZE{ErrorModule::FS, 6062};
16 RomFSNotFound = 2520,
17};
18}
19
20constexpr ResultCode ERROR_PATH_NOT_FOUND(ErrorModule::FS, ErrCodes::NotFound);
21
22// TODO(bunnei): Replace these with correct errors for Switch OS
23constexpr ResultCode ERROR_INVALID_PATH(-1);
24constexpr ResultCode ERROR_UNSUPPORTED_OPEN_FLAGS(-1);
25constexpr ResultCode ERROR_INVALID_OPEN_FLAGS(-1);
26constexpr ResultCode ERROR_FILE_NOT_FOUND(-1);
27constexpr ResultCode ERROR_UNEXPECTED_FILE_OR_DIRECTORY(-1);
28constexpr ResultCode ERROR_DIRECTORY_ALREADY_EXISTS(-1);
29constexpr ResultCode ERROR_FILE_ALREADY_EXISTS(-1);
30constexpr ResultCode ERROR_DIRECTORY_NOT_EMPTY(-1);
31 16
32} // namespace FileSys 17} // namespace FileSys
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 0c1156989..6b14e08be 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -19,12 +19,18 @@
19#include "core/file_sys/vfs_vector.h" 19#include "core/file_sys/vfs_vector.h"
20#include "core/hle/service/filesystem/filesystem.h" 20#include "core/hle/service/filesystem/filesystem.h"
21#include "core/loader/loader.h" 21#include "core/loader/loader.h"
22#include "core/settings.h"
22 23
23namespace FileSys { 24namespace FileSys {
24 25
25constexpr u64 SINGLE_BYTE_MODULUS = 0x100; 26constexpr u64 SINGLE_BYTE_MODULUS = 0x100;
26constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; 27constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
27 28
29constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{
30 "main", "main.npdm", "rtld", "sdk", "subsdk0", "subsdk1", "subsdk2",
31 "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "subsdk8", "subsdk9",
32};
33
28struct NSOBuildHeader { 34struct NSOBuildHeader {
29 u32_le magic; 35 u32_le magic;
30 INSERT_PADDING_BYTES(0x3C); 36 INSERT_PADDING_BYTES(0x3C);
@@ -56,19 +62,52 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
56 if (exefs == nullptr) 62 if (exefs == nullptr)
57 return exefs; 63 return exefs;
58 64
65 if (Settings::values.dump_exefs) {
66 LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id);
67 const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id);
68 if (dump_dir != nullptr) {
69 const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs");
70 VfsRawCopyD(exefs, exefs_dir);
71 }
72 }
73
59 const auto installed = Service::FileSystem::GetUnionContents(); 74 const auto installed = Service::FileSystem::GetUnionContents();
60 75
61 // Game Updates 76 // Game Updates
62 const auto update_tid = GetUpdateTitleID(title_id); 77 const auto update_tid = GetUpdateTitleID(title_id);
63 const auto update = installed->GetEntry(update_tid, ContentRecordType::Program); 78 const auto update = installed.GetEntry(update_tid, ContentRecordType::Program);
64 79
65 if (update != nullptr && update->GetExeFS() != nullptr && 80 if (update != nullptr && update->GetExeFS() != nullptr &&
66 update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { 81 update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
67 LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully", 82 LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully",
68 FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0))); 83 FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
69 exefs = update->GetExeFS(); 84 exefs = update->GetExeFS();
70 } 85 }
71 86
87 // LayeredExeFS
88 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
89 if (load_dir != nullptr && load_dir->GetSize() > 0) {
90 auto patch_dirs = load_dir->GetSubdirectories();
91 std::sort(
92 patch_dirs.begin(), patch_dirs.end(),
93 [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
94
95 std::vector<VirtualDir> layers;
96 layers.reserve(patch_dirs.size() + 1);
97 for (const auto& subdir : patch_dirs) {
98 auto exefs_dir = subdir->GetSubdirectory("exefs");
99 if (exefs_dir != nullptr)
100 layers.push_back(std::move(exefs_dir));
101 }
102 layers.push_back(exefs);
103
104 auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers));
105 if (layered != nullptr) {
106 LOG_INFO(Loader, " ExeFS: LayeredExeFS patches applied successfully");
107 exefs = std::move(layered);
108 }
109 }
110
72 return exefs; 111 return exefs;
73} 112}
74 113
@@ -119,6 +158,18 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso) const {
119 const auto build_id_raw = Common::HexArrayToString(header.build_id); 158 const auto build_id_raw = Common::HexArrayToString(header.build_id);
120 const auto build_id = build_id_raw.substr(0, build_id_raw.find_last_not_of('0') + 1); 159 const auto build_id = build_id_raw.substr(0, build_id_raw.find_last_not_of('0') + 1);
121 160
161 if (Settings::values.dump_nso) {
162 LOG_INFO(Loader, "Dumping NSO for build_id={}, title_id={:016X}", build_id, title_id);
163 const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id);
164 if (dump_dir != nullptr) {
165 const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso");
166 const auto file = nso_dir->CreateFile(fmt::format("{}.nso", build_id));
167
168 file->Resize(nso.size());
169 file->WriteBytes(nso);
170 }
171 }
172
122 LOG_INFO(Loader, "Patching NSO for build_id={}", build_id); 173 LOG_INFO(Loader, "Patching NSO for build_id={}", build_id);
123 174
124 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); 175 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
@@ -230,13 +281,13 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
230 281
231 // Game Updates 282 // Game Updates
232 const auto update_tid = GetUpdateTitleID(title_id); 283 const auto update_tid = GetUpdateTitleID(title_id);
233 const auto update = installed->GetEntryRaw(update_tid, type); 284 const auto update = installed.GetEntryRaw(update_tid, type);
234 if (update != nullptr) { 285 if (update != nullptr) {
235 const auto new_nca = std::make_shared<NCA>(update, romfs, ivfc_offset); 286 const auto new_nca = std::make_shared<NCA>(update, romfs, ivfc_offset);
236 if (new_nca->GetStatus() == Loader::ResultStatus::Success && 287 if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
237 new_nca->GetRomFS() != nullptr) { 288 new_nca->GetRomFS() != nullptr) {
238 LOG_INFO(Loader, " RomFS: Update ({}) applied successfully", 289 LOG_INFO(Loader, " RomFS: Update ({}) applied successfully",
239 FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0))); 290 FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
240 romfs = new_nca->GetRomFS(); 291 romfs = new_nca->GetRomFS();
241 } 292 }
242 } else if (update_raw != nullptr) { 293 } else if (update_raw != nullptr) {
@@ -278,8 +329,8 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
278 if (nacp != nullptr) { 329 if (nacp != nullptr) {
279 out.insert_or_assign("Update", nacp->GetVersionString()); 330 out.insert_or_assign("Update", nacp->GetVersionString());
280 } else { 331 } else {
281 if (installed->HasEntry(update_tid, ContentRecordType::Program)) { 332 if (installed.HasEntry(update_tid, ContentRecordType::Program)) {
282 const auto meta_ver = installed->GetEntryVersion(update_tid); 333 const auto meta_ver = installed.GetEntryVersion(update_tid);
283 if (meta_ver.value_or(0) == 0) { 334 if (meta_ver.value_or(0) == 0) {
284 out.insert_or_assign("Update", ""); 335 out.insert_or_assign("Update", "");
285 } else { 336 } else {
@@ -301,18 +352,25 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
301 if (IsDirValidAndNonEmpty(exefs_dir)) { 352 if (IsDirValidAndNonEmpty(exefs_dir)) {
302 bool ips = false; 353 bool ips = false;
303 bool ipswitch = false; 354 bool ipswitch = false;
355 bool layeredfs = false;
304 356
305 for (const auto& file : exefs_dir->GetFiles()) { 357 for (const auto& file : exefs_dir->GetFiles()) {
306 if (file->GetExtension() == "ips") 358 if (file->GetExtension() == "ips") {
307 ips = true; 359 ips = true;
308 else if (file->GetExtension() == "pchtxt") 360 } else if (file->GetExtension() == "pchtxt") {
309 ipswitch = true; 361 ipswitch = true;
362 } else if (std::find(EXEFS_FILE_NAMES.begin(), EXEFS_FILE_NAMES.end(),
363 file->GetName()) != EXEFS_FILE_NAMES.end()) {
364 layeredfs = true;
365 }
310 } 366 }
311 367
312 if (ips) 368 if (ips)
313 AppendCommaIfNotEmpty(types, "IPS"); 369 AppendCommaIfNotEmpty(types, "IPS");
314 if (ipswitch) 370 if (ipswitch)
315 AppendCommaIfNotEmpty(types, "IPSwitch"); 371 AppendCommaIfNotEmpty(types, "IPSwitch");
372 if (layeredfs)
373 AppendCommaIfNotEmpty(types, "LayeredExeFS");
316 } 374 }
317 if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs"))) 375 if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs")))
318 AppendCommaIfNotEmpty(types, "LayeredFS"); 376 AppendCommaIfNotEmpty(types, "LayeredFS");
@@ -325,14 +383,13 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
325 } 383 }
326 384
327 // DLC 385 // DLC
328 const auto dlc_entries = installed->ListEntriesFilter(TitleType::AOC, ContentRecordType::Data); 386 const auto dlc_entries = installed.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
329 std::vector<RegisteredCacheEntry> dlc_match; 387 std::vector<RegisteredCacheEntry> dlc_match;
330 dlc_match.reserve(dlc_entries.size()); 388 dlc_match.reserve(dlc_entries.size());
331 std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match), 389 std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match),
332 [this, &installed](const RegisteredCacheEntry& entry) { 390 [this, &installed](const RegisteredCacheEntry& entry) {
333 return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id && 391 return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id &&
334 installed->GetEntry(entry)->GetStatus() == 392 installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success;
335 Loader::ResultStatus::Success;
336 }); 393 });
337 if (!dlc_match.empty()) { 394 if (!dlc_match.empty()) {
338 // Ensure sorted so DLC IDs show in order. 395 // Ensure sorted so DLC IDs show in order.
@@ -353,7 +410,7 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
353std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const { 410std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const {
354 const auto installed{Service::FileSystem::GetUnionContents()}; 411 const auto installed{Service::FileSystem::GetUnionContents()};
355 412
356 const auto base_control_nca = installed->GetEntry(title_id, ContentRecordType::Control); 413 const auto base_control_nca = installed.GetEntry(title_id, ContentRecordType::Control);
357 if (base_control_nca == nullptr) 414 if (base_control_nca == nullptr)
358 return {}; 415 return {};
359 416
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 96302a241..128199063 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -106,40 +106,42 @@ static ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
106 106
107VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir, 107VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
108 std::string_view path) const { 108 std::string_view path) const {
109 if (dir->GetFileRelative(path) != nullptr) 109 const auto file = dir->GetFileRelative(path);
110 return dir->GetFileRelative(path); 110 if (file != nullptr) {
111 if (dir->GetDirectoryRelative(path) != nullptr) { 111 return file;
112 const auto nca_dir = dir->GetDirectoryRelative(path); 112 }
113 VirtualFile file = nullptr;
114
115 const auto files = nca_dir->GetFiles();
116 if (files.size() == 1 && files[0]->GetName() == "00") {
117 file = files[0];
118 } else {
119 std::vector<VirtualFile> concat;
120 // Since the files are a two-digit hex number, max is FF.
121 for (std::size_t i = 0; i < 0x100; ++i) {
122 auto next = nca_dir->GetFile(fmt::format("{:02X}", i));
123 if (next != nullptr) {
124 concat.push_back(std::move(next));
125 } else {
126 next = nca_dir->GetFile(fmt::format("{:02x}", i));
127 if (next != nullptr)
128 concat.push_back(std::move(next));
129 else
130 break;
131 }
132 }
133 113
134 if (concat.empty()) 114 const auto nca_dir = dir->GetDirectoryRelative(path);
135 return nullptr; 115 if (nca_dir == nullptr) {
116 return nullptr;
117 }
118
119 const auto files = nca_dir->GetFiles();
120 if (files.size() == 1 && files[0]->GetName() == "00") {
121 return files[0];
122 }
136 123
137 file = ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName()); 124 std::vector<VirtualFile> concat;
125 // Since the files are a two-digit hex number, max is FF.
126 for (std::size_t i = 0; i < 0x100; ++i) {
127 auto next = nca_dir->GetFile(fmt::format("{:02X}", i));
128 if (next != nullptr) {
129 concat.push_back(std::move(next));
130 } else {
131 next = nca_dir->GetFile(fmt::format("{:02x}", i));
132 if (next != nullptr) {
133 concat.push_back(std::move(next));
134 } else {
135 break;
136 }
138 } 137 }
138 }
139 139
140 return file; 140 if (concat.empty()) {
141 return nullptr;
141 } 142 }
142 return nullptr; 143
144 return ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName());
143} 145}
144 146
145VirtualFile RegisteredCache::GetFileAtID(NcaID id) const { 147VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
@@ -225,7 +227,7 @@ void RegisteredCache::ProcessFiles(const std::vector<NcaID>& ids) {
225 227
226 if (file == nullptr) 228 if (file == nullptr)
227 continue; 229 continue;
228 const auto nca = std::make_shared<NCA>(parser(file, id)); 230 const auto nca = std::make_shared<NCA>(parser(file, id), nullptr, 0, keys);
229 if (nca->GetStatus() != Loader::ResultStatus::Success || 231 if (nca->GetStatus() != Loader::ResultStatus::Success ||
230 nca->GetType() != NCAContentType::Meta) { 232 nca->GetType() != NCAContentType::Meta) {
231 continue; 233 continue;
@@ -315,7 +317,7 @@ std::unique_ptr<NCA> RegisteredCache::GetEntry(u64 title_id, ContentRecordType t
315 const auto raw = GetEntryRaw(title_id, type); 317 const auto raw = GetEntryRaw(title_id, type);
316 if (raw == nullptr) 318 if (raw == nullptr)
317 return nullptr; 319 return nullptr;
318 return std::make_unique<NCA>(raw); 320 return std::make_unique<NCA>(raw, nullptr, 0, keys);
319} 321}
320 322
321std::unique_ptr<NCA> RegisteredCache::GetEntry(RegisteredCacheEntry entry) const { 323std::unique_ptr<NCA> RegisteredCache::GetEntry(RegisteredCacheEntry entry) const {
@@ -378,22 +380,22 @@ std::vector<RegisteredCacheEntry> RegisteredCache::ListEntriesFilter(
378 return out; 380 return out;
379} 381}
380 382
381static std::shared_ptr<NCA> GetNCAFromNSPForID(std::shared_ptr<NSP> nsp, const NcaID& id) { 383static std::shared_ptr<NCA> GetNCAFromNSPForID(const NSP& nsp, const NcaID& id) {
382 const auto file = nsp->GetFile(fmt::format("{}.nca", Common::HexArrayToString(id, false))); 384 const auto file = nsp.GetFile(fmt::format("{}.nca", Common::HexArrayToString(id, false)));
383 if (file == nullptr) 385 if (file == nullptr)
384 return nullptr; 386 return nullptr;
385 return std::make_shared<NCA>(file); 387 return std::make_shared<NCA>(file);
386} 388}
387 389
388InstallResult RegisteredCache::InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists, 390InstallResult RegisteredCache::InstallEntry(const XCI& xci, bool overwrite_if_exists,
389 const VfsCopyFunction& copy) { 391 const VfsCopyFunction& copy) {
390 return InstallEntry(xci->GetSecurePartitionNSP(), overwrite_if_exists, copy); 392 return InstallEntry(*xci.GetSecurePartitionNSP(), overwrite_if_exists, copy);
391} 393}
392 394
393InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overwrite_if_exists, 395InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists,
394 const VfsCopyFunction& copy) { 396 const VfsCopyFunction& copy) {
395 const auto& ncas = nsp->GetNCAsCollapsed(); 397 const auto ncas = nsp.GetNCAsCollapsed();
396 const auto& meta_iter = std::find_if(ncas.begin(), ncas.end(), [](std::shared_ptr<NCA> nca) { 398 const auto meta_iter = std::find_if(ncas.begin(), ncas.end(), [](const auto& nca) {
397 return nca->GetType() == NCAContentType::Meta; 399 return nca->GetType() == NCAContentType::Meta;
398 }); 400 });
399 401
@@ -407,7 +409,7 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overw
407 const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32); 409 const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32);
408 const auto meta_id = Common::HexStringToArray<16>(meta_id_raw); 410 const auto meta_id = Common::HexStringToArray<16>(meta_id_raw);
409 411
410 const auto res = RawInstallNCA(*meta_iter, copy, overwrite_if_exists, meta_id); 412 const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id);
411 if (res != InstallResult::Success) 413 if (res != InstallResult::Success)
412 return res; 414 return res;
413 415
@@ -419,7 +421,7 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overw
419 const auto nca = GetNCAFromNSPForID(nsp, record.nca_id); 421 const auto nca = GetNCAFromNSPForID(nsp, record.nca_id);
420 if (nca == nullptr) 422 if (nca == nullptr)
421 return InstallResult::ErrorCopyFailed; 423 return InstallResult::ErrorCopyFailed;
422 const auto res2 = RawInstallNCA(nca, copy, overwrite_if_exists, record.nca_id); 424 const auto res2 = RawInstallNCA(*nca, copy, overwrite_if_exists, record.nca_id);
423 if (res2 != InstallResult::Success) 425 if (res2 != InstallResult::Success)
424 return res2; 426 return res2;
425 } 427 }
@@ -428,21 +430,21 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overw
428 return InstallResult::Success; 430 return InstallResult::Success;
429} 431}
430 432
431InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType type, 433InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
432 bool overwrite_if_exists, const VfsCopyFunction& copy) { 434 bool overwrite_if_exists, const VfsCopyFunction& copy) {
433 CNMTHeader header{ 435 CNMTHeader header{
434 nca->GetTitleId(), ///< Title ID 436 nca.GetTitleId(), ///< Title ID
435 0, ///< Ignore/Default title version 437 0, ///< Ignore/Default title version
436 type, ///< Type 438 type, ///< Type
437 {}, ///< Padding 439 {}, ///< Padding
438 0x10, ///< Default table offset 440 0x10, ///< Default table offset
439 1, ///< 1 Content Entry 441 1, ///< 1 Content Entry
440 0, ///< No Meta Entries 442 0, ///< No Meta Entries
441 {}, ///< Padding 443 {}, ///< Padding
442 }; 444 };
443 OptionalHeader opt_header{0, 0}; 445 OptionalHeader opt_header{0, 0};
444 ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca->GetType()), {}}; 446 ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca.GetType()), {}};
445 const auto& data = nca->GetBaseFile()->ReadBytes(0x100000); 447 const auto& data = nca.GetBaseFile()->ReadBytes(0x100000);
446 mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0); 448 mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0);
447 memcpy(&c_rec.nca_id, &c_rec.hash, 16); 449 memcpy(&c_rec.nca_id, &c_rec.hash, 16);
448 const CNMT new_cnmt(header, opt_header, {c_rec}, {}); 450 const CNMT new_cnmt(header, opt_header, {c_rec}, {});
@@ -451,10 +453,10 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType
451 return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id); 453 return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id);
452} 454}
453 455
454InstallResult RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, 456InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy,
455 bool overwrite_if_exists, 457 bool overwrite_if_exists,
456 std::optional<NcaID> override_id) { 458 std::optional<NcaID> override_id) {
457 const auto in = nca->GetBaseFile(); 459 const auto in = nca.GetBaseFile();
458 Core::Crypto::SHA256Hash hash{}; 460 Core::Crypto::SHA256Hash hash{};
459 461
460 // Calculate NcaID 462 // Calculate NcaID
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index 6cfb16017..3b77af4e0 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -6,12 +6,12 @@
6 6
7#include <array> 7#include <array>
8#include <functional> 8#include <functional>
9#include <map>
10#include <memory> 9#include <memory>
11#include <string> 10#include <string>
12#include <vector> 11#include <vector>
13#include <boost/container/flat_map.hpp> 12#include <boost/container/flat_map.hpp>
14#include "common/common_types.h" 13#include "common/common_types.h"
14#include "core/crypto/key_manager.h"
15#include "core/file_sys/vfs.h" 15#include "core/file_sys/vfs.h"
16 16
17namespace FileSys { 17namespace FileSys {
@@ -103,17 +103,16 @@ public:
103 103
104 // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure 104 // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure
105 // there is a meta NCA and all of them are accessible. 105 // there is a meta NCA and all of them are accessible.
106 InstallResult InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists = false, 106 InstallResult InstallEntry(const XCI& xci, bool overwrite_if_exists = false,
107 const VfsCopyFunction& copy = &VfsRawCopy); 107 const VfsCopyFunction& copy = &VfsRawCopy);
108 InstallResult InstallEntry(std::shared_ptr<NSP> nsp, bool overwrite_if_exists = false, 108 InstallResult InstallEntry(const NSP& nsp, bool overwrite_if_exists = false,
109 const VfsCopyFunction& copy = &VfsRawCopy); 109 const VfsCopyFunction& copy = &VfsRawCopy);
110 110
111 // Due to the fact that we must use Meta-type NCAs to determine the existance of files, this 111 // Due to the fact that we must use Meta-type NCAs to determine the existance of files, this
112 // poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a 112 // poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a
113 // dir inside the NAND called 'yuzu_meta' and store the raw CNMT there. 113 // dir inside the NAND called 'yuzu_meta' and store the raw CNMT there.
114 // TODO(DarkLordZach): Author real meta-type NCAs and install those. 114 // TODO(DarkLordZach): Author real meta-type NCAs and install those.
115 InstallResult InstallEntry(std::shared_ptr<NCA> nca, TitleType type, 115 InstallResult InstallEntry(const NCA& nca, TitleType type, bool overwrite_if_exists = false,
116 bool overwrite_if_exists = false,
117 const VfsCopyFunction& copy = &VfsRawCopy); 116 const VfsCopyFunction& copy = &VfsRawCopy);
118 117
119private: 118private:
@@ -127,12 +126,14 @@ private:
127 std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const; 126 std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const;
128 VirtualFile GetFileAtID(NcaID id) const; 127 VirtualFile GetFileAtID(NcaID id) const;
129 VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const; 128 VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const;
130 InstallResult RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, 129 InstallResult RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy,
131 bool overwrite_if_exists, std::optional<NcaID> override_id = {}); 130 bool overwrite_if_exists, std::optional<NcaID> override_id = {});
132 bool RawInstallYuzuMeta(const CNMT& cnmt); 131 bool RawInstallYuzuMeta(const CNMT& cnmt);
133 132
134 VirtualDir dir; 133 VirtualDir dir;
135 RegisteredCacheParsingFunction parser; 134 RegisteredCacheParsingFunction parser;
135 Core::Crypto::KeyManager keys;
136
136 // maps tid -> NcaID of meta 137 // maps tid -> NcaID of meta
137 boost::container::flat_map<u64, NcaID> meta_id; 138 boost::container::flat_map<u64, NcaID> meta_id;
138 // maps tid -> meta 139 // maps tid -> meta
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index 0b645b106..6ad1e4f86 100644
--- a/src/core/file_sys/romfs_factory.cpp
+++ b/src/core/file_sys/romfs_factory.cpp
@@ -48,7 +48,7 @@ ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, Conte
48 48
49 switch (storage) { 49 switch (storage) {
50 case StorageId::None: 50 case StorageId::None:
51 res = Service::FileSystem::GetUnionContents()->GetEntry(title_id, type); 51 res = Service::FileSystem::GetUnionContents().GetEntry(title_id, type);
52 break; 52 break;
53 case StorageId::NandSystem: 53 case StorageId::NandSystem:
54 res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type); 54 res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type);
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index ef1aaebbb..5434f2149 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -83,28 +83,32 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescr
83 return MakeResult<VirtualDir>(std::move(out)); 83 return MakeResult<VirtualDir>(std::move(out));
84} 84}
85 85
86std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, 86VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) const {
87 u128 user_id, u64 save_id) { 87 return dir->GetDirectoryRelative(GetSaveDataSpaceIdPath(space));
88 // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should 88}
89 // be interpreted as the title id of the current process.
90 if (type == SaveDataType::SaveData && title_id == 0)
91 title_id = Core::CurrentProcess()->GetTitleID();
92
93 std::string out;
94 89
90std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
95 switch (space) { 91 switch (space) {
96 case SaveDataSpaceId::NandSystem: 92 case SaveDataSpaceId::NandSystem:
97 out = "/system/"; 93 return "/system/";
98 break;
99 case SaveDataSpaceId::NandUser: 94 case SaveDataSpaceId::NandUser:
100 out = "/user/"; 95 return "/user/";
101 break;
102 case SaveDataSpaceId::TemporaryStorage: 96 case SaveDataSpaceId::TemporaryStorage:
103 out = "/temp/"; 97 return "/temp/";
104 break;
105 default: 98 default:
106 ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space)); 99 ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
100 return "/unrecognized/"; ///< To prevent corruption when ignoring asserts.
107 } 101 }
102}
103
104std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
105 u128 user_id, u64 save_id) {
106 // According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
107 // be interpreted as the title id of the current process.
108 if (type == SaveDataType::SaveData && title_id == 0)
109 title_id = Core::CurrentProcess()->GetTitleID();
110
111 std::string out = GetSaveDataSpaceIdPath(space);
108 112
109 switch (type) { 113 switch (type) {
110 case SaveDataType::SystemSaveData: 114 case SaveDataType::SystemSaveData:
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index d69ef6741..2a0088040 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -52,6 +52,9 @@ public:
52 52
53 ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta); 53 ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta);
54 54
55 VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
56
57 static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space);
55 static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id, 58 static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
56 u128 user_id, u64 save_id); 59 u128 user_id, u64 save_id);
57 60
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp
index 2aaba4179..e1a4210db 100644
--- a/src/core/file_sys/submission_package.cpp
+++ b/src/core/file_sys/submission_package.cpp
@@ -252,7 +252,7 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
252 continue; 252 continue;
253 } 253 }
254 254
255 auto next_nca = std::make_shared<NCA>(next_file); 255 auto next_nca = std::make_shared<NCA>(next_file, nullptr, 0, keys);
256 if (next_nca->GetType() == NCAContentType::Program) 256 if (next_nca->GetType() == NCAContentType::Program)
257 program_status[cnmt.GetTitleID()] = next_nca->GetStatus(); 257 program_status[cnmt.GetTitleID()] = next_nca->GetStatus();
258 if (next_nca->GetStatus() == Loader::ResultStatus::Success || 258 if (next_nca->GetStatus() == Loader::ResultStatus::Success ||
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h
index 338080b7e..9a28ed5bb 100644
--- a/src/core/file_sys/submission_package.h
+++ b/src/core/file_sys/submission_package.h
@@ -70,6 +70,8 @@ private:
70 std::map<u64, std::map<ContentRecordType, std::shared_ptr<NCA>>> ncas; 70 std::map<u64, std::map<ContentRecordType, std::shared_ptr<NCA>>> ncas;
71 std::vector<VirtualFile> ticket_files; 71 std::vector<VirtualFile> ticket_files;
72 72
73 Core::Crypto::KeyManager keys;
74
73 VirtualFile romfs; 75 VirtualFile romfs;
74 VirtualDir exefs; 76 VirtualDir exefs;
75}; 77};
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index 7b584de7f..e33327ef0 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -384,6 +384,28 @@ bool VfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
384 return success; 384 return success;
385} 385}
386 386
387bool VfsDirectory::CleanSubdirectoryRecursive(std::string_view name) {
388 auto dir = GetSubdirectory(name);
389 if (dir == nullptr) {
390 return false;
391 }
392
393 bool success = true;
394 for (const auto& file : dir->GetFiles()) {
395 if (!dir->DeleteFile(file->GetName())) {
396 success = false;
397 }
398 }
399
400 for (const auto& sdir : dir->GetSubdirectories()) {
401 if (!dir->DeleteSubdirectoryRecursive(sdir->GetName())) {
402 success = false;
403 }
404 }
405
406 return success;
407}
408
387bool VfsDirectory::Copy(std::string_view src, std::string_view dest) { 409bool VfsDirectory::Copy(std::string_view src, std::string_view dest) {
388 const auto f1 = GetFile(src); 410 const auto f1 = GetFile(src);
389 auto f2 = CreateFile(dest); 411 auto f2 = CreateFile(dest);
@@ -431,10 +453,34 @@ std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFile(std::string_view name)
431 return nullptr; 453 return nullptr;
432} 454}
433 455
456std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileAbsolute(std::string_view path) {
457 return nullptr;
458}
459
460std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileRelative(std::string_view path) {
461 return nullptr;
462}
463
464std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryAbsolute(std::string_view path) {
465 return nullptr;
466}
467
468std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryRelative(std::string_view path) {
469 return nullptr;
470}
471
434bool ReadOnlyVfsDirectory::DeleteSubdirectory(std::string_view name) { 472bool ReadOnlyVfsDirectory::DeleteSubdirectory(std::string_view name) {
435 return false; 473 return false;
436} 474}
437 475
476bool ReadOnlyVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
477 return false;
478}
479
480bool ReadOnlyVfsDirectory::CleanSubdirectoryRecursive(std::string_view name) {
481 return false;
482}
483
438bool ReadOnlyVfsDirectory::DeleteFile(std::string_view name) { 484bool ReadOnlyVfsDirectory::DeleteFile(std::string_view name) {
439 return false; 485 return false;
440} 486}
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h
index 002f99d4e..e5641b255 100644
--- a/src/core/file_sys/vfs.h
+++ b/src/core/file_sys/vfs.h
@@ -245,12 +245,18 @@ public:
245 // any failure. 245 // any failure.
246 virtual std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path); 246 virtual std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path);
247 247
248 // Deletes the subdirectory with name and returns true on success. 248 // Deletes the subdirectory with the given name and returns true on success.
249 virtual bool DeleteSubdirectory(std::string_view name) = 0; 249 virtual bool DeleteSubdirectory(std::string_view name) = 0;
250 // Deletes all subdirectories and files of subdirectory with name recirsively and then deletes 250
251 // the subdirectory. Returns true on success. 251 // Deletes all subdirectories and files within the provided directory and then deletes
252 // the directory itself. Returns true on success.
252 virtual bool DeleteSubdirectoryRecursive(std::string_view name); 253 virtual bool DeleteSubdirectoryRecursive(std::string_view name);
253 // Returnes whether or not the file with name name was deleted successfully. 254
255 // Deletes all subdirectories and files within the provided directory.
256 // Unlike DeleteSubdirectoryRecursive, this does not delete the provided directory.
257 virtual bool CleanSubdirectoryRecursive(std::string_view name);
258
259 // Returns whether or not the file with name name was deleted successfully.
254 virtual bool DeleteFile(std::string_view name) = 0; 260 virtual bool DeleteFile(std::string_view name) = 0;
255 261
256 // Returns whether or not this directory was renamed to name. 262 // Returns whether or not this directory was renamed to name.
@@ -276,7 +282,13 @@ public:
276 bool IsReadable() const override; 282 bool IsReadable() const override;
277 std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override; 283 std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override;
278 std::shared_ptr<VfsFile> CreateFile(std::string_view name) override; 284 std::shared_ptr<VfsFile> CreateFile(std::string_view name) override;
285 std::shared_ptr<VfsFile> CreateFileAbsolute(std::string_view path) override;
286 std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path) override;
287 std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path) override;
288 std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path) override;
279 bool DeleteSubdirectory(std::string_view name) override; 289 bool DeleteSubdirectory(std::string_view name) override;
290 bool DeleteSubdirectoryRecursive(std::string_view name) override;
291 bool CleanSubdirectoryRecursive(std::string_view name) override;
280 bool DeleteFile(std::string_view name) override; 292 bool DeleteFile(std::string_view name) override;
281 bool Rename(std::string_view name) override; 293 bool Rename(std::string_view name) override;
282}; 294};
diff --git a/src/core/frontend/applets/software_keyboard.cpp b/src/core/frontend/applets/software_keyboard.cpp
new file mode 100644
index 000000000..856ed33da
--- /dev/null
+++ b/src/core/frontend/applets/software_keyboard.cpp
@@ -0,0 +1,29 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/logging/backend.h"
6#include "common/string_util.h"
7#include "core/frontend/applets/software_keyboard.h"
8
9namespace Core::Frontend {
10SoftwareKeyboardApplet::~SoftwareKeyboardApplet() = default;
11
12void DefaultSoftwareKeyboardApplet::RequestText(
13 std::function<void(std::optional<std::u16string>)> out,
14 SoftwareKeyboardParameters parameters) const {
15 if (parameters.initial_text.empty())
16 out(u"yuzu");
17
18 out(parameters.initial_text);
19}
20
21void DefaultSoftwareKeyboardApplet::SendTextCheckDialog(
22 std::u16string error_message, std::function<void()> finished_check) const {
23 LOG_WARNING(Service_AM,
24 "(STUBBED) called - Default fallback software keyboard does not support text "
25 "check! (error_message={})",
26 Common::UTF16ToUTF8(error_message));
27 finished_check();
28}
29} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/software_keyboard.h b/src/core/frontend/applets/software_keyboard.h
new file mode 100644
index 000000000..f9b202664
--- /dev/null
+++ b/src/core/frontend/applets/software_keyboard.h
@@ -0,0 +1,54 @@
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 <functional>
8#include <optional>
9#include <string>
10#include "common/bit_field.h"
11#include "common/common_types.h"
12
13namespace Core::Frontend {
14struct SoftwareKeyboardParameters {
15 std::u16string submit_text;
16 std::u16string header_text;
17 std::u16string sub_text;
18 std::u16string guide_text;
19 std::u16string initial_text;
20 std::size_t max_length;
21 bool password;
22 bool cursor_at_beginning;
23
24 union {
25 u8 value;
26
27 BitField<1, 1, u8> disable_space;
28 BitField<2, 1, u8> disable_address;
29 BitField<3, 1, u8> disable_percent;
30 BitField<4, 1, u8> disable_slash;
31 BitField<6, 1, u8> disable_number;
32 BitField<7, 1, u8> disable_download_code;
33 };
34};
35
36class SoftwareKeyboardApplet {
37public:
38 virtual ~SoftwareKeyboardApplet();
39
40 virtual void RequestText(std::function<void(std::optional<std::u16string>)> out,
41 SoftwareKeyboardParameters parameters) const = 0;
42 virtual void SendTextCheckDialog(std::u16string error_message,
43 std::function<void()> finished_check) const = 0;
44};
45
46class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet {
47public:
48 void RequestText(std::function<void(std::optional<std::u16string>)> out,
49 SoftwareKeyboardParameters parameters) const override;
50 void SendTextCheckDialog(std::u16string error_message,
51 std::function<void()> finished_check) const override;
52};
53
54} // namespace Core::Frontend
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h
index 39bdf4e21..16fdcd376 100644
--- a/src/core/frontend/input.h
+++ b/src/core/frontend/input.h
@@ -132,4 +132,11 @@ using MotionDevice = InputDevice<std::tuple<Math::Vec3<float>, Math::Vec3<float>
132 */ 132 */
133using TouchDevice = InputDevice<std::tuple<float, float, bool>>; 133using TouchDevice = InputDevice<std::tuple<float, float, bool>>;
134 134
135/**
136 * A mouse device is an input device that returns a tuple of two floats and four ints.
137 * The first two floats are X and Y device coordinates of the mouse (from 0-1).
138 * The s32s are the mouse wheel.
139 */
140using MouseDevice = InputDevice<std::tuple<float, float, s32, s32>>;
141
135} // namespace Input 142} // namespace Input
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index bdcc889e0..e6b5171ee 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -71,10 +71,6 @@ constexpr u32 PSTATE_REGISTER = 33;
71constexpr u32 UC_ARM64_REG_Q0 = 34; 71constexpr u32 UC_ARM64_REG_Q0 = 34;
72constexpr u32 FPCR_REGISTER = 66; 72constexpr u32 FPCR_REGISTER = 66;
73 73
74// TODO/WiP - Used while working on support for FPU
75constexpr u32 TODO_DUMMY_REG_997 = 997;
76constexpr u32 TODO_DUMMY_REG_998 = 998;
77
78// For sample XML files see the GDB source /gdb/features 74// For sample XML files see the GDB source /gdb/features
79// GDB also wants the l character at the start 75// GDB also wants the l character at the start
80// This XML defines what the registers are for this specific ARM device 76// This XML defines what the registers are for this specific ARM device
@@ -260,6 +256,36 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr)
260 } 256 }
261} 257}
262 258
259static u128 FpuRead(std::size_t id, Kernel::Thread* thread = nullptr) {
260 if (!thread) {
261 return u128{0};
262 }
263
264 auto& thread_context = thread->GetContext();
265
266 if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
267 return thread_context.vector_registers[id - UC_ARM64_REG_Q0];
268 } else if (id == FPCR_REGISTER) {
269 return u128{thread_context.fpcr, 0};
270 } else {
271 return u128{0};
272 }
273}
274
275static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr) {
276 if (!thread) {
277 return;
278 }
279
280 auto& thread_context = thread->GetContext();
281
282 if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
283 thread_context.vector_registers[id - UC_ARM64_REG_Q0] = val;
284 } else if (id == FPCR_REGISTER) {
285 thread_context.fpcr = static_cast<u32>(val[0]);
286 }
287}
288
263/** 289/**
264 * Turns hex string character into the equivalent byte. 290 * Turns hex string character into the equivalent byte.
265 * 291 *
@@ -409,6 +435,27 @@ static u64 GdbHexToLong(const u8* src) {
409 return output; 435 return output;
410} 436}
411 437
438/**
439 * Convert a gdb-formatted hex string into a u128.
440 *
441 * @param src Pointer to hex string.
442 */
443static u128 GdbHexToU128(const u8* src) {
444 u128 output;
445
446 for (int i = 0; i < 16; i += 2) {
447 output[0] = (output[0] << 4) | HexCharToValue(src[15 - i - 1]);
448 output[0] = (output[0] << 4) | HexCharToValue(src[15 - i]);
449 }
450
451 for (int i = 0; i < 16; i += 2) {
452 output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i - 1]);
453 output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i]);
454 }
455
456 return output;
457}
458
412/// Read a byte from the gdb client. 459/// Read a byte from the gdb client.
413static u8 ReadByte() { 460static u8 ReadByte() {
414 u8 c; 461 u8 c;
@@ -599,8 +646,7 @@ static void HandleQuery() {
599 for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { 646 for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) {
600 const auto& threads = Core::System::GetInstance().Scheduler(core).GetThreadList(); 647 const auto& threads = Core::System::GetInstance().Scheduler(core).GetThreadList();
601 for (const auto& thread : threads) { 648 for (const auto& thread : threads) {
602 val += fmt::format("{:x}", thread->GetThreadID()); 649 val += fmt::format("{:x},", thread->GetThreadID());
603 val += ",";
604 } 650 }
605 } 651 }
606 val.pop_back(); 652 val.pop_back();
@@ -791,11 +837,15 @@ static void ReadRegister() {
791 } else if (id == PSTATE_REGISTER) { 837 } else if (id == PSTATE_REGISTER) {
792 IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread))); 838 IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread)));
793 } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { 839 } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
794 LongToGdbHex(reply, RegRead(id, current_thread)); 840 u128 r = FpuRead(id, current_thread);
841 LongToGdbHex(reply, r[0]);
842 LongToGdbHex(reply + 16, r[1]);
795 } else if (id == FPCR_REGISTER) { 843 } else if (id == FPCR_REGISTER) {
796 LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread)); 844 u128 r = FpuRead(id, current_thread);
797 } else { 845 IntToGdbHex(reply, static_cast<u32>(r[0]));
798 LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread)); 846 } else if (id == FPCR_REGISTER + 1) {
847 u128 r = FpuRead(id, current_thread);
848 IntToGdbHex(reply, static_cast<u32>(r[0] >> 32));
799 } 849 }
800 850
801 SendReply(reinterpret_cast<char*>(reply)); 851 SendReply(reinterpret_cast<char*>(reply));
@@ -822,13 +872,18 @@ static void ReadRegisters() {
822 872
823 bufptr += 8; 873 bufptr += 8;
824 874
825 for (u32 reg = UC_ARM64_REG_Q0; reg <= UC_ARM64_REG_Q0 + 31; reg++) { 875 u128 r;
826 LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); 876
877 for (u32 reg = UC_ARM64_REG_Q0; reg < FPCR_REGISTER; reg++) {
878 r = FpuRead(reg, current_thread);
879 LongToGdbHex(bufptr + reg * 32, r[0]);
880 LongToGdbHex(bufptr + reg * 32 + 16, r[1]);
827 } 881 }
828 882
829 bufptr += 32 * 32; 883 bufptr += 32 * 32;
830 884
831 LongToGdbHex(bufptr, RegRead(TODO_DUMMY_REG_998, current_thread)); 885 r = FpuRead(FPCR_REGISTER, current_thread);
886 IntToGdbHex(bufptr, static_cast<u32>(r[0]));
832 887
833 bufptr += 8; 888 bufptr += 8;
834 889
@@ -853,14 +908,12 @@ static void WriteRegister() {
853 } else if (id == PSTATE_REGISTER) { 908 } else if (id == PSTATE_REGISTER) {
854 RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); 909 RegWrite(id, GdbHexToInt(buffer_ptr), current_thread);
855 } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { 910 } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) {
856 RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); 911 FpuWrite(id, GdbHexToU128(buffer_ptr), current_thread);
857 } else if (id == FPCR_REGISTER) { 912 } else if (id == FPCR_REGISTER) {
858 RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread); 913 } else if (id == FPCR_REGISTER + 1) {
859 } else {
860 RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread);
861 } 914 }
862 915
863 // Update Unicorn context skipping scheduler, no running threads at this point 916 // Update ARM context, skipping scheduler - no running threads at this point
864 Core::System::GetInstance() 917 Core::System::GetInstance()
865 .ArmInterface(current_core) 918 .ArmInterface(current_core)
866 .LoadContext(current_thread->GetContext()); 919 .LoadContext(current_thread->GetContext());
@@ -885,13 +938,13 @@ static void WriteRegisters() {
885 } else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) { 938 } else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) {
886 RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); 939 RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread);
887 } else if (reg == FPCR_REGISTER) { 940 } else if (reg == FPCR_REGISTER) {
888 RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread); 941 RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
889 } else { 942 } else if (reg == FPCR_REGISTER + 1) {
890 UNIMPLEMENTED(); 943 RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread);
891 } 944 }
892 } 945 }
893 946
894 // Update Unicorn context skipping scheduler, no running threads at this point 947 // Update ARM context, skipping scheduler - no running threads at this point
895 Core::System::GetInstance() 948 Core::System::GetInstance()
896 .ArmInterface(current_core) 949 .ArmInterface(current_core)
897 .LoadContext(current_thread->GetContext()); 950 .LoadContext(current_thread->GetContext());
@@ -917,12 +970,6 @@ static void ReadMemory() {
917 SendReply("E01"); 970 SendReply("E01");
918 } 971 }
919 972
920 const auto& vm_manager = Core::CurrentProcess()->VMManager();
921 if (addr < vm_manager.GetCodeRegionBaseAddress() ||
922 addr >= vm_manager.GetMapRegionEndAddress()) {
923 return SendReply("E00");
924 }
925
926 if (!Memory::IsValidVirtualAddress(addr)) { 973 if (!Memory::IsValidVirtualAddress(addr)) {
927 return SendReply("E00"); 974 return SendReply("E00");
928 } 975 }
@@ -967,7 +1014,7 @@ void Break(bool is_memory_break) {
967static void Step() { 1014static void Step() {
968 if (command_length > 1) { 1015 if (command_length > 1) {
969 RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread); 1016 RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread);
970 // Update Unicorn context skipping scheduler, no running threads at this point 1017 // Update ARM context, skipping scheduler - no running threads at this point
971 Core::System::GetInstance() 1018 Core::System::GetInstance()
972 .ArmInterface(current_core) 1019 .ArmInterface(current_core)
973 .LoadContext(current_thread->GetContext()); 1020 .LoadContext(current_thread->GetContext());
@@ -1010,7 +1057,7 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) {
1010 breakpoint.addr = addr; 1057 breakpoint.addr = addr;
1011 breakpoint.len = len; 1058 breakpoint.len = len;
1012 Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); 1059 Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size());
1013 static constexpr std::array<u8, 4> btrap{{0x00, 0x7d, 0x20, 0xd4}}; 1060 static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4};
1014 Memory::WriteBlock(addr, btrap.data(), btrap.size()); 1061 Memory::WriteBlock(addr, btrap.data(), btrap.size());
1015 Core::System::GetInstance().InvalidateCpuInstructionCaches(); 1062 Core::System::GetInstance().InvalidateCpuInstructionCaches();
1016 p.insert({addr, breakpoint}); 1063 p.insert({addr, breakpoint});
@@ -1321,13 +1368,15 @@ void SetCpuStepFlag(bool is_step) {
1321} 1368}
1322 1369
1323void SendTrap(Kernel::Thread* thread, int trap) { 1370void SendTrap(Kernel::Thread* thread, int trap) {
1324 if (send_trap) { 1371 if (!send_trap) {
1325 if (!halt_loop || current_thread == thread) { 1372 return;
1326 current_thread = thread;
1327 SendSignal(thread, trap);
1328 }
1329 halt_loop = true;
1330 send_trap = false;
1331 } 1373 }
1374
1375 if (!halt_loop || current_thread == thread) {
1376 current_thread = thread;
1377 SendSignal(thread, trap);
1378 }
1379 halt_loop = true;
1380 send_trap = false;
1332} 1381}
1333}; // namespace GDBStub 1382}; // namespace GDBStub
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h
index ee698c8a7..8b58d701d 100644
--- a/src/core/hle/kernel/errors.h
+++ b/src/core/hle/kernel/errors.h
@@ -8,58 +8,28 @@
8 8
9namespace Kernel { 9namespace Kernel {
10 10
11namespace ErrCodes { 11// Confirmed Switch kernel error codes
12enum {
13 // Confirmed Switch OS error codes
14 MaxConnectionsReached = 7,
15 InvalidSize = 101,
16 InvalidAddress = 102,
17 HandleTableFull = 105,
18 InvalidMemoryState = 106,
19 InvalidMemoryPermissions = 108,
20 InvalidMemoryRange = 110,
21 InvalidThreadPriority = 112,
22 InvalidProcessorId = 113,
23 InvalidHandle = 114,
24 InvalidPointer = 115,
25 InvalidCombination = 116,
26 Timeout = 117,
27 SynchronizationCanceled = 118,
28 TooLarge = 119,
29 InvalidEnumValue = 120,
30 NoSuchEntry = 121,
31 AlreadyRegistered = 122,
32 SessionClosed = 123,
33 InvalidState = 125,
34 ResourceLimitExceeded = 132,
35};
36}
37 12
38// WARNING: The kernel is quite inconsistent in it's usage of errors code. Make sure to always 13constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED{ErrorModule::Kernel, 7};
39// double check that the code matches before re-using the constant. 14constexpr ResultCode ERR_INVALID_SIZE{ErrorModule::Kernel, 101};
40 15constexpr ResultCode ERR_INVALID_ADDRESS{ErrorModule::Kernel, 102};
41constexpr ResultCode ERR_HANDLE_TABLE_FULL(ErrorModule::Kernel, ErrCodes::HandleTableFull); 16constexpr ResultCode ERR_HANDLE_TABLE_FULL{ErrorModule::Kernel, 105};
42constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE(ErrorModule::Kernel, ErrCodes::SessionClosed); 17constexpr ResultCode ERR_INVALID_ADDRESS_STATE{ErrorModule::Kernel, 106};
43constexpr ResultCode ERR_PORT_NAME_TOO_LONG(ErrorModule::Kernel, ErrCodes::TooLarge); 18constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS{ErrorModule::Kernel, 108};
44constexpr ResultCode ERR_MAX_CONNECTIONS_REACHED(ErrorModule::Kernel, 19constexpr ResultCode ERR_INVALID_MEMORY_RANGE{ErrorModule::Kernel, 110};
45 ErrCodes::MaxConnectionsReached); 20constexpr ResultCode ERR_INVALID_PROCESSOR_ID{ErrorModule::Kernel, 113};
46constexpr ResultCode ERR_INVALID_ENUM_VALUE(ErrorModule::Kernel, ErrCodes::InvalidEnumValue); 21constexpr ResultCode ERR_INVALID_THREAD_PRIORITY{ErrorModule::Kernel, 112};
47constexpr ResultCode ERR_INVALID_COMBINATION_KERNEL(ErrorModule::Kernel, 22constexpr ResultCode ERR_INVALID_HANDLE{ErrorModule::Kernel, 114};
48 ErrCodes::InvalidCombination); 23constexpr ResultCode ERR_INVALID_POINTER{ErrorModule::Kernel, 115};
49constexpr ResultCode ERR_INVALID_ADDRESS(ErrorModule::Kernel, ErrCodes::InvalidAddress); 24constexpr ResultCode ERR_INVALID_COMBINATION{ErrorModule::Kernel, 116};
50constexpr ResultCode ERR_INVALID_ADDRESS_STATE(ErrorModule::Kernel, ErrCodes::InvalidMemoryState); 25constexpr ResultCode RESULT_TIMEOUT{ErrorModule::Kernel, 117};
51constexpr ResultCode ERR_INVALID_MEMORY_PERMISSIONS(ErrorModule::Kernel, 26constexpr ResultCode ERR_SYNCHRONIZATION_CANCELED{ErrorModule::Kernel, 118};
52 ErrCodes::InvalidMemoryPermissions); 27constexpr ResultCode ERR_OUT_OF_RANGE{ErrorModule::Kernel, 119};
53constexpr ResultCode ERR_INVALID_MEMORY_RANGE(ErrorModule::Kernel, ErrCodes::InvalidMemoryRange); 28constexpr ResultCode ERR_INVALID_ENUM_VALUE{ErrorModule::Kernel, 120};
54constexpr ResultCode ERR_INVALID_HANDLE(ErrorModule::Kernel, ErrCodes::InvalidHandle); 29constexpr ResultCode ERR_NOT_FOUND{ErrorModule::Kernel, 121};
55constexpr ResultCode ERR_INVALID_PROCESSOR_ID(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); 30constexpr ResultCode ERR_ALREADY_REGISTERED{ErrorModule::Kernel, 122};
56constexpr ResultCode ERR_INVALID_SIZE(ErrorModule::Kernel, ErrCodes::InvalidSize); 31constexpr ResultCode ERR_SESSION_CLOSED_BY_REMOTE{ErrorModule::Kernel, 123};
57constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::Kernel, ErrCodes::AlreadyRegistered); 32constexpr ResultCode ERR_INVALID_STATE{ErrorModule::Kernel, 125};
58constexpr ResultCode ERR_INVALID_STATE(ErrorModule::Kernel, ErrCodes::InvalidState); 33constexpr ResultCode ERR_RESOURCE_LIMIT_EXCEEDED{ErrorModule::Kernel, 132};
59constexpr ResultCode ERR_INVALID_THREAD_PRIORITY(ErrorModule::Kernel,
60 ErrCodes::InvalidThreadPriority);
61constexpr ResultCode ERR_INVALID_POINTER(ErrorModule::Kernel, ErrCodes::InvalidPointer);
62constexpr ResultCode ERR_NOT_FOUND(ErrorModule::Kernel, ErrCodes::NoSuchEntry);
63constexpr ResultCode RESULT_TIMEOUT(ErrorModule::Kernel, ErrCodes::Timeout);
64 34
65} // namespace Kernel 35} // namespace Kernel
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp
index 5ee5c05e3..c8acde5b1 100644
--- a/src/core/hle/kernel/handle_table.cpp
+++ b/src/core/hle/kernel/handle_table.cpp
@@ -12,12 +12,23 @@
12#include "core/hle/kernel/thread.h" 12#include "core/hle/kernel/thread.h"
13 13
14namespace Kernel { 14namespace Kernel {
15namespace {
16constexpr u16 GetSlot(Handle handle) {
17 return handle >> 15;
18}
19
20constexpr u16 GetGeneration(Handle handle) {
21 return handle & 0x7FFF;
22}
23} // Anonymous namespace
15 24
16HandleTable::HandleTable() { 25HandleTable::HandleTable() {
17 next_generation = 1; 26 next_generation = 1;
18 Clear(); 27 Clear();
19} 28}
20 29
30HandleTable::~HandleTable() = default;
31
21ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { 32ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
22 DEBUG_ASSERT(obj != nullptr); 33 DEBUG_ASSERT(obj != nullptr);
23 34
@@ -31,9 +42,10 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
31 u16 generation = next_generation++; 42 u16 generation = next_generation++;
32 43
33 // Overflow count so it fits in the 15 bits dedicated to the generation in the handle. 44 // Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
34 // CTR-OS doesn't use generation 0, so skip straight to 1. 45 // Horizon OS uses zero to represent an invalid handle, so skip to 1.
35 if (next_generation >= (1 << 15)) 46 if (next_generation >= (1 << 15)) {
36 next_generation = 1; 47 next_generation = 1;
48 }
37 49
38 generations[slot] = generation; 50 generations[slot] = generation;
39 objects[slot] = std::move(obj); 51 objects[slot] = std::move(obj);
diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h
index 9e2f33e8a..6b7927fd8 100644
--- a/src/core/hle/kernel/handle_table.h
+++ b/src/core/hle/kernel/handle_table.h
@@ -13,6 +13,7 @@
13namespace Kernel { 13namespace Kernel {
14 14
15enum KernelHandle : Handle { 15enum KernelHandle : Handle {
16 InvalidHandle = 0,
16 CurrentThread = 0xFFFF8000, 17 CurrentThread = 0xFFFF8000,
17 CurrentProcess = 0xFFFF8001, 18 CurrentProcess = 0xFFFF8001,
18}; 19};
@@ -43,6 +44,7 @@ enum KernelHandle : Handle {
43class HandleTable final : NonCopyable { 44class HandleTable final : NonCopyable {
44public: 45public:
45 HandleTable(); 46 HandleTable();
47 ~HandleTable();
46 48
47 /** 49 /**
48 * Allocates a handle for the given object. 50 * Allocates a handle for the given object.
@@ -89,18 +91,8 @@ public:
89 void Clear(); 91 void Clear();
90 92
91private: 93private:
92 /** 94 /// This is the maximum limit of handles allowed per process in Horizon
93 * This is the maximum limit of handles allowed per process in CTR-OS. It can be further 95 static constexpr std::size_t MAX_COUNT = 1024;
94 * reduced by ExHeader values, but this is not emulated here.
95 */
96 static const std::size_t MAX_COUNT = 4096;
97
98 static u16 GetSlot(Handle handle) {
99 return handle >> 15;
100 }
101 static u16 GetGeneration(Handle handle) {
102 return handle & 0x7FFF;
103 }
104 96
105 /// Stores the Object referenced by the handle or null if the slot is empty. 97 /// Stores the Object referenced by the handle or null if the slot is empty.
106 std::array<SharedPtr<Object>, MAX_COUNT> objects; 98 std::array<SharedPtr<Object>, MAX_COUNT> objects;
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 68d5376cb..61ce7d7e4 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -15,13 +15,14 @@
15#include "common/logging/log.h" 15#include "common/logging/log.h"
16#include "core/core.h" 16#include "core/core.h"
17#include "core/hle/ipc_helpers.h" 17#include "core/hle/ipc_helpers.h"
18#include "core/hle/kernel/event.h"
19#include "core/hle/kernel/handle_table.h" 18#include "core/hle/kernel/handle_table.h"
20#include "core/hle/kernel/hle_ipc.h" 19#include "core/hle/kernel/hle_ipc.h"
21#include "core/hle/kernel/kernel.h" 20#include "core/hle/kernel/kernel.h"
22#include "core/hle/kernel/object.h" 21#include "core/hle/kernel/object.h"
23#include "core/hle/kernel/process.h" 22#include "core/hle/kernel/process.h"
23#include "core/hle/kernel/readable_event.h"
24#include "core/hle/kernel/server_session.h" 24#include "core/hle/kernel/server_session.h"
25#include "core/hle/kernel/writable_event.h"
25#include "core/memory.h" 26#include "core/memory.h"
26 27
27namespace Kernel { 28namespace Kernel {
@@ -36,11 +37,9 @@ void SessionRequestHandler::ClientDisconnected(const SharedPtr<ServerSession>& s
36 boost::range::remove_erase(connected_sessions, server_session); 37 boost::range::remove_erase(connected_sessions, server_session);
37} 38}
38 39
39SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread, 40SharedPtr<WritableEvent> HLERequestContext::SleepClientThread(
40 const std::string& reason, u64 timeout, 41 SharedPtr<Thread> thread, const std::string& reason, u64 timeout, WakeupCallback&& callback,
41 WakeupCallback&& callback, 42 SharedPtr<WritableEvent> writable_event) {
42 Kernel::SharedPtr<Kernel::Event> event) {
43
44 // Put the client thread to sleep until the wait event is signaled or the timeout expires. 43 // Put the client thread to sleep until the wait event is signaled or the timeout expires.
45 thread->SetWakeupCallback([context = *this, callback]( 44 thread->SetWakeupCallback([context = *this, callback](
46 ThreadWakeupReason reason, SharedPtr<Thread> thread, 45 ThreadWakeupReason reason, SharedPtr<Thread> thread,
@@ -51,23 +50,25 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
51 return true; 50 return true;
52 }); 51 });
53 52
54 if (!event) { 53 auto& kernel = Core::System::GetInstance().Kernel();
54 if (!writable_event) {
55 // Create event if not provided 55 // Create event if not provided
56 auto& kernel = Core::System::GetInstance().Kernel(); 56 const auto pair = WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
57 event = 57 "HLE Pause Event: " + reason);
58 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "HLE Pause Event: " + reason); 58 writable_event = pair.writable;
59 } 59 }
60 60
61 event->Clear(); 61 const auto readable_event{writable_event->GetReadableEvent()};
62 writable_event->Clear();
62 thread->SetStatus(ThreadStatus::WaitHLEEvent); 63 thread->SetStatus(ThreadStatus::WaitHLEEvent);
63 thread->SetWaitObjects({event}); 64 thread->SetWaitObjects({readable_event});
64 event->AddWaitingThread(thread); 65 readable_event->AddWaitingThread(thread);
65 66
66 if (timeout > 0) { 67 if (timeout > 0) {
67 thread->WakeAfterDelay(timeout); 68 thread->WakeAfterDelay(timeout);
68 } 69 }
69 70
70 return event; 71 return writable_event;
71} 72}
72 73
73HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session) 74HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session)
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index a38e34b74..e5c0610cd 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -24,10 +24,11 @@ class ServiceFrameworkBase;
24namespace Kernel { 24namespace Kernel {
25 25
26class Domain; 26class Domain;
27class Event;
28class HandleTable; 27class HandleTable;
29class HLERequestContext; 28class HLERequestContext;
30class Process; 29class Process;
30class ReadableEvent;
31class WritableEvent;
31 32
32/** 33/**
33 * Interface implemented by HLE Session handlers. 34 * Interface implemented by HLE Session handlers.
@@ -119,12 +120,13 @@ public:
119 * @param callback Callback to be invoked when the thread is resumed. This callback must write 120 * @param callback Callback to be invoked when the thread is resumed. This callback must write
120 * the entire command response once again, regardless of the state of it before this function 121 * the entire command response once again, regardless of the state of it before this function
121 * was called. 122 * was called.
122 * @param event Event to use to wake up the thread. If unspecified, an event will be created. 123 * @param writable_event Event to use to wake up the thread. If unspecified, an event will be
124 * created.
123 * @returns Event that when signaled will resume the thread and call the callback function. 125 * @returns Event that when signaled will resume the thread and call the callback function.
124 */ 126 */
125 SharedPtr<Event> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason, 127 SharedPtr<WritableEvent> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason,
126 u64 timeout, WakeupCallback&& callback, 128 u64 timeout, WakeupCallback&& callback,
127 Kernel::SharedPtr<Kernel::Event> event = nullptr); 129 SharedPtr<WritableEvent> writable_event = nullptr);
128 130
129 /// Populates this context with data from the requesting process/thread. 131 /// Populates this context with data from the requesting process/thread.
130 ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, 132 ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 1fd4ba5d2..e441c5bc6 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -105,7 +105,7 @@ struct KernelCore::Impl {
105 void Initialize(KernelCore& kernel) { 105 void Initialize(KernelCore& kernel) {
106 Shutdown(); 106 Shutdown();
107 107
108 InitializeResourceLimits(kernel); 108 InitializeSystemResourceLimit(kernel);
109 InitializeThreads(); 109 InitializeThreads();
110 InitializeTimers(); 110 InitializeTimers();
111 } 111 }
@@ -118,7 +118,7 @@ struct KernelCore::Impl {
118 process_list.clear(); 118 process_list.clear();
119 current_process = nullptr; 119 current_process = nullptr;
120 120
121 resource_limits.fill(nullptr); 121 system_resource_limit = nullptr;
122 122
123 thread_wakeup_callback_handle_table.Clear(); 123 thread_wakeup_callback_handle_table.Clear();
124 thread_wakeup_event_type = nullptr; 124 thread_wakeup_event_type = nullptr;
@@ -129,63 +129,17 @@ struct KernelCore::Impl {
129 named_ports.clear(); 129 named_ports.clear();
130 } 130 }
131 131
132 void InitializeResourceLimits(KernelCore& kernel) { 132 // Creates the default system resource limit
133 // Create the four resource limits that the system uses 133 void InitializeSystemResourceLimit(KernelCore& kernel) {
134 // Create the APPLICATION resource limit 134 system_resource_limit = ResourceLimit::Create(kernel, "System");
135 SharedPtr<ResourceLimit> resource_limit = ResourceLimit::Create(kernel, "Applications"); 135
136 resource_limit->max_priority = 0x18; 136 // If setting the default system values fails, then something seriously wrong has occurred.
137 resource_limit->max_commit = 0x4000000; 137 ASSERT(system_resource_limit->SetLimitValue(ResourceType::PhysicalMemory, 0x200000000)
138 resource_limit->max_threads = 0x20; 138 .IsSuccess());
139 resource_limit->max_events = 0x20; 139 ASSERT(system_resource_limit->SetLimitValue(ResourceType::Threads, 800).IsSuccess());
140 resource_limit->max_mutexes = 0x20; 140 ASSERT(system_resource_limit->SetLimitValue(ResourceType::Events, 700).IsSuccess());
141 resource_limit->max_semaphores = 0x8; 141 ASSERT(system_resource_limit->SetLimitValue(ResourceType::TransferMemory, 200).IsSuccess());
142 resource_limit->max_timers = 0x8; 142 ASSERT(system_resource_limit->SetLimitValue(ResourceType::Sessions, 900).IsSuccess());
143 resource_limit->max_shared_mems = 0x10;
144 resource_limit->max_address_arbiters = 0x2;
145 resource_limit->max_cpu_time = 0x1E;
146 resource_limits[static_cast<u8>(ResourceLimitCategory::APPLICATION)] = resource_limit;
147
148 // Create the SYS_APPLET resource limit
149 resource_limit = ResourceLimit::Create(kernel, "System Applets");
150 resource_limit->max_priority = 0x4;
151 resource_limit->max_commit = 0x5E00000;
152 resource_limit->max_threads = 0x1D;
153 resource_limit->max_events = 0xB;
154 resource_limit->max_mutexes = 0x8;
155 resource_limit->max_semaphores = 0x4;
156 resource_limit->max_timers = 0x4;
157 resource_limit->max_shared_mems = 0x8;
158 resource_limit->max_address_arbiters = 0x3;
159 resource_limit->max_cpu_time = 0x2710;
160 resource_limits[static_cast<u8>(ResourceLimitCategory::SYS_APPLET)] = resource_limit;
161
162 // Create the LIB_APPLET resource limit
163 resource_limit = ResourceLimit::Create(kernel, "Library Applets");
164 resource_limit->max_priority = 0x4;
165 resource_limit->max_commit = 0x600000;
166 resource_limit->max_threads = 0xE;
167 resource_limit->max_events = 0x8;
168 resource_limit->max_mutexes = 0x8;
169 resource_limit->max_semaphores = 0x4;
170 resource_limit->max_timers = 0x4;
171 resource_limit->max_shared_mems = 0x8;
172 resource_limit->max_address_arbiters = 0x1;
173 resource_limit->max_cpu_time = 0x2710;
174 resource_limits[static_cast<u8>(ResourceLimitCategory::LIB_APPLET)] = resource_limit;
175
176 // Create the OTHER resource limit
177 resource_limit = ResourceLimit::Create(kernel, "Others");
178 resource_limit->max_priority = 0x4;
179 resource_limit->max_commit = 0x2180000;
180 resource_limit->max_threads = 0xE1;
181 resource_limit->max_events = 0x108;
182 resource_limit->max_mutexes = 0x25;
183 resource_limit->max_semaphores = 0x43;
184 resource_limit->max_timers = 0x2C;
185 resource_limit->max_shared_mems = 0x1F;
186 resource_limit->max_address_arbiters = 0x2D;
187 resource_limit->max_cpu_time = 0x3E8;
188 resource_limits[static_cast<u8>(ResourceLimitCategory::OTHER)] = resource_limit;
189 } 143 }
190 144
191 void InitializeThreads() { 145 void InitializeThreads() {
@@ -208,7 +162,7 @@ struct KernelCore::Impl {
208 std::vector<SharedPtr<Process>> process_list; 162 std::vector<SharedPtr<Process>> process_list;
209 Process* current_process = nullptr; 163 Process* current_process = nullptr;
210 164
211 std::array<SharedPtr<ResourceLimit>, 4> resource_limits; 165 SharedPtr<ResourceLimit> system_resource_limit;
212 166
213 /// The event type of the generic timer callback event 167 /// The event type of the generic timer callback event
214 CoreTiming::EventType* timer_callback_event_type = nullptr; 168 CoreTiming::EventType* timer_callback_event_type = nullptr;
@@ -239,9 +193,8 @@ void KernelCore::Shutdown() {
239 impl->Shutdown(); 193 impl->Shutdown();
240} 194}
241 195
242SharedPtr<ResourceLimit> KernelCore::ResourceLimitForCategory( 196SharedPtr<ResourceLimit> KernelCore::GetSystemResourceLimit() const {
243 ResourceLimitCategory category) const { 197 return impl->system_resource_limit;
244 return impl->resource_limits.at(static_cast<std::size_t>(category));
245} 198}
246 199
247SharedPtr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const { 200SharedPtr<Thread> KernelCore::RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 7f822d524..ea00c89f5 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -24,8 +24,6 @@ class ResourceLimit;
24class Thread; 24class Thread;
25class Timer; 25class Timer;
26 26
27enum class ResourceLimitCategory : u8;
28
29/// Represents a single instance of the kernel. 27/// Represents a single instance of the kernel.
30class KernelCore { 28class KernelCore {
31private: 29private:
@@ -47,8 +45,8 @@ public:
47 /// Clears all resources in use by the kernel instance. 45 /// Clears all resources in use by the kernel instance.
48 void Shutdown(); 46 void Shutdown();
49 47
50 /// Retrieves a shared pointer to a ResourceLimit identified by the given category. 48 /// Retrieves a shared pointer to the system resource limit instance.
51 SharedPtr<ResourceLimit> ResourceLimitForCategory(ResourceLimitCategory category) const; 49 SharedPtr<ResourceLimit> GetSystemResourceLimit() const;
52 50
53 /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table. 51 /// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
54 SharedPtr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const; 52 SharedPtr<Thread> RetrieveThreadFromWakeupCallbackHandleTable(Handle handle) const;
diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp
index d87a62bb9..bb1b68778 100644
--- a/src/core/hle/kernel/object.cpp
+++ b/src/core/hle/kernel/object.cpp
@@ -13,7 +13,7 @@ Object::~Object() = default;
13 13
14bool Object::IsWaitable() const { 14bool Object::IsWaitable() const {
15 switch (GetHandleType()) { 15 switch (GetHandleType()) {
16 case HandleType::Event: 16 case HandleType::ReadableEvent:
17 case HandleType::Thread: 17 case HandleType::Thread:
18 case HandleType::Timer: 18 case HandleType::Timer:
19 case HandleType::ServerPort: 19 case HandleType::ServerPort:
@@ -21,6 +21,7 @@ bool Object::IsWaitable() const {
21 return true; 21 return true;
22 22
23 case HandleType::Unknown: 23 case HandleType::Unknown:
24 case HandleType::WritableEvent:
24 case HandleType::SharedMemory: 25 case HandleType::SharedMemory:
25 case HandleType::Process: 26 case HandleType::Process:
26 case HandleType::AddressArbiter: 27 case HandleType::AddressArbiter:
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h
index c9f4d0bb3..f1606a204 100644
--- a/src/core/hle/kernel/object.h
+++ b/src/core/hle/kernel/object.h
@@ -19,7 +19,8 @@ using Handle = u32;
19 19
20enum class HandleType : u32 { 20enum class HandleType : u32 {
21 Unknown, 21 Unknown,
22 Event, 22 WritableEvent,
23 ReadableEvent,
23 SharedMemory, 24 SharedMemory,
24 Thread, 25 Thread,
25 Process, 26 Process,
@@ -33,9 +34,9 @@ enum class HandleType : u32 {
33}; 34};
34 35
35enum class ResetType { 36enum class ResetType {
36 OneShot, 37 OneShot, ///< Reset automatically on object acquisition
37 Sticky, 38 Sticky, ///< Never reset automatically
38 Pulse, 39 Pulse, ///< Reset automatically on wakeup
39}; 40};
40 41
41class Object : NonCopyable { 42class Object : NonCopyable {
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 420218d59..4ecb8c926 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -4,12 +4,11 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <memory> 6#include <memory>
7#include <random>
7#include "common/assert.h" 8#include "common/assert.h"
8#include "common/common_funcs.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "core/core.h" 10#include "core/core.h"
11#include "core/file_sys/program_metadata.h" 11#include "core/file_sys/program_metadata.h"
12#include "core/hle/kernel/errors.h"
13#include "core/hle/kernel/kernel.h" 12#include "core/hle/kernel/kernel.h"
14#include "core/hle/kernel/process.h" 13#include "core/hle/kernel/process.h"
15#include "core/hle/kernel/resource_limit.h" 14#include "core/hle/kernel/resource_limit.h"
@@ -17,6 +16,7 @@
17#include "core/hle/kernel/thread.h" 16#include "core/hle/kernel/thread.h"
18#include "core/hle/kernel/vm_manager.h" 17#include "core/hle/kernel/vm_manager.h"
19#include "core/memory.h" 18#include "core/memory.h"
19#include "core/settings.h"
20 20
21namespace Kernel { 21namespace Kernel {
22 22
@@ -29,16 +29,25 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) {
29 process->name = std::move(name); 29 process->name = std::move(name);
30 process->flags.raw = 0; 30 process->flags.raw = 0;
31 process->flags.memory_region.Assign(MemoryRegion::APPLICATION); 31 process->flags.memory_region.Assign(MemoryRegion::APPLICATION);
32 process->resource_limit = kernel.ResourceLimitForCategory(ResourceLimitCategory::APPLICATION); 32 process->resource_limit = kernel.GetSystemResourceLimit();
33 process->status = ProcessStatus::Created; 33 process->status = ProcessStatus::Created;
34 process->program_id = 0; 34 process->program_id = 0;
35 process->process_id = kernel.CreateNewProcessID(); 35 process->process_id = kernel.CreateNewProcessID();
36 process->svc_access_mask.set(); 36 process->svc_access_mask.set();
37 37
38 std::mt19937 rng(Settings::values.rng_seed.value_or(0));
39 std::uniform_int_distribution<u64> distribution;
40 std::generate(process->random_entropy.begin(), process->random_entropy.end(),
41 [&] { return distribution(rng); });
42
38 kernel.AppendNewProcess(process); 43 kernel.AppendNewProcess(process);
39 return process; 44 return process;
40} 45}
41 46
47SharedPtr<ResourceLimit> Process::GetResourceLimit() const {
48 return resource_limit;
49}
50
42void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { 51void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
43 program_id = metadata.GetTitleID(); 52 program_id = metadata.GetTitleID();
44 is_64bit_process = metadata.Is64BitProgram(); 53 is_64bit_process = metadata.Is64BitProgram();
@@ -241,83 +250,15 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) {
241} 250}
242 251
243ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { 252ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
244 if (target < vm_manager.GetHeapRegionBaseAddress() || 253 return vm_manager.HeapAllocate(target, size, perms);
245 target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) {
246 return ERR_INVALID_ADDRESS;
247 }
248
249 if (heap_memory == nullptr) {
250 // Initialize heap
251 heap_memory = std::make_shared<std::vector<u8>>();
252 heap_start = heap_end = target;
253 } else {
254 vm_manager.UnmapRange(heap_start, heap_end - heap_start);
255 }
256
257 // If necessary, expand backing vector to cover new heap extents.
258 if (target < heap_start) {
259 heap_memory->insert(begin(*heap_memory), heap_start - target, 0);
260 heap_start = target;
261 vm_manager.RefreshMemoryBlockMappings(heap_memory.get());
262 }
263 if (target + size > heap_end) {
264 heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0);
265 heap_end = target + size;
266 vm_manager.RefreshMemoryBlockMappings(heap_memory.get());
267 }
268 ASSERT(heap_end - heap_start == heap_memory->size());
269
270 CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start,
271 size, MemoryState::Heap));
272 vm_manager.Reprotect(vma, perms);
273
274 heap_used = size;
275
276 return MakeResult<VAddr>(heap_end - size);
277} 254}
278 255
279ResultCode Process::HeapFree(VAddr target, u32 size) { 256ResultCode Process::HeapFree(VAddr target, u32 size) {
280 if (target < vm_manager.GetHeapRegionBaseAddress() || 257 return vm_manager.HeapFree(target, size);
281 target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) {
282 return ERR_INVALID_ADDRESS;
283 }
284
285 if (size == 0) {
286 return RESULT_SUCCESS;
287 }
288
289 ResultCode result = vm_manager.UnmapRange(target, size);
290 if (result.IsError())
291 return result;
292
293 heap_used -= size;
294
295 return RESULT_SUCCESS;
296} 258}
297 259
298ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) { 260ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state) {
299 auto vma = vm_manager.FindVMA(src_addr); 261 return vm_manager.MirrorMemory(dst_addr, src_addr, size, state);
300
301 ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address");
302 ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address");
303
304 // The returned VMA might be a bigger one encompassing the desired address.
305 auto vma_offset = src_addr - vma->first;
306 ASSERT_MSG(vma_offset + size <= vma->second.size,
307 "Shared memory exceeds bounds of mapped block");
308
309 const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block;
310 std::size_t backing_block_offset = vma->second.offset + vma_offset;
311
312 CASCADE_RESULT(auto new_vma,
313 vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size,
314 MemoryState::Mapped));
315 // Protect mirror with permissions from old region
316 vm_manager.Reprotect(new_vma, vma->second.permissions);
317 // Remove permissions from old region
318 vm_manager.Reprotect(vma, VMAPermission::None);
319
320 return RESULT_SUCCESS;
321} 262}
322 263
323ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) { 264ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) {
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 8d2616c79..49345aa66 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -119,6 +119,8 @@ struct CodeSet final {
119 119
120class Process final : public Object { 120class Process final : public Object {
121public: 121public:
122 static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4;
123
122 static SharedPtr<Process> Create(KernelCore& kernel, std::string&& name); 124 static SharedPtr<Process> Create(KernelCore& kernel, std::string&& name);
123 125
124 std::string GetTypeName() const override { 126 std::string GetTypeName() const override {
@@ -169,14 +171,7 @@ public:
169 } 171 }
170 172
171 /// Gets the resource limit descriptor for this process 173 /// Gets the resource limit descriptor for this process
172 ResourceLimit& GetResourceLimit() { 174 SharedPtr<ResourceLimit> GetResourceLimit() const;
173 return *resource_limit;
174 }
175
176 /// Gets the resource limit descriptor for this process
177 const ResourceLimit& GetResourceLimit() const {
178 return *resource_limit;
179 }
180 175
181 /// Gets the default CPU ID for this process 176 /// Gets the default CPU ID for this process
182 u8 GetDefaultProcessorID() const { 177 u8 GetDefaultProcessorID() const {
@@ -212,6 +207,11 @@ public:
212 total_process_running_time_ticks += ticks; 207 total_process_running_time_ticks += ticks;
213 } 208 }
214 209
210 /// Gets 8 bytes of random data for svcGetInfo RandomEntropy
211 u64 GetRandomEntropy(std::size_t index) const {
212 return random_entropy.at(index);
213 }
214
215 /** 215 /**
216 * Loads process-specifics configuration info with metadata provided 216 * Loads process-specifics configuration info with metadata provided
217 * by an executable. 217 * by an executable.
@@ -251,7 +251,8 @@ public:
251 ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms); 251 ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
252 ResultCode HeapFree(VAddr target, u32 size); 252 ResultCode HeapFree(VAddr target, u32 size);
253 253
254 ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size); 254 ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size,
255 MemoryState state = MemoryState::Mapped);
255 256
256 ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size); 257 ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
257 258
@@ -292,17 +293,6 @@ private:
292 u32 allowed_thread_priority_mask = 0xFFFFFFFF; 293 u32 allowed_thread_priority_mask = 0xFFFFFFFF;
293 u32 is_virtual_address_memory_enabled = 0; 294 u32 is_virtual_address_memory_enabled = 0;
294 295
295 // Memory used to back the allocations in the regular heap. A single vector is used to cover
296 // the entire virtual address space extents that bound the allocations, including any holes.
297 // This makes deallocation and reallocation of holes fast and keeps process memory contiguous
298 // in the emulator address space, allowing Memory::GetPointer to be reasonably safe.
299 std::shared_ptr<std::vector<u8>> heap_memory;
300
301 // The left/right bounds of the address space covered by heap_memory.
302 VAddr heap_start = 0;
303 VAddr heap_end = 0;
304 u64 heap_used = 0;
305
306 /// The Thread Local Storage area is allocated as processes create threads, 296 /// The Thread Local Storage area is allocated as processes create threads,
307 /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part 297 /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part
308 /// holds the TLS for a specific thread. This vector contains which parts are in use for each 298 /// holds the TLS for a specific thread. This vector contains which parts are in use for each
@@ -321,6 +311,9 @@ private:
321 /// Per-process handle table for storing created object handles in. 311 /// Per-process handle table for storing created object handles in.
322 HandleTable handle_table; 312 HandleTable handle_table;
323 313
314 /// Random values for svcGetInfo RandomEntropy
315 std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy;
316
324 std::string name; 317 std::string name;
325}; 318};
326 319
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/readable_event.cpp
index 8967e602e..92e16b4e6 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/readable_event.cpp
@@ -4,46 +4,37 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include "common/assert.h" 6#include "common/assert.h"
7#include "core/hle/kernel/event.h"
8#include "core/hle/kernel/object.h" 7#include "core/hle/kernel/object.h"
8#include "core/hle/kernel/readable_event.h"
9#include "core/hle/kernel/thread.h" 9#include "core/hle/kernel/thread.h"
10#include "core/hle/kernel/writable_event.h"
10 11
11namespace Kernel { 12namespace Kernel {
12 13
13Event::Event(KernelCore& kernel) : WaitObject{kernel} {} 14ReadableEvent::ReadableEvent(KernelCore& kernel) : WaitObject{kernel} {}
14Event::~Event() = default; 15ReadableEvent::~ReadableEvent() = default;
15 16
16SharedPtr<Event> Event::Create(KernelCore& kernel, ResetType reset_type, std::string name) { 17bool ReadableEvent::ShouldWait(Thread* thread) const {
17 SharedPtr<Event> evt(new Event(kernel));
18
19 evt->signaled = false;
20 evt->reset_type = reset_type;
21 evt->name = std::move(name);
22
23 return evt;
24}
25
26bool Event::ShouldWait(Thread* thread) const {
27 return !signaled; 18 return !signaled;
28} 19}
29 20
30void Event::Acquire(Thread* thread) { 21void ReadableEvent::Acquire(Thread* thread) {
31 ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); 22 ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
32 23
33 if (reset_type == ResetType::OneShot) 24 if (reset_type == ResetType::OneShot)
34 signaled = false; 25 signaled = false;
35} 26}
36 27
37void Event::Signal() { 28void ReadableEvent::Signal() {
38 signaled = true; 29 signaled = true;
39 WakeupAllWaitingThreads(); 30 WakeupAllWaitingThreads();
40} 31}
41 32
42void Event::Clear() { 33void ReadableEvent::Clear() {
43 signaled = false; 34 signaled = false;
44} 35}
45 36
46void Event::WakeupAllWaitingThreads() { 37void ReadableEvent::WakeupAllWaitingThreads() {
47 WaitObject::WakeupAllWaitingThreads(); 38 WaitObject::WakeupAllWaitingThreads();
48 39
49 if (reset_type == ResetType::Pulse) 40 if (reset_type == ResetType::Pulse)
diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h
new file mode 100644
index 000000000..867ff3051
--- /dev/null
+++ b/src/core/hle/kernel/readable_event.h
@@ -0,0 +1,55 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/kernel/object.h"
8#include "core/hle/kernel/wait_object.h"
9
10namespace Kernel {
11
12class KernelCore;
13class WritableEvent;
14
15class ReadableEvent final : public WaitObject {
16 friend class WritableEvent;
17
18public:
19 ~ReadableEvent() override;
20
21 std::string GetTypeName() const override {
22 return "ReadableEvent";
23 }
24 std::string GetName() const override {
25 return name;
26 }
27
28 ResetType GetResetType() const {
29 return reset_type;
30 }
31
32 static const HandleType HANDLE_TYPE = HandleType::ReadableEvent;
33 HandleType GetHandleType() const override {
34 return HANDLE_TYPE;
35 }
36
37 bool ShouldWait(Thread* thread) const override;
38 void Acquire(Thread* thread) override;
39
40 void WakeupAllWaitingThreads() override;
41
42 void Clear();
43
44private:
45 explicit ReadableEvent(KernelCore& kernel);
46
47 void Signal();
48
49 ResetType reset_type;
50 bool signaled;
51
52 std::string name; ///< Name of event (optional)
53};
54
55} // namespace Kernel
diff --git a/src/core/hle/kernel/resource_limit.cpp b/src/core/hle/kernel/resource_limit.cpp
index b253a680f..2f9695005 100644
--- a/src/core/hle/kernel/resource_limit.cpp
+++ b/src/core/hle/kernel/resource_limit.cpp
@@ -2,12 +2,16 @@
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 <cstring> 5#include "core/hle/kernel/errors.h"
6#include "common/assert.h"
7#include "common/logging/log.h"
8#include "core/hle/kernel/resource_limit.h" 6#include "core/hle/kernel/resource_limit.h"
7#include "core/hle/result.h"
9 8
10namespace Kernel { 9namespace Kernel {
10namespace {
11constexpr std::size_t ResourceTypeToIndex(ResourceType type) {
12 return static_cast<std::size_t>(type);
13}
14} // Anonymous namespace
11 15
12ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {} 16ResourceLimit::ResourceLimit(KernelCore& kernel) : Object{kernel} {}
13ResourceLimit::~ResourceLimit() = default; 17ResourceLimit::~ResourceLimit() = default;
@@ -19,59 +23,22 @@ SharedPtr<ResourceLimit> ResourceLimit::Create(KernelCore& kernel, std::string n
19 return resource_limit; 23 return resource_limit;
20} 24}
21 25
22s32 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const { 26s64 ResourceLimit::GetCurrentResourceValue(ResourceType resource) const {
23 switch (resource) { 27 return values.at(ResourceTypeToIndex(resource));
24 case ResourceType::Commit: 28}
25 return current_commit; 29
26 case ResourceType::Thread: 30s64 ResourceLimit::GetMaxResourceValue(ResourceType resource) const {
27 return current_threads; 31 return limits.at(ResourceTypeToIndex(resource));
28 case ResourceType::Event:
29 return current_events;
30 case ResourceType::Mutex:
31 return current_mutexes;
32 case ResourceType::Semaphore:
33 return current_semaphores;
34 case ResourceType::Timer:
35 return current_timers;
36 case ResourceType::SharedMemory:
37 return current_shared_mems;
38 case ResourceType::AddressArbiter:
39 return current_address_arbiters;
40 case ResourceType::CPUTime:
41 return current_cpu_time;
42 default:
43 LOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource));
44 UNIMPLEMENTED();
45 return 0;
46 }
47} 32}
48 33
49u32 ResourceLimit::GetMaxResourceValue(ResourceType resource) const { 34ResultCode ResourceLimit::SetLimitValue(ResourceType resource, s64 value) {
50 switch (resource) { 35 const auto index = ResourceTypeToIndex(resource);
51 case ResourceType::Priority: 36
52 return max_priority; 37 if (value < values[index]) {
53 case ResourceType::Commit: 38 return ERR_INVALID_STATE;
54 return max_commit;
55 case ResourceType::Thread:
56 return max_threads;
57 case ResourceType::Event:
58 return max_events;
59 case ResourceType::Mutex:
60 return max_mutexes;
61 case ResourceType::Semaphore:
62 return max_semaphores;
63 case ResourceType::Timer:
64 return max_timers;
65 case ResourceType::SharedMemory:
66 return max_shared_mems;
67 case ResourceType::AddressArbiter:
68 return max_address_arbiters;
69 case ResourceType::CPUTime:
70 return max_cpu_time;
71 default:
72 LOG_ERROR(Kernel, "Unknown resource type={:08X}", static_cast<u32>(resource));
73 UNIMPLEMENTED();
74 return 0;
75 } 39 }
40
41 values[index] = value;
42 return RESULT_SUCCESS;
76} 43}
77} // namespace Kernel 44} // namespace Kernel
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
index 219e49562..59dc11c22 100644
--- a/src/core/hle/kernel/resource_limit.h
+++ b/src/core/hle/kernel/resource_limit.h
@@ -4,33 +4,31 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
7#include "common/common_types.h" 8#include "common/common_types.h"
8#include "core/hle/kernel/object.h" 9#include "core/hle/kernel/object.h"
9 10
11union ResultCode;
12
10namespace Kernel { 13namespace Kernel {
11 14
12class KernelCore; 15class KernelCore;
13 16
14enum class ResourceLimitCategory : u8 { 17enum class ResourceType : u32 {
15 APPLICATION = 0, 18 PhysicalMemory,
16 SYS_APPLET = 1, 19 Threads,
17 LIB_APPLET = 2, 20 Events,
18 OTHER = 3 21 TransferMemory,
19}; 22 Sessions,
20 23
21enum class ResourceType { 24 // Used as a count, not an actual type.
22 Priority = 0, 25 ResourceTypeCount
23 Commit = 1,
24 Thread = 2,
25 Event = 3,
26 Mutex = 4,
27 Semaphore = 5,
28 Timer = 6,
29 SharedMemory = 7,
30 AddressArbiter = 8,
31 CPUTime = 9,
32}; 26};
33 27
28constexpr bool IsValidResourceType(ResourceType type) {
29 return type < ResourceType::ResourceTypeCount;
30}
31
34class ResourceLimit final : public Object { 32class ResourceLimit final : public Object {
35public: 33public:
36 /** 34 /**
@@ -55,61 +53,51 @@ public:
55 * @param resource Requested resource type 53 * @param resource Requested resource type
56 * @returns The current value of the resource type 54 * @returns The current value of the resource type
57 */ 55 */
58 s32 GetCurrentResourceValue(ResourceType resource) const; 56 s64 GetCurrentResourceValue(ResourceType resource) const;
59 57
60 /** 58 /**
61 * Gets the max value for the specified resource. 59 * Gets the max value for the specified resource.
62 * @param resource Requested resource type 60 * @param resource Requested resource type
63 * @returns The max value of the resource type 61 * @returns The max value of the resource type
64 */ 62 */
65 u32 GetMaxResourceValue(ResourceType resource) const; 63 s64 GetMaxResourceValue(ResourceType resource) const;
66
67 /// Name of resource limit object.
68 std::string name;
69
70 /// Max thread priority that a process in this category can create
71 s32 max_priority = 0;
72
73 /// Max memory that processes in this category can use
74 s32 max_commit = 0;
75 64
76 ///< Max number of objects that can be collectively created by the processes in this category 65 /**
77 s32 max_threads = 0; 66 * Sets the limit value for a given resource type.
78 s32 max_events = 0; 67 *
79 s32 max_mutexes = 0; 68 * @param resource The resource type to apply the limit to.
80 s32 max_semaphores = 0; 69 * @param value The limit to apply to the given resource type.
81 s32 max_timers = 0; 70 *
82 s32 max_shared_mems = 0; 71 * @return A result code indicating if setting the limit value
83 s32 max_address_arbiters = 0; 72 * was successful or not.
73 *
74 * @note The supplied limit value *must* be greater than or equal to
75 * the current resource value for the given resource type,
76 * otherwise ERR_INVALID_STATE will be returned.
77 */
78 ResultCode SetLimitValue(ResourceType resource, s64 value);
84 79
85 /// Max CPU time that the processes in this category can utilize 80private:
86 s32 max_cpu_time = 0; 81 explicit ResourceLimit(KernelCore& kernel);
82 ~ResourceLimit() override;
87 83
88 // TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind 84 // TODO(Subv): Increment resource limit current values in their respective Kernel::T::Create
89 // that APPLICATION resource limits should not be affected by the objects created by service 85 // functions
90 // modules. 86 //
91 // Currently we have no way of distinguishing if a Create was called by the running application, 87 // Currently we have no way of distinguishing if a Create was called by the running application,
92 // or by a service module. Approach this once we have separated the service modules into their 88 // or by a service module. Approach this once we have separated the service modules into their
93 // own processes 89 // own processes
94 90
95 /// Current memory that the processes in this category are using 91 using ResourceArray =
96 s32 current_commit = 0; 92 std::array<s64, static_cast<std::size_t>(ResourceType::ResourceTypeCount)>;
97 93
98 ///< Current number of objects among all processes in this category 94 /// Maximum values a resource type may reach.
99 s32 current_threads = 0; 95 ResourceArray limits{};
100 s32 current_events = 0; 96 /// Current resource limit values.
101 s32 current_mutexes = 0; 97 ResourceArray values{};
102 s32 current_semaphores = 0;
103 s32 current_timers = 0;
104 s32 current_shared_mems = 0;
105 s32 current_address_arbiters = 0;
106 98
107 /// Current CPU time that the processes in this category are utilizing 99 /// Name of resource limit object.
108 s32 current_cpu_time = 0; 100 std::string name;
109
110private:
111 explicit ResourceLimit(KernelCore& kernel);
112 ~ResourceLimit() override;
113}; 101};
114 102
115} // namespace Kernel 103} // namespace Kernel
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index a016a86b6..0494581f5 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -61,7 +61,7 @@ SharedPtr<SharedMemory> SharedMemory::Create(KernelCore& kernel, SharedPtr<Proce
61} 61}
62 62
63SharedPtr<SharedMemory> SharedMemory::CreateForApplet( 63SharedPtr<SharedMemory> SharedMemory::CreateForApplet(
64 KernelCore& kernel, std::shared_ptr<std::vector<u8>> heap_block, u32 offset, u32 size, 64 KernelCore& kernel, std::shared_ptr<std::vector<u8>> heap_block, std::size_t offset, u64 size,
65 MemoryPermission permissions, MemoryPermission other_permissions, std::string name) { 65 MemoryPermission permissions, MemoryPermission other_permissions, std::string name) {
66 SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel)); 66 SharedPtr<SharedMemory> shared_memory(new SharedMemory(kernel));
67 67
@@ -78,10 +78,10 @@ SharedPtr<SharedMemory> SharedMemory::CreateForApplet(
78 return shared_memory; 78 return shared_memory;
79} 79}
80 80
81ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermission permissions, 81ResultCode SharedMemory::Map(Process& target_process, VAddr address, MemoryPermission permissions,
82 MemoryPermission other_permissions) { 82 MemoryPermission other_permissions) {
83 const MemoryPermission own_other_permissions = 83 const MemoryPermission own_other_permissions =
84 target_process == owner_process ? this->permissions : this->other_permissions; 84 &target_process == owner_process ? this->permissions : this->other_permissions;
85 85
86 // Automatically allocated memory blocks can only be mapped with other_permissions = DontCare 86 // Automatically allocated memory blocks can only be mapped with other_permissions = DontCare
87 if (base_address == 0 && other_permissions != MemoryPermission::DontCare) { 87 if (base_address == 0 && other_permissions != MemoryPermission::DontCare) {
@@ -106,7 +106,7 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
106 VAddr target_address = address; 106 VAddr target_address = address;
107 107
108 // Map the memory block into the target process 108 // Map the memory block into the target process
109 auto result = target_process->VMManager().MapMemoryBlock( 109 auto result = target_process.VMManager().MapMemoryBlock(
110 target_address, backing_block, backing_block_offset, size, MemoryState::Shared); 110 target_address, backing_block, backing_block_offset, size, MemoryState::Shared);
111 if (result.Failed()) { 111 if (result.Failed()) {
112 LOG_ERROR( 112 LOG_ERROR(
@@ -116,14 +116,14 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
116 return result.Code(); 116 return result.Code();
117 } 117 }
118 118
119 return target_process->VMManager().ReprotectRange(target_address, size, 119 return target_process.VMManager().ReprotectRange(target_address, size,
120 ConvertPermissions(permissions)); 120 ConvertPermissions(permissions));
121} 121}
122 122
123ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) { 123ResultCode SharedMemory::Unmap(Process& target_process, VAddr address) {
124 // TODO(Subv): Verify what happens if the application tries to unmap an address that is not 124 // TODO(Subv): Verify what happens if the application tries to unmap an address that is not
125 // mapped to a SharedMemory. 125 // mapped to a SharedMemory.
126 return target_process->VMManager().UnmapRange(address, size); 126 return target_process.VMManager().UnmapRange(address, size);
127} 127}
128 128
129VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) { 129VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) {
@@ -132,7 +132,11 @@ VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) {
132 return static_cast<VMAPermission>(masked_permissions); 132 return static_cast<VMAPermission>(masked_permissions);
133} 133}
134 134
135u8* SharedMemory::GetPointer(u32 offset) { 135u8* SharedMemory::GetPointer(std::size_t offset) {
136 return backing_block->data() + backing_block_offset + offset;
137}
138
139const u8* SharedMemory::GetPointer(std::size_t offset) const {
136 return backing_block->data() + backing_block_offset + offset; 140 return backing_block->data() + backing_block_offset + offset;
137} 141}
138 142
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 2c06bb7ce..0b48db699 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -64,7 +64,7 @@ public:
64 */ 64 */
65 static SharedPtr<SharedMemory> CreateForApplet(KernelCore& kernel, 65 static SharedPtr<SharedMemory> CreateForApplet(KernelCore& kernel,
66 std::shared_ptr<std::vector<u8>> heap_block, 66 std::shared_ptr<std::vector<u8>> heap_block,
67 u32 offset, u32 size, 67 std::size_t offset, u64 size,
68 MemoryPermission permissions, 68 MemoryPermission permissions,
69 MemoryPermission other_permissions, 69 MemoryPermission other_permissions,
70 std::string name = "Unknown Applet"); 70 std::string name = "Unknown Applet");
@@ -81,6 +81,11 @@ public:
81 return HANDLE_TYPE; 81 return HANDLE_TYPE;
82 } 82 }
83 83
84 /// Gets the size of the underlying memory block in bytes.
85 u64 GetSize() const {
86 return size;
87 }
88
84 /** 89 /**
85 * Converts the specified MemoryPermission into the equivalent VMAPermission. 90 * Converts the specified MemoryPermission into the equivalent VMAPermission.
86 * @param permission The MemoryPermission to convert. 91 * @param permission The MemoryPermission to convert.
@@ -94,44 +99,51 @@ public:
94 * @param permissions Memory block map permissions (specified by SVC field) 99 * @param permissions Memory block map permissions (specified by SVC field)
95 * @param other_permissions Memory block map other permissions (specified by SVC field) 100 * @param other_permissions Memory block map other permissions (specified by SVC field)
96 */ 101 */
97 ResultCode Map(Process* target_process, VAddr address, MemoryPermission permissions, 102 ResultCode Map(Process& target_process, VAddr address, MemoryPermission permissions,
98 MemoryPermission other_permissions); 103 MemoryPermission other_permissions);
99 104
100 /** 105 /**
101 * Unmaps a shared memory block from the specified address in system memory 106 * Unmaps a shared memory block from the specified address in system memory
102 * @param target_process Process from which to umap the memory block. 107 * @param target_process Process from which to unmap the memory block.
103 * @param address Address in system memory where the shared memory block is mapped 108 * @param address Address in system memory where the shared memory block is mapped
104 * @return Result code of the unmap operation 109 * @return Result code of the unmap operation
105 */ 110 */
106 ResultCode Unmap(Process* target_process, VAddr address); 111 ResultCode Unmap(Process& target_process, VAddr address);
107 112
108 /** 113 /**
109 * Gets a pointer to the shared memory block 114 * Gets a pointer to the shared memory block
110 * @param offset Offset from the start of the shared memory block to get pointer 115 * @param offset Offset from the start of the shared memory block to get pointer
111 * @return Pointer to the shared memory block from the specified offset 116 * @return A pointer to the shared memory block from the specified offset
112 */ 117 */
113 u8* GetPointer(u32 offset = 0); 118 u8* GetPointer(std::size_t offset = 0);
119
120 /**
121 * Gets a constant pointer to the shared memory block
122 * @param offset Offset from the start of the shared memory block to get pointer
123 * @return A constant pointer to the shared memory block from the specified offset
124 */
125 const u8* GetPointer(std::size_t offset = 0) const;
126
127private:
128 explicit SharedMemory(KernelCore& kernel);
129 ~SharedMemory() override;
114 130
115 /// Process that created this shared memory block.
116 SharedPtr<Process> owner_process;
117 /// Address of shared memory block in the owner process if specified.
118 VAddr base_address;
119 /// Backing memory for this shared memory block. 131 /// Backing memory for this shared memory block.
120 std::shared_ptr<std::vector<u8>> backing_block; 132 std::shared_ptr<std::vector<u8>> backing_block;
121 /// Offset into the backing block for this shared memory. 133 /// Offset into the backing block for this shared memory.
122 std::size_t backing_block_offset; 134 std::size_t backing_block_offset = 0;
123 /// Size of the memory block. Page-aligned. 135 /// Size of the memory block. Page-aligned.
124 u64 size; 136 u64 size = 0;
125 /// Permission restrictions applied to the process which created the block. 137 /// Permission restrictions applied to the process which created the block.
126 MemoryPermission permissions; 138 MemoryPermission permissions{};
127 /// Permission restrictions applied to other processes mapping the block. 139 /// Permission restrictions applied to other processes mapping the block.
128 MemoryPermission other_permissions; 140 MemoryPermission other_permissions{};
141 /// Process that created this shared memory block.
142 SharedPtr<Process> owner_process;
143 /// Address of shared memory block in the owner process if specified.
144 VAddr base_address = 0;
129 /// Name of shared memory object. 145 /// Name of shared memory object.
130 std::string name; 146 std::string name;
131
132private:
133 explicit SharedMemory(KernelCore& kernel);
134 ~SharedMemory() override;
135}; 147};
136 148
137} // namespace Kernel 149} // namespace Kernel
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 7e8e87c33..e6c77f9db 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -20,17 +20,18 @@
20#include "core/hle/kernel/address_arbiter.h" 20#include "core/hle/kernel/address_arbiter.h"
21#include "core/hle/kernel/client_port.h" 21#include "core/hle/kernel/client_port.h"
22#include "core/hle/kernel/client_session.h" 22#include "core/hle/kernel/client_session.h"
23#include "core/hle/kernel/event.h"
24#include "core/hle/kernel/handle_table.h" 23#include "core/hle/kernel/handle_table.h"
25#include "core/hle/kernel/kernel.h" 24#include "core/hle/kernel/kernel.h"
26#include "core/hle/kernel/mutex.h" 25#include "core/hle/kernel/mutex.h"
27#include "core/hle/kernel/process.h" 26#include "core/hle/kernel/process.h"
27#include "core/hle/kernel/readable_event.h"
28#include "core/hle/kernel/resource_limit.h" 28#include "core/hle/kernel/resource_limit.h"
29#include "core/hle/kernel/scheduler.h" 29#include "core/hle/kernel/scheduler.h"
30#include "core/hle/kernel/shared_memory.h" 30#include "core/hle/kernel/shared_memory.h"
31#include "core/hle/kernel/svc.h" 31#include "core/hle/kernel/svc.h"
32#include "core/hle/kernel/svc_wrap.h" 32#include "core/hle/kernel/svc_wrap.h"
33#include "core/hle/kernel/thread.h" 33#include "core/hle/kernel/thread.h"
34#include "core/hle/kernel/writable_event.h"
34#include "core/hle/lock.h" 35#include "core/hle/lock.h"
35#include "core/hle/result.h" 36#include "core/hle/result.h"
36#include "core/hle/service/service.h" 37#include "core/hle/service/service.h"
@@ -62,56 +63,129 @@ bool IsInsideNewMapRegion(const VMManager& vm, VAddr address, u64 size) {
62 vm.GetNewMapRegionEndAddress()); 63 vm.GetNewMapRegionEndAddress());
63} 64}
64 65
66// 8 GiB
67constexpr u64 MAIN_MEMORY_SIZE = 0x200000000;
68
65// Helper function that performs the common sanity checks for svcMapMemory 69// Helper function that performs the common sanity checks for svcMapMemory
66// and svcUnmapMemory. This is doable, as both functions perform their sanitizing 70// and svcUnmapMemory. This is doable, as both functions perform their sanitizing
67// in the same order. 71// in the same order.
68ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_addr, VAddr src_addr, 72ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_addr, VAddr src_addr,
69 u64 size) { 73 u64 size) {
70 if (!Common::Is4KBAligned(dst_addr) || !Common::Is4KBAligned(src_addr)) { 74 if (!Common::Is4KBAligned(dst_addr)) {
75 LOG_ERROR(Kernel_SVC, "Destination address is not aligned to 4KB, 0x{:016X}", dst_addr);
71 return ERR_INVALID_ADDRESS; 76 return ERR_INVALID_ADDRESS;
72 } 77 }
73 78
74 if (size == 0 || !Common::Is4KBAligned(size)) { 79 if (!Common::Is4KBAligned(src_addr)) {
80 LOG_ERROR(Kernel_SVC, "Source address is not aligned to 4KB, 0x{:016X}", src_addr);
81 return ERR_INVALID_SIZE;
82 }
83
84 if (size == 0) {
85 LOG_ERROR(Kernel_SVC, "Size is 0");
86 return ERR_INVALID_SIZE;
87 }
88
89 if (!Common::Is4KBAligned(size)) {
90 LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:016X}", size);
75 return ERR_INVALID_SIZE; 91 return ERR_INVALID_SIZE;
76 } 92 }
77 93
78 if (!IsValidAddressRange(dst_addr, size)) { 94 if (!IsValidAddressRange(dst_addr, size)) {
95 LOG_ERROR(Kernel_SVC,
96 "Destination is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
97 dst_addr, size);
79 return ERR_INVALID_ADDRESS_STATE; 98 return ERR_INVALID_ADDRESS_STATE;
80 } 99 }
81 100
82 if (!IsValidAddressRange(src_addr, size)) { 101 if (!IsValidAddressRange(src_addr, size)) {
102 LOG_ERROR(Kernel_SVC, "Source is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
103 src_addr, size);
83 return ERR_INVALID_ADDRESS_STATE; 104 return ERR_INVALID_ADDRESS_STATE;
84 } 105 }
85 106
86 if (!IsInsideAddressSpace(vm_manager, src_addr, size)) { 107 if (!IsInsideAddressSpace(vm_manager, src_addr, size)) {
108 LOG_ERROR(Kernel_SVC,
109 "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}",
110 src_addr, size);
87 return ERR_INVALID_ADDRESS_STATE; 111 return ERR_INVALID_ADDRESS_STATE;
88 } 112 }
89 113
90 if (!IsInsideNewMapRegion(vm_manager, dst_addr, size)) { 114 if (!IsInsideNewMapRegion(vm_manager, dst_addr, size)) {
115 LOG_ERROR(Kernel_SVC,
116 "Destination is not within the new map region, addr=0x{:016X}, size=0x{:016X}",
117 dst_addr, size);
91 return ERR_INVALID_MEMORY_RANGE; 118 return ERR_INVALID_MEMORY_RANGE;
92 } 119 }
93 120
94 const VAddr dst_end_address = dst_addr + size; 121 const VAddr dst_end_address = dst_addr + size;
95 if (dst_end_address > vm_manager.GetHeapRegionBaseAddress() && 122 if (dst_end_address > vm_manager.GetHeapRegionBaseAddress() &&
96 vm_manager.GetHeapRegionEndAddress() > dst_addr) { 123 vm_manager.GetHeapRegionEndAddress() > dst_addr) {
124 LOG_ERROR(Kernel_SVC,
125 "Destination does not fit within the heap region, addr=0x{:016X}, "
126 "size=0x{:016X}, end_addr=0x{:016X}",
127 dst_addr, size, dst_end_address);
97 return ERR_INVALID_MEMORY_RANGE; 128 return ERR_INVALID_MEMORY_RANGE;
98 } 129 }
99 130
100 if (dst_end_address > vm_manager.GetMapRegionBaseAddress() && 131 if (dst_end_address > vm_manager.GetMapRegionBaseAddress() &&
101 vm_manager.GetMapRegionEndAddress() > dst_addr) { 132 vm_manager.GetMapRegionEndAddress() > dst_addr) {
133 LOG_ERROR(Kernel_SVC,
134 "Destination does not fit within the map region, addr=0x{:016X}, "
135 "size=0x{:016X}, end_addr=0x{:016X}",
136 dst_addr, size, dst_end_address);
102 return ERR_INVALID_MEMORY_RANGE; 137 return ERR_INVALID_MEMORY_RANGE;
103 } 138 }
104 139
105 return RESULT_SUCCESS; 140 return RESULT_SUCCESS;
106} 141}
142
143enum class ResourceLimitValueType {
144 CurrentValue,
145 LimitValue,
146};
147
148ResultVal<s64> RetrieveResourceLimitValue(Handle resource_limit, u32 resource_type,
149 ResourceLimitValueType value_type) {
150 const auto type = static_cast<ResourceType>(resource_type);
151 if (!IsValidResourceType(type)) {
152 LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
153 return ERR_INVALID_ENUM_VALUE;
154 }
155
156 const auto& kernel = Core::System::GetInstance().Kernel();
157 const auto* const current_process = kernel.CurrentProcess();
158 ASSERT(current_process != nullptr);
159
160 const auto resource_limit_object =
161 current_process->GetHandleTable().Get<ResourceLimit>(resource_limit);
162 if (!resource_limit_object) {
163 LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
164 resource_limit);
165 return ERR_INVALID_HANDLE;
166 }
167
168 if (value_type == ResourceLimitValueType::CurrentValue) {
169 return MakeResult(resource_limit_object->GetCurrentResourceValue(type));
170 }
171
172 return MakeResult(resource_limit_object->GetMaxResourceValue(type));
173}
107} // Anonymous namespace 174} // Anonymous namespace
108 175
109/// Set the process heap to a given Size. It can both extend and shrink the heap. 176/// Set the process heap to a given Size. It can both extend and shrink the heap.
110static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { 177static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
111 LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); 178 LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size);
112 179
113 // Size must be a multiple of 0x200000 (2MB) and be equal to or less than 4GB. 180 // Size must be a multiple of 0x200000 (2MB) and be equal to or less than 8GB.
114 if ((heap_size & 0xFFFFFFFE001FFFFF) != 0) { 181 if ((heap_size % 0x200000) != 0) {
182 LOG_ERROR(Kernel_SVC, "The heap size is not a multiple of 2MB, heap_size=0x{:016X}",
183 heap_size);
184 return ERR_INVALID_SIZE;
185 }
186
187 if (heap_size >= 0x200000000) {
188 LOG_ERROR(Kernel_SVC, "The heap size is not less than 8GB, heap_size=0x{:016X}", heap_size);
115 return ERR_INVALID_SIZE; 189 return ERR_INVALID_SIZE;
116 } 190 }
117 191
@@ -122,6 +196,63 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
122 return RESULT_SUCCESS; 196 return RESULT_SUCCESS;
123} 197}
124 198
199static ResultCode SetMemoryPermission(VAddr addr, u64 size, u32 prot) {
200 LOG_TRACE(Kernel_SVC, "called, addr=0x{:X}, size=0x{:X}, prot=0x{:X}", addr, size, prot);
201
202 if (!Common::Is4KBAligned(addr)) {
203 LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr);
204 return ERR_INVALID_ADDRESS;
205 }
206
207 if (size == 0) {
208 LOG_ERROR(Kernel_SVC, "Size is 0");
209 return ERR_INVALID_SIZE;
210 }
211
212 if (!Common::Is4KBAligned(size)) {
213 LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size);
214 return ERR_INVALID_SIZE;
215 }
216
217 if (!IsValidAddressRange(addr, size)) {
218 LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
219 addr, size);
220 return ERR_INVALID_ADDRESS_STATE;
221 }
222
223 const auto permission = static_cast<MemoryPermission>(prot);
224 if (permission != MemoryPermission::None && permission != MemoryPermission::Read &&
225 permission != MemoryPermission::ReadWrite) {
226 LOG_ERROR(Kernel_SVC, "Invalid memory permission specified, Got memory permission=0x{:08X}",
227 static_cast<u32>(permission));
228 return ERR_INVALID_MEMORY_PERMISSIONS;
229 }
230
231 auto* const current_process = Core::CurrentProcess();
232 auto& vm_manager = current_process->VMManager();
233
234 if (!IsInsideAddressSpace(vm_manager, addr, size)) {
235 LOG_ERROR(Kernel_SVC,
236 "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr,
237 size);
238 return ERR_INVALID_ADDRESS_STATE;
239 }
240
241 const VMManager::VMAHandle iter = vm_manager.FindVMA(addr);
242 if (iter == vm_manager.vma_map.end()) {
243 LOG_ERROR(Kernel_SVC, "Unable to find VMA for address=0x{:016X}", addr);
244 return ERR_INVALID_ADDRESS_STATE;
245 }
246
247 LOG_WARNING(Kernel_SVC, "Uniformity check on protected memory is not implemented.");
248 // TODO: Performs a uniformity check to make sure only protected memory is changed (it doesn't
249 // make sense to allow changing permissions on kernel memory itself, etc).
250
251 const auto converted_permissions = SharedMemory::ConvertPermissions(permission);
252
253 return vm_manager.ReprotectRange(addr, size, converted_permissions);
254}
255
125static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state1) { 256static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state1) {
126 LOG_WARNING(Kernel_SVC, 257 LOG_WARNING(Kernel_SVC,
127 "(STUBBED) called, addr=0x{:X}, size=0x{:X}, state0=0x{:X}, state1=0x{:X}", addr, 258 "(STUBBED) called, addr=0x{:X}, size=0x{:X}, state0=0x{:X}, state1=0x{:X}", addr,
@@ -164,6 +295,9 @@ static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
164/// Connect to an OS service given the port name, returns the handle to the port to out 295/// Connect to an OS service given the port name, returns the handle to the port to out
165static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address) { 296static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address) {
166 if (!Memory::IsValidVirtualAddress(port_name_address)) { 297 if (!Memory::IsValidVirtualAddress(port_name_address)) {
298 LOG_ERROR(Kernel_SVC,
299 "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}",
300 port_name_address);
167 return ERR_NOT_FOUND; 301 return ERR_NOT_FOUND;
168 } 302 }
169 303
@@ -171,7 +305,9 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address
171 // Read 1 char beyond the max allowed port name to detect names that are too long. 305 // Read 1 char beyond the max allowed port name to detect names that are too long.
172 std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1); 306 std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1);
173 if (port_name.size() > PortNameMaxLength) { 307 if (port_name.size() > PortNameMaxLength) {
174 return ERR_PORT_NAME_TOO_LONG; 308 LOG_ERROR(Kernel_SVC, "Port name is too long, expected {} but got {}", PortNameMaxLength,
309 port_name.size());
310 return ERR_OUT_OF_RANGE;
175 } 311 }
176 312
177 LOG_TRACE(Kernel_SVC, "called port_name={}", port_name); 313 LOG_TRACE(Kernel_SVC, "called port_name={}", port_name);
@@ -219,6 +355,7 @@ static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) {
219 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 355 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
220 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); 356 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
221 if (!thread) { 357 if (!thread) {
358 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", thread_handle);
222 return ERR_INVALID_HANDLE; 359 return ERR_INVALID_HANDLE;
223 } 360 }
224 361
@@ -233,6 +370,8 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
233 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 370 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
234 const SharedPtr<Process> process = handle_table.Get<Process>(process_handle); 371 const SharedPtr<Process> process = handle_table.Get<Process>(process_handle);
235 if (!process) { 372 if (!process) {
373 LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
374 process_handle);
236 return ERR_INVALID_HANDLE; 375 return ERR_INVALID_HANDLE;
237 } 376 }
238 377
@@ -262,13 +401,20 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
262 LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", 401 LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}",
263 handles_address, handle_count, nano_seconds); 402 handles_address, handle_count, nano_seconds);
264 403
265 if (!Memory::IsValidVirtualAddress(handles_address)) 404 if (!Memory::IsValidVirtualAddress(handles_address)) {
405 LOG_ERROR(Kernel_SVC,
406 "Handle address is not a valid virtual address, handle_address=0x{:016X}",
407 handles_address);
266 return ERR_INVALID_POINTER; 408 return ERR_INVALID_POINTER;
409 }
267 410
268 static constexpr u64 MaxHandles = 0x40; 411 static constexpr u64 MaxHandles = 0x40;
269 412
270 if (handle_count > MaxHandles) 413 if (handle_count > MaxHandles) {
271 return ResultCode(ErrorModule::Kernel, ErrCodes::TooLarge); 414 LOG_ERROR(Kernel_SVC, "Handle count specified is too large, expected {} but got {}",
415 MaxHandles, handle_count);
416 return ERR_OUT_OF_RANGE;
417 }
272 418
273 auto* const thread = GetCurrentThread(); 419 auto* const thread = GetCurrentThread();
274 420
@@ -281,6 +427,7 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
281 const auto object = handle_table.Get<WaitObject>(handle); 427 const auto object = handle_table.Get<WaitObject>(handle);
282 428
283 if (object == nullptr) { 429 if (object == nullptr) {
430 LOG_ERROR(Kernel_SVC, "Object is a nullptr");
284 return ERR_INVALID_HANDLE; 431 return ERR_INVALID_HANDLE;
285 } 432 }
286 433
@@ -304,11 +451,13 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
304 451
305 // If a timeout value of 0 was provided, just return the Timeout error code instead of 452 // If a timeout value of 0 was provided, just return the Timeout error code instead of
306 // suspending the thread. 453 // suspending the thread.
307 if (nano_seconds == 0) 454 if (nano_seconds == 0) {
308 return RESULT_TIMEOUT; 455 return RESULT_TIMEOUT;
456 }
309 457
310 for (auto& object : objects) 458 for (auto& object : objects) {
311 object->AddWaitingThread(thread); 459 object->AddWaitingThread(thread);
460 }
312 461
313 thread->SetWaitObjects(std::move(objects)); 462 thread->SetWaitObjects(std::move(objects));
314 thread->SetStatus(ThreadStatus::WaitSynchAny); 463 thread->SetStatus(ThreadStatus::WaitSynchAny);
@@ -329,12 +478,13 @@ static ResultCode CancelSynchronization(Handle thread_handle) {
329 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 478 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
330 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); 479 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
331 if (!thread) { 480 if (!thread) {
481 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
482 thread_handle);
332 return ERR_INVALID_HANDLE; 483 return ERR_INVALID_HANDLE;
333 } 484 }
334 485
335 ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny); 486 ASSERT(thread->GetStatus() == ThreadStatus::WaitSynchAny);
336 thread->SetWaitSynchronizationResult( 487 thread->SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED);
337 ResultCode(ErrorModule::Kernel, ErrCodes::SynchronizationCanceled));
338 thread->ResumeFromWait(); 488 thread->ResumeFromWait();
339 return RESULT_SUCCESS; 489 return RESULT_SUCCESS;
340} 490}
@@ -348,10 +498,13 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
348 holding_thread_handle, mutex_addr, requesting_thread_handle); 498 holding_thread_handle, mutex_addr, requesting_thread_handle);
349 499
350 if (Memory::IsKernelVirtualAddress(mutex_addr)) { 500 if (Memory::IsKernelVirtualAddress(mutex_addr)) {
501 LOG_ERROR(Kernel_SVC, "Mutex Address is a kernel virtual address, mutex_addr={:016X}",
502 mutex_addr);
351 return ERR_INVALID_ADDRESS_STATE; 503 return ERR_INVALID_ADDRESS_STATE;
352 } 504 }
353 505
354 if (!Common::IsWordAligned(mutex_addr)) { 506 if (!Common::IsWordAligned(mutex_addr)) {
507 LOG_ERROR(Kernel_SVC, "Mutex Address is not word aligned, mutex_addr={:016X}", mutex_addr);
355 return ERR_INVALID_ADDRESS; 508 return ERR_INVALID_ADDRESS;
356 } 509 }
357 510
@@ -365,10 +518,13 @@ static ResultCode ArbitrateUnlock(VAddr mutex_addr) {
365 LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr); 518 LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr);
366 519
367 if (Memory::IsKernelVirtualAddress(mutex_addr)) { 520 if (Memory::IsKernelVirtualAddress(mutex_addr)) {
521 LOG_ERROR(Kernel_SVC, "Mutex Address is a kernel virtual address, mutex_addr={:016X}",
522 mutex_addr);
368 return ERR_INVALID_ADDRESS_STATE; 523 return ERR_INVALID_ADDRESS_STATE;
369 } 524 }
370 525
371 if (!Common::IsWordAligned(mutex_addr)) { 526 if (!Common::IsWordAligned(mutex_addr)) {
527 LOG_ERROR(Kernel_SVC, "Mutex Address is not word aligned, mutex_addr={:016X}", mutex_addr);
372 return ERR_INVALID_ADDRESS; 528 return ERR_INVALID_ADDRESS;
373 } 529 }
374 530
@@ -506,7 +662,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
506 TotalMemoryUsage = 6, 662 TotalMemoryUsage = 6,
507 TotalHeapUsage = 7, 663 TotalHeapUsage = 7,
508 IsCurrentProcessBeingDebugged = 8, 664 IsCurrentProcessBeingDebugged = 8,
509 ResourceHandleLimit = 9, 665 RegisterResourceLimit = 9,
510 IdleTickCount = 10, 666 IdleTickCount = 10,
511 RandomEntropy = 11, 667 RandomEntropy = 11,
512 PerformanceCounter = 0xF0000002, 668 PerformanceCounter = 0xF0000002,
@@ -526,77 +682,172 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
526 ThreadTickCount = 0xF0000002, 682 ThreadTickCount = 0xF0000002,
527 }; 683 };
528 684
529 const auto* current_process = Core::CurrentProcess(); 685 const auto info_id_type = static_cast<GetInfoType>(info_id);
530 const auto& vm_manager = current_process->VMManager();
531 686
532 switch (static_cast<GetInfoType>(info_id)) { 687 switch (info_id_type) {
533 case GetInfoType::AllowedCpuIdBitmask: 688 case GetInfoType::AllowedCpuIdBitmask:
534 *result = current_process->GetAllowedProcessorMask();
535 break;
536 case GetInfoType::AllowedThreadPrioBitmask: 689 case GetInfoType::AllowedThreadPrioBitmask:
537 *result = current_process->GetAllowedThreadPriorityMask();
538 break;
539 case GetInfoType::MapRegionBaseAddr: 690 case GetInfoType::MapRegionBaseAddr:
540 *result = vm_manager.GetMapRegionBaseAddress();
541 break;
542 case GetInfoType::MapRegionSize: 691 case GetInfoType::MapRegionSize:
543 *result = vm_manager.GetMapRegionSize();
544 break;
545 case GetInfoType::HeapRegionBaseAddr: 692 case GetInfoType::HeapRegionBaseAddr:
546 *result = vm_manager.GetHeapRegionBaseAddress();
547 break;
548 case GetInfoType::HeapRegionSize: 693 case GetInfoType::HeapRegionSize:
549 *result = vm_manager.GetHeapRegionSize();
550 break;
551 case GetInfoType::TotalMemoryUsage:
552 *result = vm_manager.GetTotalMemoryUsage();
553 break;
554 case GetInfoType::TotalHeapUsage:
555 *result = vm_manager.GetTotalHeapUsage();
556 break;
557 case GetInfoType::IsCurrentProcessBeingDebugged:
558 *result = 0;
559 break;
560 case GetInfoType::RandomEntropy:
561 *result = 0;
562 break;
563 case GetInfoType::ASLRRegionBaseAddr: 694 case GetInfoType::ASLRRegionBaseAddr:
564 *result = vm_manager.GetASLRRegionBaseAddress();
565 break;
566 case GetInfoType::ASLRRegionSize: 695 case GetInfoType::ASLRRegionSize:
567 *result = vm_manager.GetASLRRegionSize();
568 break;
569 case GetInfoType::NewMapRegionBaseAddr: 696 case GetInfoType::NewMapRegionBaseAddr:
570 *result = vm_manager.GetNewMapRegionBaseAddress();
571 break;
572 case GetInfoType::NewMapRegionSize: 697 case GetInfoType::NewMapRegionSize:
573 *result = vm_manager.GetNewMapRegionSize(); 698 case GetInfoType::TotalMemoryUsage:
574 break; 699 case GetInfoType::TotalHeapUsage:
575 case GetInfoType::IsVirtualAddressMemoryEnabled: 700 case GetInfoType::IsVirtualAddressMemoryEnabled:
576 *result = current_process->IsVirtualMemoryEnabled(); 701 case GetInfoType::PersonalMmHeapUsage:
577 break;
578 case GetInfoType::TitleId: 702 case GetInfoType::TitleId:
579 *result = current_process->GetTitleID(); 703 case GetInfoType::UserExceptionContextAddr: {
580 break; 704 if (info_sub_id != 0) {
705 return ERR_INVALID_ENUM_VALUE;
706 }
707
708 const auto& current_process_handle_table = Core::CurrentProcess()->GetHandleTable();
709 const auto process = current_process_handle_table.Get<Process>(static_cast<Handle>(handle));
710 if (!process) {
711 return ERR_INVALID_HANDLE;
712 }
713
714 switch (info_id_type) {
715 case GetInfoType::AllowedCpuIdBitmask:
716 *result = process->GetAllowedProcessorMask();
717 return RESULT_SUCCESS;
718
719 case GetInfoType::AllowedThreadPrioBitmask:
720 *result = process->GetAllowedThreadPriorityMask();
721 return RESULT_SUCCESS;
722
723 case GetInfoType::MapRegionBaseAddr:
724 *result = process->VMManager().GetMapRegionBaseAddress();
725 return RESULT_SUCCESS;
726
727 case GetInfoType::MapRegionSize:
728 *result = process->VMManager().GetMapRegionSize();
729 return RESULT_SUCCESS;
730
731 case GetInfoType::HeapRegionBaseAddr:
732 *result = process->VMManager().GetHeapRegionBaseAddress();
733 return RESULT_SUCCESS;
734
735 case GetInfoType::HeapRegionSize:
736 *result = process->VMManager().GetHeapRegionSize();
737 return RESULT_SUCCESS;
738
739 case GetInfoType::ASLRRegionBaseAddr:
740 *result = process->VMManager().GetASLRRegionBaseAddress();
741 return RESULT_SUCCESS;
742
743 case GetInfoType::ASLRRegionSize:
744 *result = process->VMManager().GetASLRRegionSize();
745 return RESULT_SUCCESS;
746
747 case GetInfoType::NewMapRegionBaseAddr:
748 *result = process->VMManager().GetNewMapRegionBaseAddress();
749 return RESULT_SUCCESS;
750
751 case GetInfoType::NewMapRegionSize:
752 *result = process->VMManager().GetNewMapRegionSize();
753 return RESULT_SUCCESS;
754
755 case GetInfoType::TotalMemoryUsage:
756 *result = process->VMManager().GetTotalMemoryUsage();
757 return RESULT_SUCCESS;
758
759 case GetInfoType::TotalHeapUsage:
760 *result = process->VMManager().GetTotalHeapUsage();
761 return RESULT_SUCCESS;
762
763 case GetInfoType::IsVirtualAddressMemoryEnabled:
764 *result = process->IsVirtualMemoryEnabled();
765 return RESULT_SUCCESS;
766
767 case GetInfoType::TitleId:
768 *result = process->GetTitleID();
769 return RESULT_SUCCESS;
770
771 case GetInfoType::UserExceptionContextAddr:
772 LOG_WARNING(Kernel_SVC,
773 "(STUBBED) Attempted to query user exception context address, returned 0");
774 *result = 0;
775 return RESULT_SUCCESS;
776
777 default:
778 break;
779 }
780
781 LOG_WARNING(Kernel_SVC, "(STUBBED) Unimplemented svcGetInfo id=0x{:016X}", info_id);
782 return ERR_INVALID_ENUM_VALUE;
783 }
784
785 case GetInfoType::IsCurrentProcessBeingDebugged:
786 *result = 0;
787 return RESULT_SUCCESS;
788
789 case GetInfoType::RegisterResourceLimit: {
790 if (handle != 0) {
791 return ERR_INVALID_HANDLE;
792 }
793
794 if (info_sub_id != 0) {
795 return ERR_INVALID_COMBINATION;
796 }
797
798 Process* const current_process = Core::CurrentProcess();
799 HandleTable& handle_table = current_process->GetHandleTable();
800 const auto resource_limit = current_process->GetResourceLimit();
801 if (!resource_limit) {
802 *result = KernelHandle::InvalidHandle;
803 // Yes, the kernel considers this a successful operation.
804 return RESULT_SUCCESS;
805 }
806
807 const auto table_result = handle_table.Create(resource_limit);
808 if (table_result.Failed()) {
809 return table_result.Code();
810 }
811
812 *result = *table_result;
813 return RESULT_SUCCESS;
814 }
815
816 case GetInfoType::RandomEntropy:
817 if (handle != 0) {
818 LOG_ERROR(Kernel_SVC, "Process Handle is non zero, expected 0 result but got {:016X}",
819 handle);
820 return ERR_INVALID_HANDLE;
821 }
822
823 if (info_sub_id >= Process::RANDOM_ENTROPY_SIZE) {
824 LOG_ERROR(Kernel_SVC, "Entropy size is out of range, expected {} but got {}",
825 Process::RANDOM_ENTROPY_SIZE, info_sub_id);
826 return ERR_INVALID_COMBINATION;
827 }
828
829 *result = Core::CurrentProcess()->GetRandomEntropy(info_sub_id);
830 return RESULT_SUCCESS;
831
581 case GetInfoType::PrivilegedProcessId: 832 case GetInfoType::PrivilegedProcessId:
582 LOG_WARNING(Kernel_SVC, 833 LOG_WARNING(Kernel_SVC,
583 "(STUBBED) Attempted to query privileged process id bounds, returned 0"); 834 "(STUBBED) Attempted to query privileged process id bounds, returned 0");
584 *result = 0; 835 *result = 0;
585 break; 836 return RESULT_SUCCESS;
586 case GetInfoType::UserExceptionContextAddr: 837
587 LOG_WARNING(Kernel_SVC,
588 "(STUBBED) Attempted to query user exception context address, returned 0");
589 *result = 0;
590 break;
591 case GetInfoType::ThreadTickCount: { 838 case GetInfoType::ThreadTickCount: {
592 constexpr u64 num_cpus = 4; 839 constexpr u64 num_cpus = 4;
593 if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) { 840 if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) {
594 return ERR_INVALID_COMBINATION_KERNEL; 841 LOG_ERROR(Kernel_SVC, "Core count is out of range, expected {} but got {}", num_cpus,
842 info_sub_id);
843 return ERR_INVALID_COMBINATION;
595 } 844 }
596 845
597 const auto thread = 846 const auto thread =
598 current_process->GetHandleTable().Get<Thread>(static_cast<Handle>(handle)); 847 Core::CurrentProcess()->GetHandleTable().Get<Thread>(static_cast<Handle>(handle));
599 if (!thread) { 848 if (!thread) {
849 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
850 static_cast<Handle>(handle));
600 return ERR_INVALID_HANDLE; 851 return ERR_INVALID_HANDLE;
601 } 852 }
602 853
@@ -616,13 +867,13 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
616 } 867 }
617 868
618 *result = out_ticks; 869 *result = out_ticks;
619 break; 870 return RESULT_SUCCESS;
620 } 871 }
872
621 default: 873 default:
622 UNIMPLEMENTED(); 874 LOG_WARNING(Kernel_SVC, "(STUBBED) Unimplemented svcGetInfo id=0x{:016X}", info_id);
875 return ERR_INVALID_ENUM_VALUE;
623 } 876 }
624
625 return RESULT_SUCCESS;
626} 877}
627 878
628/// Sets the thread activity 879/// Sets the thread activity
@@ -638,14 +889,22 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
638 const auto* current_process = Core::CurrentProcess(); 889 const auto* current_process = Core::CurrentProcess();
639 const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); 890 const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
640 if (!thread) { 891 if (!thread) {
892 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
641 return ERR_INVALID_HANDLE; 893 return ERR_INVALID_HANDLE;
642 } 894 }
643 895
644 if (thread->GetOwnerProcess() != current_process) { 896 if (thread->GetOwnerProcess() != current_process) {
897 LOG_ERROR(Kernel_SVC,
898 "The current process does not own the current thread, thread_handle={:08X} "
899 "thread_pid={}, "
900 "current_process_pid={}",
901 handle, thread->GetOwnerProcess()->GetProcessID(),
902 current_process->GetProcessID());
645 return ERR_INVALID_HANDLE; 903 return ERR_INVALID_HANDLE;
646 } 904 }
647 905
648 if (thread == GetCurrentThread()) { 906 if (thread == GetCurrentThread()) {
907 LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread");
649 return ERR_ALREADY_REGISTERED; 908 return ERR_ALREADY_REGISTERED;
650 } 909 }
651 910
@@ -666,9 +925,12 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
666 925
667/// Gets the priority for the specified thread 926/// Gets the priority for the specified thread
668static ResultCode GetThreadPriority(u32* priority, Handle handle) { 927static ResultCode GetThreadPriority(u32* priority, Handle handle) {
928 LOG_TRACE(Kernel_SVC, "called");
929
669 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 930 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
670 const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle); 931 const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle);
671 if (!thread) { 932 if (!thread) {
933 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
672 return ERR_INVALID_HANDLE; 934 return ERR_INVALID_HANDLE;
673 } 935 }
674 936
@@ -678,21 +940,21 @@ static ResultCode GetThreadPriority(u32* priority, Handle handle) {
678 940
679/// Sets the priority for the specified thread 941/// Sets the priority for the specified thread
680static ResultCode SetThreadPriority(Handle handle, u32 priority) { 942static ResultCode SetThreadPriority(Handle handle, u32 priority) {
943 LOG_TRACE(Kernel_SVC, "called");
944
681 if (priority > THREADPRIO_LOWEST) { 945 if (priority > THREADPRIO_LOWEST) {
946 LOG_ERROR(
947 Kernel_SVC,
948 "An invalid priority was specified, expected {} but got {} for thread_handle={:08X}",
949 THREADPRIO_LOWEST, priority, handle);
682 return ERR_INVALID_THREAD_PRIORITY; 950 return ERR_INVALID_THREAD_PRIORITY;
683 } 951 }
684 952
685 const auto* const current_process = Core::CurrentProcess(); 953 const auto* const current_process = Core::CurrentProcess();
686 954
687 // Note: The kernel uses the current process's resource limit instead of
688 // the one from the thread owner's resource limit.
689 const ResourceLimit& resource_limit = current_process->GetResourceLimit();
690 if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) {
691 return ERR_INVALID_THREAD_PRIORITY;
692 }
693
694 SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); 955 SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
695 if (!thread) { 956 if (!thread) {
957 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle);
696 return ERR_INVALID_HANDLE; 958 return ERR_INVALID_HANDLE;
697 } 959 }
698 960
@@ -715,36 +977,50 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s
715 shared_memory_handle, addr, size, permissions); 977 shared_memory_handle, addr, size, permissions);
716 978
717 if (!Common::Is4KBAligned(addr)) { 979 if (!Common::Is4KBAligned(addr)) {
980 LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr);
718 return ERR_INVALID_ADDRESS; 981 return ERR_INVALID_ADDRESS;
719 } 982 }
720 983
721 if (size == 0 || !Common::Is4KBAligned(size)) { 984 if (size == 0) {
985 LOG_ERROR(Kernel_SVC, "Size is 0");
986 return ERR_INVALID_SIZE;
987 }
988
989 if (!Common::Is4KBAligned(size)) {
990 LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size);
722 return ERR_INVALID_SIZE; 991 return ERR_INVALID_SIZE;
723 } 992 }
724 993
725 if (!IsValidAddressRange(addr, size)) { 994 if (!IsValidAddressRange(addr, size)) {
995 LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
996 addr, size);
726 return ERR_INVALID_ADDRESS_STATE; 997 return ERR_INVALID_ADDRESS_STATE;
727 } 998 }
728 999
729 const auto permissions_type = static_cast<MemoryPermission>(permissions); 1000 const auto permissions_type = static_cast<MemoryPermission>(permissions);
730 if (permissions_type != MemoryPermission::Read && 1001 if (permissions_type != MemoryPermission::Read &&
731 permissions_type != MemoryPermission::ReadWrite) { 1002 permissions_type != MemoryPermission::ReadWrite) {
732 LOG_ERROR(Kernel_SVC, "Invalid permissions=0x{:08X}", permissions); 1003 LOG_ERROR(Kernel_SVC, "Expected Read or ReadWrite permission but got permissions=0x{:08X}",
1004 permissions);
733 return ERR_INVALID_MEMORY_PERMISSIONS; 1005 return ERR_INVALID_MEMORY_PERMISSIONS;
734 } 1006 }
735 1007
736 auto* const current_process = Core::CurrentProcess(); 1008 auto* const current_process = Core::CurrentProcess();
737 auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle); 1009 auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle);
738 if (!shared_memory) { 1010 if (!shared_memory) {
1011 LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}",
1012 shared_memory_handle);
739 return ERR_INVALID_HANDLE; 1013 return ERR_INVALID_HANDLE;
740 } 1014 }
741 1015
742 const auto& vm_manager = current_process->VMManager(); 1016 const auto& vm_manager = current_process->VMManager();
743 if (!vm_manager.IsWithinASLRRegion(addr, size)) { 1017 if (!vm_manager.IsWithinASLRRegion(addr, size)) {
1018 LOG_ERROR(Kernel_SVC, "Region is not within the ASLR region. addr=0x{:016X}, size={:016X}",
1019 addr, size);
744 return ERR_INVALID_MEMORY_RANGE; 1020 return ERR_INVALID_MEMORY_RANGE;
745 } 1021 }
746 1022
747 return shared_memory->Map(current_process, addr, permissions_type, MemoryPermission::DontCare); 1023 return shared_memory->Map(*current_process, addr, permissions_type, MemoryPermission::DontCare);
748} 1024}
749 1025
750static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) { 1026static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size) {
@@ -752,37 +1028,53 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64
752 shared_memory_handle, addr, size); 1028 shared_memory_handle, addr, size);
753 1029
754 if (!Common::Is4KBAligned(addr)) { 1030 if (!Common::Is4KBAligned(addr)) {
1031 LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr);
755 return ERR_INVALID_ADDRESS; 1032 return ERR_INVALID_ADDRESS;
756 } 1033 }
757 1034
758 if (size == 0 || !Common::Is4KBAligned(size)) { 1035 if (size == 0) {
1036 LOG_ERROR(Kernel_SVC, "Size is 0");
1037 return ERR_INVALID_SIZE;
1038 }
1039
1040 if (!Common::Is4KBAligned(size)) {
1041 LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size);
759 return ERR_INVALID_SIZE; 1042 return ERR_INVALID_SIZE;
760 } 1043 }
761 1044
762 if (!IsValidAddressRange(addr, size)) { 1045 if (!IsValidAddressRange(addr, size)) {
1046 LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}",
1047 addr, size);
763 return ERR_INVALID_ADDRESS_STATE; 1048 return ERR_INVALID_ADDRESS_STATE;
764 } 1049 }
765 1050
766 auto* const current_process = Core::CurrentProcess(); 1051 auto* const current_process = Core::CurrentProcess();
767 auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle); 1052 auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle);
768 if (!shared_memory) { 1053 if (!shared_memory) {
1054 LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}",
1055 shared_memory_handle);
769 return ERR_INVALID_HANDLE; 1056 return ERR_INVALID_HANDLE;
770 } 1057 }
771 1058
772 const auto& vm_manager = current_process->VMManager(); 1059 const auto& vm_manager = current_process->VMManager();
773 if (!vm_manager.IsWithinASLRRegion(addr, size)) { 1060 if (!vm_manager.IsWithinASLRRegion(addr, size)) {
1061 LOG_ERROR(Kernel_SVC, "Region is not within the ASLR region. addr=0x{:016X}, size={:016X}",
1062 addr, size);
774 return ERR_INVALID_MEMORY_RANGE; 1063 return ERR_INVALID_MEMORY_RANGE;
775 } 1064 }
776 1065
777 return shared_memory->Unmap(current_process, addr); 1066 return shared_memory->Unmap(*current_process, addr);
778} 1067}
779 1068
780/// Query process memory 1069/// Query process memory
781static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/, 1070static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/,
782 Handle process_handle, u64 addr) { 1071 Handle process_handle, u64 addr) {
1072 LOG_TRACE(Kernel_SVC, "called process=0x{:08X} addr={:X}", process_handle, addr);
783 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 1073 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
784 SharedPtr<Process> process = handle_table.Get<Process>(process_handle); 1074 SharedPtr<Process> process = handle_table.Get<Process>(process_handle);
785 if (!process) { 1075 if (!process) {
1076 LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
1077 process_handle);
786 return ERR_INVALID_HANDLE; 1078 return ERR_INVALID_HANDLE;
787 } 1079 }
788 auto vma = process->VMManager().FindVMA(addr); 1080 auto vma = process->VMManager().FindVMA(addr);
@@ -798,8 +1090,6 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i
798 memory_info->size = vma->second.size; 1090 memory_info->size = vma->second.size;
799 memory_info->type = static_cast<u32>(vma->second.meminfo_state); 1091 memory_info->type = static_cast<u32>(vma->second.meminfo_state);
800 } 1092 }
801
802 LOG_TRACE(Kernel_SVC, "called process=0x{:08X} addr={:X}", process_handle, addr);
803 return RESULT_SUCCESS; 1093 return RESULT_SUCCESS;
804} 1094}
805 1095
@@ -828,15 +1118,18 @@ static void ExitProcess() {
828/// Creates a new thread 1118/// Creates a new thread
829static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top, 1119static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top,
830 u32 priority, s32 processor_id) { 1120 u32 priority, s32 processor_id) {
1121 LOG_TRACE(Kernel_SVC,
1122 "called entrypoint=0x{:08X}, arg=0x{:08X}, stacktop=0x{:08X}, "
1123 "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}",
1124 entry_point, arg, stack_top, priority, processor_id, *out_handle);
1125
831 if (priority > THREADPRIO_LOWEST) { 1126 if (priority > THREADPRIO_LOWEST) {
1127 LOG_ERROR(Kernel_SVC, "An invalid priority was specified, expected {} but got {}",
1128 THREADPRIO_LOWEST, priority);
832 return ERR_INVALID_THREAD_PRIORITY; 1129 return ERR_INVALID_THREAD_PRIORITY;
833 } 1130 }
834 1131
835 auto* const current_process = Core::CurrentProcess(); 1132 auto* const current_process = Core::CurrentProcess();
836 const ResourceLimit& resource_limit = current_process->GetResourceLimit();
837 if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) {
838 return ERR_INVALID_THREAD_PRIORITY;
839 }
840 1133
841 if (processor_id == THREADPROCESSORID_DEFAULT) { 1134 if (processor_id == THREADPROCESSORID_DEFAULT) {
842 // Set the target CPU to the one specified in the process' exheader. 1135 // Set the target CPU to the one specified in the process' exheader.
@@ -863,6 +1156,8 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
863 1156
864 const auto new_guest_handle = current_process->GetHandleTable().Create(thread); 1157 const auto new_guest_handle = current_process->GetHandleTable().Create(thread);
865 if (new_guest_handle.Failed()) { 1158 if (new_guest_handle.Failed()) {
1159 LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}",
1160 new_guest_handle.Code().raw);
866 return new_guest_handle.Code(); 1161 return new_guest_handle.Code();
867 } 1162 }
868 thread->SetGuestHandle(*new_guest_handle); 1163 thread->SetGuestHandle(*new_guest_handle);
@@ -870,11 +1165,6 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
870 1165
871 Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule(); 1166 Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule();
872 1167
873 LOG_TRACE(Kernel_SVC,
874 "called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, "
875 "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}",
876 entry_point, name, arg, stack_top, priority, processor_id, *out_handle);
877
878 return RESULT_SUCCESS; 1168 return RESULT_SUCCESS;
879} 1169}
880 1170
@@ -885,6 +1175,8 @@ static ResultCode StartThread(Handle thread_handle) {
885 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 1175 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
886 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); 1176 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
887 if (!thread) { 1177 if (!thread) {
1178 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
1179 thread_handle);
888 return ERR_INVALID_HANDLE; 1180 return ERR_INVALID_HANDLE;
889 } 1181 }
890 1182
@@ -1064,10 +1356,12 @@ static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout
1064 address, type, value, timeout); 1356 address, type, value, timeout);
1065 // If the passed address is a kernel virtual address, return invalid memory state. 1357 // If the passed address is a kernel virtual address, return invalid memory state.
1066 if (Memory::IsKernelVirtualAddress(address)) { 1358 if (Memory::IsKernelVirtualAddress(address)) {
1359 LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address);
1067 return ERR_INVALID_ADDRESS_STATE; 1360 return ERR_INVALID_ADDRESS_STATE;
1068 } 1361 }
1069 // If the address is not properly aligned to 4 bytes, return invalid address. 1362 // If the address is not properly aligned to 4 bytes, return invalid address.
1070 if (address % sizeof(u32) != 0) { 1363 if (!Common::IsWordAligned(address)) {
1364 LOG_ERROR(Kernel_SVC, "Address is not word aligned, address={:016X}", address);
1071 return ERR_INVALID_ADDRESS; 1365 return ERR_INVALID_ADDRESS;
1072 } 1366 }
1073 1367
@@ -1079,6 +1373,10 @@ static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout
1079 case AddressArbiter::ArbitrationType::WaitIfEqual: 1373 case AddressArbiter::ArbitrationType::WaitIfEqual:
1080 return AddressArbiter::WaitForAddressIfEqual(address, value, timeout); 1374 return AddressArbiter::WaitForAddressIfEqual(address, value, timeout);
1081 default: 1375 default:
1376 LOG_ERROR(Kernel_SVC,
1377 "Invalid arbitration type, expected WaitIfLessThan, DecrementAndWaitIfLessThan "
1378 "or WaitIfEqual but got {}",
1379 type);
1082 return ERR_INVALID_ENUM_VALUE; 1380 return ERR_INVALID_ENUM_VALUE;
1083 } 1381 }
1084} 1382}
@@ -1089,10 +1387,12 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to
1089 address, type, value, num_to_wake); 1387 address, type, value, num_to_wake);
1090 // If the passed address is a kernel virtual address, return invalid memory state. 1388 // If the passed address is a kernel virtual address, return invalid memory state.
1091 if (Memory::IsKernelVirtualAddress(address)) { 1389 if (Memory::IsKernelVirtualAddress(address)) {
1390 LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address);
1092 return ERR_INVALID_ADDRESS_STATE; 1391 return ERR_INVALID_ADDRESS_STATE;
1093 } 1392 }
1094 // If the address is not properly aligned to 4 bytes, return invalid address. 1393 // If the address is not properly aligned to 4 bytes, return invalid address.
1095 if (address % sizeof(u32) != 0) { 1394 if (!Common::IsWordAligned(address)) {
1395 LOG_ERROR(Kernel_SVC, "Address is not word aligned, address={:016X}", address);
1096 return ERR_INVALID_ADDRESS; 1396 return ERR_INVALID_ADDRESS;
1097 } 1397 }
1098 1398
@@ -1105,12 +1405,18 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to
1105 return AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, 1405 return AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(address, value,
1106 num_to_wake); 1406 num_to_wake);
1107 default: 1407 default:
1408 LOG_ERROR(Kernel_SVC,
1409 "Invalid signal type, expected Signal, IncrementAndSignalIfEqual "
1410 "or ModifyByWaitingCountAndSignalIfEqual but got {}",
1411 type);
1108 return ERR_INVALID_ENUM_VALUE; 1412 return ERR_INVALID_ENUM_VALUE;
1109 } 1413 }
1110} 1414}
1111 1415
1112/// This returns the total CPU ticks elapsed since the CPU was powered-on 1416/// This returns the total CPU ticks elapsed since the CPU was powered-on
1113static u64 GetSystemTick() { 1417static u64 GetSystemTick() {
1418 LOG_TRACE(Kernel_SVC, "called");
1419
1114 const u64 result{CoreTiming::GetTicks()}; 1420 const u64 result{CoreTiming::GetTicks()};
1115 1421
1116 // Advance time to defeat dumb games that busy-wait for the frame to end. 1422 // Advance time to defeat dumb games that busy-wait for the frame to end.
@@ -1129,10 +1435,10 @@ static ResultCode CloseHandle(Handle handle) {
1129 1435
1130/// Reset an event 1436/// Reset an event
1131static ResultCode ResetSignal(Handle handle) { 1437static ResultCode ResetSignal(Handle handle) {
1132 LOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x{:08X}", handle); 1438 LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle);
1133 1439
1134 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 1440 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1135 auto event = handle_table.Get<Event>(handle); 1441 auto event = handle_table.Get<ReadableEvent>(handle);
1136 1442
1137 ASSERT(event != nullptr); 1443 ASSERT(event != nullptr);
1138 1444
@@ -1142,9 +1448,39 @@ static ResultCode ResetSignal(Handle handle) {
1142 1448
1143/// Creates a TransferMemory object 1449/// Creates a TransferMemory object
1144static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 permissions) { 1450static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32 permissions) {
1145 LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size, 1451 LOG_DEBUG(Kernel_SVC, "called addr=0x{:X}, size=0x{:X}, perms=0x{:08X}", addr, size,
1146 permissions); 1452 permissions);
1147 *handle = 0; 1453
1454 if (!Common::Is4KBAligned(addr)) {
1455 LOG_ERROR(Kernel_SVC, "Address ({:016X}) is not page aligned!", addr);
1456 return ERR_INVALID_ADDRESS;
1457 }
1458
1459 if (!Common::Is4KBAligned(size) || size == 0) {
1460 LOG_ERROR(Kernel_SVC, "Size ({:016X}) is not page aligned or equal to zero!", size);
1461 return ERR_INVALID_ADDRESS;
1462 }
1463
1464 if (!IsValidAddressRange(addr, size)) {
1465 LOG_ERROR(Kernel_SVC, "Address and size cause overflow! (address={:016X}, size={:016X})",
1466 addr, size);
1467 return ERR_INVALID_ADDRESS_STATE;
1468 }
1469
1470 const auto perms = static_cast<MemoryPermission>(permissions);
1471 if (perms != MemoryPermission::None && perms != MemoryPermission::Read &&
1472 perms != MemoryPermission::ReadWrite) {
1473 LOG_ERROR(Kernel_SVC, "Invalid memory permissions for transfer memory! (perms={:08X})",
1474 permissions);
1475 return ERR_INVALID_MEMORY_PERMISSIONS;
1476 }
1477
1478 auto& kernel = Core::System::GetInstance().Kernel();
1479 auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1480 const auto shared_mem_handle = SharedMemory::Create(
1481 kernel, handle_table.Get<Process>(CurrentProcess), size, perms, perms, addr);
1482
1483 CASCADE_RESULT(*handle, handle_table.Create(shared_mem_handle));
1148 return RESULT_SUCCESS; 1484 return RESULT_SUCCESS;
1149} 1485}
1150 1486
@@ -1154,6 +1490,8 @@ static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask)
1154 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 1490 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1155 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); 1491 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
1156 if (!thread) { 1492 if (!thread) {
1493 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
1494 thread_handle);
1157 return ERR_INVALID_HANDLE; 1495 return ERR_INVALID_HANDLE;
1158 } 1496 }
1159 1497
@@ -1164,12 +1502,14 @@ static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask)
1164} 1502}
1165 1503
1166static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { 1504static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
1167 LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle, 1505 LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:016X}, core=0x{:X}", thread_handle,
1168 mask, core); 1506 mask, core);
1169 1507
1170 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 1508 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1171 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); 1509 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
1172 if (!thread) { 1510 if (!thread) {
1511 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}",
1512 thread_handle);
1173 return ERR_INVALID_HANDLE; 1513 return ERR_INVALID_HANDLE;
1174 } 1514 }
1175 1515
@@ -1184,7 +1524,8 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
1184 } 1524 }
1185 1525
1186 if (mask == 0) { 1526 if (mask == 0) {
1187 return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination); 1527 LOG_ERROR(Kernel_SVC, "Mask is 0");
1528 return ERR_INVALID_COMBINATION;
1188 } 1529 }
1189 1530
1190 /// This value is used to only change the affinity mask without changing the current ideal core. 1531 /// This value is used to only change the affinity mask without changing the current ideal core.
@@ -1193,12 +1534,15 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
1193 if (core == OnlyChangeMask) { 1534 if (core == OnlyChangeMask) {
1194 core = thread->GetIdealCore(); 1535 core = thread->GetIdealCore();
1195 } else if (core >= Core::NUM_CPU_CORES && core != static_cast<u32>(-1)) { 1536 } else if (core >= Core::NUM_CPU_CORES && core != static_cast<u32>(-1)) {
1196 return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidProcessorId); 1537 LOG_ERROR(Kernel_SVC, "Invalid core specified, got {}", core);
1538 return ERR_INVALID_PROCESSOR_ID;
1197 } 1539 }
1198 1540
1199 // Error out if the input core isn't enabled in the input mask. 1541 // Error out if the input core isn't enabled in the input mask.
1200 if (core < Core::NUM_CPU_CORES && (mask & (1ull << core)) == 0) { 1542 if (core < Core::NUM_CPU_CORES && (mask & (1ull << core)) == 0) {
1201 return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination); 1543 LOG_ERROR(Kernel_SVC, "Core is not enabled for the current mask, core={}, mask={:016X}",
1544 core, mask);
1545 return ERR_INVALID_COMBINATION;
1202 } 1546 }
1203 1547
1204 thread->ChangeCore(core, mask); 1548 thread->ChangeCore(core, mask);
@@ -1210,21 +1554,36 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
1210 u32 remote_permissions) { 1554 u32 remote_permissions) {
1211 LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, 1555 LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size,
1212 local_permissions, remote_permissions); 1556 local_permissions, remote_permissions);
1557 if (size == 0) {
1558 LOG_ERROR(Kernel_SVC, "Size is 0");
1559 return ERR_INVALID_SIZE;
1560 }
1561 if (!Common::Is4KBAligned(size)) {
1562 LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:016X}", size);
1563 return ERR_INVALID_SIZE;
1564 }
1213 1565
1214 // Size must be a multiple of 4KB and be less than or equal to 1566 if (size >= MAIN_MEMORY_SIZE) {
1215 // approx. 8 GB (actually (1GB - 512B) * 8) 1567 LOG_ERROR(Kernel_SVC, "Size is not less than 8GB, 0x{:016X}", size);
1216 if (size == 0 || (size & 0xFFFFFFFE00000FFF) != 0) {
1217 return ERR_INVALID_SIZE; 1568 return ERR_INVALID_SIZE;
1218 } 1569 }
1219 1570
1220 const auto local_perms = static_cast<MemoryPermission>(local_permissions); 1571 const auto local_perms = static_cast<MemoryPermission>(local_permissions);
1221 if (local_perms != MemoryPermission::Read && local_perms != MemoryPermission::ReadWrite) { 1572 if (local_perms != MemoryPermission::Read && local_perms != MemoryPermission::ReadWrite) {
1573 LOG_ERROR(Kernel_SVC,
1574 "Invalid local memory permissions, expected Read or ReadWrite but got "
1575 "local_permissions={}",
1576 static_cast<u32>(local_permissions));
1222 return ERR_INVALID_MEMORY_PERMISSIONS; 1577 return ERR_INVALID_MEMORY_PERMISSIONS;
1223 } 1578 }
1224 1579
1225 const auto remote_perms = static_cast<MemoryPermission>(remote_permissions); 1580 const auto remote_perms = static_cast<MemoryPermission>(remote_permissions);
1226 if (remote_perms != MemoryPermission::Read && remote_perms != MemoryPermission::ReadWrite && 1581 if (remote_perms != MemoryPermission::Read && remote_perms != MemoryPermission::ReadWrite &&
1227 remote_perms != MemoryPermission::DontCare) { 1582 remote_perms != MemoryPermission::DontCare) {
1583 LOG_ERROR(Kernel_SVC,
1584 "Invalid remote memory permissions, expected Read, ReadWrite or DontCare but got "
1585 "remote_permissions={}",
1586 static_cast<u32>(remote_permissions));
1228 return ERR_INVALID_MEMORY_PERMISSIONS; 1587 return ERR_INVALID_MEMORY_PERMISSIONS;
1229 } 1588 }
1230 1589
@@ -1238,16 +1597,67 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
1238 return RESULT_SUCCESS; 1597 return RESULT_SUCCESS;
1239} 1598}
1240 1599
1600static ResultCode CreateEvent(Handle* write_handle, Handle* read_handle) {
1601 LOG_DEBUG(Kernel_SVC, "called");
1602
1603 auto& kernel = Core::System::GetInstance().Kernel();
1604 const auto [readable_event, writable_event] =
1605 WritableEvent::CreateEventPair(kernel, ResetType::Sticky, "CreateEvent");
1606
1607 HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable();
1608
1609 const auto write_create_result = handle_table.Create(writable_event);
1610 if (write_create_result.Failed()) {
1611 return write_create_result.Code();
1612 }
1613 *write_handle = *write_create_result;
1614
1615 const auto read_create_result = handle_table.Create(readable_event);
1616 if (read_create_result.Failed()) {
1617 handle_table.Close(*write_create_result);
1618 return read_create_result.Code();
1619 }
1620 *read_handle = *read_create_result;
1621
1622 LOG_DEBUG(Kernel_SVC,
1623 "successful. Writable event handle=0x{:08X}, Readable event handle=0x{:08X}",
1624 *write_create_result, *read_create_result);
1625 return RESULT_SUCCESS;
1626}
1627
1241static ResultCode ClearEvent(Handle handle) { 1628static ResultCode ClearEvent(Handle handle) {
1242 LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle); 1629 LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle);
1243 1630
1244 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 1631 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1245 SharedPtr<Event> evt = handle_table.Get<Event>(handle); 1632
1246 if (evt == nullptr) { 1633 auto writable_event = handle_table.Get<WritableEvent>(handle);
1634 if (writable_event) {
1635 writable_event->Clear();
1636 return RESULT_SUCCESS;
1637 }
1638
1639 auto readable_event = handle_table.Get<ReadableEvent>(handle);
1640 if (readable_event) {
1641 readable_event->Clear();
1642 return RESULT_SUCCESS;
1643 }
1644
1645 LOG_ERROR(Kernel_SVC, "Event handle does not exist, handle=0x{:08X}", handle);
1646 return ERR_INVALID_HANDLE;
1647}
1648
1649static ResultCode SignalEvent(Handle handle) {
1650 LOG_DEBUG(Kernel_SVC, "called. Handle=0x{:08X}", handle);
1651
1652 HandleTable& handle_table = Core::CurrentProcess()->GetHandleTable();
1653 auto writable_event = handle_table.Get<WritableEvent>(handle);
1654
1655 if (!writable_event) {
1656 LOG_ERROR(Kernel_SVC, "Non-existent writable event handle used (0x{:08X})", handle);
1247 return ERR_INVALID_HANDLE; 1657 return ERR_INVALID_HANDLE;
1248 } 1658 }
1249 1659
1250 evt->Clear(); 1660 writable_event->Signal();
1251 return RESULT_SUCCESS; 1661 return RESULT_SUCCESS;
1252} 1662}
1253 1663
@@ -1262,11 +1672,14 @@ static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) {
1262 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 1672 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1263 const auto process = handle_table.Get<Process>(process_handle); 1673 const auto process = handle_table.Get<Process>(process_handle);
1264 if (!process) { 1674 if (!process) {
1675 LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}",
1676 process_handle);
1265 return ERR_INVALID_HANDLE; 1677 return ERR_INVALID_HANDLE;
1266 } 1678 }
1267 1679
1268 const auto info_type = static_cast<InfoType>(type); 1680 const auto info_type = static_cast<InfoType>(type);
1269 if (info_type != InfoType::Status) { 1681 if (info_type != InfoType::Status) {
1682 LOG_ERROR(Kernel_SVC, "Expected info_type to be Status but got {} instead", type);
1270 return ERR_INVALID_ENUM_VALUE; 1683 return ERR_INVALID_ENUM_VALUE;
1271 } 1684 }
1272 1685
@@ -1274,6 +1687,87 @@ static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) {
1274 return RESULT_SUCCESS; 1687 return RESULT_SUCCESS;
1275} 1688}
1276 1689
1690static ResultCode CreateResourceLimit(Handle* out_handle) {
1691 LOG_DEBUG(Kernel_SVC, "called");
1692
1693 auto& kernel = Core::System::GetInstance().Kernel();
1694 auto resource_limit = ResourceLimit::Create(kernel);
1695
1696 auto* const current_process = kernel.CurrentProcess();
1697 ASSERT(current_process != nullptr);
1698
1699 const auto handle = current_process->GetHandleTable().Create(std::move(resource_limit));
1700 if (handle.Failed()) {
1701 return handle.Code();
1702 }
1703
1704 *out_handle = *handle;
1705 return RESULT_SUCCESS;
1706}
1707
1708static ResultCode GetResourceLimitLimitValue(u64* out_value, Handle resource_limit,
1709 u32 resource_type) {
1710 LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type);
1711
1712 const auto limit_value = RetrieveResourceLimitValue(resource_limit, resource_type,
1713 ResourceLimitValueType::LimitValue);
1714 if (limit_value.Failed()) {
1715 return limit_value.Code();
1716 }
1717
1718 *out_value = static_cast<u64>(*limit_value);
1719 return RESULT_SUCCESS;
1720}
1721
1722static ResultCode GetResourceLimitCurrentValue(u64* out_value, Handle resource_limit,
1723 u32 resource_type) {
1724 LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type);
1725
1726 const auto current_value = RetrieveResourceLimitValue(resource_limit, resource_type,
1727 ResourceLimitValueType::CurrentValue);
1728 if (current_value.Failed()) {
1729 return current_value.Code();
1730 }
1731
1732 *out_value = static_cast<u64>(*current_value);
1733 return RESULT_SUCCESS;
1734}
1735
1736static ResultCode SetResourceLimitLimitValue(Handle resource_limit, u32 resource_type, u64 value) {
1737 LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit,
1738 resource_type, value);
1739
1740 const auto type = static_cast<ResourceType>(resource_type);
1741 if (!IsValidResourceType(type)) {
1742 LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type);
1743 return ERR_INVALID_ENUM_VALUE;
1744 }
1745
1746 auto& kernel = Core::System::GetInstance().Kernel();
1747 auto* const current_process = kernel.CurrentProcess();
1748 ASSERT(current_process != nullptr);
1749
1750 auto resource_limit_object =
1751 current_process->GetHandleTable().Get<ResourceLimit>(resource_limit);
1752 if (!resource_limit_object) {
1753 LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}",
1754 resource_limit);
1755 return ERR_INVALID_HANDLE;
1756 }
1757
1758 const auto set_result = resource_limit_object->SetLimitValue(type, static_cast<s64>(value));
1759 if (set_result.IsError()) {
1760 LOG_ERROR(
1761 Kernel_SVC,
1762 "Attempted to lower resource limit ({}) for category '{}' below its current value ({})",
1763 resource_limit_object->GetMaxResourceValue(type), resource_type,
1764 resource_limit_object->GetCurrentResourceValue(type));
1765 return set_result;
1766 }
1767
1768 return RESULT_SUCCESS;
1769}
1770
1277namespace { 1771namespace {
1278struct FunctionDef { 1772struct FunctionDef {
1279 using Func = void(); 1773 using Func = void();
@@ -1287,7 +1781,7 @@ struct FunctionDef {
1287static const FunctionDef SVC_Table[] = { 1781static const FunctionDef SVC_Table[] = {
1288 {0x00, nullptr, "Unknown"}, 1782 {0x00, nullptr, "Unknown"},
1289 {0x01, SvcWrap<SetHeapSize>, "SetHeapSize"}, 1783 {0x01, SvcWrap<SetHeapSize>, "SetHeapSize"},
1290 {0x02, nullptr, "SetMemoryPermission"}, 1784 {0x02, SvcWrap<SetMemoryPermission>, "SetMemoryPermission"},
1291 {0x03, SvcWrap<SetMemoryAttribute>, "SetMemoryAttribute"}, 1785 {0x03, SvcWrap<SetMemoryAttribute>, "SetMemoryAttribute"},
1292 {0x04, SvcWrap<MapMemory>, "MapMemory"}, 1786 {0x04, SvcWrap<MapMemory>, "MapMemory"},
1293 {0x05, SvcWrap<UnmapMemory>, "UnmapMemory"}, 1787 {0x05, SvcWrap<UnmapMemory>, "UnmapMemory"},
@@ -1302,7 +1796,7 @@ static const FunctionDef SVC_Table[] = {
1302 {0x0E, SvcWrap<GetThreadCoreMask>, "GetThreadCoreMask"}, 1796 {0x0E, SvcWrap<GetThreadCoreMask>, "GetThreadCoreMask"},
1303 {0x0F, SvcWrap<SetThreadCoreMask>, "SetThreadCoreMask"}, 1797 {0x0F, SvcWrap<SetThreadCoreMask>, "SetThreadCoreMask"},
1304 {0x10, SvcWrap<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"}, 1798 {0x10, SvcWrap<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"},
1305 {0x11, nullptr, "SignalEvent"}, 1799 {0x11, SvcWrap<SignalEvent>, "SignalEvent"},
1306 {0x12, SvcWrap<ClearEvent>, "ClearEvent"}, 1800 {0x12, SvcWrap<ClearEvent>, "ClearEvent"},
1307 {0x13, SvcWrap<MapSharedMemory>, "MapSharedMemory"}, 1801 {0x13, SvcWrap<MapSharedMemory>, "MapSharedMemory"},
1308 {0x14, SvcWrap<UnmapSharedMemory>, "UnmapSharedMemory"}, 1802 {0x14, SvcWrap<UnmapSharedMemory>, "UnmapSharedMemory"},
@@ -1333,8 +1827,8 @@ static const FunctionDef SVC_Table[] = {
1333 {0x2D, nullptr, "UnmapPhysicalMemory"}, 1827 {0x2D, nullptr, "UnmapPhysicalMemory"},
1334 {0x2E, nullptr, "GetFutureThreadInfo"}, 1828 {0x2E, nullptr, "GetFutureThreadInfo"},
1335 {0x2F, nullptr, "GetLastThreadInfo"}, 1829 {0x2F, nullptr, "GetLastThreadInfo"},
1336 {0x30, nullptr, "GetResourceLimitLimitValue"}, 1830 {0x30, SvcWrap<GetResourceLimitLimitValue>, "GetResourceLimitLimitValue"},
1337 {0x31, nullptr, "GetResourceLimitCurrentValue"}, 1831 {0x31, SvcWrap<GetResourceLimitCurrentValue>, "GetResourceLimitCurrentValue"},
1338 {0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"}, 1832 {0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"},
1339 {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"}, 1833 {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"},
1340 {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"}, 1834 {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"},
@@ -1354,7 +1848,7 @@ static const FunctionDef SVC_Table[] = {
1354 {0x42, nullptr, "ReplyAndReceiveLight"}, 1848 {0x42, nullptr, "ReplyAndReceiveLight"},
1355 {0x43, nullptr, "ReplyAndReceive"}, 1849 {0x43, nullptr, "ReplyAndReceive"},
1356 {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"}, 1850 {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"},
1357 {0x45, nullptr, "CreateEvent"}, 1851 {0x45, SvcWrap<CreateEvent>, "CreateEvent"},
1358 {0x46, nullptr, "Unknown"}, 1852 {0x46, nullptr, "Unknown"},
1359 {0x47, nullptr, "Unknown"}, 1853 {0x47, nullptr, "Unknown"},
1360 {0x48, nullptr, "MapPhysicalMemoryUnsafe"}, 1854 {0x48, nullptr, "MapPhysicalMemoryUnsafe"},
@@ -1410,8 +1904,8 @@ static const FunctionDef SVC_Table[] = {
1410 {0x7A, nullptr, "StartProcess"}, 1904 {0x7A, nullptr, "StartProcess"},
1411 {0x7B, nullptr, "TerminateProcess"}, 1905 {0x7B, nullptr, "TerminateProcess"},
1412 {0x7C, SvcWrap<GetProcessInfo>, "GetProcessInfo"}, 1906 {0x7C, SvcWrap<GetProcessInfo>, "GetProcessInfo"},
1413 {0x7D, nullptr, "CreateResourceLimit"}, 1907 {0x7D, SvcWrap<CreateResourceLimit>, "CreateResourceLimit"},
1414 {0x7E, nullptr, "SetResourceLimitLimitValue"}, 1908 {0x7E, SvcWrap<SetResourceLimitLimitValue>, "SetResourceLimitLimitValue"},
1415 {0x7F, nullptr, "CallSecureMonitor"}, 1909 {0x7F, nullptr, "CallSecureMonitor"},
1416}; 1910};
1417 1911
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index b09753c80..24aef46c9 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -43,6 +43,14 @@ void SvcWrap() {
43 FuncReturn(func(static_cast<u32>(Param(0)), static_cast<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*)>
47void SvcWrap() {
48 u32 param = 0;
49 const u32 retval = func(&param).raw;
50 Core::CurrentArmInterface().SetReg(1, param);
51 FuncReturn(retval);
52}
53
46template <ResultCode func(u32*, u32)> 54template <ResultCode func(u32*, u32)>
47void SvcWrap() { 55void SvcWrap() {
48 u32 param_1 = 0; 56 u32 param_1 = 0;
@@ -51,6 +59,19 @@ void SvcWrap() {
51 FuncReturn(retval); 59 FuncReturn(retval);
52} 60}
53 61
62template <ResultCode func(u32*, u32*)>
63void SvcWrap() {
64 u32 param_1 = 0;
65 u32 param_2 = 0;
66 const u32 retval = func(&param_1, &param_2).raw;
67
68 auto& arm_interface = Core::CurrentArmInterface();
69 arm_interface.SetReg(1, param_1);
70 arm_interface.SetReg(2, param_2);
71
72 FuncReturn(retval);
73}
74
54template <ResultCode func(u32*, u64)> 75template <ResultCode func(u32*, u64)>
55void SvcWrap() { 76void SvcWrap() {
56 u32 param_1 = 0; 77 u32 param_1 = 0;
@@ -121,6 +142,11 @@ void SvcWrap() {
121 FuncReturn(func(Param(0), Param(1), Param(2)).raw); 142 FuncReturn(func(Param(0), Param(1), Param(2)).raw);
122} 143}
123 144
145template <ResultCode func(u64, u64, u32)>
146void SvcWrap() {
147 FuncReturn(func(Param(0), Param(1), static_cast<u32>(Param(2))).raw);
148}
149
124template <ResultCode func(u32, u64, u64, u32)> 150template <ResultCode func(u32, u64, u64, u32)>
125void SvcWrap() { 151void SvcWrap() {
126 FuncReturn( 152 FuncReturn(
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index dd5cd9ced..4ffb76818 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -142,36 +142,7 @@ void Thread::ResumeFromWait() {
142 142
143 status = ThreadStatus::Ready; 143 status = ThreadStatus::Ready;
144 144
145 std::optional<s32> new_processor_id = GetNextProcessorId(affinity_mask); 145 ChangeScheduler();
146 if (!new_processor_id) {
147 new_processor_id = processor_id;
148 }
149 if (ideal_core != -1 &&
150 Core::System::GetInstance().Scheduler(ideal_core).GetCurrentThread() == nullptr) {
151 new_processor_id = ideal_core;
152 }
153
154 ASSERT(*new_processor_id < 4);
155
156 // Add thread to new core's scheduler
157 auto* next_scheduler = &Core::System::GetInstance().Scheduler(*new_processor_id);
158
159 if (*new_processor_id != processor_id) {
160 // Remove thread from previous core's scheduler
161 scheduler->RemoveThread(this);
162 next_scheduler->AddThread(this, current_priority);
163 }
164
165 processor_id = *new_processor_id;
166
167 // If the thread was ready, unschedule from the previous core and schedule on the new core
168 scheduler->UnscheduleThread(this, current_priority);
169 next_scheduler->ScheduleThread(this, current_priority);
170
171 // Change thread's scheduler
172 scheduler = next_scheduler;
173
174 Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule();
175} 146}
176 147
177/** 148/**
@@ -364,42 +335,45 @@ void Thread::UpdatePriority() {
364void Thread::ChangeCore(u32 core, u64 mask) { 335void Thread::ChangeCore(u32 core, u64 mask) {
365 ideal_core = core; 336 ideal_core = core;
366 affinity_mask = mask; 337 affinity_mask = mask;
338 ChangeScheduler();
339}
367 340
341void Thread::ChangeScheduler() {
368 if (status != ThreadStatus::Ready) { 342 if (status != ThreadStatus::Ready) {
369 return; 343 return;
370 } 344 }
371 345
346 auto& system = Core::System::GetInstance();
372 std::optional<s32> new_processor_id{GetNextProcessorId(affinity_mask)}; 347 std::optional<s32> new_processor_id{GetNextProcessorId(affinity_mask)};
373 348
374 if (!new_processor_id) { 349 if (!new_processor_id) {
375 new_processor_id = processor_id; 350 new_processor_id = processor_id;
376 } 351 }
377 if (ideal_core != -1 && 352 if (ideal_core != -1 && system.Scheduler(ideal_core).GetCurrentThread() == nullptr) {
378 Core::System::GetInstance().Scheduler(ideal_core).GetCurrentThread() == nullptr) {
379 new_processor_id = ideal_core; 353 new_processor_id = ideal_core;
380 } 354 }
381 355
382 ASSERT(*new_processor_id < 4); 356 ASSERT(*new_processor_id < 4);
383 357
384 // Add thread to new core's scheduler 358 // Add thread to new core's scheduler
385 auto* next_scheduler = &Core::System::GetInstance().Scheduler(*new_processor_id); 359 auto& next_scheduler = system.Scheduler(*new_processor_id);
386 360
387 if (*new_processor_id != processor_id) { 361 if (*new_processor_id != processor_id) {
388 // Remove thread from previous core's scheduler 362 // Remove thread from previous core's scheduler
389 scheduler->RemoveThread(this); 363 scheduler->RemoveThread(this);
390 next_scheduler->AddThread(this, current_priority); 364 next_scheduler.AddThread(this, current_priority);
391 } 365 }
392 366
393 processor_id = *new_processor_id; 367 processor_id = *new_processor_id;
394 368
395 // If the thread was ready, unschedule from the previous core and schedule on the new core 369 // If the thread was ready, unschedule from the previous core and schedule on the new core
396 scheduler->UnscheduleThread(this, current_priority); 370 scheduler->UnscheduleThread(this, current_priority);
397 next_scheduler->ScheduleThread(this, current_priority); 371 next_scheduler.ScheduleThread(this, current_priority);
398 372
399 // Change thread's scheduler 373 // Change thread's scheduler
400 scheduler = next_scheduler; 374 scheduler = &next_scheduler;
401 375
402 Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); 376 system.CpuCore(processor_id).PrepareReschedule();
403} 377}
404 378
405bool Thread::AllWaitObjectsReady() { 379bool Thread::AllWaitObjectsReady() {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 4a6e11239..d384d50db 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -374,6 +374,8 @@ private:
374 explicit Thread(KernelCore& kernel); 374 explicit Thread(KernelCore& kernel);
375 ~Thread() override; 375 ~Thread() override;
376 376
377 void ChangeScheduler();
378
377 Core::ARM_Interface::ThreadContext context{}; 379 Core::ARM_Interface::ThreadContext context{};
378 380
379 u32 thread_id = 0; 381 u32 thread_id = 0;
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 1a92c8f70..100f8f6bf 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -243,6 +243,85 @@ ResultCode VMManager::ReprotectRange(VAddr target, u64 size, VMAPermission new_p
243 return RESULT_SUCCESS; 243 return RESULT_SUCCESS;
244} 244}
245 245
246ResultVal<VAddr> VMManager::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
247 if (target < GetHeapRegionBaseAddress() || target + size > GetHeapRegionEndAddress() ||
248 target + size < target) {
249 return ERR_INVALID_ADDRESS;
250 }
251
252 if (heap_memory == nullptr) {
253 // Initialize heap
254 heap_memory = std::make_shared<std::vector<u8>>();
255 heap_start = heap_end = target;
256 } else {
257 UnmapRange(heap_start, heap_end - heap_start);
258 }
259
260 // If necessary, expand backing vector to cover new heap extents.
261 if (target < heap_start) {
262 heap_memory->insert(begin(*heap_memory), heap_start - target, 0);
263 heap_start = target;
264 RefreshMemoryBlockMappings(heap_memory.get());
265 }
266 if (target + size > heap_end) {
267 heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0);
268 heap_end = target + size;
269 RefreshMemoryBlockMappings(heap_memory.get());
270 }
271 ASSERT(heap_end - heap_start == heap_memory->size());
272
273 CASCADE_RESULT(auto vma, MapMemoryBlock(target, heap_memory, target - heap_start, size,
274 MemoryState::Heap));
275 Reprotect(vma, perms);
276
277 heap_used = size;
278
279 return MakeResult<VAddr>(heap_end - size);
280}
281
282ResultCode VMManager::HeapFree(VAddr target, u64 size) {
283 if (target < GetHeapRegionBaseAddress() || target + size > GetHeapRegionEndAddress() ||
284 target + size < target) {
285 return ERR_INVALID_ADDRESS;
286 }
287
288 if (size == 0) {
289 return RESULT_SUCCESS;
290 }
291
292 const ResultCode result = UnmapRange(target, size);
293 if (result.IsError()) {
294 return result;
295 }
296
297 heap_used -= size;
298 return RESULT_SUCCESS;
299}
300
301ResultCode VMManager::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state) {
302 const auto vma = FindVMA(src_addr);
303
304 ASSERT_MSG(vma != vma_map.end(), "Invalid memory address");
305 ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address");
306
307 // The returned VMA might be a bigger one encompassing the desired address.
308 const auto vma_offset = src_addr - vma->first;
309 ASSERT_MSG(vma_offset + size <= vma->second.size,
310 "Shared memory exceeds bounds of mapped block");
311
312 const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block;
313 const std::size_t backing_block_offset = vma->second.offset + vma_offset;
314
315 CASCADE_RESULT(auto new_vma,
316 MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size, state));
317 // Protect mirror with permissions from old region
318 Reprotect(new_vma, vma->second.permissions);
319 // Remove permissions from old region
320 Reprotect(vma, VMAPermission::None);
321
322 return RESULT_SUCCESS;
323}
324
246void VMManager::RefreshMemoryBlockMappings(const std::vector<u8>* block) { 325void VMManager::RefreshMemoryBlockMappings(const std::vector<u8>* block) {
247 // If this ever proves to have a noticeable performance impact, allow users of the function to 326 // If this ever proves to have a noticeable performance impact, allow users of the function to
248 // specify a specific range of addresses to limit the scan to. 327 // specify a specific range of addresses to limit the scan to.
@@ -495,8 +574,7 @@ u64 VMManager::GetTotalMemoryUsage() const {
495} 574}
496 575
497u64 VMManager::GetTotalHeapUsage() const { 576u64 VMManager::GetTotalHeapUsage() const {
498 LOG_WARNING(Kernel, "(STUBBED) called"); 577 return heap_used;
499 return 0x0;
500} 578}
501 579
502VAddr VMManager::GetAddressSpaceBaseAddress() const { 580VAddr VMManager::GetAddressSpaceBaseAddress() const {
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 2447cbb8f..d522404fe 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -186,6 +186,12 @@ public:
186 /// Changes the permissions of a range of addresses, splitting VMAs as necessary. 186 /// Changes the permissions of a range of addresses, splitting VMAs as necessary.
187 ResultCode ReprotectRange(VAddr target, u64 size, VMAPermission new_perms); 187 ResultCode ReprotectRange(VAddr target, u64 size, VMAPermission new_perms);
188 188
189 ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
190 ResultCode HeapFree(VAddr target, u64 size);
191
192 ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size,
193 MemoryState state = MemoryState::Mapped);
194
189 /** 195 /**
190 * Scans all VMAs and updates the page table range of any that use the given vector as backing 196 * Scans all VMAs and updates the page table range of any that use the given vector as backing
191 * memory. This should be called after any operation that causes reallocation of the vector. 197 * memory. This should be called after any operation that causes reallocation of the vector.
@@ -343,5 +349,15 @@ private:
343 349
344 VAddr tls_io_region_base = 0; 350 VAddr tls_io_region_base = 0;
345 VAddr tls_io_region_end = 0; 351 VAddr tls_io_region_end = 0;
352
353 // Memory used to back the allocations in the regular heap. A single vector is used to cover
354 // the entire virtual address space extents that bound the allocations, including any holes.
355 // This makes deallocation and reallocation of holes fast and keeps process memory contiguous
356 // in the emulator address space, allowing Memory::GetPointer to be reasonably safe.
357 std::shared_ptr<std::vector<u8>> heap_memory;
358 // The left/right bounds of the address space covered by heap_memory.
359 VAddr heap_start = 0;
360 VAddr heap_end = 0;
361 u64 heap_used = 0;
346}; 362};
347} // namespace Kernel 363} // namespace Kernel
diff --git a/src/core/hle/kernel/writable_event.cpp b/src/core/hle/kernel/writable_event.cpp
new file mode 100644
index 000000000..a58ea6ec8
--- /dev/null
+++ b/src/core/hle/kernel/writable_event.cpp
@@ -0,0 +1,52 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include "common/assert.h"
7#include "core/hle/kernel/kernel.h"
8#include "core/hle/kernel/object.h"
9#include "core/hle/kernel/readable_event.h"
10#include "core/hle/kernel/thread.h"
11#include "core/hle/kernel/writable_event.h"
12
13namespace Kernel {
14
15WritableEvent::WritableEvent(KernelCore& kernel) : Object{kernel} {}
16WritableEvent::~WritableEvent() = default;
17
18EventPair WritableEvent::CreateEventPair(KernelCore& kernel, ResetType reset_type,
19 std::string name) {
20 SharedPtr<WritableEvent> writable_event(new WritableEvent(kernel));
21 SharedPtr<ReadableEvent> readable_event(new ReadableEvent(kernel));
22
23 writable_event->name = name + ":Writable";
24 writable_event->readable = readable_event;
25 readable_event->name = name + ":Readable";
26 readable_event->signaled = false;
27 readable_event->reset_type = reset_type;
28
29 return {std::move(readable_event), std::move(writable_event)};
30}
31
32SharedPtr<ReadableEvent> WritableEvent::GetReadableEvent() const {
33 return readable;
34}
35
36ResetType WritableEvent::GetResetType() const {
37 return readable->reset_type;
38}
39
40void WritableEvent::Signal() {
41 readable->Signal();
42}
43
44void WritableEvent::Clear() {
45 readable->Clear();
46}
47
48bool WritableEvent::IsSignaled() const {
49 return readable->signaled;
50}
51
52} // namespace Kernel
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/writable_event.h
index 27d6126b0..8fa8d68ee 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/writable_event.h
@@ -11,49 +11,52 @@
11namespace Kernel { 11namespace Kernel {
12 12
13class KernelCore; 13class KernelCore;
14class ReadableEvent;
15class WritableEvent;
14 16
15class Event final : public WaitObject { 17struct EventPair {
18 SharedPtr<ReadableEvent> readable;
19 SharedPtr<WritableEvent> writable;
20};
21
22class WritableEvent final : public Object {
16public: 23public:
24 ~WritableEvent() override;
25
17 /** 26 /**
18 * Creates an event 27 * Creates an event
19 * @param kernel The kernel instance to create this event under. 28 * @param kernel The kernel instance to create this event under.
20 * @param reset_type ResetType describing how to create event 29 * @param reset_type ResetType describing how to create event
21 * @param name Optional name of event 30 * @param name Optional name of event
22 */ 31 */
23 static SharedPtr<Event> Create(KernelCore& kernel, ResetType reset_type, 32 static EventPair CreateEventPair(KernelCore& kernel, ResetType reset_type,
24 std::string name = "Unknown"); 33 std::string name = "Unknown");
25 34
26 std::string GetTypeName() const override { 35 std::string GetTypeName() const override {
27 return "Event"; 36 return "WritableEvent";
28 } 37 }
29 std::string GetName() const override { 38 std::string GetName() const override {
30 return name; 39 return name;
31 } 40 }
32 41
33 static const HandleType HANDLE_TYPE = HandleType::Event; 42 static const HandleType HANDLE_TYPE = HandleType::WritableEvent;
34 HandleType GetHandleType() const override { 43 HandleType GetHandleType() const override {
35 return HANDLE_TYPE; 44 return HANDLE_TYPE;
36 } 45 }
37 46
38 ResetType GetResetType() const { 47 SharedPtr<ReadableEvent> GetReadableEvent() const;
39 return reset_type;
40 }
41
42 bool ShouldWait(Thread* thread) const override;
43 void Acquire(Thread* thread) override;
44 48
45 void WakeupAllWaitingThreads() override; 49 ResetType GetResetType() const;
46 50
47 void Signal(); 51 void Signal();
48 void Clear(); 52 void Clear();
53 bool IsSignaled() const;
49 54
50private: 55private:
51 explicit Event(KernelCore& kernel); 56 explicit WritableEvent(KernelCore& kernel);
52 ~Event() override;
53 57
54 ResetType reset_type; ///< Current ResetType 58 SharedPtr<ReadableEvent> readable;
55 59
56 bool signaled; ///< Whether the event has already been signaled
57 std::string name; ///< Name of event (optional) 60 std::string name; ///< Name of event (optional)
58}; 61};
59 62
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index c6b18cfba..bfb77cc31 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -19,8 +19,6 @@
19enum class ErrorDescription : u32 { 19enum class ErrorDescription : u32 {
20 Success = 0, 20 Success = 0,
21 RemoteProcessDead = 301, 21 RemoteProcessDead = 301,
22 InvalidOffset = 6061,
23 InvalidLength = 6062,
24}; 22};
25 23
26/** 24/**
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 8318eff5f..1f8ed265e 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -21,17 +21,6 @@
21 21
22namespace Service::Account { 22namespace Service::Account {
23 23
24// TODO: RE this structure
25struct UserData {
26 INSERT_PADDING_WORDS(1);
27 u32 icon_id;
28 u8 bg_color_id;
29 INSERT_PADDING_BYTES(0x7);
30 INSERT_PADDING_BYTES(0x10);
31 INSERT_PADDING_BYTES(0x60);
32};
33static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size");
34
35// Smallest JPEG https://github.com/mathiasbynens/small/blob/master/jpeg.jpg 24// Smallest JPEG https://github.com/mathiasbynens/small/blob/master/jpeg.jpg
36// used as a backup should the one on disk not exist 25// used as a backup should the one on disk not exist
37constexpr u32 backup_jpeg_size = 107; 26constexpr u32 backup_jpeg_size = 107;
@@ -72,9 +61,11 @@ private:
72 void Get(Kernel::HLERequestContext& ctx) { 61 void Get(Kernel::HLERequestContext& ctx) {
73 LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); 62 LOG_INFO(Service_ACC, "called user_id={}", user_id.Format());
74 ProfileBase profile_base{}; 63 ProfileBase profile_base{};
75 std::array<u8, MAX_DATA> data{}; 64 ProfileData data{};
76 if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) { 65 if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) {
77 ctx.WriteBuffer(data); 66 std::array<u8, sizeof(ProfileData)> raw_data;
67 std::memcpy(raw_data.data(), &data, sizeof(ProfileData));
68 ctx.WriteBuffer(raw_data);
78 IPC::ResponseBuilder rb{ctx, 16}; 69 IPC::ResponseBuilder rb{ctx, 16};
79 rb.Push(RESULT_SUCCESS); 70 rb.Push(RESULT_SUCCESS);
80 rb.PushRaw(profile_base); 71 rb.PushRaw(profile_base);
@@ -216,10 +207,11 @@ void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) {
216void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) { 207void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) {
217 IPC::RequestParser rp{ctx}; 208 IPC::RequestParser rp{ctx};
218 UUID user_id = rp.PopRaw<UUID>(); 209 UUID user_id = rp.PopRaw<UUID>();
210 LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
211
219 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 212 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
220 rb.Push(RESULT_SUCCESS); 213 rb.Push(RESULT_SUCCESS);
221 rb.PushIpcInterface<IProfile>(user_id, *profile_manager); 214 rb.PushIpcInterface<IProfile>(user_id, *profile_manager);
222 LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format());
223} 215}
224 216
225void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx) { 217void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx) {
@@ -236,10 +228,10 @@ void Module::Interface::InitializeApplicationInfo(Kernel::HLERequestContext& ctx
236} 228}
237 229
238void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) { 230void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) {
231 LOG_DEBUG(Service_ACC, "called");
239 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 232 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
240 rb.Push(RESULT_SUCCESS); 233 rb.Push(RESULT_SUCCESS);
241 rb.PushIpcInterface<IManagerForApplication>(); 234 rb.PushIpcInterface<IManagerForApplication>();
242 LOG_DEBUG(Service_ACC, "called");
243} 235}
244 236
245void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) { 237void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) {
@@ -252,8 +244,10 @@ void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContex
252 rb.PushRaw<u128>(INVALID_UUID); 244 rb.PushRaw<u128>(INVALID_UUID);
253 return; 245 return;
254 } 246 }
255 auto user_list = profile_manager->GetAllUsers(); 247
256 if (user_list.empty()) { 248 const auto user_list = profile_manager->GetAllUsers();
249 if (std::all_of(user_list.begin(), user_list.end(),
250 [](const auto& user) { return user.uuid == INVALID_UUID; })) {
257 rb.Push(ResultCode(-1)); // TODO(ogniK): Find the correct error code 251 rb.Push(ResultCode(-1)); // TODO(ogniK): Find the correct error code
258 rb.PushRaw<u128>(INVALID_UUID); 252 rb.PushRaw<u128>(INVALID_UUID);
259 return; 253 return;
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index c08394e4c..1316d0b07 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -2,8 +2,11 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
5#include <random> 6#include <random>
6 7
8#include <fmt/format.h>
9
7#include "common/file_util.h" 10#include "common/file_util.h"
8#include "core/hle/service/acc/profile_manager.h" 11#include "core/hle/service/acc/profile_manager.h"
9#include "core/settings.h" 12#include "core/settings.h"
@@ -15,7 +18,7 @@ struct UserRaw {
15 UUID uuid2; 18 UUID uuid2;
16 u64 timestamp; 19 u64 timestamp;
17 ProfileUsername username; 20 ProfileUsername username;
18 INSERT_PADDING_BYTES(0x80); 21 ProfileData extra_data;
19}; 22};
20static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size."); 23static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size.");
21 24
@@ -39,6 +42,19 @@ UUID UUID::Generate() {
39 return UUID{distribution(gen), distribution(gen)}; 42 return UUID{distribution(gen), distribution(gen)};
40} 43}
41 44
45std::string UUID::Format() const {
46 return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]);
47}
48
49std::string UUID::FormatSwitch() const {
50 std::array<u8, 16> s{};
51 std::memcpy(s.data(), uuid.data(), sizeof(u128));
52 return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{"
53 ":02x}{:02x}{:02x}{:02x}{:02x}",
54 s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11],
55 s[12], s[13], s[14], s[15]);
56}
57
42ProfileManager::ProfileManager() { 58ProfileManager::ProfileManager() {
43 ParseUserSaveFile(); 59 ParseUserSaveFile();
44 60
@@ -325,11 +341,12 @@ void ProfileManager::ParseUserSaveFile() {
325 return; 341 return;
326 } 342 }
327 343
328 for (std::size_t i = 0; i < MAX_USERS; ++i) { 344 for (const auto& user : data.users) {
329 const auto& user = data.users[i]; 345 if (user.uuid == UUID(INVALID_UUID)) {
346 continue;
347 }
330 348
331 if (user.uuid != UUID(INVALID_UUID)) 349 AddUser({user.uuid, user.username, user.timestamp, user.extra_data, false});
332 AddUser({user.uuid, user.username, user.timestamp, {}, false});
333 } 350 }
334 351
335 std::stable_partition(profiles.begin(), profiles.end(), 352 std::stable_partition(profiles.begin(), profiles.end(),
@@ -344,6 +361,7 @@ void ProfileManager::WriteUserSaveFile() {
344 raw.users[i].uuid2 = profiles[i].user_uuid; 361 raw.users[i].uuid2 = profiles[i].user_uuid;
345 raw.users[i].uuid = profiles[i].user_uuid; 362 raw.users[i].uuid = profiles[i].user_uuid;
346 raw.users[i].timestamp = profiles[i].creation_time; 363 raw.users[i].timestamp = profiles[i].creation_time;
364 raw.users[i].extra_data = profiles[i].data;
347 } 365 }
348 366
349 const auto raw_path = 367 const auto raw_path =
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h
index 747c46c20..c4ce2e0b3 100644
--- a/src/core/hle/service/acc/profile_manager.h
+++ b/src/core/hle/service/acc/profile_manager.h
@@ -13,7 +13,6 @@
13 13
14namespace Service::Account { 14namespace Service::Account {
15constexpr std::size_t MAX_USERS = 8; 15constexpr std::size_t MAX_USERS = 8;
16constexpr std::size_t MAX_DATA = 128;
17constexpr u128 INVALID_UUID{{0, 0}}; 16constexpr u128 INVALID_UUID{{0, 0}};
18 17
19struct UUID { 18struct UUID {
@@ -42,26 +41,28 @@ struct UUID {
42 void Invalidate() { 41 void Invalidate() {
43 uuid = INVALID_UUID; 42 uuid = INVALID_UUID;
44 } 43 }
45 std::string Format() const {
46 return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]);
47 }
48 44
49 std::string FormatSwitch() const { 45 std::string Format() const;
50 std::array<u8, 16> s{}; 46 std::string FormatSwitch() const;
51 std::memcpy(s.data(), uuid.data(), sizeof(u128));
52 return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{"
53 ":02x}{:02x}{:02x}{:02x}{:02x}",
54 s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11],
55 s[12], s[13], s[14], s[15]);
56 }
57}; 47};
58static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); 48static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
59 49
60constexpr std::size_t profile_username_size = 32; 50constexpr std::size_t profile_username_size = 32;
61using ProfileUsername = std::array<u8, profile_username_size>; 51using ProfileUsername = std::array<u8, profile_username_size>;
62using ProfileData = std::array<u8, MAX_DATA>;
63using UserIDArray = std::array<UUID, MAX_USERS>; 52using UserIDArray = std::array<UUID, MAX_USERS>;
64 53
54/// Contains extra data related to a user.
55/// TODO: RE this structure
56struct ProfileData {
57 INSERT_PADDING_WORDS(1);
58 u32 icon_id;
59 u8 bg_color_id;
60 INSERT_PADDING_BYTES(0x7);
61 INSERT_PADDING_BYTES(0x10);
62 INSERT_PADDING_BYTES(0x60);
63};
64static_assert(sizeof(ProfileData) == 0x80, "ProfileData structure has incorrect size");
65
65/// This holds general information about a users profile. This is where we store all the information 66/// This holds general information about a users profile. This is where we store all the information
66/// based on a specific user 67/// based on a specific user
67struct ProfileInfo { 68struct ProfileInfo {
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 0477ce66e..3a7b6da84 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -6,14 +6,21 @@
6#include <cinttypes> 6#include <cinttypes>
7#include <cstring> 7#include <cstring>
8#include <stack> 8#include <stack>
9#include "audio_core/audio_renderer.h"
9#include "core/core.h" 10#include "core/core.h"
10#include "core/hle/ipc_helpers.h" 11#include "core/hle/ipc_helpers.h"
11#include "core/hle/kernel/event.h" 12#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/process.h" 13#include "core/hle/kernel/process.h"
14#include "core/hle/kernel/readable_event.h"
15#include "core/hle/kernel/shared_memory.h"
16#include "core/hle/kernel/writable_event.h"
13#include "core/hle/service/acc/profile_manager.h" 17#include "core/hle/service/acc/profile_manager.h"
14#include "core/hle/service/am/am.h" 18#include "core/hle/service/am/am.h"
15#include "core/hle/service/am/applet_ae.h" 19#include "core/hle/service/am/applet_ae.h"
16#include "core/hle/service/am/applet_oe.h" 20#include "core/hle/service/am/applet_oe.h"
21#include "core/hle/service/am/applets/applets.h"
22#include "core/hle/service/am/applets/software_keyboard.h"
23#include "core/hle/service/am/applets/stub_applet.h"
17#include "core/hle/service/am/idle.h" 24#include "core/hle/service/am/idle.h"
18#include "core/hle/service/am/omm.h" 25#include "core/hle/service/am/omm.h"
19#include "core/hle/service/am/spsm.h" 26#include "core/hle/service/am/spsm.h"
@@ -28,6 +35,13 @@
28 35
29namespace Service::AM { 36namespace Service::AM {
30 37
38constexpr ResultCode ERR_NO_DATA_IN_CHANNEL{ErrorModule::AM, 0x2};
39constexpr ResultCode ERR_SIZE_OUT_OF_BOUNDS{ErrorModule::AM, 0x1F7};
40
41enum class AppletId : u32 {
42 SoftwareKeyboard = 0x11,
43};
44
31constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA; 45constexpr u32 POP_LAUNCH_PARAMETER_MAGIC = 0xC79497CA;
32 46
33struct LaunchParameters { 47struct LaunchParameters {
@@ -196,15 +210,16 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
196 RegisterHandlers(functions); 210 RegisterHandlers(functions);
197 211
198 auto& kernel = Core::System::GetInstance().Kernel(); 212 auto& kernel = Core::System::GetInstance().Kernel();
199 launchable_event = 213 launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
200 Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent"); 214 "ISelfController:LaunchableEvent");
201} 215}
202 216
203ISelfController::~ISelfController() = default; 217ISelfController::~ISelfController() = default;
204 218
205void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { 219void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
206 // Takes 3 input u8s with each field located immediately after the previous u8, these are 220 // Takes 3 input u8s with each field located immediately after the previous
207 // bool flags. No output. 221 // u8, these are bool flags. No output.
222 LOG_WARNING(Service_AM, "(STUBBED) called");
208 223
209 IPC::RequestParser rp{ctx}; 224 IPC::RequestParser rp{ctx};
210 225
@@ -217,159 +232,156 @@ void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
217 232
218 IPC::ResponseBuilder rb{ctx, 2}; 233 IPC::ResponseBuilder rb{ctx, 2};
219 rb.Push(RESULT_SUCCESS); 234 rb.Push(RESULT_SUCCESS);
220
221 LOG_WARNING(Service_AM, "(STUBBED) called");
222} 235}
223 236
224void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) { 237void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) {
238 LOG_WARNING(Service_AM, "(STUBBED) called");
239
225 IPC::ResponseBuilder rb{ctx, 2}; 240 IPC::ResponseBuilder rb{ctx, 2};
226 rb.Push(RESULT_SUCCESS); 241 rb.Push(RESULT_SUCCESS);
227
228 LOG_WARNING(Service_AM, "(STUBBED) called");
229} 242}
230 243
231void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) { 244void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) {
232 IPC::RequestParser rp{ctx}; 245 IPC::RequestParser rp{ctx};
233 246
234 bool flag = rp.Pop<bool>(); 247 bool flag = rp.Pop<bool>();
248 LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
235 249
236 IPC::ResponseBuilder rb{ctx, 2}; 250 IPC::ResponseBuilder rb{ctx, 2};
237 rb.Push(RESULT_SUCCESS); 251 rb.Push(RESULT_SUCCESS);
238
239 LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
240} 252}
241 253
242void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { 254void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) {
255 LOG_WARNING(Service_AM, "(STUBBED) called");
256
243 IPC::ResponseBuilder rb{ctx, 2}; 257 IPC::ResponseBuilder rb{ctx, 2};
244 rb.Push(RESULT_SUCCESS); 258 rb.Push(RESULT_SUCCESS);
245
246 LOG_WARNING(Service_AM, "(STUBBED) called");
247} 259}
248 260
249void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) { 261void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) {
250 IPC::RequestParser rp{ctx}; 262 IPC::RequestParser rp{ctx};
251 263
252 bool flag = rp.Pop<bool>(); 264 bool flag = rp.Pop<bool>();
265 LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
253 266
254 IPC::ResponseBuilder rb{ctx, 2}; 267 IPC::ResponseBuilder rb{ctx, 2};
255 rb.Push(RESULT_SUCCESS); 268 rb.Push(RESULT_SUCCESS);
256
257 LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag);
258} 269}
259 270
260void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) { 271void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) {
261 // Takes 3 input u8s with each field located immediately after the previous u8, these are 272 // Takes 3 input u8s with each field located immediately after the previous
262 // bool flags. No output. 273 // u8, these are bool flags. No output.
263 IPC::RequestParser rp{ctx}; 274 IPC::RequestParser rp{ctx};
264 275
265 bool enabled = rp.Pop<bool>(); 276 bool enabled = rp.Pop<bool>();
277 LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled);
266 278
267 IPC::ResponseBuilder rb{ctx, 2}; 279 IPC::ResponseBuilder rb{ctx, 2};
268 rb.Push(RESULT_SUCCESS); 280 rb.Push(RESULT_SUCCESS);
269
270 LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled);
271} 281}
272 282
273void ISelfController::LockExit(Kernel::HLERequestContext& ctx) { 283void ISelfController::LockExit(Kernel::HLERequestContext& ctx) {
284 LOG_WARNING(Service_AM, "(STUBBED) called");
285
274 IPC::ResponseBuilder rb{ctx, 2}; 286 IPC::ResponseBuilder rb{ctx, 2};
275 rb.Push(RESULT_SUCCESS); 287 rb.Push(RESULT_SUCCESS);
276
277 LOG_WARNING(Service_AM, "(STUBBED) called");
278} 288}
279 289
280void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) { 290void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) {
291 LOG_WARNING(Service_AM, "(STUBBED) called");
292
281 IPC::ResponseBuilder rb{ctx, 2}; 293 IPC::ResponseBuilder rb{ctx, 2};
282 rb.Push(RESULT_SUCCESS); 294 rb.Push(RESULT_SUCCESS);
283
284 LOG_WARNING(Service_AM, "(STUBBED) called");
285} 295}
286 296
287void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { 297void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) {
288 launchable_event->Signal(); 298 LOG_WARNING(Service_AM, "(STUBBED) called");
299
300 launchable_event.writable->Signal();
289 301
290 IPC::ResponseBuilder rb{ctx, 2, 1}; 302 IPC::ResponseBuilder rb{ctx, 2, 1};
291 rb.Push(RESULT_SUCCESS); 303 rb.Push(RESULT_SUCCESS);
292 rb.PushCopyObjects(launchable_event); 304 rb.PushCopyObjects(launchable_event.readable);
293
294 LOG_WARNING(Service_AM, "(STUBBED) called");
295} 305}
296 306
297void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) { 307void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) {
308 LOG_WARNING(Service_AM, "(STUBBED) called");
309
298 IPC::ResponseBuilder rb{ctx, 2}; 310 IPC::ResponseBuilder rb{ctx, 2};
299 rb.Push(RESULT_SUCCESS); 311 rb.Push(RESULT_SUCCESS);
300
301 LOG_WARNING(Service_AM, "(STUBBED) called");
302} 312}
303 313
304void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) { 314void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) {
305 // TODO(Subv): Find out how AM determines the display to use, for now just create the layer 315 LOG_WARNING(Service_AM, "(STUBBED) called");
306 // in the Default display. 316 // TODO(Subv): Find out how AM determines the display to use, for now just
317 // create the layer in the Default display.
307 u64 display_id = nvflinger->OpenDisplay("Default"); 318 u64 display_id = nvflinger->OpenDisplay("Default");
308 u64 layer_id = nvflinger->CreateLayer(display_id); 319 u64 layer_id = nvflinger->CreateLayer(display_id);
309 320
310 IPC::ResponseBuilder rb{ctx, 4}; 321 IPC::ResponseBuilder rb{ctx, 4};
311 rb.Push(RESULT_SUCCESS); 322 rb.Push(RESULT_SUCCESS);
312 rb.Push(layer_id); 323 rb.Push(layer_id);
313
314 LOG_WARNING(Service_AM, "(STUBBED) called");
315} 324}
316 325
317void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) { 326void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) {
327 LOG_WARNING(Service_AM, "(STUBBED) called");
328
318 IPC::ResponseBuilder rb{ctx, 2}; 329 IPC::ResponseBuilder rb{ctx, 2};
319 rb.Push(RESULT_SUCCESS); 330 rb.Push(RESULT_SUCCESS);
320
321 LOG_WARNING(Service_AM, "(STUBBED) called");
322} 331}
323 332
324void ISelfController::SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) { 333void ISelfController::SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) {
325 IPC::RequestParser rp{ctx}; 334 IPC::RequestParser rp{ctx};
326 idle_time_detection_extension = rp.Pop<u32>(); 335 idle_time_detection_extension = rp.Pop<u32>();
336 LOG_WARNING(Service_AM, "(STUBBED) called idle_time_detection_extension={}",
337 idle_time_detection_extension);
338
327 IPC::ResponseBuilder rb{ctx, 2}; 339 IPC::ResponseBuilder rb{ctx, 2};
328 rb.Push(RESULT_SUCCESS); 340 rb.Push(RESULT_SUCCESS);
329
330 LOG_WARNING(Service_AM, "(STUBBED) called");
331} 341}
332 342
333void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) { 343void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) {
344 LOG_WARNING(Service_AM, "(STUBBED) called");
345
334 IPC::ResponseBuilder rb{ctx, 3}; 346 IPC::ResponseBuilder rb{ctx, 3};
335 rb.Push(RESULT_SUCCESS); 347 rb.Push(RESULT_SUCCESS);
336 rb.Push<u32>(idle_time_detection_extension); 348 rb.Push<u32>(idle_time_detection_extension);
337
338 LOG_WARNING(Service_AM, "(STUBBED) called");
339} 349}
340 350
341AppletMessageQueue::AppletMessageQueue() { 351AppletMessageQueue::AppletMessageQueue() {
342 auto& kernel = Core::System::GetInstance().Kernel(); 352 auto& kernel = Core::System::GetInstance().Kernel();
343 on_new_message = Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, 353 on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
344 "AMMessageQueue:OnMessageRecieved"); 354 "AMMessageQueue:OnMessageRecieved");
345 on_operation_mode_changed = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, 355 on_operation_mode_changed = Kernel::WritableEvent::CreateEventPair(
346 "AMMessageQueue:OperationModeChanged"); 356 kernel, Kernel::ResetType::OneShot, "AMMessageQueue:OperationModeChanged");
347} 357}
348 358
349AppletMessageQueue::~AppletMessageQueue() = default; 359AppletMessageQueue::~AppletMessageQueue() = default;
350 360
351const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetMesssageRecieveEvent() const { 361const Kernel::SharedPtr<Kernel::ReadableEvent>& AppletMessageQueue::GetMesssageRecieveEvent()
352 return on_new_message; 362 const {
363 return on_new_message.readable;
353} 364}
354 365
355const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetOperationModeChangedEvent() const { 366const Kernel::SharedPtr<Kernel::ReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent()
356 return on_operation_mode_changed; 367 const {
368 return on_operation_mode_changed.readable;
357} 369}
358 370
359void AppletMessageQueue::PushMessage(AppletMessage msg) { 371void AppletMessageQueue::PushMessage(AppletMessage msg) {
360 messages.push(msg); 372 messages.push(msg);
361 on_new_message->Signal(); 373 on_new_message.writable->Signal();
362} 374}
363 375
364AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { 376AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
365 if (messages.empty()) { 377 if (messages.empty()) {
366 on_new_message->Clear(); 378 on_new_message.writable->Clear();
367 return AppletMessage::NoMessage; 379 return AppletMessage::NoMessage;
368 } 380 }
369 auto msg = messages.front(); 381 auto msg = messages.front();
370 messages.pop(); 382 messages.pop();
371 if (messages.empty()) { 383 if (messages.empty()) {
372 on_new_message->Clear(); 384 on_new_message.writable->Clear();
373 } 385 }
374 return msg; 386 return msg;
375} 387}
@@ -381,7 +393,7 @@ std::size_t AppletMessageQueue::GetMessageCount() const {
381void AppletMessageQueue::OperationModeChanged() { 393void AppletMessageQueue::OperationModeChanged() {
382 PushMessage(AppletMessage::OperationModeChanged); 394 PushMessage(AppletMessage::OperationModeChanged);
383 PushMessage(AppletMessage::PerformanceModeChanged); 395 PushMessage(AppletMessage::PerformanceModeChanged);
384 on_operation_mode_changed->Signal(); 396 on_operation_mode_changed.writable->Signal();
385} 397}
386 398
387ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue) 399ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue)
@@ -418,97 +430,131 @@ ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_q
418 // clang-format on 430 // clang-format on
419 431
420 RegisterHandlers(functions); 432 RegisterHandlers(functions);
421
422 auto& kernel = Core::System::GetInstance().Kernel();
423 event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "ICommonStateGetter:Event");
424} 433}
425 434
426ICommonStateGetter::~ICommonStateGetter() = default; 435ICommonStateGetter::~ICommonStateGetter() = default;
427 436
428void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) { 437void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) {
438 LOG_DEBUG(Service_AM, "called");
439
429 IPC::ResponseBuilder rb{ctx, 3}; 440 IPC::ResponseBuilder rb{ctx, 3};
430 rb.Push(RESULT_SUCCESS); 441 rb.Push(RESULT_SUCCESS);
431 442
432 rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode 443 rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode
433
434 LOG_DEBUG(Service_AM, "called");
435} 444}
436 445
437void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) { 446void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) {
447 LOG_DEBUG(Service_AM, "called");
448
438 IPC::ResponseBuilder rb{ctx, 2, 1}; 449 IPC::ResponseBuilder rb{ctx, 2, 1};
439 rb.Push(RESULT_SUCCESS); 450 rb.Push(RESULT_SUCCESS);
440 rb.PushCopyObjects(msg_queue->GetMesssageRecieveEvent()); 451 rb.PushCopyObjects(msg_queue->GetMesssageRecieveEvent());
441
442 LOG_DEBUG(Service_AM, "called");
443} 452}
444 453
445void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { 454void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
455 LOG_DEBUG(Service_AM, "called");
456
446 IPC::ResponseBuilder rb{ctx, 3}; 457 IPC::ResponseBuilder rb{ctx, 3};
447 rb.Push(RESULT_SUCCESS); 458 rb.Push(RESULT_SUCCESS);
448 rb.PushEnum<AppletMessageQueue::AppletMessage>(msg_queue->PopMessage()); 459 rb.PushEnum<AppletMessageQueue::AppletMessage>(msg_queue->PopMessage());
449
450 LOG_DEBUG(Service_AM, "called");
451} 460}
452 461
453void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { 462void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
463 LOG_WARNING(Service_AM, "(STUBBED) called");
464
454 IPC::ResponseBuilder rb{ctx, 3}; 465 IPC::ResponseBuilder rb{ctx, 3};
455 rb.Push(RESULT_SUCCESS); 466 rb.Push(RESULT_SUCCESS);
456 rb.Push(static_cast<u8>(FocusState::InFocus)); 467 rb.Push(static_cast<u8>(FocusState::InFocus));
457
458 LOG_WARNING(Service_AM, "(STUBBED) called");
459} 468}
460 469
461void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) { 470void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) {
471 LOG_DEBUG(Service_AM, "called");
472
462 IPC::ResponseBuilder rb{ctx, 2, 1}; 473 IPC::ResponseBuilder rb{ctx, 2, 1};
463 rb.Push(RESULT_SUCCESS); 474 rb.Push(RESULT_SUCCESS);
464 rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent()); 475 rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent());
465
466 LOG_DEBUG(Service_AM, "called");
467} 476}
468 477
469void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) { 478void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) {
479 LOG_DEBUG(Service_AM, "called");
480
470 IPC::ResponseBuilder rb{ctx, 4}; 481 IPC::ResponseBuilder rb{ctx, 4};
471 rb.Push(RESULT_SUCCESS); 482 rb.Push(RESULT_SUCCESS);
472 483
473 if (Settings::values.use_docked_mode) { 484 if (Settings::values.use_docked_mode) {
474 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth)); 485 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
475 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); 486 static_cast<u32>(Settings::values.resolution_factor));
487 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
488 static_cast<u32>(Settings::values.resolution_factor));
476 } else { 489 } else {
477 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth)); 490 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) *
478 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight)); 491 static_cast<u32>(Settings::values.resolution_factor));
492 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) *
493 static_cast<u32>(Settings::values.resolution_factor));
479 } 494 }
495}
480 496
481 LOG_DEBUG(Service_AM, "called"); 497IStorage::IStorage(std::vector<u8> buffer)
498 : ServiceFramework("IStorage"), buffer(std::move(buffer)) {
499 // clang-format off
500 static const FunctionInfo functions[] = {
501 {0, &IStorage::Open, "Open"},
502 {1, nullptr, "OpenTransferStorage"},
503 };
504 // clang-format on
505
506 RegisterHandlers(functions);
507}
508
509IStorage::~IStorage() = default;
510
511const std::vector<u8>& IStorage::GetData() const {
512 return buffer;
482} 513}
483 514
484void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { 515void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
485 const bool use_docked_mode{Settings::values.use_docked_mode}; 516 const bool use_docked_mode{Settings::values.use_docked_mode};
517 LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
518
486 IPC::ResponseBuilder rb{ctx, 3}; 519 IPC::ResponseBuilder rb{ctx, 3};
487 rb.Push(RESULT_SUCCESS); 520 rb.Push(RESULT_SUCCESS);
488 rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld)); 521 rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld));
489
490 LOG_DEBUG(Service_AM, "called");
491} 522}
492 523
493void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { 524void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
494 const bool use_docked_mode{Settings::values.use_docked_mode}; 525 const bool use_docked_mode{Settings::values.use_docked_mode};
526 LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
527
495 IPC::ResponseBuilder rb{ctx, 3}; 528 IPC::ResponseBuilder rb{ctx, 3};
496 rb.Push(RESULT_SUCCESS); 529 rb.Push(RESULT_SUCCESS);
497 rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked 530 rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked
498 : APM::PerformanceMode::Handheld)); 531 : APM::PerformanceMode::Handheld));
499
500 LOG_DEBUG(Service_AM, "called");
501} 532}
502 533
503class IStorageAccessor final : public ServiceFramework<IStorageAccessor> { 534class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
504public: 535public:
505 explicit IStorageAccessor(std::vector<u8> buffer) 536 explicit ILibraryAppletAccessor(std::shared_ptr<Applets::Applet> applet)
506 : ServiceFramework("IStorageAccessor"), buffer(std::move(buffer)) { 537 : ServiceFramework("ILibraryAppletAccessor"), applet(std::move(applet)) {
507 // clang-format off 538 // clang-format off
508 static const FunctionInfo functions[] = { 539 static const FunctionInfo functions[] = {
509 {0, &IStorageAccessor::GetSize, "GetSize"}, 540 {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
510 {10, &IStorageAccessor::Write, "Write"}, 541 {1, &ILibraryAppletAccessor::IsCompleted, "IsCompleted"},
511 {11, &IStorageAccessor::Read, "Read"}, 542 {10, &ILibraryAppletAccessor::Start, "Start"},
543 {20, nullptr, "RequestExit"},
544 {25, nullptr, "Terminate"},
545 {30, &ILibraryAppletAccessor::GetResult, "GetResult"},
546 {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
547 {100, &ILibraryAppletAccessor::PushInData, "PushInData"},
548 {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"},
549 {102, nullptr, "PushExtraStorage"},
550 {103, &ILibraryAppletAccessor::PushInteractiveInData, "PushInteractiveInData"},
551 {104, &ILibraryAppletAccessor::PopInteractiveOutData, "PopInteractiveOutData"},
552 {105, &ILibraryAppletAccessor::GetPopOutDataEvent, "GetPopOutDataEvent"},
553 {106, &ILibraryAppletAccessor::GetPopInteractiveOutDataEvent, "GetPopInteractiveOutDataEvent"},
554 {110, nullptr, "NeedsToExitProcess"},
555 {120, nullptr, "GetLibraryAppletInfo"},
556 {150, nullptr, "RequestForAppletToGetForeground"},
557 {160, nullptr, "GetIndirectLayerConsumerHandle"},
512 }; 558 };
513 // clang-format on 559 // clang-format on
514 560
@@ -516,158 +562,200 @@ public:
516 } 562 }
517 563
518private: 564private:
519 std::vector<u8> buffer; 565 void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) {
566 LOG_DEBUG(Service_AM, "called");
520 567
521 void GetSize(Kernel::HLERequestContext& ctx) { 568 applet->GetBroker().SignalStateChanged();
522 IPC::ResponseBuilder rb{ctx, 4}; 569 const auto event = applet->GetBroker().GetStateChangedEvent();
523 570
571 IPC::ResponseBuilder rb{ctx, 2, 1};
524 rb.Push(RESULT_SUCCESS); 572 rb.Push(RESULT_SUCCESS);
525 rb.Push(static_cast<u64>(buffer.size())); 573 rb.PushCopyObjects(event);
574 }
526 575
576 void IsCompleted(Kernel::HLERequestContext& ctx) {
527 LOG_DEBUG(Service_AM, "called"); 577 LOG_DEBUG(Service_AM, "called");
578
579 IPC::ResponseBuilder rb{ctx, 3};
580 rb.Push(RESULT_SUCCESS);
581 rb.Push<u32>(applet->TransactionComplete());
528 } 582 }
529 583
530 void Write(Kernel::HLERequestContext& ctx) { 584 void GetResult(Kernel::HLERequestContext& ctx) {
531 IPC::RequestParser rp{ctx}; 585 LOG_DEBUG(Service_AM, "called");
532 586
533 const u64 offset{rp.Pop<u64>()}; 587 IPC::ResponseBuilder rb{ctx, 2};
534 const std::vector<u8> data{ctx.ReadBuffer()}; 588 rb.Push(applet->GetStatus());
589 }
535 590
536 ASSERT(offset + data.size() <= buffer.size()); 591 void Start(Kernel::HLERequestContext& ctx) {
592 LOG_DEBUG(Service_AM, "called");
537 593
538 std::memcpy(&buffer[offset], data.data(), data.size()); 594 ASSERT(applet != nullptr);
595
596 applet->Initialize();
597 applet->Execute();
539 598
540 IPC::ResponseBuilder rb{ctx, 2}; 599 IPC::ResponseBuilder rb{ctx, 2};
541 rb.Push(RESULT_SUCCESS); 600 rb.Push(RESULT_SUCCESS);
542
543 LOG_DEBUG(Service_AM, "called, offset={}", offset);
544 } 601 }
545 602
546 void Read(Kernel::HLERequestContext& ctx) { 603 void PushInData(Kernel::HLERequestContext& ctx) {
604 LOG_DEBUG(Service_AM, "called");
605
547 IPC::RequestParser rp{ctx}; 606 IPC::RequestParser rp{ctx};
607 applet->GetBroker().PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>());
608
609 IPC::ResponseBuilder rb{ctx, 2};
610 rb.Push(RESULT_SUCCESS);
611 }
612
613 void PopOutData(Kernel::HLERequestContext& ctx) {
614 LOG_DEBUG(Service_AM, "called");
548 615
549 const u64 offset{rp.Pop<u64>()}; 616 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
550 const std::size_t size{ctx.GetWriteBufferSize()};
551 617
552 ASSERT(offset + size <= buffer.size()); 618 const auto storage = applet->GetBroker().PopNormalDataToGame();
619 if (storage == nullptr) {
620 LOG_ERROR(Service_AM,
621 "storage is a nullptr. There is no data in the current normal channel");
553 622
554 ctx.WriteBuffer(buffer.data() + offset, size); 623 rb.Push(ERR_NO_DATA_IN_CHANNEL);
624 return;
625 }
555 626
556 IPC::ResponseBuilder rb{ctx, 2};
557 rb.Push(RESULT_SUCCESS); 627 rb.Push(RESULT_SUCCESS);
558 628 rb.PushIpcInterface<IStorage>(std::move(*storage));
559 LOG_DEBUG(Service_AM, "called, offset={}", offset);
560 } 629 }
561};
562 630
563class IStorage final : public ServiceFramework<IStorage> { 631 void PushInteractiveInData(Kernel::HLERequestContext& ctx) {
564public: 632 LOG_DEBUG(Service_AM, "called");
565 explicit IStorage(std::vector<u8> buffer)
566 : ServiceFramework("IStorage"), buffer(std::move(buffer)) {
567 // clang-format off
568 static const FunctionInfo functions[] = {
569 {0, &IStorage::Open, "Open"},
570 {1, nullptr, "OpenTransferStorage"},
571 };
572 // clang-format on
573 633
574 RegisterHandlers(functions); 634 IPC::RequestParser rp{ctx};
635 applet->GetBroker().PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>());
636
637 ASSERT(applet->IsInitialized());
638 applet->ExecuteInteractive();
639 applet->Execute();
640
641 IPC::ResponseBuilder rb{ctx, 2};
642 rb.Push(RESULT_SUCCESS);
575 } 643 }
576 644
577private: 645 void PopInteractiveOutData(Kernel::HLERequestContext& ctx) {
578 std::vector<u8> buffer; 646 LOG_DEBUG(Service_AM, "called");
579 647
580 void Open(Kernel::HLERequestContext& ctx) {
581 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 648 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
582 649
650 const auto storage = applet->GetBroker().PopInteractiveDataToGame();
651 if (storage == nullptr) {
652 LOG_ERROR(Service_AM,
653 "storage is a nullptr. There is no data in the current interactive channel");
654
655 rb.Push(ERR_NO_DATA_IN_CHANNEL);
656 return;
657 }
658
659 rb.Push(RESULT_SUCCESS);
660 rb.PushIpcInterface<IStorage>(std::move(*storage));
661 }
662
663 void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) {
664 LOG_DEBUG(Service_AM, "called");
665
666 IPC::ResponseBuilder rb{ctx, 2, 1};
583 rb.Push(RESULT_SUCCESS); 667 rb.Push(RESULT_SUCCESS);
584 rb.PushIpcInterface<AM::IStorageAccessor>(buffer); 668 rb.PushCopyObjects(applet->GetBroker().GetNormalDataEvent());
669 }
585 670
671 void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) {
586 LOG_DEBUG(Service_AM, "called"); 672 LOG_DEBUG(Service_AM, "called");
673
674 IPC::ResponseBuilder rb{ctx, 2, 1};
675 rb.Push(RESULT_SUCCESS);
676 rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent());
587 } 677 }
678
679 std::shared_ptr<Applets::Applet> applet;
588}; 680};
589 681
590class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { 682void IStorage::Open(Kernel::HLERequestContext& ctx) {
591public: 683 LOG_DEBUG(Service_AM, "called");
592 explicit ILibraryAppletAccessor() : ServiceFramework("ILibraryAppletAccessor") { 684
593 // clang-format off 685 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
686
687 rb.Push(RESULT_SUCCESS);
688 rb.PushIpcInterface<IStorageAccessor>(*this);
689}
690
691IStorageAccessor::IStorageAccessor(IStorage& storage)
692 : ServiceFramework("IStorageAccessor"), backing(storage) {
693 // clang-format off
594 static const FunctionInfo functions[] = { 694 static const FunctionInfo functions[] = {
595 {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, 695 {0, &IStorageAccessor::GetSize, "GetSize"},
596 {1, nullptr, "IsCompleted"}, 696 {10, &IStorageAccessor::Write, "Write"},
597 {10, &ILibraryAppletAccessor::Start, "Start"}, 697 {11, &IStorageAccessor::Read, "Read"},
598 {20, nullptr, "RequestExit"},
599 {25, nullptr, "Terminate"},
600 {30, &ILibraryAppletAccessor::GetResult, "GetResult"},
601 {50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
602 {100, &ILibraryAppletAccessor::PushInData, "PushInData"},
603 {101, &ILibraryAppletAccessor::PopOutData, "PopOutData"},
604 {102, nullptr, "PushExtraStorage"},
605 {103, nullptr, "PushInteractiveInData"},
606 {104, nullptr, "PopInteractiveOutData"},
607 {105, nullptr, "GetPopOutDataEvent"},
608 {106, nullptr, "GetPopInteractiveOutDataEvent"},
609 {110, nullptr, "NeedsToExitProcess"},
610 {120, nullptr, "GetLibraryAppletInfo"},
611 {150, nullptr, "RequestForAppletToGetForeground"},
612 {160, nullptr, "GetIndirectLayerConsumerHandle"},
613 }; 698 };
614 // clang-format on 699 // clang-format on
615 700
616 RegisterHandlers(functions); 701 RegisterHandlers(functions);
702}
617 703
618 auto& kernel = Core::System::GetInstance().Kernel(); 704IStorageAccessor::~IStorageAccessor() = default;
619 state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
620 "ILibraryAppletAccessor:StateChangedEvent");
621 }
622 705
623private: 706void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) {
624 void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) { 707 LOG_DEBUG(Service_AM, "called");
625 state_changed_event->Signal();
626 708
627 IPC::ResponseBuilder rb{ctx, 2, 1}; 709 IPC::ResponseBuilder rb{ctx, 4};
628 rb.Push(RESULT_SUCCESS);
629 rb.PushCopyObjects(state_changed_event);
630 710
631 LOG_WARNING(Service_AM, "(STUBBED) called"); 711 rb.Push(RESULT_SUCCESS);
632 } 712 rb.Push(static_cast<u64>(backing.buffer.size()));
713}
633 714
634 void GetResult(Kernel::HLERequestContext& ctx) { 715void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
635 IPC::ResponseBuilder rb{ctx, 2}; 716 IPC::RequestParser rp{ctx};
636 rb.Push(RESULT_SUCCESS);
637 717
638 LOG_WARNING(Service_AM, "(STUBBED) called"); 718 const u64 offset{rp.Pop<u64>()};
639 } 719 LOG_DEBUG(Service_AM, "called, offset={}", offset);
640 720
641 void Start(Kernel::HLERequestContext& ctx) { 721 const std::vector<u8> data{ctx.ReadBuffer()};
642 IPC::ResponseBuilder rb{ctx, 2}; 722
643 rb.Push(RESULT_SUCCESS); 723 if (data.size() > backing.buffer.size() - offset) {
724 LOG_ERROR(Service_AM,
725 "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}",
726 backing.buffer.size(), data.size(), offset);
644 727
645 LOG_WARNING(Service_AM, "(STUBBED) called"); 728 IPC::ResponseBuilder rb{ctx, 2};
729 rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
646 } 730 }
647 731
648 void PushInData(Kernel::HLERequestContext& ctx) { 732 std::memcpy(backing.buffer.data() + offset, data.data(), data.size());
649 IPC::RequestParser rp{ctx};
650 storage_stack.push(rp.PopIpcInterface<AM::IStorage>());
651 733
652 IPC::ResponseBuilder rb{ctx, 2}; 734 IPC::ResponseBuilder rb{ctx, 2};
653 rb.Push(RESULT_SUCCESS); 735 rb.Push(RESULT_SUCCESS);
736}
654 737
655 LOG_DEBUG(Service_AM, "called"); 738void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
656 } 739 IPC::RequestParser rp{ctx};
657 740
658 void PopOutData(Kernel::HLERequestContext& ctx) { 741 const u64 offset{rp.Pop<u64>()};
659 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 742 LOG_DEBUG(Service_AM, "called, offset={}", offset);
660 rb.Push(RESULT_SUCCESS);
661 rb.PushIpcInterface<AM::IStorage>(std::move(storage_stack.top()));
662 743
663 storage_stack.pop(); 744 const std::size_t size{ctx.GetWriteBufferSize()};
664 745
665 LOG_DEBUG(Service_AM, "called"); 746 if (size > backing.buffer.size() - offset) {
747 LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}",
748 backing.buffer.size(), size, offset);
749
750 IPC::ResponseBuilder rb{ctx, 2};
751 rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
666 } 752 }
667 753
668 std::stack<std::shared_ptr<AM::IStorage>> storage_stack; 754 ctx.WriteBuffer(backing.buffer.data() + offset, size);
669 Kernel::SharedPtr<Kernel::Event> state_changed_event; 755
670}; 756 IPC::ResponseBuilder rb{ctx, 2};
757 rb.Push(RESULT_SUCCESS);
758}
671 759
672ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") { 760ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") {
673 static const FunctionInfo functions[] = { 761 static const FunctionInfo functions[] = {
@@ -675,7 +763,7 @@ ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryApple
675 {1, nullptr, "TerminateAllLibraryApplets"}, 763 {1, nullptr, "TerminateAllLibraryApplets"},
676 {2, nullptr, "AreAnyLibraryAppletsLeft"}, 764 {2, nullptr, "AreAnyLibraryAppletsLeft"},
677 {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"}, 765 {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"},
678 {11, nullptr, "CreateTransferMemoryStorage"}, 766 {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"},
679 {12, nullptr, "CreateHandleStorage"}, 767 {12, nullptr, "CreateHandleStorage"},
680 }; 768 };
681 RegisterHandlers(functions); 769 RegisterHandlers(functions);
@@ -683,25 +771,79 @@ ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryApple
683 771
684ILibraryAppletCreator::~ILibraryAppletCreator() = default; 772ILibraryAppletCreator::~ILibraryAppletCreator() = default;
685 773
774static std::shared_ptr<Applets::Applet> GetAppletFromId(AppletId id) {
775 switch (id) {
776 case AppletId::SoftwareKeyboard:
777 return std::make_shared<Applets::SoftwareKeyboard>();
778 default:
779 LOG_ERROR(Service_AM, "Unimplemented AppletId [{:08X}]! -- Falling back to stub!",
780 static_cast<u32>(id));
781 return std::make_shared<Applets::StubApplet>();
782 }
783}
784
686void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) { 785void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) {
786 IPC::RequestParser rp{ctx};
787 const auto applet_id = rp.PopRaw<AppletId>();
788 const auto applet_mode = rp.PopRaw<u32>();
789
790 LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}",
791 static_cast<u32>(applet_id), applet_mode);
792
793 const auto applet = GetAppletFromId(applet_id);
794
795 if (applet == nullptr) {
796 LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id));
797
798 IPC::ResponseBuilder rb{ctx, 2};
799 rb.Push(ResultCode(-1));
800 return;
801 }
802
687 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 803 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
688 804
689 rb.Push(RESULT_SUCCESS); 805 rb.Push(RESULT_SUCCESS);
690 rb.PushIpcInterface<AM::ILibraryAppletAccessor>(); 806 rb.PushIpcInterface<AM::ILibraryAppletAccessor>(applet);
691
692 LOG_DEBUG(Service_AM, "called");
693} 807}
694 808
695void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { 809void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
696 IPC::RequestParser rp{ctx}; 810 IPC::RequestParser rp{ctx};
697 const u64 size{rp.Pop<u64>()}; 811 const u64 size{rp.Pop<u64>()};
812 LOG_DEBUG(Service_AM, "called, size={}", size);
813
698 std::vector<u8> buffer(size); 814 std::vector<u8> buffer(size);
699 815
700 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 816 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
701 rb.Push(RESULT_SUCCESS); 817 rb.Push(RESULT_SUCCESS);
702 rb.PushIpcInterface<AM::IStorage>(std::move(buffer)); 818 rb.PushIpcInterface<AM::IStorage>(std::move(buffer));
819}
703 820
704 LOG_DEBUG(Service_AM, "called, size={}", size); 821void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) {
822 LOG_DEBUG(Service_AM, "called");
823
824 IPC::RequestParser rp{ctx};
825
826 rp.SetCurrentOffset(3);
827 const auto handle{rp.Pop<Kernel::Handle>()};
828
829 const auto shared_mem =
830 Core::System::GetInstance().CurrentProcess()->GetHandleTable().Get<Kernel::SharedMemory>(
831 handle);
832
833 if (shared_mem == nullptr) {
834 LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle);
835 IPC::ResponseBuilder rb{ctx, 2};
836 rb.Push(ResultCode(-1));
837 return;
838 }
839
840 const u8* mem_begin = shared_mem->GetPointer();
841 const u8* mem_end = mem_begin + shared_mem->GetSize();
842 std::vector<u8> memory{mem_begin, mem_end};
843
844 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
845 rb.Push(RESULT_SUCCESS);
846 rb.PushIpcInterface(std::make_shared<IStorage>(std::move(memory)));
705} 847}
706 848
707IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") { 849IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") {
@@ -733,7 +875,7 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
733 {70, nullptr, "RequestToShutdown"}, 875 {70, nullptr, "RequestToShutdown"},
734 {71, nullptr, "RequestToReboot"}, 876 {71, nullptr, "RequestToReboot"},
735 {80, nullptr, "ExitAndRequestToShowThanksMessage"}, 877 {80, nullptr, "ExitAndRequestToShowThanksMessage"},
736 {90, nullptr, "EnableApplicationCrashReport"}, 878 {90, &IApplicationFunctions::EnableApplicationCrashReport, "EnableApplicationCrashReport"},
737 {100, nullptr, "InitializeApplicationCopyrightFrameBuffer"}, 879 {100, nullptr, "InitializeApplicationCopyrightFrameBuffer"},
738 {101, nullptr, "SetApplicationCopyrightImage"}, 880 {101, nullptr, "SetApplicationCopyrightImage"},
739 {102, nullptr, "SetApplicationCopyrightVisibility"}, 881 {102, nullptr, "SetApplicationCopyrightVisibility"},
@@ -752,33 +894,46 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
752 894
753IApplicationFunctions::~IApplicationFunctions() = default; 895IApplicationFunctions::~IApplicationFunctions() = default;
754 896
897void IApplicationFunctions::EnableApplicationCrashReport(Kernel::HLERequestContext& ctx) {
898 LOG_WARNING(Service_AM, "(STUBBED) called");
899
900 IPC::ResponseBuilder rb{ctx, 2};
901 rb.Push(RESULT_SUCCESS);
902}
903
755void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed( 904void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(
756 Kernel::HLERequestContext& ctx) { 905 Kernel::HLERequestContext& ctx) {
906 LOG_WARNING(Service_AM, "(STUBBED) called");
907
757 IPC::ResponseBuilder rb{ctx, 2}; 908 IPC::ResponseBuilder rb{ctx, 2};
758 rb.Push(RESULT_SUCCESS); 909 rb.Push(RESULT_SUCCESS);
759 LOG_WARNING(Service_AM, "(STUBBED) called");
760} 910}
761 911
762void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed( 912void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed(
763 Kernel::HLERequestContext& ctx) { 913 Kernel::HLERequestContext& ctx) {
914 LOG_WARNING(Service_AM, "(STUBBED) called");
915
764 IPC::ResponseBuilder rb{ctx, 2}; 916 IPC::ResponseBuilder rb{ctx, 2};
765 rb.Push(RESULT_SUCCESS); 917 rb.Push(RESULT_SUCCESS);
766 LOG_WARNING(Service_AM, "(STUBBED) called");
767} 918}
768 919
769void IApplicationFunctions::BeginBlockingHomeButton(Kernel::HLERequestContext& ctx) { 920void IApplicationFunctions::BeginBlockingHomeButton(Kernel::HLERequestContext& ctx) {
921 LOG_WARNING(Service_AM, "(STUBBED) called");
922
770 IPC::ResponseBuilder rb{ctx, 2}; 923 IPC::ResponseBuilder rb{ctx, 2};
771 rb.Push(RESULT_SUCCESS); 924 rb.Push(RESULT_SUCCESS);
772 LOG_WARNING(Service_AM, "(STUBBED) called");
773} 925}
774 926
775void IApplicationFunctions::EndBlockingHomeButton(Kernel::HLERequestContext& ctx) { 927void IApplicationFunctions::EndBlockingHomeButton(Kernel::HLERequestContext& ctx) {
928 LOG_WARNING(Service_AM, "(STUBBED) called");
929
776 IPC::ResponseBuilder rb{ctx, 2}; 930 IPC::ResponseBuilder rb{ctx, 2};
777 rb.Push(RESULT_SUCCESS); 931 rb.Push(RESULT_SUCCESS);
778 LOG_WARNING(Service_AM, "(STUBBED) called");
779} 932}
780 933
781void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { 934void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
935 LOG_DEBUG(Service_AM, "called");
936
782 LaunchParameters params{}; 937 LaunchParameters params{};
783 938
784 params.magic = POP_LAUNCH_PARAMETER_MAGIC; 939 params.magic = POP_LAUNCH_PARAMETER_MAGIC;
@@ -797,21 +952,19 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
797 std::memcpy(buffer.data(), &params, buffer.size()); 952 std::memcpy(buffer.data(), &params, buffer.size());
798 953
799 rb.PushIpcInterface<AM::IStorage>(buffer); 954 rb.PushIpcInterface<AM::IStorage>(buffer);
800
801 LOG_DEBUG(Service_AM, "called");
802} 955}
803 956
804void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest( 957void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(
805 Kernel::HLERequestContext& ctx) { 958 Kernel::HLERequestContext& ctx) {
959 LOG_WARNING(Service_AM, "(STUBBED) called");
960
806 IPC::ResponseBuilder rb{ctx, 2}; 961 IPC::ResponseBuilder rb{ctx, 2};
807 rb.Push(RESULT_SUCCESS); 962 rb.Push(RESULT_SUCCESS);
808 LOG_WARNING(Service_AM, "(STUBBED) called");
809} 963}
810 964
811void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { 965void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
812 IPC::RequestParser rp{ctx}; 966 IPC::RequestParser rp{ctx};
813 u128 uid = rp.PopRaw<u128>(); // What does this do? 967 u128 uid = rp.PopRaw<u128>(); // What does this do?
814
815 LOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]); 968 LOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]);
816 969
817 IPC::ResponseBuilder rb{ctx, 4}; 970 IPC::ResponseBuilder rb{ctx, 4};
@@ -821,71 +974,74 @@ void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
821 974
822void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) { 975void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) {
823 // Takes an input u32 Result, no output. 976 // Takes an input u32 Result, no output.
824 // For example, in some cases official apps use this with error 0x2A2 then uses svcBreak. 977 // For example, in some cases official apps use this with error 0x2A2 then
978 // uses svcBreak.
825 979
826 IPC::RequestParser rp{ctx}; 980 IPC::RequestParser rp{ctx};
827 u32 result = rp.Pop<u32>(); 981 u32 result = rp.Pop<u32>();
982 LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result);
828 983
829 IPC::ResponseBuilder rb{ctx, 2}; 984 IPC::ResponseBuilder rb{ctx, 2};
830 rb.Push(RESULT_SUCCESS); 985 rb.Push(RESULT_SUCCESS);
831
832 LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result);
833} 986}
834 987
835void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) { 988void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) {
989 LOG_WARNING(Service_AM, "(STUBBED) called");
990
836 IPC::ResponseBuilder rb{ctx, 6}; 991 IPC::ResponseBuilder rb{ctx, 6};
837 rb.Push(RESULT_SUCCESS); 992 rb.Push(RESULT_SUCCESS);
838 rb.Push<u64>(1); 993 rb.Push<u64>(1);
839 rb.Push<u64>(0); 994 rb.Push<u64>(0);
840 LOG_WARNING(Service_AM, "(STUBBED) called");
841} 995}
842 996
843void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { 997void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
844 // TODO(bunnei): This should be configurable 998 // TODO(bunnei): This should be configurable
999 LOG_DEBUG(Service_AM, "called");
1000
845 IPC::ResponseBuilder rb{ctx, 4}; 1001 IPC::ResponseBuilder rb{ctx, 4};
846 rb.Push(RESULT_SUCCESS); 1002 rb.Push(RESULT_SUCCESS);
847 rb.Push( 1003 rb.Push(
848 static_cast<u64>(Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index))); 1004 static_cast<u64>(Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index)));
849 LOG_DEBUG(Service_AM, "called");
850} 1005}
851 1006
852void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) { 1007void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) {
1008 LOG_WARNING(Service_AM, "(STUBBED) called");
1009
853 IPC::ResponseBuilder rb{ctx, 2}; 1010 IPC::ResponseBuilder rb{ctx, 2};
854 rb.Push(RESULT_SUCCESS); 1011 rb.Push(RESULT_SUCCESS);
855 LOG_WARNING(Service_AM, "(STUBBED) called");
856} 1012}
857 1013
858void IApplicationFunctions::SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) { 1014void IApplicationFunctions::SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) {
1015 LOG_WARNING(Service_AM, "(STUBBED) called");
1016
859 IPC::ResponseBuilder rb{ctx, 2}; 1017 IPC::ResponseBuilder rb{ctx, 2};
860 rb.Push(RESULT_SUCCESS); 1018 rb.Push(RESULT_SUCCESS);
861
862 LOG_WARNING(Service_AM, "(STUBBED) called");
863} 1019}
864 1020
865void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) { 1021void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) {
1022 LOG_WARNING(Service_AM, "(STUBBED) called");
1023
866 IPC::ResponseBuilder rb{ctx, 3}; 1024 IPC::ResponseBuilder rb{ctx, 3};
867 rb.Push(RESULT_SUCCESS); 1025 rb.Push(RESULT_SUCCESS);
868 rb.Push<u8>(0); // Unknown, seems to be ignored by official processes 1026 rb.Push<u8>(0); // Unknown, seems to be ignored by official processes
869
870 LOG_WARNING(Service_AM, "(STUBBED) called");
871} 1027}
872 1028
873void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) { 1029void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) {
1030 LOG_WARNING(Service_AM, "(STUBBED) called");
1031
874 IPC::ResponseBuilder rb{ctx, 6}; 1032 IPC::ResponseBuilder rb{ctx, 6};
875 rb.Push(RESULT_SUCCESS); 1033 rb.Push(RESULT_SUCCESS);
876 1034
877 // Returns a 128-bit UUID 1035 // Returns a 128-bit UUID
878 rb.Push<u64>(0); 1036 rb.Push<u64>(0);
879 rb.Push<u64>(0); 1037 rb.Push<u64>(0);
880
881 LOG_WARNING(Service_AM, "(STUBBED) called");
882} 1038}
883 1039
884void InstallInterfaces(SM::ServiceManager& service_manager, 1040void InstallInterfaces(SM::ServiceManager& service_manager,
885 std::shared_ptr<NVFlinger::NVFlinger> nvflinger) { 1041 std::shared_ptr<NVFlinger::NVFlinger> nvflinger) {
886 auto message_queue = std::make_shared<AppletMessageQueue>(); 1042 auto message_queue = std::make_shared<AppletMessageQueue>();
887 message_queue->PushMessage( 1043 message_queue->PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on
888 AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on game boot 1044 // game boot
889 1045
890 std::make_shared<AppletAE>(nvflinger, message_queue)->InstallAsService(service_manager); 1046 std::make_shared<AppletAE>(nvflinger, message_queue)->InstallAsService(service_manager);
891 std::make_shared<AppletOE>(nvflinger, message_queue)->InstallAsService(service_manager); 1047 std::make_shared<AppletOE>(nvflinger, message_queue)->InstallAsService(service_manager);
@@ -915,9 +1071,10 @@ IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions"
915IHomeMenuFunctions::~IHomeMenuFunctions() = default; 1071IHomeMenuFunctions::~IHomeMenuFunctions() = default;
916 1072
917void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) { 1073void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) {
1074 LOG_WARNING(Service_AM, "(STUBBED) called");
1075
918 IPC::ResponseBuilder rb{ctx, 2}; 1076 IPC::ResponseBuilder rb{ctx, 2};
919 rb.Push(RESULT_SUCCESS); 1077 rb.Push(RESULT_SUCCESS);
920 LOG_WARNING(Service_AM, "(STUBBED) called");
921} 1078}
922 1079
923IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") { 1080IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") {
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 2f1c20bce..34c45fadf 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -6,12 +6,9 @@
6 6
7#include <memory> 7#include <memory>
8#include <queue> 8#include <queue>
9#include "core/hle/kernel/writable_event.h"
9#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
10 11
11namespace Kernel {
12class Event;
13}
14
15namespace Service { 12namespace Service {
16namespace NVFlinger { 13namespace NVFlinger {
17class NVFlinger; 14class NVFlinger;
@@ -52,8 +49,8 @@ public:
52 AppletMessageQueue(); 49 AppletMessageQueue();
53 ~AppletMessageQueue(); 50 ~AppletMessageQueue();
54 51
55 const Kernel::SharedPtr<Kernel::Event>& GetMesssageRecieveEvent() const; 52 const Kernel::SharedPtr<Kernel::ReadableEvent>& GetMesssageRecieveEvent() const;
56 const Kernel::SharedPtr<Kernel::Event>& GetOperationModeChangedEvent() const; 53 const Kernel::SharedPtr<Kernel::ReadableEvent>& GetOperationModeChangedEvent() const;
57 void PushMessage(AppletMessage msg); 54 void PushMessage(AppletMessage msg);
58 AppletMessage PopMessage(); 55 AppletMessage PopMessage();
59 std::size_t GetMessageCount() const; 56 std::size_t GetMessageCount() const;
@@ -61,8 +58,8 @@ public:
61 58
62private: 59private:
63 std::queue<AppletMessage> messages; 60 std::queue<AppletMessage> messages;
64 Kernel::SharedPtr<Kernel::Event> on_new_message; 61 Kernel::EventPair on_new_message;
65 Kernel::SharedPtr<Kernel::Event> on_operation_mode_changed; 62 Kernel::EventPair on_operation_mode_changed;
66}; 63};
67 64
68class IWindowController final : public ServiceFramework<IWindowController> { 65class IWindowController final : public ServiceFramework<IWindowController> {
@@ -122,7 +119,7 @@ private:
122 void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx); 119 void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
123 120
124 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 121 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
125 Kernel::SharedPtr<Kernel::Event> launchable_event; 122 Kernel::EventPair launchable_event;
126 u32 idle_time_detection_extension = 0; 123 u32 idle_time_detection_extension = 0;
127}; 124};
128 125
@@ -151,10 +148,37 @@ private:
151 void GetBootMode(Kernel::HLERequestContext& ctx); 148 void GetBootMode(Kernel::HLERequestContext& ctx);
152 void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); 149 void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx);
153 150
154 Kernel::SharedPtr<Kernel::Event> event;
155 std::shared_ptr<AppletMessageQueue> msg_queue; 151 std::shared_ptr<AppletMessageQueue> msg_queue;
156}; 152};
157 153
154class IStorage final : public ServiceFramework<IStorage> {
155public:
156 explicit IStorage(std::vector<u8> buffer);
157 ~IStorage() override;
158
159 const std::vector<u8>& GetData() const;
160
161private:
162 void Open(Kernel::HLERequestContext& ctx);
163
164 std::vector<u8> buffer;
165
166 friend class IStorageAccessor;
167};
168
169class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
170public:
171 explicit IStorageAccessor(IStorage& backing);
172 ~IStorageAccessor() override;
173
174private:
175 void GetSize(Kernel::HLERequestContext& ctx);
176 void Write(Kernel::HLERequestContext& ctx);
177 void Read(Kernel::HLERequestContext& ctx);
178
179 IStorage& backing;
180};
181
158class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> { 182class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
159public: 183public:
160 ILibraryAppletCreator(); 184 ILibraryAppletCreator();
@@ -163,6 +187,7 @@ public:
163private: 187private:
164 void CreateLibraryApplet(Kernel::HLERequestContext& ctx); 188 void CreateLibraryApplet(Kernel::HLERequestContext& ctx);
165 void CreateStorage(Kernel::HLERequestContext& ctx); 189 void CreateStorage(Kernel::HLERequestContext& ctx);
190 void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx);
166}; 191};
167 192
168class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { 193class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
@@ -185,6 +210,7 @@ private:
185 void EndBlockingHomeButtonShortAndLongPressed(Kernel::HLERequestContext& ctx); 210 void EndBlockingHomeButtonShortAndLongPressed(Kernel::HLERequestContext& ctx);
186 void BeginBlockingHomeButton(Kernel::HLERequestContext& ctx); 211 void BeginBlockingHomeButton(Kernel::HLERequestContext& ctx);
187 void EndBlockingHomeButton(Kernel::HLERequestContext& ctx); 212 void EndBlockingHomeButton(Kernel::HLERequestContext& ctx);
213 void EnableApplicationCrashReport(Kernel::HLERequestContext& ctx);
188}; 214};
189 215
190class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> { 216class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp
index ec93e3529..41a573a91 100644
--- a/src/core/hle/service/am/applet_ae.cpp
+++ b/src/core/hle/service/am/applet_ae.cpp
@@ -32,66 +32,75 @@ public:
32 32
33private: 33private:
34 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { 34 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
35 LOG_DEBUG(Service_AM, "called");
36
35 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 37 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
36 rb.Push(RESULT_SUCCESS); 38 rb.Push(RESULT_SUCCESS);
37 rb.PushIpcInterface<ICommonStateGetter>(msg_queue); 39 rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
38 LOG_DEBUG(Service_AM, "called");
39 } 40 }
40 41
41 void GetSelfController(Kernel::HLERequestContext& ctx) { 42 void GetSelfController(Kernel::HLERequestContext& ctx) {
43 LOG_DEBUG(Service_AM, "called");
44
42 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 45 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
43 rb.Push(RESULT_SUCCESS); 46 rb.Push(RESULT_SUCCESS);
44 rb.PushIpcInterface<ISelfController>(nvflinger); 47 rb.PushIpcInterface<ISelfController>(nvflinger);
45 LOG_DEBUG(Service_AM, "called");
46 } 48 }
47 49
48 void GetWindowController(Kernel::HLERequestContext& ctx) { 50 void GetWindowController(Kernel::HLERequestContext& ctx) {
51 LOG_DEBUG(Service_AM, "called");
52
49 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 53 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
50 rb.Push(RESULT_SUCCESS); 54 rb.Push(RESULT_SUCCESS);
51 rb.PushIpcInterface<IWindowController>(); 55 rb.PushIpcInterface<IWindowController>();
52 LOG_DEBUG(Service_AM, "called");
53 } 56 }
54 57
55 void GetAudioController(Kernel::HLERequestContext& ctx) { 58 void GetAudioController(Kernel::HLERequestContext& ctx) {
59 LOG_DEBUG(Service_AM, "called");
60
56 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 61 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
57 rb.Push(RESULT_SUCCESS); 62 rb.Push(RESULT_SUCCESS);
58 rb.PushIpcInterface<IAudioController>(); 63 rb.PushIpcInterface<IAudioController>();
59 LOG_DEBUG(Service_AM, "called");
60 } 64 }
61 65
62 void GetDisplayController(Kernel::HLERequestContext& ctx) { 66 void GetDisplayController(Kernel::HLERequestContext& ctx) {
67 LOG_DEBUG(Service_AM, "called");
68
63 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 69 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
64 rb.Push(RESULT_SUCCESS); 70 rb.Push(RESULT_SUCCESS);
65 rb.PushIpcInterface<IDisplayController>(); 71 rb.PushIpcInterface<IDisplayController>();
66 LOG_DEBUG(Service_AM, "called");
67 } 72 }
68 73
69 void GetProcessWindingController(Kernel::HLERequestContext& ctx) { 74 void GetProcessWindingController(Kernel::HLERequestContext& ctx) {
75 LOG_DEBUG(Service_AM, "called");
76
70 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 77 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
71 rb.Push(RESULT_SUCCESS); 78 rb.Push(RESULT_SUCCESS);
72 rb.PushIpcInterface<IProcessWindingController>(); 79 rb.PushIpcInterface<IProcessWindingController>();
73 LOG_DEBUG(Service_AM, "called");
74 } 80 }
75 81
76 void GetDebugFunctions(Kernel::HLERequestContext& ctx) { 82 void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
83 LOG_DEBUG(Service_AM, "called");
84
77 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 85 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
78 rb.Push(RESULT_SUCCESS); 86 rb.Push(RESULT_SUCCESS);
79 rb.PushIpcInterface<IDebugFunctions>(); 87 rb.PushIpcInterface<IDebugFunctions>();
80 LOG_DEBUG(Service_AM, "called");
81 } 88 }
82 89
83 void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { 90 void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
91 LOG_DEBUG(Service_AM, "called");
92
84 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 93 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
85 rb.Push(RESULT_SUCCESS); 94 rb.Push(RESULT_SUCCESS);
86 rb.PushIpcInterface<ILibraryAppletCreator>(); 95 rb.PushIpcInterface<ILibraryAppletCreator>();
87 LOG_DEBUG(Service_AM, "called");
88 } 96 }
89 97
90 void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { 98 void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
99 LOG_DEBUG(Service_AM, "called");
100
91 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 101 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
92 rb.Push(RESULT_SUCCESS); 102 rb.Push(RESULT_SUCCESS);
93 rb.PushIpcInterface<IApplicationFunctions>(); 103 rb.PushIpcInterface<IApplicationFunctions>();
94 LOG_DEBUG(Service_AM, "called");
95 } 104 }
96 105
97 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 106 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
@@ -122,97 +131,110 @@ public:
122 131
123private: 132private:
124 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { 133 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
134 LOG_DEBUG(Service_AM, "called");
135
125 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 136 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
126 rb.Push(RESULT_SUCCESS); 137 rb.Push(RESULT_SUCCESS);
127 rb.PushIpcInterface<ICommonStateGetter>(msg_queue); 138 rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
128 LOG_DEBUG(Service_AM, "called");
129 } 139 }
130 140
131 void GetSelfController(Kernel::HLERequestContext& ctx) { 141 void GetSelfController(Kernel::HLERequestContext& ctx) {
142 LOG_DEBUG(Service_AM, "called");
143
132 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 144 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
133 rb.Push(RESULT_SUCCESS); 145 rb.Push(RESULT_SUCCESS);
134 rb.PushIpcInterface<ISelfController>(nvflinger); 146 rb.PushIpcInterface<ISelfController>(nvflinger);
135 LOG_DEBUG(Service_AM, "called");
136 } 147 }
137 148
138 void GetWindowController(Kernel::HLERequestContext& ctx) { 149 void GetWindowController(Kernel::HLERequestContext& ctx) {
150 LOG_DEBUG(Service_AM, "called");
151
139 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 152 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
140 rb.Push(RESULT_SUCCESS); 153 rb.Push(RESULT_SUCCESS);
141 rb.PushIpcInterface<IWindowController>(); 154 rb.PushIpcInterface<IWindowController>();
142 LOG_DEBUG(Service_AM, "called");
143 } 155 }
144 156
145 void GetAudioController(Kernel::HLERequestContext& ctx) { 157 void GetAudioController(Kernel::HLERequestContext& ctx) {
158 LOG_DEBUG(Service_AM, "called");
159
146 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 160 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
147 rb.Push(RESULT_SUCCESS); 161 rb.Push(RESULT_SUCCESS);
148 rb.PushIpcInterface<IAudioController>(); 162 rb.PushIpcInterface<IAudioController>();
149 LOG_DEBUG(Service_AM, "called");
150 } 163 }
151 164
152 void GetDisplayController(Kernel::HLERequestContext& ctx) { 165 void GetDisplayController(Kernel::HLERequestContext& ctx) {
166 LOG_DEBUG(Service_AM, "called");
167
153 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 168 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
154 rb.Push(RESULT_SUCCESS); 169 rb.Push(RESULT_SUCCESS);
155 rb.PushIpcInterface<IDisplayController>(); 170 rb.PushIpcInterface<IDisplayController>();
156 LOG_DEBUG(Service_AM, "called");
157 } 171 }
158 172
159 void GetDebugFunctions(Kernel::HLERequestContext& ctx) { 173 void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
174 LOG_DEBUG(Service_AM, "called");
175
160 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 176 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
161 rb.Push(RESULT_SUCCESS); 177 rb.Push(RESULT_SUCCESS);
162 rb.PushIpcInterface<IDebugFunctions>(); 178 rb.PushIpcInterface<IDebugFunctions>();
163 LOG_DEBUG(Service_AM, "called");
164 } 179 }
165 180
166 void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { 181 void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
182 LOG_DEBUG(Service_AM, "called");
183
167 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 184 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
168 rb.Push(RESULT_SUCCESS); 185 rb.Push(RESULT_SUCCESS);
169 rb.PushIpcInterface<ILibraryAppletCreator>(); 186 rb.PushIpcInterface<ILibraryAppletCreator>();
170 LOG_DEBUG(Service_AM, "called");
171 } 187 }
172 188
173 void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) { 189 void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) {
190 LOG_DEBUG(Service_AM, "called");
191
174 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 192 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
175 rb.Push(RESULT_SUCCESS); 193 rb.Push(RESULT_SUCCESS);
176 rb.PushIpcInterface<IHomeMenuFunctions>(); 194 rb.PushIpcInterface<IHomeMenuFunctions>();
177 LOG_DEBUG(Service_AM, "called");
178 } 195 }
179 196
180 void GetGlobalStateController(Kernel::HLERequestContext& ctx) { 197 void GetGlobalStateController(Kernel::HLERequestContext& ctx) {
198 LOG_DEBUG(Service_AM, "called");
199
181 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 200 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
182 rb.Push(RESULT_SUCCESS); 201 rb.Push(RESULT_SUCCESS);
183 rb.PushIpcInterface<IGlobalStateController>(); 202 rb.PushIpcInterface<IGlobalStateController>();
184 LOG_DEBUG(Service_AM, "called");
185 } 203 }
186 204
187 void GetApplicationCreator(Kernel::HLERequestContext& ctx) { 205 void GetApplicationCreator(Kernel::HLERequestContext& ctx) {
206 LOG_DEBUG(Service_AM, "called");
207
188 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 208 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
189 rb.Push(RESULT_SUCCESS); 209 rb.Push(RESULT_SUCCESS);
190 rb.PushIpcInterface<IApplicationCreator>(); 210 rb.PushIpcInterface<IApplicationCreator>();
191 LOG_DEBUG(Service_AM, "called");
192 } 211 }
193 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 212 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
194 std::shared_ptr<AppletMessageQueue> msg_queue; 213 std::shared_ptr<AppletMessageQueue> msg_queue;
195}; 214};
196 215
197void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) { 216void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
217 LOG_DEBUG(Service_AM, "called");
218
198 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 219 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
199 rb.Push(RESULT_SUCCESS); 220 rb.Push(RESULT_SUCCESS);
200 rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue); 221 rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue);
201 LOG_DEBUG(Service_AM, "called");
202} 222}
203 223
204void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) { 224void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {
225 LOG_DEBUG(Service_AM, "called");
226
205 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 227 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
206 rb.Push(RESULT_SUCCESS); 228 rb.Push(RESULT_SUCCESS);
207 rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue); 229 rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
208 LOG_DEBUG(Service_AM, "called");
209} 230}
210 231
211void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) { 232void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
233 LOG_DEBUG(Service_AM, "called");
234
212 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 235 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
213 rb.Push(RESULT_SUCCESS); 236 rb.Push(RESULT_SUCCESS);
214 rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue); 237 rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
215 LOG_DEBUG(Service_AM, "called");
216} 238}
217 239
218AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 240AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp
index 20c8d5fff..d3a0a1568 100644
--- a/src/core/hle/service/am/applet_oe.cpp
+++ b/src/core/hle/service/am/applet_oe.cpp
@@ -35,59 +35,67 @@ public:
35 35
36private: 36private:
37 void GetAudioController(Kernel::HLERequestContext& ctx) { 37 void GetAudioController(Kernel::HLERequestContext& ctx) {
38 LOG_DEBUG(Service_AM, "called");
39
38 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 40 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
39 rb.Push(RESULT_SUCCESS); 41 rb.Push(RESULT_SUCCESS);
40 rb.PushIpcInterface<IAudioController>(); 42 rb.PushIpcInterface<IAudioController>();
41 LOG_DEBUG(Service_AM, "called");
42 } 43 }
43 44
44 void GetDisplayController(Kernel::HLERequestContext& ctx) { 45 void GetDisplayController(Kernel::HLERequestContext& ctx) {
46 LOG_DEBUG(Service_AM, "called");
47
45 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 48 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
46 rb.Push(RESULT_SUCCESS); 49 rb.Push(RESULT_SUCCESS);
47 rb.PushIpcInterface<IDisplayController>(); 50 rb.PushIpcInterface<IDisplayController>();
48 LOG_DEBUG(Service_AM, "called");
49 } 51 }
50 52
51 void GetDebugFunctions(Kernel::HLERequestContext& ctx) { 53 void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
54 LOG_DEBUG(Service_AM, "called");
55
52 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 56 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
53 rb.Push(RESULT_SUCCESS); 57 rb.Push(RESULT_SUCCESS);
54 rb.PushIpcInterface<IDebugFunctions>(); 58 rb.PushIpcInterface<IDebugFunctions>();
55 LOG_DEBUG(Service_AM, "called");
56 } 59 }
57 60
58 void GetWindowController(Kernel::HLERequestContext& ctx) { 61 void GetWindowController(Kernel::HLERequestContext& ctx) {
62 LOG_DEBUG(Service_AM, "called");
63
59 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 64 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
60 rb.Push(RESULT_SUCCESS); 65 rb.Push(RESULT_SUCCESS);
61 rb.PushIpcInterface<IWindowController>(); 66 rb.PushIpcInterface<IWindowController>();
62 LOG_DEBUG(Service_AM, "called");
63 } 67 }
64 68
65 void GetSelfController(Kernel::HLERequestContext& ctx) { 69 void GetSelfController(Kernel::HLERequestContext& ctx) {
70 LOG_DEBUG(Service_AM, "called");
71
66 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 72 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
67 rb.Push(RESULT_SUCCESS); 73 rb.Push(RESULT_SUCCESS);
68 rb.PushIpcInterface<ISelfController>(nvflinger); 74 rb.PushIpcInterface<ISelfController>(nvflinger);
69 LOG_DEBUG(Service_AM, "called");
70 } 75 }
71 76
72 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { 77 void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
78 LOG_DEBUG(Service_AM, "called");
79
73 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 80 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
74 rb.Push(RESULT_SUCCESS); 81 rb.Push(RESULT_SUCCESS);
75 rb.PushIpcInterface<ICommonStateGetter>(msg_queue); 82 rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
76 LOG_DEBUG(Service_AM, "called");
77 } 83 }
78 84
79 void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { 85 void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
86 LOG_DEBUG(Service_AM, "called");
87
80 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 88 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
81 rb.Push(RESULT_SUCCESS); 89 rb.Push(RESULT_SUCCESS);
82 rb.PushIpcInterface<ILibraryAppletCreator>(); 90 rb.PushIpcInterface<ILibraryAppletCreator>();
83 LOG_DEBUG(Service_AM, "called");
84 } 91 }
85 92
86 void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { 93 void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
94 LOG_DEBUG(Service_AM, "called");
95
87 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 96 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
88 rb.Push(RESULT_SUCCESS); 97 rb.Push(RESULT_SUCCESS);
89 rb.PushIpcInterface<IApplicationFunctions>(); 98 rb.PushIpcInterface<IApplicationFunctions>();
90 LOG_DEBUG(Service_AM, "called");
91 } 99 }
92 100
93 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 101 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
@@ -95,10 +103,11 @@ private:
95}; 103};
96 104
97void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { 105void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
106 LOG_DEBUG(Service_AM, "called");
107
98 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 108 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
99 rb.Push(RESULT_SUCCESS); 109 rb.Push(RESULT_SUCCESS);
100 rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue); 110 rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue);
101 LOG_DEBUG(Service_AM, "called");
102} 111}
103 112
104AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 113AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
new file mode 100644
index 000000000..47da35537
--- /dev/null
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -0,0 +1,114 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6#include "common/assert.h"
7#include "core/core.h"
8#include "core/hle/kernel/readable_event.h"
9#include "core/hle/kernel/server_port.h"
10#include "core/hle/kernel/writable_event.h"
11#include "core/hle/service/am/am.h"
12#include "core/hle/service/am/applets/applets.h"
13
14namespace Service::AM::Applets {
15
16AppletDataBroker::AppletDataBroker() {
17 auto& kernel = Core::System::GetInstance().Kernel();
18 state_changed_event = Kernel::WritableEvent::CreateEventPair(
19 kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:StateChangedEvent");
20 pop_out_data_event = Kernel::WritableEvent::CreateEventPair(
21 kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopDataOutEvent");
22 pop_interactive_out_data_event = Kernel::WritableEvent::CreateEventPair(
23 kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
24}
25
26AppletDataBroker::~AppletDataBroker() = default;
27
28std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
29 if (out_channel.empty())
30 return nullptr;
31
32 auto out = std::move(out_channel.front());
33 out_channel.pop();
34 return out;
35}
36
37std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToApplet() {
38 if (in_channel.empty())
39 return nullptr;
40
41 auto out = std::move(in_channel.front());
42 in_channel.pop();
43 return out;
44}
45
46std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
47 if (out_interactive_channel.empty())
48 return nullptr;
49
50 auto out = std::move(out_interactive_channel.front());
51 out_interactive_channel.pop();
52 return out;
53}
54
55std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
56 if (in_interactive_channel.empty())
57 return nullptr;
58
59 auto out = std::move(in_interactive_channel.front());
60 in_interactive_channel.pop();
61 return out;
62}
63
64void AppletDataBroker::PushNormalDataFromGame(IStorage storage) {
65 in_channel.push(std::make_unique<IStorage>(storage));
66}
67
68void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) {
69 out_channel.push(std::make_unique<IStorage>(storage));
70 pop_out_data_event.writable->Signal();
71}
72
73void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) {
74 in_interactive_channel.push(std::make_unique<IStorage>(storage));
75}
76
77void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) {
78 out_interactive_channel.push(std::make_unique<IStorage>(storage));
79 pop_interactive_out_data_event.writable->Signal();
80}
81
82void AppletDataBroker::SignalStateChanged() const {
83 state_changed_event.writable->Signal();
84}
85
86Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetNormalDataEvent() const {
87 return pop_out_data_event.readable;
88}
89
90Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const {
91 return pop_interactive_out_data_event.readable;
92}
93
94Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent() const {
95 return state_changed_event.readable;
96}
97
98Applet::Applet() = default;
99
100Applet::~Applet() = default;
101
102void Applet::Initialize() {
103 const auto common = broker.PopNormalDataToApplet();
104 ASSERT(common != nullptr);
105
106 const auto common_data = common->GetData();
107
108 ASSERT(common_data.size() >= sizeof(CommonArguments));
109 std::memcpy(&common_args, common_data.data(), sizeof(CommonArguments));
110
111 initialized = true;
112}
113
114} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
new file mode 100644
index 000000000..b0a8913c3
--- /dev/null
+++ b/src/core/hle/service/am/applets/applets.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 <memory>
8#include <queue>
9#include "common/swap.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/writable_event.h"
12
13union ResultCode;
14
15namespace Service::AM {
16
17class IStorage;
18
19namespace Applets {
20
21class AppletDataBroker final {
22public:
23 AppletDataBroker();
24 ~AppletDataBroker();
25
26 std::unique_ptr<IStorage> PopNormalDataToGame();
27 std::unique_ptr<IStorage> PopNormalDataToApplet();
28
29 std::unique_ptr<IStorage> PopInteractiveDataToGame();
30 std::unique_ptr<IStorage> PopInteractiveDataToApplet();
31
32 void PushNormalDataFromGame(IStorage storage);
33 void PushNormalDataFromApplet(IStorage storage);
34
35 void PushInteractiveDataFromGame(IStorage storage);
36 void PushInteractiveDataFromApplet(IStorage storage);
37
38 void SignalStateChanged() const;
39
40 Kernel::SharedPtr<Kernel::ReadableEvent> GetNormalDataEvent() const;
41 Kernel::SharedPtr<Kernel::ReadableEvent> GetInteractiveDataEvent() const;
42 Kernel::SharedPtr<Kernel::ReadableEvent> GetStateChangedEvent() const;
43
44private:
45 // Queues are named from applet's perspective
46
47 // PopNormalDataToApplet and PushNormalDataFromGame
48 std::queue<std::unique_ptr<IStorage>> in_channel;
49
50 // PopNormalDataToGame and PushNormalDataFromApplet
51 std::queue<std::unique_ptr<IStorage>> out_channel;
52
53 // PopInteractiveDataToApplet and PushInteractiveDataFromGame
54 std::queue<std::unique_ptr<IStorage>> in_interactive_channel;
55
56 // PopInteractiveDataToGame and PushInteractiveDataFromApplet
57 std::queue<std::unique_ptr<IStorage>> out_interactive_channel;
58
59 Kernel::EventPair state_changed_event;
60
61 // Signaled on PushNormalDataFromApplet
62 Kernel::EventPair pop_out_data_event;
63
64 // Signaled on PushInteractiveDataFromApplet
65 Kernel::EventPair pop_interactive_out_data_event;
66};
67
68class Applet {
69public:
70 Applet();
71 virtual ~Applet();
72
73 virtual void Initialize();
74
75 virtual bool TransactionComplete() const = 0;
76 virtual ResultCode GetStatus() const = 0;
77 virtual void ExecuteInteractive() = 0;
78 virtual void Execute() = 0;
79
80 bool IsInitialized() const {
81 return initialized;
82 }
83
84 AppletDataBroker& GetBroker() {
85 return broker;
86 }
87
88 const AppletDataBroker& GetBroker() const {
89 return broker;
90 }
91
92protected:
93 struct CommonArguments {
94 u32_le arguments_version;
95 u32_le size;
96 u32_le library_version;
97 u32_le theme_color;
98 u8 play_startup_sound;
99 u64_le system_tick;
100 };
101 static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size.");
102
103 CommonArguments common_args{};
104 AppletDataBroker broker;
105 bool initialized = false;
106};
107
108} // namespace Applets
109} // namespace Service::AM
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp
new file mode 100644
index 000000000..981bdec51
--- /dev/null
+++ b/src/core/hle/service/am/applets/software_keyboard.cpp
@@ -0,0 +1,161 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6#include "common/assert.h"
7#include "common/string_util.h"
8#include "core/core.h"
9#include "core/frontend/applets/software_keyboard.h"
10#include "core/hle/service/am/am.h"
11#include "core/hle/service/am/applets/software_keyboard.h"
12
13namespace Service::AM::Applets {
14
15constexpr std::size_t SWKBD_OUTPUT_BUFFER_SIZE = 0x7D8;
16constexpr std::size_t SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE = 0x7D4;
17constexpr std::size_t DEFAULT_MAX_LENGTH = 500;
18constexpr bool INTERACTIVE_STATUS_OK = false;
19
20static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters(
21 KeyboardConfig config, std::u16string initial_text) {
22 Core::Frontend::SoftwareKeyboardParameters params{};
23
24 params.submit_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
25 config.submit_text.data(), config.submit_text.size());
26 params.header_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(
27 config.header_text.data(), config.header_text.size());
28 params.sub_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.sub_text.data(),
29 config.sub_text.size());
30 params.guide_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(config.guide_text.data(),
31 config.guide_text.size());
32 params.initial_text = initial_text;
33 params.max_length = config.length_limit == 0 ? DEFAULT_MAX_LENGTH : config.length_limit;
34 params.password = static_cast<bool>(config.is_password);
35 params.cursor_at_beginning = static_cast<bool>(config.initial_cursor_position);
36 params.value = static_cast<u8>(config.keyset_disable_bitmask);
37
38 return params;
39}
40
41SoftwareKeyboard::SoftwareKeyboard() = default;
42
43SoftwareKeyboard::~SoftwareKeyboard() = default;
44
45void SoftwareKeyboard::Initialize() {
46 complete = false;
47 initial_text.clear();
48 final_data.clear();
49
50 Applet::Initialize();
51
52 const auto keyboard_config_storage = broker.PopNormalDataToApplet();
53 ASSERT(keyboard_config_storage != nullptr);
54 const auto& keyboard_config = keyboard_config_storage->GetData();
55
56 ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig));
57 std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig));
58
59 const auto work_buffer_storage = broker.PopNormalDataToApplet();
60 ASSERT(work_buffer_storage != nullptr);
61 const auto& work_buffer = work_buffer_storage->GetData();
62
63 if (config.initial_string_size == 0)
64 return;
65
66 std::vector<char16_t> string(config.initial_string_size);
67 std::memcpy(string.data(), work_buffer.data() + config.initial_string_offset,
68 string.size() * 2);
69 initial_text = Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size());
70}
71
72bool SoftwareKeyboard::TransactionComplete() const {
73 return complete;
74}
75
76ResultCode SoftwareKeyboard::GetStatus() const {
77 return RESULT_SUCCESS;
78}
79
80void SoftwareKeyboard::ExecuteInteractive() {
81 if (complete)
82 return;
83
84 const auto storage = broker.PopInteractiveDataToApplet();
85 ASSERT(storage != nullptr);
86 const auto data = storage->GetData();
87 const auto status = static_cast<bool>(data[0]);
88
89 if (status == INTERACTIVE_STATUS_OK) {
90 complete = true;
91 } else {
92 const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()};
93
94 std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string;
95 std::memcpy(string.data(), data.data() + 4, string.size() * 2);
96 frontend.SendTextCheckDialog(
97 Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()),
98 [this] { broker.SignalStateChanged(); });
99 }
100}
101
102void SoftwareKeyboard::Execute() {
103 if (complete) {
104 broker.PushNormalDataFromApplet(IStorage{final_data});
105 return;
106 }
107
108 const auto& frontend{Core::System::GetInstance().GetSoftwareKeyboard()};
109
110 const auto parameters = ConvertToFrontendParameters(config, initial_text);
111
112 frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(text); },
113 parameters);
114}
115
116void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
117 std::vector<u8> output_main(SWKBD_OUTPUT_BUFFER_SIZE);
118
119 if (text.has_value()) {
120 std::vector<u8> output_sub(SWKBD_OUTPUT_BUFFER_SIZE);
121
122 if (config.utf_8) {
123 const u64 size = text->size() + 8;
124 const auto new_text = Common::UTF16ToUTF8(*text);
125
126 std::memcpy(output_sub.data(), &size, sizeof(u64));
127 std::memcpy(output_sub.data() + 8, new_text.data(),
128 std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 8));
129
130 output_main[0] = INTERACTIVE_STATUS_OK;
131 std::memcpy(output_main.data() + 4, new_text.data(),
132 std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 4));
133 } else {
134 const u64 size = text->size() * 2 + 8;
135 std::memcpy(output_sub.data(), &size, sizeof(u64));
136 std::memcpy(output_sub.data() + 8, text->data(),
137 std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8));
138
139 output_main[0] = INTERACTIVE_STATUS_OK;
140 std::memcpy(output_main.data() + 4, text->data(),
141 std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 4));
142 }
143
144 complete = !config.text_check;
145 final_data = output_main;
146
147 if (complete) {
148 broker.PushNormalDataFromApplet(IStorage{output_main});
149 } else {
150 broker.PushInteractiveDataFromApplet(IStorage{output_sub});
151 }
152
153 broker.SignalStateChanged();
154 } else {
155 output_main[0] = 1;
156 complete = true;
157 broker.PushNormalDataFromApplet(IStorage{output_main});
158 broker.SignalStateChanged();
159 }
160}
161} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h
new file mode 100644
index 000000000..efd5753a1
--- /dev/null
+++ b/src/core/hle/service/am/applets/software_keyboard.h
@@ -0,0 +1,74 @@
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 <array>
8#include <string>
9#include <vector>
10
11#include "common/common_funcs.h"
12#include "common/swap.h"
13#include "core/hle/service/am/am.h"
14#include "core/hle/service/am/applets/applets.h"
15
16namespace Service::AM::Applets {
17
18enum class KeysetDisable : u32 {
19 Space = 0x02,
20 Address = 0x04,
21 Percent = 0x08,
22 Slashes = 0x10,
23 Numbers = 0x40,
24 DownloadCode = 0x80,
25};
26
27struct KeyboardConfig {
28 INSERT_PADDING_BYTES(4);
29 std::array<char16_t, 9> submit_text;
30 u16_le left_symbol_key;
31 u16_le right_symbol_key;
32 INSERT_PADDING_BYTES(1);
33 KeysetDisable keyset_disable_bitmask;
34 u32_le initial_cursor_position;
35 std::array<char16_t, 65> header_text;
36 std::array<char16_t, 129> sub_text;
37 std::array<char16_t, 257> guide_text;
38 u32_le length_limit;
39 INSERT_PADDING_BYTES(4);
40 u32_le is_password;
41 INSERT_PADDING_BYTES(5);
42 bool utf_8;
43 bool draw_background;
44 u32_le initial_string_offset;
45 u32_le initial_string_size;
46 u32_le user_dictionary_offset;
47 u32_le user_dictionary_size;
48 bool text_check;
49 u64_le text_check_callback;
50};
51static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect size.");
52
53class SoftwareKeyboard final : public Applet {
54public:
55 SoftwareKeyboard();
56 ~SoftwareKeyboard() override;
57
58 void Initialize() override;
59
60 bool TransactionComplete() const override;
61 ResultCode GetStatus() const override;
62 void ExecuteInteractive() override;
63 void Execute() override;
64
65 void WriteText(std::optional<std::u16string> text);
66
67private:
68 KeyboardConfig config;
69 std::u16string initial_text;
70 bool complete = false;
71 std::vector<u8> final_data;
72};
73
74} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/stub_applet.cpp b/src/core/hle/service/am/applets/stub_applet.cpp
new file mode 100644
index 000000000..ed166b87d
--- /dev/null
+++ b/src/core/hle/service/am/applets/stub_applet.cpp
@@ -0,0 +1,70 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <string>
6
7#include "common/hex_util.h"
8#include "common/logging/log.h"
9#include "core/hle/result.h"
10#include "core/hle/service/am/am.h"
11#include "core/hle/service/am/applets/stub_applet.h"
12
13namespace Service::AM::Applets {
14
15static void LogCurrentStorage(AppletDataBroker& broker, std::string prefix) {
16 std::unique_ptr<IStorage> storage = broker.PopNormalDataToApplet();
17 for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) {
18 const auto data = storage->GetData();
19 LOG_INFO(Service_AM,
20 "called (STUBBED), during {} recieved normal data with size={:08X}, data={}",
21 prefix, data.size(), Common::HexVectorToString(data));
22 }
23
24 storage = broker.PopInteractiveDataToApplet();
25 for (; storage != nullptr; storage = broker.PopInteractiveDataToApplet()) {
26 const auto data = storage->GetData();
27 LOG_INFO(Service_AM,
28 "called (STUBBED), during {} recieved interactive data with size={:08X}, data={}",
29 prefix, data.size(), Common::HexVectorToString(data));
30 }
31}
32
33StubApplet::StubApplet() = default;
34
35StubApplet::~StubApplet() = default;
36
37void StubApplet::Initialize() {
38 LOG_WARNING(Service_AM, "called (STUBBED)");
39 Applet::Initialize();
40 LogCurrentStorage(broker, "Initialize");
41}
42
43bool StubApplet::TransactionComplete() const {
44 LOG_WARNING(Service_AM, "called (STUBBED)");
45 return true;
46}
47
48ResultCode StubApplet::GetStatus() const {
49 LOG_WARNING(Service_AM, "called (STUBBED)");
50 return RESULT_SUCCESS;
51}
52
53void StubApplet::ExecuteInteractive() {
54 LOG_WARNING(Service_AM, "called (STUBBED)");
55 LogCurrentStorage(broker, "ExecuteInteractive");
56
57 broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)});
58 broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)});
59 broker.SignalStateChanged();
60}
61
62void StubApplet::Execute() {
63 LOG_WARNING(Service_AM, "called (STUBBED)");
64 LogCurrentStorage(broker, "Execute");
65
66 broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)});
67 broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)});
68 broker.SignalStateChanged();
69}
70} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/stub_applet.h b/src/core/hle/service/am/applets/stub_applet.h
new file mode 100644
index 000000000..7d8dc968d
--- /dev/null
+++ b/src/core/hle/service/am/applets/stub_applet.h
@@ -0,0 +1,24 @@
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 "core/hle/service/am/applets/applets.h"
8
9namespace Service::AM::Applets {
10
11class StubApplet final : public Applet {
12public:
13 StubApplet();
14 ~StubApplet() override;
15
16 void Initialize() override;
17
18 bool TransactionComplete() const override;
19 ResultCode GetStatus() const override;
20 void ExecuteInteractive() override;
21 void Execute() override;
22};
23
24} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index 54305cf05..0417fdb92 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -13,8 +13,10 @@
13#include "core/file_sys/patch_manager.h" 13#include "core/file_sys/patch_manager.h"
14#include "core/file_sys/registered_cache.h" 14#include "core/file_sys/registered_cache.h"
15#include "core/hle/ipc_helpers.h" 15#include "core/hle/ipc_helpers.h"
16#include "core/hle/kernel/event.h" 16#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/process.h" 17#include "core/hle/kernel/process.h"
18#include "core/hle/kernel/readable_event.h"
19#include "core/hle/kernel/writable_event.h"
18#include "core/hle/service/aoc/aoc_u.h" 20#include "core/hle/service/aoc/aoc_u.h"
19#include "core/hle/service/filesystem/filesystem.h" 21#include "core/hle/service/filesystem/filesystem.h"
20#include "core/loader/loader.h" 22#include "core/loader/loader.h"
@@ -32,14 +34,14 @@ static std::vector<u64> AccumulateAOCTitleIDs() {
32 std::vector<u64> add_on_content; 34 std::vector<u64> add_on_content;
33 const auto rcu = FileSystem::GetUnionContents(); 35 const auto rcu = FileSystem::GetUnionContents();
34 const auto list = 36 const auto list =
35 rcu->ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); 37 rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
36 std::transform(list.begin(), list.end(), std::back_inserter(add_on_content), 38 std::transform(list.begin(), list.end(), std::back_inserter(add_on_content),
37 [](const FileSys::RegisteredCacheEntry& rce) { return rce.title_id; }); 39 [](const FileSys::RegisteredCacheEntry& rce) { return rce.title_id; });
38 add_on_content.erase( 40 add_on_content.erase(
39 std::remove_if( 41 std::remove_if(
40 add_on_content.begin(), add_on_content.end(), 42 add_on_content.begin(), add_on_content.end(),
41 [&rcu](u64 tid) { 43 [&rcu](u64 tid) {
42 return rcu->GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() != 44 return rcu.GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() !=
43 Loader::ResultStatus::Success; 45 Loader::ResultStatus::Success;
44 }), 46 }),
45 add_on_content.end()); 47 add_on_content.end());
@@ -61,13 +63,15 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs
61 RegisterHandlers(functions); 63 RegisterHandlers(functions);
62 64
63 auto& kernel = Core::System::GetInstance().Kernel(); 65 auto& kernel = Core::System::GetInstance().Kernel();
64 aoc_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, 66 aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
65 "GetAddOnContentListChanged:Event"); 67 "GetAddOnContentListChanged:Event");
66} 68}
67 69
68AOC_U::~AOC_U() = default; 70AOC_U::~AOC_U() = default;
69 71
70void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { 72void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) {
73 LOG_DEBUG(Service_AOC, "called");
74
71 IPC::ResponseBuilder rb{ctx, 3}; 75 IPC::ResponseBuilder rb{ctx, 3};
72 rb.Push(RESULT_SUCCESS); 76 rb.Push(RESULT_SUCCESS);
73 77
@@ -82,6 +86,7 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
82 86
83 const auto offset = rp.PopRaw<u32>(); 87 const auto offset = rp.PopRaw<u32>();
84 auto count = rp.PopRaw<u32>(); 88 auto count = rp.PopRaw<u32>();
89 LOG_DEBUG(Service_AOC, "called with offset={}, count={}", offset, count);
85 90
86 const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID(); 91 const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID();
87 92
@@ -110,6 +115,8 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) {
110} 115}
111 116
112void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) { 117void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) {
118 LOG_DEBUG(Service_AOC, "called");
119
113 IPC::ResponseBuilder rb{ctx, 4}; 120 IPC::ResponseBuilder rb{ctx, 4};
114 rb.Push(RESULT_SUCCESS); 121 rb.Push(RESULT_SUCCESS);
115 const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); 122 const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
@@ -128,7 +135,6 @@ void AOC_U::PrepareAddOnContent(Kernel::HLERequestContext& ctx) {
128 IPC::RequestParser rp{ctx}; 135 IPC::RequestParser rp{ctx};
129 136
130 const auto aoc_id = rp.PopRaw<u32>(); 137 const auto aoc_id = rp.PopRaw<u32>();
131
132 LOG_WARNING(Service_AOC, "(STUBBED) called with aoc_id={:08X}", aoc_id); 138 LOG_WARNING(Service_AOC, "(STUBBED) called with aoc_id={:08X}", aoc_id);
133 139
134 IPC::ResponseBuilder rb{ctx, 2}; 140 IPC::ResponseBuilder rb{ctx, 2};
@@ -140,7 +146,7 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) {
140 146
141 IPC::ResponseBuilder rb{ctx, 2, 1}; 147 IPC::ResponseBuilder rb{ctx, 2, 1};
142 rb.Push(RESULT_SUCCESS); 148 rb.Push(RESULT_SUCCESS);
143 rb.PushCopyObjects(aoc_change_event); 149 rb.PushCopyObjects(aoc_change_event.readable);
144} 150}
145 151
146void InstallInterfaces(SM::ServiceManager& service_manager) { 152void InstallInterfaces(SM::ServiceManager& service_manager) {
diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h
index 68d94fdaa..5effea730 100644
--- a/src/core/hle/service/aoc/aoc_u.h
+++ b/src/core/hle/service/aoc/aoc_u.h
@@ -6,6 +6,10 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Kernel {
10class WritableEvent;
11}
12
9namespace Service::AOC { 13namespace Service::AOC {
10 14
11class AOC_U final : public ServiceFramework<AOC_U> { 15class AOC_U final : public ServiceFramework<AOC_U> {
@@ -21,7 +25,7 @@ private:
21 void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx); 25 void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx);
22 26
23 std::vector<u64> add_on_content; 27 std::vector<u64> add_on_content;
24 Kernel::SharedPtr<Kernel::Event> aoc_change_event; 28 Kernel::EventPair aoc_change_event;
25}; 29};
26 30
27/// Registers all AOC services with the specified service manager. 31/// Registers all AOC services with the specified service manager.
diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp
index c22bd3859..fcacbab72 100644
--- a/src/core/hle/service/apm/interface.cpp
+++ b/src/core/hle/service/apm/interface.cpp
@@ -40,24 +40,22 @@ private:
40 40
41 auto mode = static_cast<PerformanceMode>(rp.Pop<u32>()); 41 auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
42 u32 config = rp.Pop<u32>(); 42 u32 config = rp.Pop<u32>();
43 LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode),
44 config);
43 45
44 IPC::ResponseBuilder rb{ctx, 2}; 46 IPC::ResponseBuilder rb{ctx, 2};
45 rb.Push(RESULT_SUCCESS); 47 rb.Push(RESULT_SUCCESS);
46
47 LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode),
48 config);
49 } 48 }
50 49
51 void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) { 50 void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) {
52 IPC::RequestParser rp{ctx}; 51 IPC::RequestParser rp{ctx};
53 52
54 auto mode = static_cast<PerformanceMode>(rp.Pop<u32>()); 53 auto mode = static_cast<PerformanceMode>(rp.Pop<u32>());
54 LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode));
55 55
56 IPC::ResponseBuilder rb{ctx, 3}; 56 IPC::ResponseBuilder rb{ctx, 3};
57 rb.Push(RESULT_SUCCESS); 57 rb.Push(RESULT_SUCCESS);
58 rb.Push<u32>(static_cast<u32>(PerformanceConfiguration::Config1)); 58 rb.Push<u32>(static_cast<u32>(PerformanceConfiguration::Config1));
59
60 LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode));
61 } 59 }
62}; 60};
63 61
@@ -73,11 +71,11 @@ APM::APM(std::shared_ptr<Module> apm, const char* name)
73APM::~APM() = default; 71APM::~APM() = default;
74 72
75void APM::OpenSession(Kernel::HLERequestContext& ctx) { 73void APM::OpenSession(Kernel::HLERequestContext& ctx) {
74 LOG_DEBUG(Service_APM, "called");
75
76 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 76 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
77 rb.Push(RESULT_SUCCESS); 77 rb.Push(RESULT_SUCCESS);
78 rb.PushIpcInterface<ISession>(); 78 rb.PushIpcInterface<ISession>();
79
80 LOG_DEBUG(Service_APM, "called");
81} 79}
82 80
83APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} { 81APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
@@ -98,11 +96,11 @@ APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
98APM_Sys::~APM_Sys() = default; 96APM_Sys::~APM_Sys() = default;
99 97
100void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) { 98void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) {
99 LOG_DEBUG(Service_APM, "called");
100
101 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 101 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
102 rb.Push(RESULT_SUCCESS); 102 rb.Push(RESULT_SUCCESS);
103 rb.PushIpcInterface<ISession>(); 103 rb.PushIpcInterface<ISession>();
104
105 LOG_DEBUG(Service_APM, "called");
106} 104}
107 105
108} // namespace Service::APM 106} // namespace Service::APM
diff --git a/src/core/hle/service/arp/arp.cpp b/src/core/hle/service/arp/arp.cpp
index 358ef2576..e675b0188 100644
--- a/src/core/hle/service/arp/arp.cpp
+++ b/src/core/hle/service/arp/arp.cpp
@@ -59,11 +59,11 @@ public:
59 59
60private: 60private:
61 void AcquireRegistrar(Kernel::HLERequestContext& ctx) { 61 void AcquireRegistrar(Kernel::HLERequestContext& ctx) {
62 LOG_DEBUG(Service_ARP, "called");
63
62 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 64 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
63 rb.Push(RESULT_SUCCESS); 65 rb.Push(RESULT_SUCCESS);
64 rb.PushIpcInterface<IRegistrar>(); 66 rb.PushIpcInterface<IRegistrar>();
65
66 LOG_DEBUG(Service_ARP, "called");
67 } 67 }
68}; 68};
69 69
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index ff1edefbb..dc6a6b188 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -13,8 +13,10 @@
13#include "common/swap.h" 13#include "common/swap.h"
14#include "core/core.h" 14#include "core/core.h"
15#include "core/hle/ipc_helpers.h" 15#include "core/hle/ipc_helpers.h"
16#include "core/hle/kernel/event.h"
17#include "core/hle/kernel/hle_ipc.h" 16#include "core/hle/kernel/hle_ipc.h"
17#include "core/hle/kernel/kernel.h"
18#include "core/hle/kernel/readable_event.h"
19#include "core/hle/kernel/writable_event.h"
18#include "core/hle/service/audio/audout_u.h" 20#include "core/hle/service/audio/audout_u.h"
19#include "core/memory.h" 21#include "core/memory.h"
20 22
@@ -44,8 +46,10 @@ enum class AudioState : u32 {
44 46
45class IAudioOut final : public ServiceFramework<IAudioOut> { 47class IAudioOut final : public ServiceFramework<IAudioOut> {
46public: 48public:
47 IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core) 49 IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core, std::string&& device_name,
48 : ServiceFramework("IAudioOut"), audio_core(audio_core), audio_params(audio_params) { 50 std::string&& unique_name)
51 : ServiceFramework("IAudioOut"), audio_core(audio_core),
52 device_name(std::move(device_name)), audio_params(audio_params) {
49 53
50 static const FunctionInfo functions[] = { 54 static const FunctionInfo functions[] = {
51 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, 55 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
@@ -65,11 +69,12 @@ public:
65 69
66 // This is the event handle used to check if the audio buffer was released 70 // This is the event handle used to check if the audio buffer was released
67 auto& kernel = Core::System::GetInstance().Kernel(); 71 auto& kernel = Core::System::GetInstance().Kernel();
68 buffer_event = 72 buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
69 Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioOutBufferReleased"); 73 "IAudioOutBufferReleased");
70 74
71 stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count, 75 stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count,
72 "IAudioOut", [=]() { buffer_event->Signal(); }); 76 std::move(unique_name),
77 [=]() { buffer_event.writable->Signal(); });
73 } 78 }
74 79
75private: 80private:
@@ -84,6 +89,7 @@ private:
84 89
85 void GetAudioOutState(Kernel::HLERequestContext& ctx) { 90 void GetAudioOutState(Kernel::HLERequestContext& ctx) {
86 LOG_DEBUG(Service_Audio, "called"); 91 LOG_DEBUG(Service_Audio, "called");
92
87 IPC::ResponseBuilder rb{ctx, 3}; 93 IPC::ResponseBuilder rb{ctx, 3};
88 rb.Push(RESULT_SUCCESS); 94 rb.Push(RESULT_SUCCESS);
89 rb.Push(static_cast<u32>(stream->IsPlaying() ? AudioState::Started : AudioState::Stopped)); 95 rb.Push(static_cast<u32>(stream->IsPlaying() ? AudioState::Started : AudioState::Stopped));
@@ -118,7 +124,7 @@ private:
118 124
119 IPC::ResponseBuilder rb{ctx, 2, 1}; 125 IPC::ResponseBuilder rb{ctx, 2, 1};
120 rb.Push(RESULT_SUCCESS); 126 rb.Push(RESULT_SUCCESS);
121 rb.PushCopyObjects(buffer_event); 127 rb.PushCopyObjects(buffer_event.readable);
122 } 128 }
123 129
124 void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { 130 void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
@@ -146,6 +152,7 @@ private:
146 152
147 void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { 153 void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
148 LOG_DEBUG(Service_Audio, "called {}", ctx.Description()); 154 LOG_DEBUG(Service_Audio, "called {}", ctx.Description());
155
149 IPC::RequestParser rp{ctx}; 156 IPC::RequestParser rp{ctx};
150 const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)}; 157 const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)};
151 const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)}; 158 const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)};
@@ -161,6 +168,7 @@ private:
161 168
162 void ContainsAudioOutBuffer(Kernel::HLERequestContext& ctx) { 169 void ContainsAudioOutBuffer(Kernel::HLERequestContext& ctx) {
163 LOG_DEBUG(Service_Audio, "called"); 170 LOG_DEBUG(Service_Audio, "called");
171
164 IPC::RequestParser rp{ctx}; 172 IPC::RequestParser rp{ctx};
165 const u64 tag{rp.Pop<u64>()}; 173 const u64 tag{rp.Pop<u64>()};
166 IPC::ResponseBuilder rb{ctx, 3}; 174 IPC::ResponseBuilder rb{ctx, 3};
@@ -170,6 +178,7 @@ private:
170 178
171 void GetAudioOutBufferCount(Kernel::HLERequestContext& ctx) { 179 void GetAudioOutBufferCount(Kernel::HLERequestContext& ctx) {
172 LOG_DEBUG(Service_Audio, "called"); 180 LOG_DEBUG(Service_Audio, "called");
181
173 IPC::ResponseBuilder rb{ctx, 3}; 182 IPC::ResponseBuilder rb{ctx, 3};
174 rb.Push(RESULT_SUCCESS); 183 rb.Push(RESULT_SUCCESS);
175 rb.Push(static_cast<u32>(stream->GetQueueSize())); 184 rb.Push(static_cast<u32>(stream->GetQueueSize()));
@@ -177,15 +186,17 @@ private:
177 186
178 AudioCore::AudioOut& audio_core; 187 AudioCore::AudioOut& audio_core;
179 AudioCore::StreamPtr stream; 188 AudioCore::StreamPtr stream;
189 std::string device_name;
180 190
181 AudoutParams audio_params{}; 191 AudoutParams audio_params{};
182 192
183 /// This is the evend handle used to check if the audio buffer was released 193 /// This is the event handle used to check if the audio buffer was released
184 Kernel::SharedPtr<Kernel::Event> buffer_event; 194 Kernel::EventPair buffer_event;
185}; 195};
186 196
187void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) { 197void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
188 LOG_DEBUG(Service_Audio, "called"); 198 LOG_DEBUG(Service_Audio, "called");
199
189 IPC::RequestParser rp{ctx}; 200 IPC::RequestParser rp{ctx};
190 201
191 ctx.WriteBuffer(DefaultDevice); 202 ctx.WriteBuffer(DefaultDevice);
@@ -199,7 +210,15 @@ void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
199void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) { 210void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
200 LOG_DEBUG(Service_Audio, "called"); 211 LOG_DEBUG(Service_Audio, "called");
201 212
202 ctx.WriteBuffer(DefaultDevice); 213 const auto device_name_data{ctx.ReadBuffer()};
214 std::string device_name;
215 if (device_name_data[0] != '\0') {
216 device_name.assign(device_name_data.begin(), device_name_data.end());
217 } else {
218 device_name.assign(DefaultDevice.begin(), DefaultDevice.end());
219 }
220 ctx.WriteBuffer(device_name);
221
203 IPC::RequestParser rp{ctx}; 222 IPC::RequestParser rp{ctx};
204 auto params{rp.PopRaw<AudoutParams>()}; 223 auto params{rp.PopRaw<AudoutParams>()};
205 if (params.channel_count <= 2) { 224 if (params.channel_count <= 2) {
@@ -212,10 +231,9 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
212 params.sample_rate = DefaultSampleRate; 231 params.sample_rate = DefaultSampleRate;
213 } 232 }
214 233
215 // TODO(bunnei): Support more than one IAudioOut interface. When we add this, ListAudioOutsImpl 234 std::string unique_name{fmt::format("{}-{}", device_name, audio_out_interfaces.size())};
216 // will likely need to be updated as well. 235 auto audio_out_interface = std::make_shared<IAudioOut>(
217 ASSERT_MSG(!audio_out_interface, "Unimplemented"); 236 params, *audio_core, std::move(device_name), std::move(unique_name));
218 audio_out_interface = std::make_shared<IAudioOut>(params, *audio_core);
219 237
220 IPC::ResponseBuilder rb{ctx, 6, 0, 1}; 238 IPC::ResponseBuilder rb{ctx, 6, 0, 1};
221 rb.Push(RESULT_SUCCESS); 239 rb.Push(RESULT_SUCCESS);
@@ -224,6 +242,8 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) {
224 rb.Push<u32>(static_cast<u32>(AudioCore::Codec::PcmFormat::Int16)); 242 rb.Push<u32>(static_cast<u32>(AudioCore::Codec::PcmFormat::Int16));
225 rb.Push<u32>(static_cast<u32>(AudioState::Stopped)); 243 rb.Push<u32>(static_cast<u32>(AudioState::Stopped));
226 rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface); 244 rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface);
245
246 audio_out_interfaces.push_back(std::move(audio_out_interface));
227} 247}
228 248
229AudOutU::AudOutU() : ServiceFramework("audout:u") { 249AudOutU::AudOutU() : ServiceFramework("audout:u") {
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h
index dcaf64708..aed4c43b2 100644
--- a/src/core/hle/service/audio/audout_u.h
+++ b/src/core/hle/service/audio/audout_u.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <vector>
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8 9
9namespace AudioCore { 10namespace AudioCore {
@@ -24,7 +25,7 @@ public:
24 ~AudOutU() override; 25 ~AudOutU() override;
25 26
26private: 27private:
27 std::shared_ptr<IAudioOut> audio_out_interface; 28 std::vector<std::shared_ptr<IAudioOut>> audio_out_interfaces;
28 std::unique_ptr<AudioCore::AudioOut> audio_core; 29 std::unique_ptr<AudioCore::AudioOut> audio_core;
29 30
30 void ListAudioOutsImpl(Kernel::HLERequestContext& ctx); 31 void ListAudioOutsImpl(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index fac6785a5..945259c7d 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -12,8 +12,10 @@
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "core/core.h" 13#include "core/core.h"
14#include "core/hle/ipc_helpers.h" 14#include "core/hle/ipc_helpers.h"
15#include "core/hle/kernel/event.h"
16#include "core/hle/kernel/hle_ipc.h" 15#include "core/hle/kernel/hle_ipc.h"
16#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/readable_event.h"
18#include "core/hle/kernel/writable_event.h"
17#include "core/hle/service/audio/audren_u.h" 19#include "core/hle/service/audio/audren_u.h"
18 20
19namespace Service::Audio { 21namespace Service::Audio {
@@ -28,90 +30,116 @@ public:
28 {1, &IAudioRenderer::GetSampleCount, "GetSampleCount"}, 30 {1, &IAudioRenderer::GetSampleCount, "GetSampleCount"},
29 {2, &IAudioRenderer::GetMixBufferCount, "GetMixBufferCount"}, 31 {2, &IAudioRenderer::GetMixBufferCount, "GetMixBufferCount"},
30 {3, &IAudioRenderer::GetState, "GetState"}, 32 {3, &IAudioRenderer::GetState, "GetState"},
31 {4, &IAudioRenderer::RequestUpdate, "RequestUpdate"}, 33 {4, &IAudioRenderer::RequestUpdateImpl, "RequestUpdate"},
32 {5, &IAudioRenderer::Start, "Start"}, 34 {5, &IAudioRenderer::Start, "Start"},
33 {6, &IAudioRenderer::Stop, "Stop"}, 35 {6, &IAudioRenderer::Stop, "Stop"},
34 {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"}, 36 {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
35 {8, nullptr, "SetRenderingTimeLimit"}, 37 {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"},
36 {9, nullptr, "GetRenderingTimeLimit"}, 38 {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"},
37 {10, nullptr, "RequestUpdateAuto"}, 39 {10, &IAudioRenderer::RequestUpdateImpl, "RequestUpdateAuto"},
38 {11, nullptr, "ExecuteAudioRendererRendering"}, 40 {11, nullptr, "ExecuteAudioRendererRendering"},
39 }; 41 };
40 // clang-format on 42 // clang-format on
41 RegisterHandlers(functions); 43 RegisterHandlers(functions);
42 44
43 auto& kernel = Core::System::GetInstance().Kernel(); 45 auto& kernel = Core::System::GetInstance().Kernel();
44 system_event = 46 system_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
45 Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent"); 47 "IAudioRenderer:SystemEvent");
46 renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event); 48 renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event.writable);
47 } 49 }
48 50
49private: 51private:
50 void UpdateAudioCallback() { 52 void UpdateAudioCallback() {
51 system_event->Signal(); 53 system_event.writable->Signal();
52 } 54 }
53 55
54 void GetSampleRate(Kernel::HLERequestContext& ctx) { 56 void GetSampleRate(Kernel::HLERequestContext& ctx) {
57 LOG_DEBUG(Service_Audio, "called");
58
55 IPC::ResponseBuilder rb{ctx, 3}; 59 IPC::ResponseBuilder rb{ctx, 3};
56 rb.Push(RESULT_SUCCESS); 60 rb.Push(RESULT_SUCCESS);
57 rb.Push<u32>(renderer->GetSampleRate()); 61 rb.Push<u32>(renderer->GetSampleRate());
58 LOG_DEBUG(Service_Audio, "called");
59 } 62 }
60 63
61 void GetSampleCount(Kernel::HLERequestContext& ctx) { 64 void GetSampleCount(Kernel::HLERequestContext& ctx) {
65 LOG_DEBUG(Service_Audio, "called");
66
62 IPC::ResponseBuilder rb{ctx, 3}; 67 IPC::ResponseBuilder rb{ctx, 3};
63 rb.Push(RESULT_SUCCESS); 68 rb.Push(RESULT_SUCCESS);
64 rb.Push<u32>(renderer->GetSampleCount()); 69 rb.Push<u32>(renderer->GetSampleCount());
65 LOG_DEBUG(Service_Audio, "called");
66 } 70 }
67 71
68 void GetState(Kernel::HLERequestContext& ctx) { 72 void GetState(Kernel::HLERequestContext& ctx) {
73 LOG_DEBUG(Service_Audio, "called");
74
69 IPC::ResponseBuilder rb{ctx, 3}; 75 IPC::ResponseBuilder rb{ctx, 3};
70 rb.Push(RESULT_SUCCESS); 76 rb.Push(RESULT_SUCCESS);
71 rb.Push<u32>(static_cast<u32>(renderer->GetStreamState())); 77 rb.Push<u32>(static_cast<u32>(renderer->GetStreamState()));
72 LOG_DEBUG(Service_Audio, "called");
73 } 78 }
74 79
75 void GetMixBufferCount(Kernel::HLERequestContext& ctx) { 80 void GetMixBufferCount(Kernel::HLERequestContext& ctx) {
81 LOG_DEBUG(Service_Audio, "called");
82
76 IPC::ResponseBuilder rb{ctx, 3}; 83 IPC::ResponseBuilder rb{ctx, 3};
77 rb.Push(RESULT_SUCCESS); 84 rb.Push(RESULT_SUCCESS);
78 rb.Push<u32>(renderer->GetMixBufferCount()); 85 rb.Push<u32>(renderer->GetMixBufferCount());
79 LOG_DEBUG(Service_Audio, "called");
80 } 86 }
81 87
82 void RequestUpdate(Kernel::HLERequestContext& ctx) { 88 void RequestUpdateImpl(Kernel::HLERequestContext& ctx) {
89 LOG_WARNING(Service_Audio, "(STUBBED) called");
90
83 ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer())); 91 ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer()));
84 IPC::ResponseBuilder rb{ctx, 2}; 92 IPC::ResponseBuilder rb{ctx, 2};
85 rb.Push(RESULT_SUCCESS); 93 rb.Push(RESULT_SUCCESS);
86 LOG_WARNING(Service_Audio, "(STUBBED) called");
87 } 94 }
88 95
89 void Start(Kernel::HLERequestContext& ctx) { 96 void Start(Kernel::HLERequestContext& ctx) {
97 LOG_WARNING(Service_Audio, "(STUBBED) called");
98
90 IPC::ResponseBuilder rb{ctx, 2}; 99 IPC::ResponseBuilder rb{ctx, 2};
91 100
92 rb.Push(RESULT_SUCCESS); 101 rb.Push(RESULT_SUCCESS);
93
94 LOG_WARNING(Service_Audio, "(STUBBED) called");
95 } 102 }
96 103
97 void Stop(Kernel::HLERequestContext& ctx) { 104 void Stop(Kernel::HLERequestContext& ctx) {
105 LOG_WARNING(Service_Audio, "(STUBBED) called");
106
98 IPC::ResponseBuilder rb{ctx, 2}; 107 IPC::ResponseBuilder rb{ctx, 2};
99 108
100 rb.Push(RESULT_SUCCESS); 109 rb.Push(RESULT_SUCCESS);
101
102 LOG_WARNING(Service_Audio, "(STUBBED) called");
103 } 110 }
104 111
105 void QuerySystemEvent(Kernel::HLERequestContext& ctx) { 112 void QuerySystemEvent(Kernel::HLERequestContext& ctx) {
113 LOG_WARNING(Service_Audio, "(STUBBED) called");
114
106 IPC::ResponseBuilder rb{ctx, 2, 1}; 115 IPC::ResponseBuilder rb{ctx, 2, 1};
107 rb.Push(RESULT_SUCCESS); 116 rb.Push(RESULT_SUCCESS);
108 rb.PushCopyObjects(system_event); 117 rb.PushCopyObjects(system_event.readable);
118 }
109 119
110 LOG_WARNING(Service_Audio, "(STUBBED) called"); 120 void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
121 IPC::RequestParser rp{ctx};
122 rendering_time_limit_percent = rp.Pop<u32>();
123 LOG_DEBUG(Service_Audio, "called. rendering_time_limit_percent={}",
124 rendering_time_limit_percent);
125
126 ASSERT(rendering_time_limit_percent >= 0 && rendering_time_limit_percent <= 100);
127
128 IPC::ResponseBuilder rb{ctx, 2};
129 rb.Push(RESULT_SUCCESS);
111 } 130 }
112 131
113 Kernel::SharedPtr<Kernel::Event> system_event; 132 void GetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
133 LOG_DEBUG(Service_Audio, "called");
134
135 IPC::ResponseBuilder rb{ctx, 3};
136 rb.Push(RESULT_SUCCESS);
137 rb.Push(rendering_time_limit_percent);
138 }
139
140 Kernel::EventPair system_event;
114 std::unique_ptr<AudioCore::AudioRenderer> renderer; 141 std::unique_ptr<AudioCore::AudioRenderer> renderer;
142 u32 rendering_time_limit_percent = 100;
115}; 143};
116 144
117class IAudioDevice final : public ServiceFramework<IAudioDevice> { 145class IAudioDevice final : public ServiceFramework<IAudioDevice> {
@@ -136,8 +164,8 @@ public:
136 RegisterHandlers(functions); 164 RegisterHandlers(functions);
137 165
138 auto& kernel = Core::System::GetInstance().Kernel(); 166 auto& kernel = Core::System::GetInstance().Kernel();
139 buffer_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, 167 buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
140 "IAudioOutBufferReleasedEvent"); 168 "IAudioOutBufferReleasedEvent");
141 } 169 }
142 170
143private: 171private:
@@ -181,21 +209,22 @@ private:
181 void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) { 209 void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) {
182 LOG_WARNING(Service_Audio, "(STUBBED) called"); 210 LOG_WARNING(Service_Audio, "(STUBBED) called");
183 211
184 buffer_event->Signal(); 212 buffer_event.writable->Signal();
185 213
186 IPC::ResponseBuilder rb{ctx, 2, 1}; 214 IPC::ResponseBuilder rb{ctx, 2, 1};
187 rb.Push(RESULT_SUCCESS); 215 rb.Push(RESULT_SUCCESS);
188 rb.PushCopyObjects(buffer_event); 216 rb.PushCopyObjects(buffer_event.readable);
189 } 217 }
190 218
191 void GetActiveChannelCount(Kernel::HLERequestContext& ctx) { 219 void GetActiveChannelCount(Kernel::HLERequestContext& ctx) {
192 LOG_WARNING(Service_Audio, "(STUBBED) called"); 220 LOG_WARNING(Service_Audio, "(STUBBED) called");
221
193 IPC::ResponseBuilder rb{ctx, 3}; 222 IPC::ResponseBuilder rb{ctx, 3};
194 rb.Push(RESULT_SUCCESS); 223 rb.Push(RESULT_SUCCESS);
195 rb.Push<u32>(1); 224 rb.Push<u32>(1);
196 } 225 }
197 226
198 Kernel::SharedPtr<Kernel::Event> buffer_event; 227 Kernel::EventPair buffer_event;
199 228
200}; // namespace Audio 229}; // namespace Audio
201 230
@@ -214,19 +243,20 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") {
214AudRenU::~AudRenU() = default; 243AudRenU::~AudRenU() = default;
215 244
216void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { 245void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
246 LOG_DEBUG(Service_Audio, "called");
247
217 IPC::RequestParser rp{ctx}; 248 IPC::RequestParser rp{ctx};
218 auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); 249 auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
219 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 250 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
220 251
221 rb.Push(RESULT_SUCCESS); 252 rb.Push(RESULT_SUCCESS);
222 rb.PushIpcInterface<Audio::IAudioRenderer>(std::move(params)); 253 rb.PushIpcInterface<Audio::IAudioRenderer>(std::move(params));
223
224 LOG_DEBUG(Service_Audio, "called");
225} 254}
226 255
227void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { 256void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
228 IPC::RequestParser rp{ctx}; 257 IPC::RequestParser rp{ctx};
229 auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); 258 auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
259 LOG_DEBUG(Service_Audio, "called");
230 260
231 u64 buffer_sz = Common::AlignUp(4 * params.mix_buffer_count, 0x40); 261 u64 buffer_sz = Common::AlignUp(4 * params.mix_buffer_count, 0x40);
232 buffer_sz += params.unknown_c * 1024; 262 buffer_sz += params.unknown_c * 1024;
@@ -280,26 +310,26 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
280 rb.Push(RESULT_SUCCESS); 310 rb.Push(RESULT_SUCCESS);
281 rb.Push<u64>(output_sz); 311 rb.Push<u64>(output_sz);
282 312
283 LOG_DEBUG(Service_Audio, "called, buffer_size=0x{:X}", output_sz); 313 LOG_DEBUG(Service_Audio, "buffer_size=0x{:X}", output_sz);
284} 314}
285 315
286void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) { 316void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) {
317 LOG_DEBUG(Service_Audio, "called");
318
287 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 319 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
288 320
289 rb.Push(RESULT_SUCCESS); 321 rb.Push(RESULT_SUCCESS);
290 rb.PushIpcInterface<Audio::IAudioDevice>(); 322 rb.PushIpcInterface<Audio::IAudioDevice>();
291
292 LOG_DEBUG(Service_Audio, "called");
293} 323}
294 324
295void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) { 325void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) {
326 LOG_WARNING(Service_Audio, "(STUBBED) called");
327
296 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 328 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
297 329
298 rb.Push(RESULT_SUCCESS); 330 rb.Push(RESULT_SUCCESS);
299 rb.PushIpcInterface<Audio::IAudioDevice>(); 331 rb.PushIpcInterface<Audio::IAudioDevice>(); // TODO(ogniK): Figure out what is different
300 332 // based on the current revision
301 LOG_WARNING(Service_Audio, "(STUBBED) called"); // TODO(ogniK): Figure out what is different
302 // based on the current revision
303} 333}
304 334
305bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const { 335bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const {
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 783c39503..a850cadc8 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -46,10 +46,13 @@ public:
46 46
47private: 47private:
48 void DecodeInterleaved(Kernel::HLERequestContext& ctx) { 48 void DecodeInterleaved(Kernel::HLERequestContext& ctx) {
49 LOG_DEBUG(Audio, "called");
50
49 u32 consumed = 0; 51 u32 consumed = 0;
50 u32 sample_count = 0; 52 u32 sample_count = 0;
51 std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16)); 53 std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16));
52 if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples)) { 54 if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples)) {
55 LOG_ERROR(Audio, "Failed to decode opus data");
53 IPC::ResponseBuilder rb{ctx, 2}; 56 IPC::ResponseBuilder rb{ctx, 2};
54 // TODO(ogniK): Use correct error code 57 // TODO(ogniK): Use correct error code
55 rb.Push(ResultCode(-1)); 58 rb.Push(ResultCode(-1));
@@ -63,12 +66,15 @@ private:
63 } 66 }
64 67
65 void DecodeInterleavedWithPerformance(Kernel::HLERequestContext& ctx) { 68 void DecodeInterleavedWithPerformance(Kernel::HLERequestContext& ctx) {
69 LOG_DEBUG(Audio, "called");
70
66 u32 consumed = 0; 71 u32 consumed = 0;
67 u32 sample_count = 0; 72 u32 sample_count = 0;
68 u64 performance = 0; 73 u64 performance = 0;
69 std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16)); 74 std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16));
70 if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples, 75 if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples,
71 performance)) { 76 performance)) {
77 LOG_ERROR(Audio, "Failed to decode opus data");
72 IPC::ResponseBuilder rb{ctx, 2}; 78 IPC::ResponseBuilder rb{ctx, 2};
73 // TODO(ogniK): Use correct error code 79 // TODO(ogniK): Use correct error code
74 rb.Push(ResultCode(-1)); 80 rb.Push(ResultCode(-1));
@@ -77,8 +83,8 @@ private:
77 IPC::ResponseBuilder rb{ctx, 6}; 83 IPC::ResponseBuilder rb{ctx, 6};
78 rb.Push(RESULT_SUCCESS); 84 rb.Push(RESULT_SUCCESS);
79 rb.Push<u32>(consumed); 85 rb.Push<u32>(consumed);
80 rb.Push<u64>(performance);
81 rb.Push<u32>(sample_count); 86 rb.Push<u32>(sample_count);
87 rb.Push<u64>(performance);
82 ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16)); 88 ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16));
83 } 89 }
84 90
@@ -88,24 +94,39 @@ private:
88 std::optional<std::reference_wrapper<u64>> performance_time = std::nullopt) { 94 std::optional<std::reference_wrapper<u64>> performance_time = std::nullopt) {
89 const auto start_time = std::chrono::high_resolution_clock::now(); 95 const auto start_time = std::chrono::high_resolution_clock::now();
90 std::size_t raw_output_sz = output.size() * sizeof(opus_int16); 96 std::size_t raw_output_sz = output.size() * sizeof(opus_int16);
91 if (sizeof(OpusHeader) > input.size()) 97 if (sizeof(OpusHeader) > input.size()) {
98 LOG_ERROR(Audio, "Input is smaller than the header size, header_sz={}, input_sz={}",
99 sizeof(OpusHeader), input.size());
92 return false; 100 return false;
101 }
93 OpusHeader hdr{}; 102 OpusHeader hdr{};
94 std::memcpy(&hdr, input.data(), sizeof(OpusHeader)); 103 std::memcpy(&hdr, input.data(), sizeof(OpusHeader));
95 if (sizeof(OpusHeader) + static_cast<u32>(hdr.sz) > input.size()) { 104 if (sizeof(OpusHeader) + static_cast<u32>(hdr.sz) > input.size()) {
105 LOG_ERROR(Audio, "Input does not fit in the opus header size. data_sz={}, input_sz={}",
106 sizeof(OpusHeader) + static_cast<u32>(hdr.sz), input.size());
96 return false; 107 return false;
97 } 108 }
98 auto frame = input.data() + sizeof(OpusHeader); 109 auto frame = input.data() + sizeof(OpusHeader);
99 auto decoded_sample_count = opus_packet_get_nb_samples( 110 auto decoded_sample_count = opus_packet_get_nb_samples(
100 frame, static_cast<opus_int32>(input.size() - sizeof(OpusHeader)), 111 frame, static_cast<opus_int32>(input.size() - sizeof(OpusHeader)),
101 static_cast<opus_int32>(sample_rate)); 112 static_cast<opus_int32>(sample_rate));
102 if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz) 113 if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz) {
114 LOG_ERROR(
115 Audio,
116 "Decoded data does not fit into the output data, decoded_sz={}, raw_output_sz={}",
117 decoded_sample_count * channel_count * sizeof(u16), raw_output_sz);
103 return false; 118 return false;
119 }
120 const int frame_size = (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count));
104 auto out_sample_count = 121 auto out_sample_count =
105 opus_decode(decoder.get(), frame, hdr.sz, output.data(), 122 opus_decode(decoder.get(), frame, hdr.sz, output.data(), frame_size, 0);
106 (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)), 0); 123 if (out_sample_count < 0) {
107 if (out_sample_count < 0) 124 LOG_ERROR(Audio,
125 "Incorrect sample count received from opus_decode, "
126 "output_sample_count={}, frame_size={}, data_sz_from_hdr={}",
127 out_sample_count, frame_size, static_cast<u32>(hdr.sz));
108 return false; 128 return false;
129 }
109 const auto end_time = std::chrono::high_resolution_clock::now() - start_time; 130 const auto end_time = std::chrono::high_resolution_clock::now() - start_time;
110 sample_count = out_sample_count; 131 sample_count = out_sample_count;
111 consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz); 132 consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz);
@@ -134,14 +155,17 @@ static std::size_t WorkerBufferSize(u32 channel_count) {
134 155
135void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) { 156void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) {
136 IPC::RequestParser rp{ctx}; 157 IPC::RequestParser rp{ctx};
137 auto sample_rate = rp.Pop<u32>(); 158 const auto sample_rate = rp.Pop<u32>();
138 auto channel_count = rp.Pop<u32>(); 159 const auto channel_count = rp.Pop<u32>();
160 LOG_DEBUG(Audio, "called with sample_rate={}, channel_count={}", sample_rate, channel_count);
161
139 ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 || 162 ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
140 sample_rate == 12000 || sample_rate == 8000, 163 sample_rate == 12000 || sample_rate == 8000,
141 "Invalid sample rate"); 164 "Invalid sample rate");
142 ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); 165 ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
143 u32 worker_buffer_sz = static_cast<u32>(WorkerBufferSize(channel_count)); 166
144 LOG_DEBUG(Audio, "called worker_buffer_sz={}", worker_buffer_sz); 167 const u32 worker_buffer_sz = static_cast<u32>(WorkerBufferSize(channel_count));
168 LOG_DEBUG(Audio, "worker_buffer_sz={}", worker_buffer_sz);
145 169
146 IPC::ResponseBuilder rb{ctx, 3}; 170 IPC::ResponseBuilder rb{ctx, 3};
147 rb.Push(RESULT_SUCCESS); 171 rb.Push(RESULT_SUCCESS);
@@ -155,6 +179,7 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
155 auto buffer_sz = rp.Pop<u32>(); 179 auto buffer_sz = rp.Pop<u32>();
156 LOG_DEBUG(Audio, "called sample_rate={}, channel_count={}, buffer_size={}", sample_rate, 180 LOG_DEBUG(Audio, "called sample_rate={}, channel_count={}, buffer_size={}", sample_rate,
157 channel_count, buffer_sz); 181 channel_count, buffer_sz);
182
158 ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 || 183 ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
159 sample_rate == 12000 || sample_rate == 8000, 184 sample_rate == 12000 || sample_rate == 8000,
160 "Invalid sample rate"); 185 "Invalid sample rate");
@@ -164,7 +189,8 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
164 ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large"); 189 ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large");
165 std::unique_ptr<OpusDecoder, OpusDeleter> decoder{ 190 std::unique_ptr<OpusDecoder, OpusDeleter> decoder{
166 static_cast<OpusDecoder*>(operator new(worker_sz))}; 191 static_cast<OpusDecoder*>(operator new(worker_sz))};
167 if (opus_decoder_init(decoder.get(), sample_rate, channel_count)) { 192 if (const int err = opus_decoder_init(decoder.get(), sample_rate, channel_count)) {
193 LOG_ERROR(Audio, "Failed to init opus decoder with error={}", err);
168 IPC::ResponseBuilder rb{ctx, 2}; 194 IPC::ResponseBuilder rb{ctx, 2};
169 // TODO(ogniK): Use correct error code 195 // TODO(ogniK): Use correct error code
170 rb.Push(ResultCode(-1)); 196 rb.Push(ResultCode(-1));
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp
index 6e7b795fb..b7bd738fc 100644
--- a/src/core/hle/service/bcat/module.cpp
+++ b/src/core/hle/service/bcat/module.cpp
@@ -33,10 +33,11 @@ public:
33}; 33};
34 34
35void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { 35void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) {
36 LOG_DEBUG(Service_BCAT, "called");
37
36 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 38 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
37 rb.Push(RESULT_SUCCESS); 39 rb.Push(RESULT_SUCCESS);
38 rb.PushIpcInterface<IBcatService>(); 40 rb.PushIpcInterface<IBcatService>();
39 LOG_DEBUG(Service_BCAT, "called");
40} 41}
41 42
42Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 43Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp
index d0a15cc4c..5704ca0ab 100644
--- a/src/core/hle/service/btdrv/btdrv.cpp
+++ b/src/core/hle/service/btdrv/btdrv.cpp
@@ -2,12 +2,54 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/hle_ipc.h"
8#include "core/hle/kernel/kernel.h"
9#include "core/hle/kernel/readable_event.h"
10#include "core/hle/kernel/writable_event.h"
5#include "core/hle/service/btdrv/btdrv.h" 11#include "core/hle/service/btdrv/btdrv.h"
6#include "core/hle/service/service.h" 12#include "core/hle/service/service.h"
7#include "core/hle/service/sm/sm.h" 13#include "core/hle/service/sm/sm.h"
8 14
9namespace Service::BtDrv { 15namespace Service::BtDrv {
10 16
17class Bt final : public ServiceFramework<Bt> {
18public:
19 explicit Bt() : ServiceFramework{"bt"} {
20 // clang-format off
21 static const FunctionInfo functions[] = {
22 {0, nullptr, "Unknown0"},
23 {1, nullptr, "Unknown1"},
24 {2, nullptr, "Unknown2"},
25 {3, nullptr, "Unknown3"},
26 {4, nullptr, "Unknown4"},
27 {5, nullptr, "Unknown5"},
28 {6, nullptr, "Unknown6"},
29 {7, nullptr, "Unknown7"},
30 {8, nullptr, "Unknown8"},
31 {9, &Bt::RegisterEvent, "RegisterEvent"},
32 };
33 // clang-format on
34 RegisterHandlers(functions);
35
36 auto& kernel = Core::System::GetInstance().Kernel();
37 register_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
38 "BT:RegisterEvent");
39 }
40
41private:
42 void RegisterEvent(Kernel::HLERequestContext& ctx) {
43 LOG_WARNING(Service_BTM, "(STUBBED) called");
44
45 IPC::ResponseBuilder rb{ctx, 2, 1};
46 rb.Push(RESULT_SUCCESS);
47 rb.PushCopyObjects(register_event.readable);
48 }
49
50 Kernel::EventPair register_event;
51};
52
11class BtDrv final : public ServiceFramework<BtDrv> { 53class BtDrv final : public ServiceFramework<BtDrv> {
12public: 54public:
13 explicit BtDrv() : ServiceFramework{"btdrv"} { 55 explicit BtDrv() : ServiceFramework{"btdrv"} {
@@ -67,6 +109,7 @@ public:
67 109
68void InstallInterfaces(SM::ServiceManager& sm) { 110void InstallInterfaces(SM::ServiceManager& sm) {
69 std::make_shared<BtDrv>()->InstallAsService(sm); 111 std::make_shared<BtDrv>()->InstallAsService(sm);
112 std::make_shared<Bt>()->InstallAsService(sm);
70} 113}
71 114
72} // namespace Service::BtDrv 115} // namespace Service::BtDrv
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
index b949bfabd..ef7398a23 100644
--- a/src/core/hle/service/btm/btm.cpp
+++ b/src/core/hle/service/btm/btm.cpp
@@ -7,12 +7,126 @@
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/hle_ipc.h" 9#include "core/hle/kernel/hle_ipc.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/readable_event.h"
12#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/btm/btm.h" 13#include "core/hle/service/btm/btm.h"
11#include "core/hle/service/service.h" 14#include "core/hle/service/service.h"
12#include "core/hle/service/sm/sm.h"
13 15
14namespace Service::BTM { 16namespace Service::BTM {
15 17
18class IBtmUserCore final : public ServiceFramework<IBtmUserCore> {
19public:
20 explicit IBtmUserCore() : ServiceFramework{"IBtmUserCore"} {
21 // clang-format off
22 static const FunctionInfo functions[] = {
23 {0, &IBtmUserCore::GetScanEvent, "GetScanEvent"},
24 {1, nullptr, "Unknown1"},
25 {2, nullptr, "Unknown2"},
26 {3, nullptr, "Unknown3"},
27 {4, nullptr, "Unknown4"},
28 {5, nullptr, "Unknown5"},
29 {6, nullptr, "Unknown6"},
30 {7, nullptr, "Unknown7"},
31 {8, nullptr, "Unknown8"},
32 {9, nullptr, "Unknown9"},
33 {10, nullptr, "Unknown10"},
34 {17, &IBtmUserCore::GetConnectionEvent, "GetConnectionEvent"},
35 {18, nullptr, "Unknown18"},
36 {19, nullptr, "Unknown19"},
37 {20, nullptr, "Unknown20"},
38 {21, nullptr, "Unknown21"},
39 {22, nullptr, "Unknown22"},
40 {23, nullptr, "Unknown23"},
41 {24, nullptr, "Unknown24"},
42 {25, nullptr, "Unknown25"},
43 {26, &IBtmUserCore::GetDiscoveryEvent, "AcquireBleServiceDiscoveryEventImpl"},
44 {27, nullptr, "Unknown27"},
45 {28, nullptr, "Unknown28"},
46 {29, nullptr, "Unknown29"},
47 {30, nullptr, "Unknown30"},
48 {31, nullptr, "Unknown31"},
49 {32, nullptr, "Unknown32"},
50 {33, &IBtmUserCore::GetConfigEvent, "GetConfigEvent"},
51 {34, nullptr, "Unknown34"},
52 {35, nullptr, "Unknown35"},
53 {36, nullptr, "Unknown36"},
54 {37, nullptr, "Unknown37"},
55 };
56 // clang-format on
57 RegisterHandlers(functions);
58
59 auto& kernel = Core::System::GetInstance().Kernel();
60 scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
61 "IBtmUserCore:ScanEvent");
62 connection_event = Kernel::WritableEvent::CreateEventPair(
63 kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ConnectionEvent");
64 service_discovery = Kernel::WritableEvent::CreateEventPair(
65 kernel, Kernel::ResetType::OneShot, "IBtmUserCore:Discovery");
66 config_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
67 "IBtmUserCore:ConfigEvent");
68 }
69
70private:
71 void GetScanEvent(Kernel::HLERequestContext& ctx) {
72 LOG_WARNING(Service_BTM, "(STUBBED) called");
73
74 IPC::ResponseBuilder rb{ctx, 2, 1};
75 rb.Push(RESULT_SUCCESS);
76 rb.PushCopyObjects(scan_event.readable);
77 }
78
79 void GetConnectionEvent(Kernel::HLERequestContext& ctx) {
80 LOG_WARNING(Service_BTM, "(STUBBED) called");
81
82 IPC::ResponseBuilder rb{ctx, 2, 1};
83 rb.Push(RESULT_SUCCESS);
84 rb.PushCopyObjects(connection_event.readable);
85 }
86
87 void GetDiscoveryEvent(Kernel::HLERequestContext& ctx) {
88 LOG_WARNING(Service_BTM, "(STUBBED) called");
89
90 IPC::ResponseBuilder rb{ctx, 2, 1};
91 rb.Push(RESULT_SUCCESS);
92 rb.PushCopyObjects(service_discovery.readable);
93 }
94
95 void GetConfigEvent(Kernel::HLERequestContext& ctx) {
96 LOG_WARNING(Service_BTM, "(STUBBED) called");
97
98 IPC::ResponseBuilder rb{ctx, 2, 1};
99 rb.Push(RESULT_SUCCESS);
100 rb.PushCopyObjects(config_event.readable);
101 }
102
103 Kernel::EventPair scan_event;
104 Kernel::EventPair connection_event;
105 Kernel::EventPair service_discovery;
106 Kernel::EventPair config_event;
107};
108
109class BTM_USR final : public ServiceFramework<BTM_USR> {
110public:
111 explicit BTM_USR() : ServiceFramework{"btm:u"} {
112 // clang-format off
113 static const FunctionInfo functions[] = {
114 {0, &BTM_USR::GetCoreImpl, "GetCoreImpl"},
115 };
116 // clang-format on
117 RegisterHandlers(functions);
118 }
119
120private:
121 void GetCoreImpl(Kernel::HLERequestContext& ctx) {
122 LOG_DEBUG(Service_BTM, "called");
123
124 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
125 rb.Push(RESULT_SUCCESS);
126 rb.PushIpcInterface<IBtmUserCore>();
127 }
128};
129
16class BTM final : public ServiceFramework<BTM> { 130class BTM final : public ServiceFramework<BTM> {
17public: 131public:
18 explicit BTM() : ServiceFramework{"btm"} { 132 explicit BTM() : ServiceFramework{"btm"} {
@@ -104,11 +218,11 @@ public:
104 218
105private: 219private:
106 void GetCoreImpl(Kernel::HLERequestContext& ctx) { 220 void GetCoreImpl(Kernel::HLERequestContext& ctx) {
221 LOG_DEBUG(Service_BTM, "called");
222
107 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 223 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
108 rb.Push(RESULT_SUCCESS); 224 rb.Push(RESULT_SUCCESS);
109 rb.PushIpcInterface<IBtmSystemCore>(); 225 rb.PushIpcInterface<IBtmSystemCore>();
110
111 LOG_DEBUG(Service_BTM, "called");
112 } 226 }
113}; 227};
114 228
@@ -116,6 +230,7 @@ void InstallInterfaces(SM::ServiceManager& sm) {
116 std::make_shared<BTM>()->InstallAsService(sm); 230 std::make_shared<BTM>()->InstallAsService(sm);
117 std::make_shared<BTM_DBG>()->InstallAsService(sm); 231 std::make_shared<BTM_DBG>()->InstallAsService(sm);
118 std::make_shared<BTM_SYS>()->InstallAsService(sm); 232 std::make_shared<BTM_SYS>()->InstallAsService(sm);
233 std::make_shared<BTM_USR>()->InstallAsService(sm);
119} 234}
120 235
121} // namespace Service::BTM 236} // namespace Service::BTM
diff --git a/src/core/hle/service/erpt/erpt.cpp b/src/core/hle/service/erpt/erpt.cpp
index ee11cd78e..d9b32954e 100644
--- a/src/core/hle/service/erpt/erpt.cpp
+++ b/src/core/hle/service/erpt/erpt.cpp
@@ -17,11 +17,13 @@ public:
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {0, nullptr, "SubmitContext"}, 18 {0, nullptr, "SubmitContext"},
19 {1, nullptr, "CreateReport"}, 19 {1, nullptr, "CreateReport"},
20 {2, nullptr, "Unknown1"}, 20 {2, nullptr, "SetInitialLaunchSettingsCompletionTime"},
21 {3, nullptr, "Unknown2"}, 21 {3, nullptr, "ClearInitialLaunchSettingsCompletionTime"},
22 {4, nullptr, "Unknown3"}, 22 {4, nullptr, "UpdatePowerOnTime"},
23 {5, nullptr, "Unknown4"}, 23 {5, nullptr, "UpdateAwakeTime"},
24 {6, nullptr, "Unknown5"}, 24 {6, nullptr, "SubmitMultipleCategoryContext"},
25 {7, nullptr, "UpdateApplicationLaunchTime"},
26 {8, nullptr, "ClearApplicationLaunchTime"},
25 }; 27 };
26 // clang-format on 28 // clang-format on
27 29
diff --git a/src/core/hle/service/fgm/fgm.cpp b/src/core/hle/service/fgm/fgm.cpp
index 566fbf924..e461274c1 100644
--- a/src/core/hle/service/fgm/fgm.cpp
+++ b/src/core/hle/service/fgm/fgm.cpp
@@ -42,11 +42,11 @@ public:
42 42
43private: 43private:
44 void Initialize(Kernel::HLERequestContext& ctx) { 44 void Initialize(Kernel::HLERequestContext& ctx) {
45 LOG_DEBUG(Service_FGM, "called");
46
45 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 47 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
46 rb.Push(RESULT_SUCCESS); 48 rb.Push(RESULT_SUCCESS);
47 rb.PushIpcInterface<IRequest>(); 49 rb.PushIpcInterface<IRequest>();
48
49 LOG_DEBUG(Service_FGM, "called");
50 } 50 }
51}; 51};
52 52
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index e32a7c48e..b1490e6fa 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -113,6 +113,18 @@ ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::str
113 return RESULT_SUCCESS; 113 return RESULT_SUCCESS;
114} 114}
115 115
116ResultCode VfsDirectoryServiceWrapper::CleanDirectoryRecursively(const std::string& path) const {
117 const std::string sanitized_path(FileUtil::SanitizePath(path));
118 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(sanitized_path));
119
120 if (!dir->CleanSubdirectoryRecursive(FileUtil::GetFilename(sanitized_path))) {
121 // TODO(DarkLordZach): Find a better error code for this
122 return ResultCode(-1);
123 }
124
125 return RESULT_SUCCESS;
126}
127
116ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_, 128ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
117 const std::string& dest_path_) const { 129 const std::string& dest_path_) const {
118 std::string src_path(FileUtil::SanitizePath(src_path_)); 130 std::string src_path(FileUtil::SanitizePath(src_path_));
@@ -303,25 +315,35 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
303 static_cast<u8>(space), save_struct.DebugInfo()); 315 static_cast<u8>(space), save_struct.DebugInfo());
304 316
305 if (save_data_factory == nullptr) { 317 if (save_data_factory == nullptr) {
306 return ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound); 318 return FileSys::ERROR_ENTITY_NOT_FOUND;
307 } 319 }
308 320
309 return save_data_factory->Open(space, save_struct); 321 return save_data_factory->Open(space, save_struct);
310} 322}
311 323
324ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) {
325 LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", static_cast<u8>(space));
326
327 if (save_data_factory == nullptr) {
328 return FileSys::ERROR_ENTITY_NOT_FOUND;
329 }
330
331 return MakeResult(save_data_factory->GetSaveDataSpaceDirectory(space));
332}
333
312ResultVal<FileSys::VirtualDir> OpenSDMC() { 334ResultVal<FileSys::VirtualDir> OpenSDMC() {
313 LOG_TRACE(Service_FS, "Opening SDMC"); 335 LOG_TRACE(Service_FS, "Opening SDMC");
314 336
315 if (sdmc_factory == nullptr) { 337 if (sdmc_factory == nullptr) {
316 return ResultCode(ErrorModule::FS, FileSys::ErrCodes::SdCardNotFound); 338 return FileSys::ERROR_SD_CARD_NOT_FOUND;
317 } 339 }
318 340
319 return sdmc_factory->Open(); 341 return sdmc_factory->Open();
320} 342}
321 343
322std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() { 344FileSys::RegisteredCacheUnion GetUnionContents() {
323 return std::make_unique<FileSys::RegisteredCacheUnion>(std::vector<FileSys::RegisteredCache*>{ 345 return FileSys::RegisteredCacheUnion{
324 GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}); 346 {GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}};
325} 347}
326 348
327FileSys::RegisteredCache* GetSystemNANDContents() { 349FileSys::RegisteredCache* GetSystemNANDContents() {
@@ -360,6 +382,15 @@ FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) {
360 return bis_factory->GetModificationLoadRoot(title_id); 382 return bis_factory->GetModificationLoadRoot(title_id);
361} 383}
362 384
385FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) {
386 LOG_TRACE(Service_FS, "Opening mod dump root for tid={:016X}", title_id);
387
388 if (bis_factory == nullptr)
389 return nullptr;
390
391 return bis_factory->GetModificationDumpRoot(title_id);
392}
393
363void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { 394void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
364 if (overwrite) { 395 if (overwrite) {
365 bis_factory = nullptr; 396 bis_factory = nullptr;
@@ -373,13 +404,21 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
373 FileSys::Mode::ReadWrite); 404 FileSys::Mode::ReadWrite);
374 auto load_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), 405 auto load_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir),
375 FileSys::Mode::ReadWrite); 406 FileSys::Mode::ReadWrite);
407 auto dump_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::DumpDir),
408 FileSys::Mode::ReadWrite);
376 409
377 if (bis_factory == nullptr) 410 if (bis_factory == nullptr) {
378 bis_factory = std::make_unique<FileSys::BISFactory>(nand_directory, load_directory); 411 bis_factory =
379 if (save_data_factory == nullptr) 412 std::make_unique<FileSys::BISFactory>(nand_directory, load_directory, dump_directory);
413 }
414
415 if (save_data_factory == nullptr) {
380 save_data_factory = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory)); 416 save_data_factory = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory));
381 if (sdmc_factory == nullptr) 417 }
418
419 if (sdmc_factory == nullptr) {
382 sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory)); 420 sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory));
421 }
383} 422}
384 423
385void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs) { 424void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs) {
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 6ca5c5636..965414be0 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -45,15 +45,17 @@ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId stora
45 FileSys::ContentRecordType type); 45 FileSys::ContentRecordType type);
46ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, 46ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
47 FileSys::SaveDataDescriptor save_struct); 47 FileSys::SaveDataDescriptor save_struct);
48ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
48ResultVal<FileSys::VirtualDir> OpenSDMC(); 49ResultVal<FileSys::VirtualDir> OpenSDMC();
49 50
50std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents(); 51FileSys::RegisteredCacheUnion GetUnionContents();
51 52
52FileSys::RegisteredCache* GetSystemNANDContents(); 53FileSys::RegisteredCache* GetSystemNANDContents();
53FileSys::RegisteredCache* GetUserNANDContents(); 54FileSys::RegisteredCache* GetUserNANDContents();
54FileSys::RegisteredCache* GetSDMCContents(); 55FileSys::RegisteredCache* GetSDMCContents();
55 56
56FileSys::VirtualDir GetModificationLoadRoot(u64 title_id); 57FileSys::VirtualDir GetModificationLoadRoot(u64 title_id);
58FileSys::VirtualDir GetModificationDumpRoot(u64 title_id);
57 59
58// Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function 60// Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function
59// above is called. 61// above is called.
@@ -111,6 +113,18 @@ public:
111 ResultCode DeleteDirectoryRecursively(const std::string& path) const; 113 ResultCode DeleteDirectoryRecursively(const std::string& path) const;
112 114
113 /** 115 /**
116 * Cleans the specified directory. This is similar to DeleteDirectoryRecursively,
117 * in that it deletes all the contents of the specified directory, however, this
118 * function does *not* delete the directory itself. It only deletes everything
119 * within it.
120 *
121 * @param path Path relative to the archive.
122 *
123 * @return Result of the operation.
124 */
125 ResultCode CleanDirectoryRecursively(const std::string& path) const;
126
127 /**
114 * Rename a File specified by its path 128 * Rename a File specified by its path
115 * @param src_path Source path relative to the archive 129 * @param src_path Source path relative to the archive
116 * @param dest_path Destination path relative to the archive 130 * @param dest_path Destination path relative to the archive
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index f06bb33ae..d2ffd5776 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -11,6 +11,7 @@
11 11
12#include "common/assert.h" 12#include "common/assert.h"
13#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/hex_util.h"
14#include "common/logging/log.h" 15#include "common/logging/log.h"
15#include "common/string_util.h" 16#include "common/string_util.h"
16#include "core/file_sys/directory.h" 17#include "core/file_sys/directory.h"
@@ -62,13 +63,15 @@ private:
62 63
63 // Error checking 64 // Error checking
64 if (length < 0) { 65 if (length < 0) {
66 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
65 IPC::ResponseBuilder rb{ctx, 2}; 67 IPC::ResponseBuilder rb{ctx, 2};
66 rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); 68 rb.Push(FileSys::ERROR_INVALID_SIZE);
67 return; 69 return;
68 } 70 }
69 if (offset < 0) { 71 if (offset < 0) {
72 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
70 IPC::ResponseBuilder rb{ctx, 2}; 73 IPC::ResponseBuilder rb{ctx, 2};
71 rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset)); 74 rb.Push(FileSys::ERROR_INVALID_OFFSET);
72 return; 75 return;
73 } 76 }
74 77
@@ -107,13 +110,15 @@ private:
107 110
108 // Error checking 111 // Error checking
109 if (length < 0) { 112 if (length < 0) {
113 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
110 IPC::ResponseBuilder rb{ctx, 2}; 114 IPC::ResponseBuilder rb{ctx, 2};
111 rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); 115 rb.Push(FileSys::ERROR_INVALID_SIZE);
112 return; 116 return;
113 } 117 }
114 if (offset < 0) { 118 if (offset < 0) {
119 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
115 IPC::ResponseBuilder rb{ctx, 2}; 120 IPC::ResponseBuilder rb{ctx, 2};
116 rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset)); 121 rb.Push(FileSys::ERROR_INVALID_OFFSET);
117 return; 122 return;
118 } 123 }
119 124
@@ -138,13 +143,15 @@ private:
138 143
139 // Error checking 144 // Error checking
140 if (length < 0) { 145 if (length < 0) {
146 LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
141 IPC::ResponseBuilder rb{ctx, 2}; 147 IPC::ResponseBuilder rb{ctx, 2};
142 rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); 148 rb.Push(FileSys::ERROR_INVALID_SIZE);
143 return; 149 return;
144 } 150 }
145 if (offset < 0) { 151 if (offset < 0) {
152 LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
146 IPC::ResponseBuilder rb{ctx, 2}; 153 IPC::ResponseBuilder rb{ctx, 2};
147 rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset)); 154 rb.Push(FileSys::ERROR_INVALID_OFFSET);
148 return; 155 return;
149 } 156 }
150 157
@@ -180,9 +187,10 @@ private:
180 void SetSize(Kernel::HLERequestContext& ctx) { 187 void SetSize(Kernel::HLERequestContext& ctx) {
181 IPC::RequestParser rp{ctx}; 188 IPC::RequestParser rp{ctx};
182 const u64 size = rp.Pop<u64>(); 189 const u64 size = rp.Pop<u64>();
183 backend->Resize(size);
184 LOG_DEBUG(Service_FS, "called, size={}", size); 190 LOG_DEBUG(Service_FS, "called, size={}", size);
185 191
192 backend->Resize(size);
193
186 IPC::ResponseBuilder rb{ctx, 2}; 194 IPC::ResponseBuilder rb{ctx, 2};
187 rb.Push(RESULT_SUCCESS); 195 rb.Push(RESULT_SUCCESS);
188 } 196 }
@@ -284,7 +292,7 @@ public:
284 {10, &IFileSystem::Commit, "Commit"}, 292 {10, &IFileSystem::Commit, "Commit"},
285 {11, nullptr, "GetFreeSpaceSize"}, 293 {11, nullptr, "GetFreeSpaceSize"},
286 {12, nullptr, "GetTotalSpaceSize"}, 294 {12, nullptr, "GetTotalSpaceSize"},
287 {13, nullptr, "CleanDirectoryRecursively"}, 295 {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"},
288 {14, nullptr, "GetFileTimeStampRaw"}, 296 {14, nullptr, "GetFileTimeStampRaw"},
289 {15, nullptr, "QueryEntry"}, 297 {15, nullptr, "QueryEntry"},
290 }; 298 };
@@ -354,6 +362,16 @@ public:
354 rb.Push(backend.DeleteDirectoryRecursively(name)); 362 rb.Push(backend.DeleteDirectoryRecursively(name));
355 } 363 }
356 364
365 void CleanDirectoryRecursively(Kernel::HLERequestContext& ctx) {
366 const auto file_buffer = ctx.ReadBuffer();
367 const std::string name = Common::StringFromBuffer(file_buffer);
368
369 LOG_DEBUG(Service_FS, "called. Directory: {}", name);
370
371 IPC::ResponseBuilder rb{ctx, 2};
372 rb.Push(backend.CleanDirectoryRecursively(name));
373 }
374
357 void RenameFile(Kernel::HLERequestContext& ctx) { 375 void RenameFile(Kernel::HLERequestContext& ctx) {
358 IPC::RequestParser rp{ctx}; 376 IPC::RequestParser rp{ctx};
359 377
@@ -452,7 +470,149 @@ private:
452 VfsDirectoryServiceWrapper backend; 470 VfsDirectoryServiceWrapper backend;
453}; 471};
454 472
473class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
474public:
475 explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space)
476 : ServiceFramework("ISaveDataInfoReader") {
477 static const FunctionInfo functions[] = {
478 {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
479 };
480 RegisterHandlers(functions);
481
482 FindAllSaves(space);
483 }
484
485 void ReadSaveDataInfo(Kernel::HLERequestContext& ctx) {
486 LOG_DEBUG(Service_FS, "called");
487
488 // Calculate how many entries we can fit in the output buffer
489 const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(SaveDataInfo);
490
491 // Cap at total number of entries.
492 const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
493
494 // Determine data start and end
495 const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
496 const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
497 const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
498
499 next_entry_index += actual_entries;
500
501 // Write the data to memory
502 ctx.WriteBuffer(begin, range_size);
503
504 IPC::ResponseBuilder rb{ctx, 3};
505 rb.Push(RESULT_SUCCESS);
506 rb.Push<u32>(static_cast<u32>(actual_entries));
507 }
508
509private:
510 static u64 stoull_be(std::string_view str) {
511 if (str.size() != 16)
512 return 0;
513
514 const auto bytes = Common::HexStringToArray<0x8>(str);
515 u64 out{};
516 std::memcpy(&out, bytes.data(), sizeof(u64));
517
518 return Common::swap64(out);
519 }
520
521 void FindAllSaves(FileSys::SaveDataSpaceId space) {
522 const auto save_root = OpenSaveDataSpace(space);
523 ASSERT(save_root.Succeeded());
524
525 for (const auto& type : (*save_root)->GetSubdirectories()) {
526 if (type->GetName() == "save") {
527 for (const auto& save_id : type->GetSubdirectories()) {
528 for (const auto& user_id : save_id->GetSubdirectories()) {
529 const auto save_id_numeric = stoull_be(save_id->GetName());
530 auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
531 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
532
533 if (save_id_numeric != 0) {
534 // System Save Data
535 info.emplace_back(SaveDataInfo{
536 0,
537 space,
538 FileSys::SaveDataType::SystemSaveData,
539 {},
540 user_id_numeric,
541 save_id_numeric,
542 0,
543 user_id->GetSize(),
544 {},
545 });
546
547 continue;
548 }
549
550 for (const auto& title_id : user_id->GetSubdirectories()) {
551 const auto device =
552 std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
553 [](u8 val) { return val == 0; });
554 info.emplace_back(SaveDataInfo{
555 0,
556 space,
557 device ? FileSys::SaveDataType::DeviceSaveData
558 : FileSys::SaveDataType::SaveData,
559 {},
560 user_id_numeric,
561 save_id_numeric,
562 stoull_be(title_id->GetName()),
563 title_id->GetSize(),
564 {},
565 });
566 }
567 }
568 }
569 } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
570 // Temporary Storage
571 for (const auto& user_id : type->GetSubdirectories()) {
572 for (const auto& title_id : user_id->GetSubdirectories()) {
573 if (!title_id->GetFiles().empty() ||
574 !title_id->GetSubdirectories().empty()) {
575 auto user_id_numeric =
576 Common::HexStringToArray<0x10>(user_id->GetName());
577 std::reverse(user_id_numeric.begin(), user_id_numeric.end());
578
579 info.emplace_back(SaveDataInfo{
580 0,
581 space,
582 FileSys::SaveDataType::TemporaryStorage,
583 {},
584 user_id_numeric,
585 stoull_be(type->GetName()),
586 stoull_be(title_id->GetName()),
587 title_id->GetSize(),
588 {},
589 });
590 }
591 }
592 }
593 }
594 }
595 }
596
597 struct SaveDataInfo {
598 u64_le save_id_unknown;
599 FileSys::SaveDataSpaceId space;
600 FileSys::SaveDataType type;
601 INSERT_PADDING_BYTES(0x6);
602 std::array<u8, 0x10> user_id;
603 u64_le save_id;
604 u64_le title_id;
605 u64_le save_image_size;
606 INSERT_PADDING_BYTES(0x28);
607 };
608 static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
609
610 std::vector<SaveDataInfo> info;
611 u64 next_entry_index = 0;
612};
613
455FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { 614FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
615 // clang-format off
456 static const FunctionInfo functions[] = { 616 static const FunctionInfo functions[] = {
457 {0, nullptr, "MountContent"}, 617 {0, nullptr, "MountContent"},
458 {1, &FSP_SRV::Initialize, "Initialize"}, 618 {1, &FSP_SRV::Initialize, "Initialize"},
@@ -486,7 +646,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
486 {58, nullptr, "ReadSaveDataFileSystemExtraData"}, 646 {58, nullptr, "ReadSaveDataFileSystemExtraData"},
487 {59, nullptr, "WriteSaveDataFileSystemExtraData"}, 647 {59, nullptr, "WriteSaveDataFileSystemExtraData"},
488 {60, nullptr, "OpenSaveDataInfoReader"}, 648 {60, nullptr, "OpenSaveDataInfoReader"},
489 {61, nullptr, "OpenSaveDataInfoReaderBySaveDataSpaceId"}, 649 {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
490 {62, nullptr, "OpenCacheStorageList"}, 650 {62, nullptr, "OpenCacheStorageList"},
491 {64, nullptr, "OpenSaveDataInternalStorageFileSystem"}, 651 {64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
492 {65, nullptr, "UpdateSaveDataMacForDebug"}, 652 {65, nullptr, "UpdateSaveDataMacForDebug"},
@@ -545,6 +705,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
545 {1009, nullptr, "GetAndClearMemoryReportInfo"}, 705 {1009, nullptr, "GetAndClearMemoryReportInfo"},
546 {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, 706 {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
547 }; 707 };
708 // clang-format on
548 RegisterHandlers(functions); 709 RegisterHandlers(functions);
549} 710}
550 711
@@ -562,6 +723,8 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
562 723
563 const auto type = rp.PopRaw<FileSystemType>(); 724 const auto type = rp.PopRaw<FileSystemType>();
564 const auto title_id = rp.PopRaw<u64>(); 725 const auto title_id = rp.PopRaw<u64>();
726 LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}",
727 static_cast<u8>(type), title_id);
565 728
566 IPC::ResponseBuilder rb{ctx, 2, 0, 0}; 729 IPC::ResponseBuilder rb{ctx, 2, 0, 0};
567 rb.Push(ResultCode(-1)); 730 rb.Push(ResultCode(-1));
@@ -597,13 +760,14 @@ void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) {
597 auto space_id = rp.PopRaw<FileSys::SaveDataSpaceId>(); 760 auto space_id = rp.PopRaw<FileSys::SaveDataSpaceId>();
598 auto unk = rp.Pop<u32>(); 761 auto unk = rp.Pop<u32>();
599 LOG_INFO(Service_FS, "called with unknown={:08X}", unk); 762 LOG_INFO(Service_FS, "called with unknown={:08X}", unk);
763
600 auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>(); 764 auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>();
601 765
602 auto dir = OpenSaveData(space_id, save_struct); 766 auto dir = OpenSaveData(space_id, save_struct);
603 767
604 if (dir.Failed()) { 768 if (dir.Failed()) {
605 IPC::ResponseBuilder rb{ctx, 2, 0, 0}; 769 IPC::ResponseBuilder rb{ctx, 2, 0, 0};
606 rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound)); 770 rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
607 return; 771 return;
608 } 772 }
609 773
@@ -619,6 +783,16 @@ void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) {
619 MountSaveData(ctx); 783 MountSaveData(ctx);
620} 784}
621 785
786void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) {
787 IPC::RequestParser rp{ctx};
788 const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
789 LOG_INFO(Service_FS, "called, space={}", static_cast<u8>(space));
790
791 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
792 rb.Push(RESULT_SUCCESS);
793 rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space));
794}
795
622void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { 796void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
623 LOG_WARNING(Service_FS, "(STUBBED) called"); 797 LOG_WARNING(Service_FS, "(STUBBED) called");
624 798
@@ -695,7 +869,7 @@ void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) {
695 static_cast<u8>(storage_id), title_id); 869 static_cast<u8>(storage_id), title_id);
696 870
697 IPC::ResponseBuilder rb{ctx, 2}; 871 IPC::ResponseBuilder rb{ctx, 2};
698 rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound)); 872 rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
699} 873}
700 874
701} // namespace Service::FileSystem 875} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index 4aa0358cb..e7abec0a3 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -25,6 +25,7 @@ private:
25 void CreateSaveData(Kernel::HLERequestContext& ctx); 25 void CreateSaveData(Kernel::HLERequestContext& ctx);
26 void MountSaveData(Kernel::HLERequestContext& ctx); 26 void MountSaveData(Kernel::HLERequestContext& ctx);
27 void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx); 27 void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx);
28 void OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx);
28 void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); 29 void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
29 void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); 30 void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
30 void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx); 31 void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp
index 3d100763f..c22357d8c 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.cpp
+++ b/src/core/hle/service/hid/controllers/debug_pad.cpp
@@ -6,9 +6,14 @@
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "core/core_timing.h" 7#include "core/core_timing.h"
8#include "core/hle/service/hid/controllers/debug_pad.h" 8#include "core/hle/service/hid/controllers/debug_pad.h"
9#include "core/settings.h"
9 10
10namespace Service::HID { 11namespace Service::HID {
11 12
13constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
14constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
15enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right };
16
12Controller_DebugPad::Controller_DebugPad() = default; 17Controller_DebugPad::Controller_DebugPad() = default;
13Controller_DebugPad::~Controller_DebugPad() = default; 18Controller_DebugPad::~Controller_DebugPad() = default;
14 19
@@ -33,10 +38,44 @@ void Controller_DebugPad::OnUpdate(u8* data, std::size_t size) {
33 38
34 cur_entry.sampling_number = last_entry.sampling_number + 1; 39 cur_entry.sampling_number = last_entry.sampling_number + 1;
35 cur_entry.sampling_number2 = cur_entry.sampling_number; 40 cur_entry.sampling_number2 = cur_entry.sampling_number;
36 // TODO(ogniK): Update debug pad states 41 cur_entry.attribute.connected.Assign(1);
42 auto& pad = cur_entry.pad_state;
43
44 using namespace Settings::NativeButton;
45 pad.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
46 pad.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
47 pad.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
48 pad.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
49 pad.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
50 pad.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
51 pad.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
52 pad.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
53 pad.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
54 pad.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
55 pad.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
56 pad.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
57 pad.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
58 pad.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
59
60 const auto [stick_l_x_f, stick_l_y_f] =
61 analogs[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
62 const auto [stick_r_x_f, stick_r_y_f] =
63 analogs[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
64 cur_entry.l_stick.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
65 cur_entry.l_stick.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
66 cur_entry.r_stick.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
67 cur_entry.r_stick.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
37 68
38 std::memcpy(data, &shared_memory, sizeof(SharedMemory)); 69 std::memcpy(data, &shared_memory, sizeof(SharedMemory));
39} 70}
40 71
41void Controller_DebugPad::OnLoadInputDevices() {} 72void Controller_DebugPad::OnLoadInputDevices() {
73 std::transform(Settings::values.debug_pad_buttons.begin(),
74 Settings::values.debug_pad_buttons.begin() +
75 Settings::NativeButton::NUM_BUTTONS_HID,
76 buttons.begin(), Input::CreateDevice<Input::ButtonDevice>);
77 std::transform(Settings::values.debug_pad_analogs.begin(),
78 Settings::values.debug_pad_analogs.end(), analogs.begin(),
79 Input::CreateDevice<Input::AnalogDevice>);
80}
42} // namespace Service::HID 81} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h
index 62b4f2682..68b734248 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.h
+++ b/src/core/hle/service/hid/controllers/debug_pad.h
@@ -5,10 +5,13 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include "common/bit_field.h"
8#include "common/common_funcs.h" 9#include "common/common_funcs.h"
9#include "common/common_types.h" 10#include "common/common_types.h"
10#include "common/swap.h" 11#include "common/swap.h"
12#include "core/frontend/input.h"
11#include "core/hle/service/hid/controllers/controller_base.h" 13#include "core/hle/service/hid/controllers/controller_base.h"
14#include "core/settings.h"
12 15
13namespace Service::HID { 16namespace Service::HID {
14class Controller_DebugPad final : public ControllerBase { 17class Controller_DebugPad final : public ControllerBase {
@@ -35,11 +38,40 @@ private:
35 }; 38 };
36 static_assert(sizeof(AnalogStick) == 0x8); 39 static_assert(sizeof(AnalogStick) == 0x8);
37 40
41 struct PadState {
42 union {
43 u32_le raw{};
44 BitField<0, 1, u32_le> a;
45 BitField<1, 1, u32_le> b;
46 BitField<2, 1, u32_le> x;
47 BitField<3, 1, u32_le> y;
48 BitField<4, 1, u32_le> l;
49 BitField<5, 1, u32_le> r;
50 BitField<6, 1, u32_le> zl;
51 BitField<7, 1, u32_le> zr;
52 BitField<8, 1, u32_le> plus;
53 BitField<9, 1, u32_le> minus;
54 BitField<10, 1, u32_le> d_left;
55 BitField<11, 1, u32_le> d_up;
56 BitField<12, 1, u32_le> d_right;
57 BitField<13, 1, u32_le> d_down;
58 };
59 };
60 static_assert(sizeof(PadState) == 0x4, "PadState is an invalid size");
61
62 struct Attributes {
63 union {
64 u32_le raw{};
65 BitField<0, 1, u32_le> connected;
66 };
67 };
68 static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size");
69
38 struct PadStates { 70 struct PadStates {
39 s64_le sampling_number; 71 s64_le sampling_number;
40 s64_le sampling_number2; 72 s64_le sampling_number2;
41 u32_le attribute; 73 Attributes attribute;
42 u32_le button_state; 74 PadState pad_state;
43 AnalogStick r_stick; 75 AnalogStick r_stick;
44 AnalogStick l_stick; 76 AnalogStick l_stick;
45 }; 77 };
@@ -52,5 +84,10 @@ private:
52 }; 84 };
53 static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); 85 static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size");
54 SharedMemory shared_memory{}; 86 SharedMemory shared_memory{};
87
88 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>
89 buttons;
90 std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>
91 analogs;
55}; 92};
56} // namespace Service::HID 93} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
index ccfbce9ac..ca75adc2b 100644
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -6,9 +6,11 @@
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "core/core_timing.h" 7#include "core/core_timing.h"
8#include "core/hle/service/hid/controllers/keyboard.h" 8#include "core/hle/service/hid/controllers/keyboard.h"
9#include "core/settings.h"
9 10
10namespace Service::HID { 11namespace Service::HID {
11constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; 12constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800;
13constexpr u8 KEYS_PER_BYTE = 8;
12 14
13Controller_Keyboard::Controller_Keyboard() = default; 15Controller_Keyboard::Controller_Keyboard() = default;
14Controller_Keyboard::~Controller_Keyboard() = default; 16Controller_Keyboard::~Controller_Keyboard() = default;
@@ -34,10 +36,24 @@ void Controller_Keyboard::OnUpdate(u8* data, std::size_t size) {
34 36
35 cur_entry.sampling_number = last_entry.sampling_number + 1; 37 cur_entry.sampling_number = last_entry.sampling_number + 1;
36 cur_entry.sampling_number2 = cur_entry.sampling_number; 38 cur_entry.sampling_number2 = cur_entry.sampling_number;
37 // TODO(ogniK): Update keyboard states 39
40 for (std::size_t i = 0; i < keyboard_keys.size(); ++i) {
41 for (std::size_t k = 0; k < KEYS_PER_BYTE; ++k) {
42 cur_entry.key[i / KEYS_PER_BYTE] |= (keyboard_keys[i]->GetStatus() << k);
43 }
44 }
45
46 for (std::size_t i = 0; i < keyboard_mods.size(); ++i) {
47 cur_entry.modifier |= (keyboard_mods[i]->GetStatus() << i);
48 }
38 49
39 std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); 50 std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
40} 51}
41 52
42void Controller_Keyboard::OnLoadInputDevices() {} 53void Controller_Keyboard::OnLoadInputDevices() {
54 std::transform(Settings::values.keyboard_keys.begin(), Settings::values.keyboard_keys.end(),
55 keyboard_keys.begin(), Input::CreateDevice<Input::ButtonDevice>);
56 std::transform(Settings::values.keyboard_mods.begin(), Settings::values.keyboard_mods.end(),
57 keyboard_mods.begin(), Input::CreateDevice<Input::ButtonDevice>);
58}
43} // namespace Service::HID 59} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h
index 493e68fce..f52775456 100644
--- a/src/core/hle/service/hid/controllers/keyboard.h
+++ b/src/core/hle/service/hid/controllers/keyboard.h
@@ -8,7 +8,9 @@
8#include "common/common_funcs.h" 8#include "common/common_funcs.h"
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/swap.h" 10#include "common/swap.h"
11#include "core/frontend/input.h"
11#include "core/hle/service/hid/controllers/controller_base.h" 12#include "core/hle/service/hid/controllers/controller_base.h"
13#include "core/settings.h"
12 14
13namespace Service::HID { 15namespace Service::HID {
14class Controller_Keyboard final : public ControllerBase { 16class Controller_Keyboard final : public ControllerBase {
@@ -46,5 +48,10 @@ private:
46 }; 48 };
47 static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); 49 static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size");
48 SharedMemory shared_memory{}; 50 SharedMemory shared_memory{};
51
52 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardKeys>
53 keyboard_keys;
54 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardMods>
55 keyboard_mods;
49}; 56};
50} // namespace Service::HID 57} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp
index 4e246a57d..63391dbe9 100644
--- a/src/core/hle/service/hid/controllers/mouse.cpp
+++ b/src/core/hle/service/hid/controllers/mouse.cpp
@@ -5,6 +5,7 @@
5#include <cstring> 5#include <cstring>
6#include "common/common_types.h" 6#include "common/common_types.h"
7#include "core/core_timing.h" 7#include "core/core_timing.h"
8#include "core/frontend/emu_window.h"
8#include "core/hle/service/hid/controllers/mouse.h" 9#include "core/hle/service/hid/controllers/mouse.h"
9 10
10namespace Service::HID { 11namespace Service::HID {
@@ -14,7 +15,6 @@ Controller_Mouse::Controller_Mouse() = default;
14Controller_Mouse::~Controller_Mouse() = default; 15Controller_Mouse::~Controller_Mouse() = default;
15 16
16void Controller_Mouse::OnInit() {} 17void Controller_Mouse::OnInit() {}
17
18void Controller_Mouse::OnRelease() {} 18void Controller_Mouse::OnRelease() {}
19 19
20void Controller_Mouse::OnUpdate(u8* data, std::size_t size) { 20void Controller_Mouse::OnUpdate(u8* data, std::size_t size) {
@@ -34,10 +34,29 @@ void Controller_Mouse::OnUpdate(u8* data, std::size_t size) {
34 34
35 cur_entry.sampling_number = last_entry.sampling_number + 1; 35 cur_entry.sampling_number = last_entry.sampling_number + 1;
36 cur_entry.sampling_number2 = cur_entry.sampling_number; 36 cur_entry.sampling_number2 = cur_entry.sampling_number;
37 // TODO(ogniK): Update mouse states 37
38 if (Settings::values.mouse_enabled) {
39 const auto [px, py, sx, sy] = mouse_device->GetStatus();
40 const auto x = static_cast<s32>(px * Layout::ScreenUndocked::Width);
41 const auto y = static_cast<s32>(py * Layout::ScreenUndocked::Height);
42 cur_entry.x = x;
43 cur_entry.y = y;
44 cur_entry.delta_x = x - last_entry.x;
45 cur_entry.delta_y = y - last_entry.y;
46 cur_entry.mouse_wheel_x = sx;
47 cur_entry.mouse_wheel_y = sy;
48
49 for (std::size_t i = 0; i < mouse_button_devices.size(); ++i) {
50 cur_entry.button |= (mouse_button_devices[i]->GetStatus() << i);
51 }
52 }
38 53
39 std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); 54 std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
40} 55}
41 56
42void Controller_Mouse::OnLoadInputDevices() {} 57void Controller_Mouse::OnLoadInputDevices() {
58 mouse_device = Input::CreateDevice<Input::MouseDevice>(Settings::values.mouse_device);
59 std::transform(Settings::values.mouse_buttons.begin(), Settings::values.mouse_buttons.end(),
60 mouse_button_devices.begin(), Input::CreateDevice<Input::ButtonDevice>);
61}
43} // namespace Service::HID 62} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h
index 543b0b71f..70b654d07 100644
--- a/src/core/hle/service/hid/controllers/mouse.h
+++ b/src/core/hle/service/hid/controllers/mouse.h
@@ -7,7 +7,9 @@
7#include <array> 7#include <array>
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "common/swap.h" 9#include "common/swap.h"
10#include "core/frontend/input.h"
10#include "core/hle/service/hid/controllers/controller_base.h" 11#include "core/hle/service/hid/controllers/controller_base.h"
12#include "core/settings.h"
11 13
12namespace Service::HID { 14namespace Service::HID {
13class Controller_Mouse final : public ControllerBase { 15class Controller_Mouse final : public ControllerBase {
@@ -35,7 +37,8 @@ private:
35 s32_le y; 37 s32_le y;
36 s32_le delta_x; 38 s32_le delta_x;
37 s32_le delta_y; 39 s32_le delta_y;
38 s32_le mouse_wheel; 40 s32_le mouse_wheel_x;
41 s32_le mouse_wheel_y;
39 s32_le button; 42 s32_le button;
40 s32_le attribute; 43 s32_le attribute;
41 }; 44 };
@@ -46,5 +49,9 @@ private:
46 std::array<MouseState, 17> mouse_states; 49 std::array<MouseState, 17> mouse_states;
47 }; 50 };
48 SharedMemory shared_memory{}; 51 SharedMemory shared_memory{};
52
53 std::unique_ptr<Input::MouseDevice> mouse_device;
54 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeMouseButton::NumMouseButtons>
55 mouse_button_devices;
49}; 56};
50} // namespace Service::HID 57} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index ff9b64be4..d6829d0b8 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -12,27 +12,20 @@
12#include "core/core.h" 12#include "core/core.h"
13#include "core/core_timing.h" 13#include "core/core_timing.h"
14#include "core/frontend/input.h" 14#include "core/frontend/input.h"
15#include "core/hle/kernel/event.h" 15#include "core/hle/kernel/kernel.h"
16#include "core/hle/kernel/readable_event.h"
17#include "core/hle/kernel/writable_event.h"
16#include "core/hle/service/hid/controllers/npad.h" 18#include "core/hle/service/hid/controllers/npad.h"
17#include "core/settings.h" 19#include "core/settings.h"
18 20
19namespace Service::HID { 21namespace Service::HID {
20
21constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;
22constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A;
23constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6;
24constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E;
25constexpr s32 HID_JOYSTICK_MAX = 0x7fff; 22constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
26constexpr s32 HID_JOYSTICK_MIN = -0x7fff; 23constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
27constexpr std::size_t NPAD_OFFSET = 0x9A00; 24constexpr std::size_t NPAD_OFFSET = 0x9A00;
28constexpr u32 BATTERY_FULL = 2; 25constexpr u32 BATTERY_FULL = 2;
29constexpr u32 NPAD_HANDHELD = 32;
30constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this?
31constexpr u32 MAX_NPAD_ID = 7; 26constexpr u32 MAX_NPAD_ID = 7;
32constexpr Controller_NPad::NPadControllerType PREFERRED_CONTROLLER =
33 Controller_NPad::NPadControllerType::JoyDual;
34constexpr std::array<u32, 10> npad_id_list{ 27constexpr std::array<u32, 10> npad_id_list{
35 0, 1, 2, 3, 4, 5, 6, 7, 32, 16, 28 0, 1, 2, 3, 4, 5, 6, 7, NPAD_HANDHELD, NPAD_UNKNOWN,
36}; 29};
37 30
38enum class JoystickId : std::size_t { 31enum class JoystickId : std::size_t {
@@ -40,6 +33,66 @@ enum class JoystickId : std::size_t {
40 Joystick_Right, 33 Joystick_Right,
41}; 34};
42 35
36static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::ControllerType type) {
37 switch (type) {
38 case Settings::ControllerType::ProController:
39 return Controller_NPad::NPadControllerType::ProController;
40 case Settings::ControllerType::DualJoycon:
41 return Controller_NPad::NPadControllerType::JoyDual;
42 case Settings::ControllerType::LeftJoycon:
43 return Controller_NPad::NPadControllerType::JoyLeft;
44 case Settings::ControllerType::RightJoycon:
45 return Controller_NPad::NPadControllerType::JoyRight;
46 default:
47 UNREACHABLE();
48 return Controller_NPad::NPadControllerType::JoyDual;
49 }
50}
51
52std::size_t Controller_NPad::NPadIdToIndex(u32 npad_id) {
53 switch (npad_id) {
54 case 0:
55 case 1:
56 case 2:
57 case 3:
58 case 4:
59 case 5:
60 case 6:
61 case 7:
62 return npad_id;
63 case 8:
64 case NPAD_HANDHELD:
65 return 8;
66 case 9:
67 case NPAD_UNKNOWN:
68 return 9;
69 default:
70 UNIMPLEMENTED_MSG("Unknown npad id {}", npad_id);
71 return 0;
72 }
73}
74
75u32 Controller_NPad::IndexToNPad(std::size_t index) {
76 switch (index) {
77 case 0:
78 case 1:
79 case 2:
80 case 3:
81 case 4:
82 case 5:
83 case 6:
84 case 7:
85 return static_cast<u32>(index);
86 case 8:
87 return NPAD_HANDHELD;
88 case 9:
89 return NPAD_UNKNOWN;
90 default:
91 UNIMPLEMENTED_MSG("Unknown npad index {}", index);
92 return 0;
93 };
94}
95
43Controller_NPad::Controller_NPad() = default; 96Controller_NPad::Controller_NPad() = default;
44Controller_NPad::~Controller_NPad() = default; 97Controller_NPad::~Controller_NPad() = default;
45 98
@@ -56,22 +109,32 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
56 controller.joy_styles.handheld.Assign(1); 109 controller.joy_styles.handheld.Assign(1);
57 controller.device_type.handheld.Assign(1); 110 controller.device_type.handheld.Assign(1);
58 controller.pad_assignment = NPadAssignments::Dual; 111 controller.pad_assignment = NPadAssignments::Dual;
112 controller.properties.is_vertical.Assign(1);
113 controller.properties.use_plus.Assign(1);
114 controller.properties.use_minus.Assign(1);
59 break; 115 break;
60 case NPadControllerType::JoyDual: 116 case NPadControllerType::JoyDual:
61 controller.joy_styles.joycon_dual.Assign(1); 117 controller.joy_styles.joycon_dual.Assign(1);
62 controller.device_type.joycon_left.Assign(1); 118 controller.device_type.joycon_left.Assign(1);
63 controller.device_type.joycon_right.Assign(1); 119 controller.device_type.joycon_right.Assign(1);
120 controller.properties.is_vertical.Assign(1);
121 controller.properties.use_plus.Assign(1);
122 controller.properties.use_minus.Assign(1);
64 controller.pad_assignment = NPadAssignments::Dual; 123 controller.pad_assignment = NPadAssignments::Dual;
65 break; 124 break;
66 case NPadControllerType::JoyLeft: 125 case NPadControllerType::JoyLeft:
67 controller.joy_styles.joycon_left.Assign(1); 126 controller.joy_styles.joycon_left.Assign(1);
68 controller.device_type.joycon_left.Assign(1); 127 controller.device_type.joycon_left.Assign(1);
69 controller.pad_assignment = NPadAssignments::Dual; 128 controller.properties.is_horizontal.Assign(1);
129 controller.properties.use_minus.Assign(1);
130 controller.pad_assignment = NPadAssignments::Single;
70 break; 131 break;
71 case NPadControllerType::JoyRight: 132 case NPadControllerType::JoyRight:
72 controller.joy_styles.joycon_right.Assign(1); 133 controller.joy_styles.joycon_right.Assign(1);
73 controller.device_type.joycon_right.Assign(1); 134 controller.device_type.joycon_right.Assign(1);
74 controller.pad_assignment = NPadAssignments::Dual; 135 controller.properties.is_horizontal.Assign(1);
136 controller.properties.use_plus.Assign(1);
137 controller.pad_assignment = NPadAssignments::Single;
75 break; 138 break;
76 case NPadControllerType::Pokeball: 139 case NPadControllerType::Pokeball:
77 controller.joy_styles.pokeball.Assign(1); 140 controller.joy_styles.pokeball.Assign(1);
@@ -81,6 +144,9 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
81 case NPadControllerType::ProController: 144 case NPadControllerType::ProController:
82 controller.joy_styles.pro_controller.Assign(1); 145 controller.joy_styles.pro_controller.Assign(1);
83 controller.device_type.pro_controller.Assign(1); 146 controller.device_type.pro_controller.Assign(1);
147 controller.properties.is_vertical.Assign(1);
148 controller.properties.use_plus.Assign(1);
149 controller.properties.use_minus.Assign(1);
84 controller.pad_assignment = NPadAssignments::Single; 150 controller.pad_assignment = NPadAssignments::Single;
85 break; 151 break;
86 } 152 }
@@ -90,14 +156,12 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
90 controller.single_color.button_color = 0; 156 controller.single_color.button_color = 0;
91 157
92 controller.dual_color_error = ColorReadError::ReadOk; 158 controller.dual_color_error = ColorReadError::ReadOk;
93 controller.left_color.body_color = JOYCON_BODY_NEON_BLUE; 159 controller.left_color.body_color = Settings::values.players[controller_idx].body_color_left;
94 controller.left_color.button_color = JOYCON_BUTTONS_NEON_BLUE; 160 controller.left_color.button_color = Settings::values.players[controller_idx].button_color_left;
95 controller.right_color.body_color = JOYCON_BODY_NEON_RED; 161 controller.right_color.body_color = Settings::values.players[controller_idx].body_color_right;
96 controller.right_color.button_color = JOYCON_BUTTONS_NEON_RED; 162 controller.right_color.button_color =
97 163 Settings::values.players[controller_idx].button_color_right;
98 controller.properties.is_vertical.Assign(1); // TODO(ogniK): Swap joycons orientations 164
99 controller.properties.use_plus.Assign(1);
100 controller.properties.use_minus.Assign(1);
101 controller.battery_level[0] = BATTERY_FULL; 165 controller.battery_level[0] = BATTERY_FULL;
102 controller.battery_level[1] = BATTERY_FULL; 166 controller.battery_level[1] = BATTERY_FULL;
103 controller.battery_level[2] = BATTERY_FULL; 167 controller.battery_level[2] = BATTERY_FULL;
@@ -105,8 +169,8 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
105 169
106void Controller_NPad::OnInit() { 170void Controller_NPad::OnInit() {
107 auto& kernel = Core::System::GetInstance().Kernel(); 171 auto& kernel = Core::System::GetInstance().Kernel();
108 styleset_changed_event = 172 styleset_changed_event = Kernel::WritableEvent::CreateEventPair(
109 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged"); 173 kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged");
110 174
111 if (!IsControllerActivated()) { 175 if (!IsControllerActivated()) {
112 return; 176 return;
@@ -121,26 +185,109 @@ void Controller_NPad::OnInit() {
121 style.pro_controller.Assign(1); 185 style.pro_controller.Assign(1);
122 style.pokeball.Assign(1); 186 style.pokeball.Assign(1);
123 } 187 }
188
189 std::transform(
190 Settings::values.players.begin(), Settings::values.players.end(),
191 connected_controllers.begin(), [](const Settings::PlayerInput& player) {
192 return ControllerHolder{MapSettingsTypeToNPad(player.type), player.connected};
193 });
194
195 std::stable_partition(connected_controllers.begin(), connected_controllers.begin() + 8,
196 [](const ControllerHolder& holder) { return holder.is_connected; });
197
198 // Account for handheld
199 if (connected_controllers[8].is_connected)
200 connected_controllers[8].type = NPadControllerType::Handheld;
201
202 supported_npad_id_types.resize(npad_id_list.size());
203 std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
204 npad_id_list.size() * sizeof(u32));
205
206 // Add a default dual joycon controller if none are present.
124 if (std::none_of(connected_controllers.begin(), connected_controllers.end(), 207 if (std::none_of(connected_controllers.begin(), connected_controllers.end(),
125 [](const ControllerHolder& controller) { return controller.is_connected; })) { 208 [](const ControllerHolder& controller) { return controller.is_connected; })) {
126 supported_npad_id_types.resize(npad_id_list.size()); 209 supported_npad_id_types.resize(npad_id_list.size());
127 std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), 210 std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
128 npad_id_list.size() * sizeof(u32)); 211 npad_id_list.size() * sizeof(u32));
129 AddNewController(PREFERRED_CONTROLLER); 212 AddNewController(NPadControllerType::JoyDual);
213 }
214
215 for (std::size_t i = 0; i < connected_controllers.size(); ++i) {
216 const auto& controller = connected_controllers[i];
217 if (controller.is_connected) {
218 AddNewControllerAt(controller.type, IndexToNPad(i));
219 }
130 } 220 }
131} 221}
132 222
133void Controller_NPad::OnLoadInputDevices() { 223void Controller_NPad::OnLoadInputDevices() {
134 std::transform(Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, 224 const auto& players = Settings::values.players;
135 Settings::values.buttons.begin() + Settings::NativeButton::BUTTON_HID_END, 225 for (std::size_t i = 0; i < players.size(); ++i) {
136 buttons.begin(), Input::CreateDevice<Input::ButtonDevice>); 226 std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
137 std::transform(Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, 227 players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END,
138 Settings::values.analogs.begin() + Settings::NativeAnalog::STICK_HID_END, 228 buttons[i].begin(), Input::CreateDevice<Input::ButtonDevice>);
139 sticks.begin(), Input::CreateDevice<Input::AnalogDevice>); 229 std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,
230 players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END,
231 sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>);
232 }
140} 233}
141 234
142void Controller_NPad::OnRelease() {} 235void Controller_NPad::OnRelease() {}
143 236
237void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
238 const auto controller_idx = NPadIdToIndex(npad_id);
239 const auto controller_type = connected_controllers[controller_idx].type;
240 if (!connected_controllers[controller_idx].is_connected) {
241 return;
242 }
243 auto& pad_state = npad_pad_states[controller_idx].pad_states;
244 auto& lstick_entry = npad_pad_states[controller_idx].l_stick;
245 auto& rstick_entry = npad_pad_states[controller_idx].r_stick;
246 const auto& button_state = buttons[controller_idx];
247 const auto& analog_state = sticks[controller_idx];
248
249 using namespace Settings::NativeButton;
250 pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus());
251 pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus());
252 pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus());
253 pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus());
254 pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus());
255 pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus());
256 pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus());
257 pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus());
258 pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus());
259 pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus());
260 pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus());
261 pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus());
262
263 pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus());
264 pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus());
265 pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus());
266 pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus());
267
268 pad_state.l_stick_left.Assign(button_state[LStick_Left - BUTTON_HID_BEGIN]->GetStatus());
269 pad_state.l_stick_up.Assign(button_state[LStick_Up - BUTTON_HID_BEGIN]->GetStatus());
270 pad_state.l_stick_right.Assign(button_state[LStick_Right - BUTTON_HID_BEGIN]->GetStatus());
271 pad_state.l_stick_down.Assign(button_state[LStick_Down - BUTTON_HID_BEGIN]->GetStatus());
272
273 pad_state.r_stick_left.Assign(button_state[RStick_Left - BUTTON_HID_BEGIN]->GetStatus());
274 pad_state.r_stick_up.Assign(button_state[RStick_Up - BUTTON_HID_BEGIN]->GetStatus());
275 pad_state.r_stick_right.Assign(button_state[RStick_Right - BUTTON_HID_BEGIN]->GetStatus());
276 pad_state.r_stick_down.Assign(button_state[RStick_Down - BUTTON_HID_BEGIN]->GetStatus());
277
278 pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
279 pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
280
281 const auto [stick_l_x_f, stick_l_y_f] =
282 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
283 const auto [stick_r_x_f, stick_r_y_f] =
284 analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
285 lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
286 lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
287 rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
288 rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
289}
290
144void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) { 291void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
145 if (!IsControllerActivated()) 292 if (!IsControllerActivated())
146 return; 293 return;
@@ -176,97 +323,9 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
176 if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) { 323 if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) {
177 continue; 324 continue;
178 } 325 }
179 326 const u32 npad_index = static_cast<u32>(i);
180 // Pad states 327 RequestPadStateUpdate(npad_index);
181 ControllerPadState pad_state{}; 328 auto& pad_state = npad_pad_states[npad_index];
182 using namespace Settings::NativeButton;
183 pad_state.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
184 pad_state.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
185 pad_state.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
186 pad_state.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
187 pad_state.l_stick.Assign(buttons[LStick - BUTTON_HID_BEGIN]->GetStatus());
188 pad_state.r_stick.Assign(buttons[RStick - BUTTON_HID_BEGIN]->GetStatus());
189 pad_state.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
190 pad_state.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
191 pad_state.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
192 pad_state.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
193 pad_state.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
194 pad_state.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
195
196 pad_state.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
197 pad_state.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
198 pad_state.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
199 pad_state.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
200
201 pad_state.l_stick_left.Assign(buttons[LStick_Left - BUTTON_HID_BEGIN]->GetStatus());
202 pad_state.l_stick_up.Assign(buttons[LStick_Up - BUTTON_HID_BEGIN]->GetStatus());
203 pad_state.l_stick_right.Assign(buttons[LStick_Right - BUTTON_HID_BEGIN]->GetStatus());
204 pad_state.l_stick_down.Assign(buttons[LStick_Down - BUTTON_HID_BEGIN]->GetStatus());
205
206 pad_state.r_stick_left.Assign(buttons[RStick_Left - BUTTON_HID_BEGIN]->GetStatus());
207 pad_state.r_stick_up.Assign(buttons[RStick_Up - BUTTON_HID_BEGIN]->GetStatus());
208 pad_state.r_stick_right.Assign(buttons[RStick_Right - BUTTON_HID_BEGIN]->GetStatus());
209 pad_state.r_stick_down.Assign(buttons[RStick_Down - BUTTON_HID_BEGIN]->GetStatus());
210
211 pad_state.sl.Assign(buttons[SL - BUTTON_HID_BEGIN]->GetStatus());
212 pad_state.sr.Assign(buttons[SR - BUTTON_HID_BEGIN]->GetStatus());
213
214 AnalogPosition lstick_entry{};
215 AnalogPosition rstick_entry{};
216
217 const auto [stick_l_x_f, stick_l_y_f] =
218 sticks[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
219 const auto [stick_r_x_f, stick_r_y_f] =
220 sticks[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
221 lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
222 lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
223 rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
224 rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
225
226 if (controller_type == NPadControllerType::JoyLeft ||
227 controller_type == NPadControllerType::JoyRight) {
228 if (npad.properties.is_horizontal) {
229 ControllerPadState state{};
230 AnalogPosition temp_lstick_entry{};
231 AnalogPosition temp_rstick_entry{};
232 if (controller_type == NPadControllerType::JoyLeft) {
233 state.d_down.Assign(pad_state.d_left.Value());
234 state.d_left.Assign(pad_state.d_up.Value());
235 state.d_right.Assign(pad_state.d_down.Value());
236 state.d_up.Assign(pad_state.d_right.Value());
237 state.l.Assign(pad_state.l.Value() | pad_state.sl.Value());
238 state.r.Assign(pad_state.r.Value() | pad_state.sr.Value());
239
240 state.zl.Assign(pad_state.zl.Value());
241 state.plus.Assign(pad_state.minus.Value());
242
243 temp_lstick_entry = lstick_entry;
244 temp_rstick_entry = rstick_entry;
245 std::swap(temp_lstick_entry.x, temp_lstick_entry.y);
246 std::swap(temp_rstick_entry.x, temp_rstick_entry.y);
247 temp_lstick_entry.y *= -1;
248 } else if (controller_type == NPadControllerType::JoyRight) {
249 state.x.Assign(pad_state.a.Value());
250 state.a.Assign(pad_state.b.Value());
251 state.b.Assign(pad_state.y.Value());
252 state.y.Assign(pad_state.b.Value());
253
254 state.l.Assign(pad_state.l.Value() | pad_state.sl.Value());
255 state.r.Assign(pad_state.r.Value() | pad_state.sr.Value());
256 state.zr.Assign(pad_state.zr.Value());
257 state.plus.Assign(pad_state.plus.Value());
258
259 temp_lstick_entry = lstick_entry;
260 temp_rstick_entry = rstick_entry;
261 std::swap(temp_lstick_entry.x, temp_lstick_entry.y);
262 std::swap(temp_rstick_entry.x, temp_rstick_entry.y);
263 temp_rstick_entry.x *= -1;
264 }
265 pad_state.raw = state.raw;
266 lstick_entry = temp_lstick_entry;
267 rstick_entry = temp_rstick_entry;
268 }
269 }
270 329
271 auto& main_controller = 330 auto& main_controller =
272 npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index]; 331 npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index];
@@ -281,20 +340,64 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
281 auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index]; 340 auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index];
282 341
283 if (hold_type == NpadHoldType::Horizontal) { 342 if (hold_type == NpadHoldType::Horizontal) {
284 // TODO(ogniK): Remap buttons for different orientations 343 ControllerPadState state{};
344 AnalogPosition temp_lstick_entry{};
345 AnalogPosition temp_rstick_entry{};
346 if (controller_type == NPadControllerType::JoyLeft) {
347 state.d_down.Assign(pad_state.pad_states.d_left.Value());
348 state.d_left.Assign(pad_state.pad_states.d_up.Value());
349 state.d_right.Assign(pad_state.pad_states.d_down.Value());
350 state.d_up.Assign(pad_state.pad_states.d_right.Value());
351 state.l.Assign(pad_state.pad_states.l.Value() |
352 pad_state.pad_states.left_sl.Value());
353 state.r.Assign(pad_state.pad_states.r.Value() |
354 pad_state.pad_states.left_sr.Value());
355
356 state.zl.Assign(pad_state.pad_states.zl.Value());
357 state.plus.Assign(pad_state.pad_states.minus.Value());
358
359 temp_lstick_entry = pad_state.l_stick;
360 temp_rstick_entry = pad_state.r_stick;
361 std::swap(temp_lstick_entry.x, temp_lstick_entry.y);
362 std::swap(temp_rstick_entry.x, temp_rstick_entry.y);
363 temp_lstick_entry.y *= -1;
364 } else if (controller_type == NPadControllerType::JoyRight) {
365 state.x.Assign(pad_state.pad_states.a.Value());
366 state.a.Assign(pad_state.pad_states.b.Value());
367 state.b.Assign(pad_state.pad_states.y.Value());
368 state.y.Assign(pad_state.pad_states.b.Value());
369
370 state.l.Assign(pad_state.pad_states.l.Value() |
371 pad_state.pad_states.right_sl.Value());
372 state.r.Assign(pad_state.pad_states.r.Value() |
373 pad_state.pad_states.right_sr.Value());
374 state.zr.Assign(pad_state.pad_states.zr.Value());
375 state.plus.Assign(pad_state.pad_states.plus.Value());
376
377 temp_lstick_entry = pad_state.l_stick;
378 temp_rstick_entry = pad_state.r_stick;
379 std::swap(temp_lstick_entry.x, temp_lstick_entry.y);
380 std::swap(temp_rstick_entry.x, temp_rstick_entry.y);
381 temp_rstick_entry.x *= -1;
382 }
383 pad_state.pad_states.raw = state.raw;
384 pad_state.l_stick = temp_lstick_entry;
385 pad_state.r_stick = temp_rstick_entry;
285 } 386 }
387
286 libnx_entry.connection_status.raw = 0; 388 libnx_entry.connection_status.raw = 0;
287 389
288 switch (controller_type) { 390 switch (controller_type) {
289 case NPadControllerType::Handheld: 391 case NPadControllerType::Handheld:
290 handheld_entry.connection_status.raw = 0; 392 handheld_entry.connection_status.raw = 0;
291 handheld_entry.connection_status.IsConnected.Assign(1); 393 handheld_entry.connection_status.IsWired.Assign(1);
292 if (!Settings::values.use_docked_mode) { 394 handheld_entry.connection_status.IsLeftJoyConnected.Assign(1);
293 handheld_entry.connection_status.IsWired.Assign(1); 395 handheld_entry.connection_status.IsRightJoyConnected.Assign(1);
294 } 396 handheld_entry.connection_status.IsLeftJoyWired.Assign(1);
295 handheld_entry.pad_states.raw = pad_state.raw; 397 handheld_entry.connection_status.IsRightJoyWired.Assign(1);
296 handheld_entry.l_stick = lstick_entry; 398 handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw;
297 handheld_entry.r_stick = rstick_entry; 399 handheld_entry.pad.l_stick = pad_state.l_stick;
400 handheld_entry.pad.r_stick = pad_state.r_stick;
298 break; 401 break;
299 case NPadControllerType::JoyDual: 402 case NPadControllerType::JoyDual:
300 dual_entry.connection_status.raw = 0; 403 dual_entry.connection_status.raw = 0;
@@ -307,24 +410,25 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
307 libnx_entry.connection_status.IsRightJoyConnected.Assign(1); 410 libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
308 libnx_entry.connection_status.IsConnected.Assign(1); 411 libnx_entry.connection_status.IsConnected.Assign(1);
309 412
310 dual_entry.pad_states.raw = pad_state.raw; 413 dual_entry.pad.pad_states.raw = pad_state.pad_states.raw;
311 dual_entry.l_stick = lstick_entry; 414 dual_entry.pad.l_stick = pad_state.l_stick;
312 dual_entry.r_stick = rstick_entry; 415 dual_entry.pad.r_stick = pad_state.r_stick;
416 break;
313 case NPadControllerType::JoyLeft: 417 case NPadControllerType::JoyLeft:
314 left_entry.connection_status.raw = 0; 418 left_entry.connection_status.raw = 0;
315 419
316 left_entry.connection_status.IsConnected.Assign(1); 420 left_entry.connection_status.IsConnected.Assign(1);
317 left_entry.pad_states.raw = pad_state.raw; 421 left_entry.pad.pad_states.raw = pad_state.pad_states.raw;
318 left_entry.l_stick = lstick_entry; 422 left_entry.pad.l_stick = pad_state.l_stick;
319 left_entry.r_stick = rstick_entry; 423 left_entry.pad.r_stick = pad_state.r_stick;
320 break; 424 break;
321 case NPadControllerType::JoyRight: 425 case NPadControllerType::JoyRight:
322 right_entry.connection_status.raw = 0; 426 right_entry.connection_status.raw = 0;
323 427
324 right_entry.connection_status.IsConnected.Assign(1); 428 right_entry.connection_status.IsConnected.Assign(1);
325 right_entry.pad_states.raw = pad_state.raw; 429 right_entry.pad.pad_states.raw = pad_state.pad_states.raw;
326 right_entry.l_stick = lstick_entry; 430 right_entry.pad.l_stick = pad_state.l_stick;
327 right_entry.r_stick = rstick_entry; 431 right_entry.pad.r_stick = pad_state.r_stick;
328 break; 432 break;
329 case NPadControllerType::Pokeball: 433 case NPadControllerType::Pokeball:
330 pokeball_entry.connection_status.raw = 0; 434 pokeball_entry.connection_status.raw = 0;
@@ -332,30 +436,30 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
332 pokeball_entry.connection_status.IsConnected.Assign(1); 436 pokeball_entry.connection_status.IsConnected.Assign(1);
333 pokeball_entry.connection_status.IsWired.Assign(1); 437 pokeball_entry.connection_status.IsWired.Assign(1);
334 438
335 pokeball_entry.pad_states.raw = pad_state.raw; 439 pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw;
336 pokeball_entry.l_stick = lstick_entry; 440 pokeball_entry.pad.l_stick = pad_state.l_stick;
337 pokeball_entry.r_stick = rstick_entry; 441 pokeball_entry.pad.r_stick = pad_state.r_stick;
338 break; 442 break;
339 case NPadControllerType::ProController: 443 case NPadControllerType::ProController:
340 main_controller.connection_status.raw = 0; 444 main_controller.connection_status.raw = 0;
341 445
342 main_controller.connection_status.IsConnected.Assign(1); 446 main_controller.connection_status.IsConnected.Assign(1);
343 main_controller.connection_status.IsWired.Assign(1); 447 main_controller.connection_status.IsWired.Assign(1);
344 main_controller.pad_states.raw = pad_state.raw; 448 main_controller.pad.pad_states.raw = pad_state.pad_states.raw;
345 main_controller.l_stick = lstick_entry; 449 main_controller.pad.l_stick = pad_state.l_stick;
346 main_controller.r_stick = rstick_entry; 450 main_controller.pad.r_stick = pad_state.r_stick;
347 break; 451 break;
348 } 452 }
349 453
350 // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate 454 // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate
351 // any controllers. 455 // any controllers.
352 libnx_entry.pad_states.raw = pad_state.raw; 456 libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw;
353 libnx_entry.l_stick = lstick_entry; 457 libnx_entry.pad.l_stick = pad_state.l_stick;
354 libnx_entry.r_stick = rstick_entry; 458 libnx_entry.pad.r_stick = pad_state.r_stick;
355 } 459 }
356 std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), 460 std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(),
357 shared_memory_entries.size() * sizeof(NPadEntry)); 461 shared_memory_entries.size() * sizeof(NPadEntry));
358} // namespace Service::HID 462}
359 463
360void Controller_NPad::SetSupportedStyleSet(NPadType style_set) { 464void Controller_NPad::SetSupportedStyleSet(NPadType style_set) {
361 style.raw = style_set.raw; 465 style.raw = style_set.raw;
@@ -370,14 +474,29 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) {
370 supported_npad_id_types.clear(); 474 supported_npad_id_types.clear();
371 supported_npad_id_types.resize(length / sizeof(u32)); 475 supported_npad_id_types.resize(length / sizeof(u32));
372 std::memcpy(supported_npad_id_types.data(), data, length); 476 std::memcpy(supported_npad_id_types.data(), data, length);
477 bool had_controller_update = false;
373 for (std::size_t i = 0; i < connected_controllers.size(); i++) { 478 for (std::size_t i = 0; i < connected_controllers.size(); i++) {
374 auto& controller = connected_controllers[i]; 479 auto& controller = connected_controllers[i];
375 if (!controller.is_connected) { 480 if (!controller.is_connected) {
376 continue; 481 continue;
377 } 482 }
378 if (!IsControllerSupported(PREFERRED_CONTROLLER)) { 483 const auto requested_controller =
379 controller.type = DecideBestController(PREFERRED_CONTROLLER); 484 i <= MAX_NPAD_ID ? MapSettingsTypeToNPad(Settings::values.players[i].type)
380 InitNewlyAddedControler(i); 485 : NPadControllerType::Handheld;
486 if (!IsControllerSupported(requested_controller)) {
487 const auto is_handheld = requested_controller == NPadControllerType::Handheld;
488 if (is_handheld) {
489 controller.type = NPadControllerType::None;
490 controller.is_connected = false;
491 AddNewController(requested_controller);
492 } else {
493 controller.type = requested_controller;
494 InitNewlyAddedControler(i);
495 }
496 had_controller_update = true;
497 }
498 if (had_controller_update) {
499 styleset_changed_event.writable->Signal();
381 } 500 }
382 } 501 }
383} 502}
@@ -392,7 +511,7 @@ std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const {
392} 511}
393 512
394void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) { 513void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) {
395 styleset_changed_event->Signal(); 514 styleset_changed_event.writable->Signal();
396 hold_type = joy_hold_type; 515 hold_type = joy_hold_type;
397} 516}
398 517
@@ -401,44 +520,40 @@ Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const {
401} 520}
402 521
403void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) { 522void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) {
404 ASSERT(npad_id < shared_memory_entries.size()); 523 const std::size_t npad_index = NPadIdToIndex(npad_id);
405 shared_memory_entries[npad_id].pad_assignment = assignment_mode; 524 ASSERT(npad_index < shared_memory_entries.size());
525 shared_memory_entries[npad_index].pad_assignment = assignment_mode;
406} 526}
407 527
408void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, 528void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
409 const std::vector<Vibration>& vibrations) { 529 const std::vector<Vibration>& vibrations) {
530 LOG_WARNING(Service_HID, "(STUBBED) called");
531
410 if (!can_controllers_vibrate) { 532 if (!can_controllers_vibrate) {
411 return; 533 return;
412 } 534 }
413 for (std::size_t i = 0; i < controller_ids.size(); i++) { 535 for (std::size_t i = 0; i < controller_ids.size(); i++) {
414 std::size_t controller_pos = i; 536 std::size_t controller_pos = NPadIdToIndex(static_cast<u32>(i));
415 // Handheld controller conversion
416 if (controller_pos == NPAD_HANDHELD) {
417 controller_pos = 8;
418 }
419 // Unknown controller conversion
420 if (controller_pos == NPAD_UNKNOWN) {
421 controller_pos = 9;
422 }
423 if (connected_controllers[controller_pos].is_connected) { 537 if (connected_controllers[controller_pos].is_connected) {
424 // TODO(ogniK): Vibrate the physical controller 538 // TODO(ogniK): Vibrate the physical controller
425 } 539 }
426 } 540 }
427 LOG_WARNING(Service_HID, "(STUBBED) called");
428 last_processed_vibration = vibrations.back(); 541 last_processed_vibration = vibrations.back();
429} 542}
430 543
431Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() const { 544Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent() const {
432 // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should 545 // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should
433 // be signalled at least once, and signaled after a new controller is connected? 546 // be signalled at least once, and signaled after a new controller is connected?
434 styleset_changed_event->Signal(); 547 styleset_changed_event.writable->Signal();
435 return styleset_changed_event; 548 return styleset_changed_event.readable;
436} 549}
437 550
438Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { 551Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
439 return last_processed_vibration; 552 return last_processed_vibration;
440} 553}
554
441void Controller_NPad::AddNewController(NPadControllerType controller) { 555void Controller_NPad::AddNewController(NPadControllerType controller) {
556 controller = DecideBestController(controller);
442 if (controller == NPadControllerType::Handheld) { 557 if (controller == NPadControllerType::Handheld) {
443 connected_controllers[8] = {controller, true}; 558 connected_controllers[8] = {controller, true};
444 InitNewlyAddedControler(8); 559 InitNewlyAddedControler(8);
@@ -456,16 +571,54 @@ void Controller_NPad::AddNewController(NPadControllerType controller) {
456 InitNewlyAddedControler(controller_id); 571 InitNewlyAddedControler(controller_id);
457} 572}
458 573
459void Controller_NPad::ConnectNPad(u32 npad_id) { 574void Controller_NPad::AddNewControllerAt(NPadControllerType controller, u32 npad_id) {
460 if (npad_id >= connected_controllers.size()) 575 controller = DecideBestController(controller);
576 if (controller == NPadControllerType::Handheld) {
577 connected_controllers[NPadIdToIndex(NPAD_HANDHELD)] = {controller, true};
578 InitNewlyAddedControler(NPadIdToIndex(NPAD_HANDHELD));
461 return; 579 return;
462 connected_controllers[npad_id].is_connected = true; 580 }
581
582 connected_controllers[NPadIdToIndex(npad_id)] = {controller, true};
583 InitNewlyAddedControler(NPadIdToIndex(npad_id));
584}
585
586void Controller_NPad::ConnectNPad(u32 npad_id) {
587 connected_controllers[NPadIdToIndex(npad_id)].is_connected = true;
463} 588}
464 589
465void Controller_NPad::DisconnectNPad(u32 npad_id) { 590void Controller_NPad::DisconnectNPad(u32 npad_id) {
466 if (npad_id >= connected_controllers.size()) 591 connected_controllers[NPadIdToIndex(npad_id)].is_connected = false;
467 return; 592}
468 connected_controllers[npad_id].is_connected = false; 593
594bool Controller_NPad::IsControllerSupported(NPadControllerType controller) {
595 if (controller == NPadControllerType::Handheld) {
596 // Handheld is not even a supported type, lets stop here
597 if (std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(),
598 NPAD_HANDHELD) == supported_npad_id_types.end()) {
599 return false;
600 }
601 // Handheld should not be supported in docked mode
602 if (Settings::values.use_docked_mode) {
603 return false;
604 }
605 }
606 switch (controller) {
607 case NPadControllerType::ProController:
608 return style.pro_controller;
609 case NPadControllerType::Handheld:
610 return style.handheld;
611 case NPadControllerType::JoyDual:
612 return style.joycon_dual;
613 case NPadControllerType::JoyLeft:
614 return style.joycon_left;
615 case NPadControllerType::JoyRight:
616 return style.joycon_right;
617 case NPadControllerType::Pokeball:
618 return style.pokeball;
619 default:
620 return false;
621 }
469} 622}
470 623
471Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { 624Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
@@ -499,6 +652,36 @@ void Controller_NPad::SetVibrationEnabled(bool can_vibrate) {
499 can_controllers_vibrate = can_vibrate; 652 can_controllers_vibrate = can_vibrate;
500} 653}
501 654
655void Controller_NPad::ClearAllConnectedControllers() {
656 for (auto& controller : connected_controllers) {
657 if (controller.is_connected && controller.type != NPadControllerType::None) {
658 controller.type = NPadControllerType::None;
659 controller.is_connected = false;
660 }
661 }
662}
663void Controller_NPad::DisconnectAllConnectedControllers() {
664 std::for_each(connected_controllers.begin(), connected_controllers.end(),
665 [](ControllerHolder& controller) { controller.is_connected = false; });
666}
667
668void Controller_NPad::ConnectAllDisconnectedControllers() {
669 std::for_each(connected_controllers.begin(), connected_controllers.end(),
670 [](ControllerHolder& controller) {
671 if (controller.type != NPadControllerType::None && !controller.is_connected) {
672 controller.is_connected = false;
673 }
674 });
675}
676
677void Controller_NPad::ClearAllControllers() {
678 std::for_each(connected_controllers.begin(), connected_controllers.end(),
679 [](ControllerHolder& controller) {
680 controller.type = NPadControllerType::None;
681 controller.is_connected = false;
682 });
683}
684
502bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const { 685bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const {
503 const bool support_handheld = 686 const bool support_handheld =
504 std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), NPAD_HANDHELD) != 687 std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), NPAD_HANDHELD) !=
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index ac86985ff..29851f16a 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -5,13 +5,19 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include "common/bit_field.h"
8#include "common/common_types.h" 9#include "common/common_types.h"
9#include "core/frontend/input.h" 10#include "core/frontend/input.h"
11#include "core/hle/kernel/object.h"
12#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/hid/controllers/controller_base.h" 13#include "core/hle/service/hid/controllers/controller_base.h"
11#include "core/settings.h" 14#include "core/settings.h"
12 15
13namespace Service::HID { 16namespace Service::HID {
14 17
18constexpr u32 NPAD_HANDHELD = 32;
19constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this?
20
15class Controller_NPad final : public ControllerBase { 21class Controller_NPad final : public ControllerBase {
16public: 22public:
17 Controller_NPad(); 23 Controller_NPad();
@@ -75,9 +81,9 @@ public:
75 struct LedPattern { 81 struct LedPattern {
76 explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { 82 explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) {
77 position1.Assign(light1); 83 position1.Assign(light1);
78 position1.Assign(light2); 84 position2.Assign(light2);
79 position1.Assign(light3); 85 position3.Assign(light3);
80 position1.Assign(light4); 86 position4.Assign(light4);
81 } 87 }
82 union { 88 union {
83 u64 raw{}; 89 u64 raw{};
@@ -103,15 +109,23 @@ public:
103 void VibrateController(const std::vector<u32>& controller_ids, 109 void VibrateController(const std::vector<u32>& controller_ids,
104 const std::vector<Vibration>& vibrations); 110 const std::vector<Vibration>& vibrations);
105 111
106 Kernel::SharedPtr<Kernel::Event> GetStyleSetChangedEvent() const; 112 Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent() const;
107 Vibration GetLastVibration() const; 113 Vibration GetLastVibration() const;
108 114
109 void AddNewController(NPadControllerType controller); 115 void AddNewController(NPadControllerType controller);
116 void AddNewControllerAt(NPadControllerType controller, u32 npad_id);
110 117
111 void ConnectNPad(u32 npad_id); 118 void ConnectNPad(u32 npad_id);
112 void DisconnectNPad(u32 npad_id); 119 void DisconnectNPad(u32 npad_id);
113 LedPattern GetLedPattern(u32 npad_id); 120 LedPattern GetLedPattern(u32 npad_id);
114 void SetVibrationEnabled(bool can_vibrate); 121 void SetVibrationEnabled(bool can_vibrate);
122 void ClearAllConnectedControllers();
123 void DisconnectAllConnectedControllers();
124 void ConnectAllDisconnectedControllers();
125 void ClearAllControllers();
126
127 static std::size_t NPadIdToIndex(u32 npad_id);
128 static u32 IndexToNPad(std::size_t index);
115 129
116private: 130private:
117 struct CommonHeader { 131 struct CommonHeader {
@@ -164,8 +178,11 @@ private:
164 BitField<23, 1, u64_le> r_stick_down; 178 BitField<23, 1, u64_le> r_stick_down;
165 179
166 // Not always active? 180 // Not always active?
167 BitField<24, 1, u64_le> sl; 181 BitField<24, 1, u64_le> left_sl;
168 BitField<25, 1, u64_le> sr; 182 BitField<25, 1, u64_le> left_sr;
183
184 BitField<26, 1, u64_le> right_sl;
185 BitField<27, 1, u64_le> right_sr;
169 }; 186 };
170 }; 187 };
171 static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size"); 188 static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size");
@@ -189,12 +206,17 @@ private:
189 }; 206 };
190 static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size"); 207 static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size");
191 208
192 struct GenericStates { 209 struct ControllerPad {
193 s64_le timestamp;
194 s64_le timestamp2;
195 ControllerPadState pad_states; 210 ControllerPadState pad_states;
196 AnalogPosition l_stick; 211 AnalogPosition l_stick;
197 AnalogPosition r_stick; 212 AnalogPosition r_stick;
213 };
214 static_assert(sizeof(ControllerPad) == 0x18, "ControllerPad is an invalid size");
215
216 struct GenericStates {
217 s64_le timestamp;
218 s64_le timestamp2;
219 ControllerPad pad;
198 ConnectionState connection_status; 220 ConnectionState connection_status;
199 }; 221 };
200 static_assert(sizeof(GenericStates) == 0x30, "NPadGenericStates is an invalid size"); 222 static_assert(sizeof(GenericStates) == 0x30, "NPadGenericStates is an invalid size");
@@ -266,18 +288,23 @@ private:
266 static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size"); 288 static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size");
267 289
268 struct ControllerHolder { 290 struct ControllerHolder {
269 Controller_NPad::NPadControllerType type; 291 NPadControllerType type;
270 bool is_connected; 292 bool is_connected;
271 }; 293 };
272 294
273 NPadType style{}; 295 NPadType style{};
274 std::array<NPadEntry, 10> shared_memory_entries{}; 296 std::array<NPadEntry, 10> shared_memory_entries{};
275 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID> 297 std::array<
298 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>,
299 10>
276 buttons; 300 buttons;
277 std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID> sticks; 301 std::array<
302 std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>,
303 10>
304 sticks;
278 std::vector<u32> supported_npad_id_types{}; 305 std::vector<u32> supported_npad_id_types{};
279 NpadHoldType hold_type{NpadHoldType::Vertical}; 306 NpadHoldType hold_type{NpadHoldType::Vertical};
280 Kernel::SharedPtr<Kernel::Event> styleset_changed_event; 307 Kernel::EventPair styleset_changed_event;
281 Vibration last_processed_vibration{}; 308 Vibration last_processed_vibration{};
282 std::array<ControllerHolder, 10> connected_controllers{}; 309 std::array<ControllerHolder, 10> connected_controllers{};
283 bool can_controllers_vibrate{true}; 310 bool can_controllers_vibrate{true};
@@ -285,5 +312,8 @@ private:
285 void InitNewlyAddedControler(std::size_t controller_idx); 312 void InitNewlyAddedControler(std::size_t controller_idx);
286 bool IsControllerSupported(NPadControllerType controller) const; 313 bool IsControllerSupported(NPadControllerType controller) const;
287 NPadControllerType DecideBestController(NPadControllerType priority) const; 314 NPadControllerType DecideBestController(NPadControllerType priority) const;
315 void RequestPadStateUpdate(u32 npad_id);
316 std::array<ControllerPad, 10> npad_pad_states{};
317 bool IsControllerSupported(NPadControllerType controller);
288}; 318};
289} // namespace Service::HID 319} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index 43efef803..f666b1bd8 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -41,16 +41,17 @@ void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) {
41 41
42 const auto [x, y, pressed] = touch_device->GetStatus(); 42 const auto [x, y, pressed] = touch_device->GetStatus();
43 auto& touch_entry = cur_entry.states[0]; 43 auto& touch_entry = cur_entry.states[0];
44 if (pressed) { 44 touch_entry.attribute.raw = 0;
45 if (pressed && Settings::values.touchscreen.enabled) {
45 touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width); 46 touch_entry.x = static_cast<u16>(x * Layout::ScreenUndocked::Width);
46 touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height); 47 touch_entry.y = static_cast<u16>(y * Layout::ScreenUndocked::Height);
47 touch_entry.diameter_x = 15; 48 touch_entry.diameter_x = Settings::values.touchscreen.diameter_x;
48 touch_entry.diameter_y = 15; 49 touch_entry.diameter_y = Settings::values.touchscreen.diameter_y;
49 touch_entry.rotation_angle = 0; 50 touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle;
50 const u64 tick = CoreTiming::GetTicks(); 51 const u64 tick = CoreTiming::GetTicks();
51 touch_entry.delta_time = tick - last_touch; 52 touch_entry.delta_time = tick - last_touch;
52 last_touch = tick; 53 last_touch = tick;
53 touch_entry.finger = 0; 54 touch_entry.finger = Settings::values.touchscreen.finger;
54 cur_entry.entry_count = 1; 55 cur_entry.entry_count = 1;
55 } else { 56 } else {
56 cur_entry.entry_count = 0; 57 cur_entry.entry_count = 0;
@@ -60,6 +61,6 @@ void Controller_Touchscreen::OnUpdate(u8* data, std::size_t size) {
60} 61}
61 62
62void Controller_Touchscreen::OnLoadInputDevices() { 63void Controller_Touchscreen::OnLoadInputDevices() {
63 touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touch_device); 64 touch_device = Input::CreateDevice<Input::TouchDevice>(Settings::values.touchscreen.device);
64} 65}
65} // namespace Service::HID 66} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
index e5db6e6ba..94cd0eba9 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.h
+++ b/src/core/hle/service/hid/controllers/touchscreen.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/bit_field.h"
7#include "common/common_funcs.h" 8#include "common/common_funcs.h"
8#include "common/common_types.h" 9#include "common/common_types.h"
9#include "common/swap.h" 10#include "common/swap.h"
@@ -29,9 +30,18 @@ public:
29 void OnLoadInputDevices() override; 30 void OnLoadInputDevices() override;
30 31
31private: 32private:
33 struct Attributes {
34 union {
35 u32 raw{};
36 BitField<0, 1, u32_le> start_touch;
37 BitField<1, 1, u32_le> end_touch;
38 };
39 };
40 static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size");
41
32 struct TouchState { 42 struct TouchState {
33 u64_le delta_time; 43 u64_le delta_time;
34 u32_le attribute; 44 Attributes attribute;
35 u32_le finger; 45 u32_le finger;
36 u32_le x; 46 u32_le x;
37 u32_le y; 47 u32_le y;
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index a45fd4954..2ec38c726 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -13,8 +13,9 @@
13#include "core/hle/ipc_helpers.h" 13#include "core/hle/ipc_helpers.h"
14#include "core/hle/kernel/client_port.h" 14#include "core/hle/kernel/client_port.h"
15#include "core/hle/kernel/client_session.h" 15#include "core/hle/kernel/client_session.h"
16#include "core/hle/kernel/event.h" 16#include "core/hle/kernel/readable_event.h"
17#include "core/hle/kernel/shared_memory.h" 17#include "core/hle/kernel/shared_memory.h"
18#include "core/hle/kernel/writable_event.h"
18#include "core/hle/service/hid/hid.h" 19#include "core/hle/service/hid/hid.h"
19#include "core/hle/service/hid/irs.h" 20#include "core/hle/service/hid/irs.h"
20#include "core/hle/service/hid/xcd.h" 21#include "core/hle/service/hid/xcd.h"
@@ -34,8 +35,8 @@
34namespace Service::HID { 35namespace Service::HID {
35 36
36// Updating period for each HID device. 37// Updating period for each HID device.
37// TODO(shinyquagsire23): These need better values. 38// TODO(ogniK): Find actual polling rate of hid
38constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; 39constexpr u64 pad_update_ticks = CoreTiming::BASE_CLOCK_RATE / 66;
39constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; 40constexpr u64 accelerometer_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
40constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100; 41constexpr u64 gyroscope_update_ticks = CoreTiming::BASE_CLOCK_RATE / 100;
41constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; 42constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
@@ -124,10 +125,11 @@ public:
124 125
125private: 126private:
126 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { 127 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
128 LOG_DEBUG(Service_HID, "called");
129
127 IPC::ResponseBuilder rb{ctx, 2, 1}; 130 IPC::ResponseBuilder rb{ctx, 2, 1};
128 rb.Push(RESULT_SUCCESS); 131 rb.Push(RESULT_SUCCESS);
129 rb.PushCopyObjects(shared_mem); 132 rb.PushCopyObjects(shared_mem);
130 LOG_DEBUG(Service_HID, "called");
131 } 133 }
132 134
133 void UpdateControllers(u64 userdata, int cycles_late) { 135 void UpdateControllers(u64 userdata, int cycles_late) {
@@ -163,9 +165,10 @@ public:
163 165
164private: 166private:
165 void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) { 167 void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) {
168 LOG_WARNING(Service_HID, "(STUBBED) called");
169
166 IPC::ResponseBuilder rb{ctx, 2}; 170 IPC::ResponseBuilder rb{ctx, 2};
167 rb.Push(RESULT_SUCCESS); 171 rb.Push(RESULT_SUCCESS);
168 LOG_WARNING(Service_HID, "(STUBBED) called");
169 } 172 }
170}; 173};
171 174
@@ -286,10 +289,10 @@ public:
286 {519, nullptr, "GetPalmaOperationResult"}, 289 {519, nullptr, "GetPalmaOperationResult"},
287 {520, nullptr, "ReadPalmaPlayLog"}, 290 {520, nullptr, "ReadPalmaPlayLog"},
288 {521, nullptr, "ResetPalmaPlayLog"}, 291 {521, nullptr, "ResetPalmaPlayLog"},
289 {522, nullptr, "SetIsPalmaAllConnectable"}, 292 {522, &Hid::SetIsPalmaAllConnectable, "SetIsPalmaAllConnectable"},
290 {523, nullptr, "SetIsPalmaPairedConnectable"}, 293 {523, nullptr, "SetIsPalmaPairedConnectable"},
291 {524, nullptr, "PairPalma"}, 294 {524, nullptr, "PairPalma"},
292 {525, nullptr, "SetPalmaBoostMode"}, 295 {525, &Hid::SetPalmaBoostMode, "SetPalmaBoostMode"},
293 {1000, nullptr, "SetNpadCommunicationMode"}, 296 {1000, nullptr, "SetNpadCommunicationMode"},
294 {1001, nullptr, "GetNpadCommunicationMode"}, 297 {1001, nullptr, "GetNpadCommunicationMode"},
295 }; 298 };
@@ -303,6 +306,8 @@ private:
303 std::shared_ptr<IAppletResource> applet_resource; 306 std::shared_ptr<IAppletResource> applet_resource;
304 307
305 void CreateAppletResource(Kernel::HLERequestContext& ctx) { 308 void CreateAppletResource(Kernel::HLERequestContext& ctx) {
309 LOG_DEBUG(Service_HID, "called");
310
306 if (applet_resource == nullptr) { 311 if (applet_resource == nullptr) {
307 applet_resource = std::make_shared<IAppletResource>(); 312 applet_resource = std::make_shared<IAppletResource>();
308 } 313 }
@@ -310,206 +315,228 @@ private:
310 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 315 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
311 rb.Push(RESULT_SUCCESS); 316 rb.Push(RESULT_SUCCESS);
312 rb.PushIpcInterface<IAppletResource>(applet_resource); 317 rb.PushIpcInterface<IAppletResource>(applet_resource);
313 LOG_DEBUG(Service_HID, "called");
314 } 318 }
315 319
316 void ActivateXpad(Kernel::HLERequestContext& ctx) { 320 void ActivateXpad(Kernel::HLERequestContext& ctx) {
321 LOG_DEBUG(Service_HID, "called");
322
317 applet_resource->ActivateController(HidController::XPad); 323 applet_resource->ActivateController(HidController::XPad);
318 IPC::ResponseBuilder rb{ctx, 2}; 324 IPC::ResponseBuilder rb{ctx, 2};
319 rb.Push(RESULT_SUCCESS); 325 rb.Push(RESULT_SUCCESS);
320 LOG_DEBUG(Service_HID, "called");
321 } 326 }
322 327
323 void ActivateDebugPad(Kernel::HLERequestContext& ctx) { 328 void ActivateDebugPad(Kernel::HLERequestContext& ctx) {
329 LOG_DEBUG(Service_HID, "called");
330
324 applet_resource->ActivateController(HidController::DebugPad); 331 applet_resource->ActivateController(HidController::DebugPad);
325 IPC::ResponseBuilder rb{ctx, 2}; 332 IPC::ResponseBuilder rb{ctx, 2};
326 rb.Push(RESULT_SUCCESS); 333 rb.Push(RESULT_SUCCESS);
327 LOG_DEBUG(Service_HID, "called");
328 } 334 }
329 335
330 void ActivateTouchScreen(Kernel::HLERequestContext& ctx) { 336 void ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
337 LOG_DEBUG(Service_HID, "called");
338
331 applet_resource->ActivateController(HidController::Touchscreen); 339 applet_resource->ActivateController(HidController::Touchscreen);
332 IPC::ResponseBuilder rb{ctx, 2}; 340 IPC::ResponseBuilder rb{ctx, 2};
333 rb.Push(RESULT_SUCCESS); 341 rb.Push(RESULT_SUCCESS);
334 LOG_DEBUG(Service_HID, "called");
335 } 342 }
336 343
337 void ActivateMouse(Kernel::HLERequestContext& ctx) { 344 void ActivateMouse(Kernel::HLERequestContext& ctx) {
345 LOG_DEBUG(Service_HID, "called");
346
338 applet_resource->ActivateController(HidController::Mouse); 347 applet_resource->ActivateController(HidController::Mouse);
339 IPC::ResponseBuilder rb{ctx, 2}; 348 IPC::ResponseBuilder rb{ctx, 2};
340 rb.Push(RESULT_SUCCESS); 349 rb.Push(RESULT_SUCCESS);
341 LOG_DEBUG(Service_HID, "called");
342 } 350 }
343 351
344 void ActivateKeyboard(Kernel::HLERequestContext& ctx) { 352 void ActivateKeyboard(Kernel::HLERequestContext& ctx) {
353 LOG_DEBUG(Service_HID, "called");
354
345 applet_resource->ActivateController(HidController::Keyboard); 355 applet_resource->ActivateController(HidController::Keyboard);
346 IPC::ResponseBuilder rb{ctx, 2}; 356 IPC::ResponseBuilder rb{ctx, 2};
347 rb.Push(RESULT_SUCCESS); 357 rb.Push(RESULT_SUCCESS);
348 LOG_DEBUG(Service_HID, "called");
349 } 358 }
350 359
351 void ActivateGesture(Kernel::HLERequestContext& ctx) { 360 void ActivateGesture(Kernel::HLERequestContext& ctx) {
361 LOG_DEBUG(Service_HID, "called");
362
352 applet_resource->ActivateController(HidController::Gesture); 363 applet_resource->ActivateController(HidController::Gesture);
353 IPC::ResponseBuilder rb{ctx, 2}; 364 IPC::ResponseBuilder rb{ctx, 2};
354 rb.Push(RESULT_SUCCESS); 365 rb.Push(RESULT_SUCCESS);
355 LOG_DEBUG(Service_HID, "called");
356 } 366 }
357 367
358 void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { 368 void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
359 // Should have no effect with how our npad sets up the data 369 // Should have no effect with how our npad sets up the data
370 LOG_DEBUG(Service_HID, "called");
371
360 applet_resource->ActivateController(HidController::NPad); 372 applet_resource->ActivateController(HidController::NPad);
361 IPC::ResponseBuilder rb{ctx, 2}; 373 IPC::ResponseBuilder rb{ctx, 2};
362 rb.Push(RESULT_SUCCESS); 374 rb.Push(RESULT_SUCCESS);
363 LOG_DEBUG(Service_HID, "called");
364 } 375 }
365 376
366 void StartSixAxisSensor(Kernel::HLERequestContext& ctx) { 377 void StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
367 IPC::RequestParser rp{ctx}; 378 IPC::RequestParser rp{ctx};
368 auto handle = rp.PopRaw<u32>(); 379 auto handle = rp.PopRaw<u32>();
380 LOG_WARNING(Service_HID, "(STUBBED) called with handle={}", handle);
381
369 IPC::ResponseBuilder rb{ctx, 2}; 382 IPC::ResponseBuilder rb{ctx, 2};
370 rb.Push(RESULT_SUCCESS); 383 rb.Push(RESULT_SUCCESS);
371 LOG_WARNING(Service_HID, "(STUBBED) called");
372 } 384 }
373 385
374 void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { 386 void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
387 LOG_WARNING(Service_HID, "(STUBBED) called");
388
375 IPC::ResponseBuilder rb{ctx, 2}; 389 IPC::ResponseBuilder rb{ctx, 2};
376 rb.Push(RESULT_SUCCESS); 390 rb.Push(RESULT_SUCCESS);
377 LOG_WARNING(Service_HID, "(STUBBED) called");
378 } 391 }
379 392
380 void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { 393 void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
394 LOG_WARNING(Service_HID, "(STUBBED) called");
395
381 IPC::ResponseBuilder rb{ctx, 3}; 396 IPC::ResponseBuilder rb{ctx, 3};
382 rb.Push(RESULT_SUCCESS); 397 rb.Push(RESULT_SUCCESS);
383 // TODO (Hexagon12): Properly implement reading gyroscope values from controllers. 398 // TODO (Hexagon12): Properly implement reading gyroscope values from controllers.
384 rb.Push(true); 399 rb.Push(true);
385 LOG_WARNING(Service_HID, "(STUBBED) called");
386 } 400 }
387 401
388 void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { 402 void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
389 IPC::RequestParser rp{ctx}; 403 IPC::RequestParser rp{ctx};
390 auto supported_styleset = rp.PopRaw<u32>(); 404 auto supported_styleset = rp.PopRaw<u32>();
405 LOG_DEBUG(Service_HID, "called with supported_styleset={}", supported_styleset);
406
391 applet_resource->GetController<Controller_NPad>(HidController::NPad) 407 applet_resource->GetController<Controller_NPad>(HidController::NPad)
392 .SetSupportedStyleSet({supported_styleset}); 408 .SetSupportedStyleSet({supported_styleset});
393 409
394 IPC::ResponseBuilder rb{ctx, 2}; 410 IPC::ResponseBuilder rb{ctx, 2};
395 rb.Push(RESULT_SUCCESS); 411 rb.Push(RESULT_SUCCESS);
396
397 LOG_DEBUG(Service_HID, "called");
398 } 412 }
399 413
400 void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { 414 void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
415 LOG_DEBUG(Service_HID, "called");
416
401 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); 417 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
402 418
403 IPC::ResponseBuilder rb{ctx, 3}; 419 IPC::ResponseBuilder rb{ctx, 3};
404 rb.Push(RESULT_SUCCESS); 420 rb.Push(RESULT_SUCCESS);
405 rb.Push<u32>(controller.GetSupportedStyleSet().raw); 421 rb.Push<u32>(controller.GetSupportedStyleSet().raw);
406 LOG_DEBUG(Service_HID, "called");
407 } 422 }
408 423
409 void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { 424 void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
425 LOG_DEBUG(Service_HID, "called");
426
410 applet_resource->GetController<Controller_NPad>(HidController::NPad) 427 applet_resource->GetController<Controller_NPad>(HidController::NPad)
411 .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize()); 428 .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
412 IPC::ResponseBuilder rb{ctx, 2}; 429 IPC::ResponseBuilder rb{ctx, 2};
413 rb.Push(RESULT_SUCCESS); 430 rb.Push(RESULT_SUCCESS);
414 LOG_DEBUG(Service_HID, "called");
415 } 431 }
416 432
417 void ActivateNpad(Kernel::HLERequestContext& ctx) { 433 void ActivateNpad(Kernel::HLERequestContext& ctx) {
434 LOG_DEBUG(Service_HID, "called");
435
418 IPC::ResponseBuilder rb{ctx, 2}; 436 IPC::ResponseBuilder rb{ctx, 2};
419 rb.Push(RESULT_SUCCESS); 437 rb.Push(RESULT_SUCCESS);
420 applet_resource->ActivateController(HidController::NPad); 438 applet_resource->ActivateController(HidController::NPad);
421 LOG_DEBUG(Service_HID, "called");
422 } 439 }
423 440
424 void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { 441 void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
425 IPC::RequestParser rp{ctx}; 442 IPC::RequestParser rp{ctx};
426 auto npad_id = rp.PopRaw<u32>(); 443 auto npad_id = rp.PopRaw<u32>();
444 LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id);
445
427 IPC::ResponseBuilder rb{ctx, 2, 1}; 446 IPC::ResponseBuilder rb{ctx, 2, 1};
428 rb.Push(RESULT_SUCCESS); 447 rb.Push(RESULT_SUCCESS);
429 rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) 448 rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad)
430 .GetStyleSetChangedEvent()); 449 .GetStyleSetChangedEvent());
431 LOG_DEBUG(Service_HID, "called");
432 } 450 }
433 451
434 void DisconnectNpad(Kernel::HLERequestContext& ctx) { 452 void DisconnectNpad(Kernel::HLERequestContext& ctx) {
435 IPC::RequestParser rp{ctx}; 453 IPC::RequestParser rp{ctx};
436 auto npad_id = rp.PopRaw<u32>(); 454 auto npad_id = rp.PopRaw<u32>();
455 LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id);
456
437 applet_resource->GetController<Controller_NPad>(HidController::NPad) 457 applet_resource->GetController<Controller_NPad>(HidController::NPad)
438 .DisconnectNPad(npad_id); 458 .DisconnectNPad(npad_id);
439 IPC::ResponseBuilder rb{ctx, 2}; 459 IPC::ResponseBuilder rb{ctx, 2};
440 rb.Push(RESULT_SUCCESS); 460 rb.Push(RESULT_SUCCESS);
441 LOG_DEBUG(Service_HID, "called");
442 } 461 }
443 462
444 void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { 463 void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
445 IPC::RequestParser rp{ctx}; 464 IPC::RequestParser rp{ctx};
446 auto npad_id = rp.PopRaw<u32>(); 465 auto npad_id = rp.PopRaw<u32>();
466 LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id);
467
447 IPC::ResponseBuilder rb{ctx, 4}; 468 IPC::ResponseBuilder rb{ctx, 4};
448 rb.Push(RESULT_SUCCESS); 469 rb.Push(RESULT_SUCCESS);
449 rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) 470 rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad)
450 .GetLedPattern(npad_id) 471 .GetLedPattern(npad_id)
451 .raw); 472 .raw);
452 LOG_DEBUG(Service_HID, "called");
453 } 473 }
454 474
455 void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { 475 void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
456 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
457 IPC::RequestParser rp{ctx}; 476 IPC::RequestParser rp{ctx};
458 const auto hold_type = rp.PopRaw<u64>(); 477 const auto hold_type = rp.PopRaw<u64>();
478 LOG_DEBUG(Service_HID, "called with hold_type={}", hold_type);
479
480 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
459 controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type}); 481 controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type});
460 482
461 IPC::ResponseBuilder rb{ctx, 2}; 483 IPC::ResponseBuilder rb{ctx, 2};
462 rb.Push(RESULT_SUCCESS); 484 rb.Push(RESULT_SUCCESS);
463 LOG_DEBUG(Service_HID, "called");
464 } 485 }
465 486
466 void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { 487 void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
488 LOG_DEBUG(Service_HID, "called");
489
467 const auto& controller = 490 const auto& controller =
468 applet_resource->GetController<Controller_NPad>(HidController::NPad); 491 applet_resource->GetController<Controller_NPad>(HidController::NPad);
469 IPC::ResponseBuilder rb{ctx, 4}; 492 IPC::ResponseBuilder rb{ctx, 4};
470 rb.Push(RESULT_SUCCESS); 493 rb.Push(RESULT_SUCCESS);
471 rb.Push<u64>(static_cast<u64>(controller.GetHoldType())); 494 rb.Push<u64>(static_cast<u64>(controller.GetHoldType()));
472 LOG_DEBUG(Service_HID, "called");
473 } 495 }
474 496
475 void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { 497 void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
476 IPC::RequestParser rp{ctx}; 498 IPC::RequestParser rp{ctx};
477 auto npad_id = rp.PopRaw<u32>(); 499 auto npad_id = rp.PopRaw<u32>();
500 LOG_WARNING(Service_HID, "(STUBBED) called with npad_id={}", npad_id);
501
478 IPC::ResponseBuilder rb{ctx, 2}; 502 IPC::ResponseBuilder rb{ctx, 2};
479 rb.Push(RESULT_SUCCESS); 503 rb.Push(RESULT_SUCCESS);
480 LOG_WARNING(Service_HID, "(STUBBED) called");
481 } 504 }
482 505
483 void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { 506 void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
507 LOG_DEBUG(Service_HID, "called");
508
484 applet_resource->GetController<Controller_NPad>(HidController::NPad) 509 applet_resource->GetController<Controller_NPad>(HidController::NPad)
485 .SetVibrationEnabled(true); 510 .SetVibrationEnabled(true);
486 IPC::ResponseBuilder rb{ctx, 2}; 511 IPC::ResponseBuilder rb{ctx, 2};
487 rb.Push(RESULT_SUCCESS); 512 rb.Push(RESULT_SUCCESS);
488 LOG_DEBUG(Service_HID, "called");
489 } 513 }
490 514
491 void EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { 515 void EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
516 LOG_DEBUG(Service_HID, "called");
517
492 applet_resource->GetController<Controller_NPad>(HidController::NPad) 518 applet_resource->GetController<Controller_NPad>(HidController::NPad)
493 .SetVibrationEnabled(false); 519 .SetVibrationEnabled(false);
494 IPC::ResponseBuilder rb{ctx, 2}; 520 IPC::ResponseBuilder rb{ctx, 2};
495 rb.Push(RESULT_SUCCESS); 521 rb.Push(RESULT_SUCCESS);
496 LOG_DEBUG(Service_HID, "called");
497 } 522 }
498 523
499 void SendVibrationValue(Kernel::HLERequestContext& ctx) { 524 void SendVibrationValue(Kernel::HLERequestContext& ctx) {
500 IPC::RequestParser rp{ctx}; 525 IPC::RequestParser rp{ctx};
501 const auto controller_id = rp.PopRaw<u32>(); 526 const auto controller_id = rp.PopRaw<u32>();
502 const auto vibration_values = rp.PopRaw<Controller_NPad::Vibration>(); 527 const auto vibration_values = rp.PopRaw<Controller_NPad::Vibration>();
528 LOG_DEBUG(Service_HID, "called with controller_id={}", controller_id);
503 529
504 IPC::ResponseBuilder rb{ctx, 2}; 530 IPC::ResponseBuilder rb{ctx, 2};
505 rb.Push(RESULT_SUCCESS); 531 rb.Push(RESULT_SUCCESS);
506 532
507 applet_resource->GetController<Controller_NPad>(HidController::NPad) 533 applet_resource->GetController<Controller_NPad>(HidController::NPad)
508 .VibrateController({controller_id}, {vibration_values}); 534 .VibrateController({controller_id}, {vibration_values});
509 LOG_DEBUG(Service_HID, "called");
510 } 535 }
511 536
512 void SendVibrationValues(Kernel::HLERequestContext& ctx) { 537 void SendVibrationValues(Kernel::HLERequestContext& ctx) {
538 LOG_DEBUG(Service_HID, "called");
539
513 const auto controllers = ctx.ReadBuffer(0); 540 const auto controllers = ctx.ReadBuffer(0);
514 const auto vibrations = ctx.ReadBuffer(1); 541 const auto vibrations = ctx.ReadBuffer(1);
515 542
@@ -527,74 +554,96 @@ private:
527 554
528 IPC::ResponseBuilder rb{ctx, 2}; 555 IPC::ResponseBuilder rb{ctx, 2};
529 rb.Push(RESULT_SUCCESS); 556 rb.Push(RESULT_SUCCESS);
530 LOG_DEBUG(Service_HID, "called");
531 } 557 }
532 558
533 void GetActualVibrationValue(Kernel::HLERequestContext& ctx) { 559 void GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
560 LOG_DEBUG(Service_HID, "called");
561
534 IPC::ResponseBuilder rb{ctx, 6}; 562 IPC::ResponseBuilder rb{ctx, 6};
535 rb.Push(RESULT_SUCCESS); 563 rb.Push(RESULT_SUCCESS);
536 rb.PushRaw<Controller_NPad::Vibration>( 564 rb.PushRaw<Controller_NPad::Vibration>(
537 applet_resource->GetController<Controller_NPad>(HidController::NPad) 565 applet_resource->GetController<Controller_NPad>(HidController::NPad)
538 .GetLastVibration()); 566 .GetLastVibration());
539 LOG_DEBUG(Service_HID, "called");
540 } 567 }
541 568
542 void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { 569 void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
543 IPC::RequestParser rp{ctx}; 570 IPC::RequestParser rp{ctx};
544 const auto npad_id = rp.PopRaw<u32>(); 571 const auto npad_id = rp.PopRaw<u32>();
572 LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id);
573
545 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); 574 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
546 controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); 575 controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual);
547 576
548 IPC::ResponseBuilder rb{ctx, 2}; 577 IPC::ResponseBuilder rb{ctx, 2};
549 rb.Push(RESULT_SUCCESS); 578 rb.Push(RESULT_SUCCESS);
550 LOG_DEBUG(Service_HID, "called");
551 } 579 }
552 580
553 void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { 581 void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
582 LOG_WARNING(Service_HID, "(STUBBED) called");
583
554 IPC::ResponseBuilder rb{ctx, 2}; 584 IPC::ResponseBuilder rb{ctx, 2};
555 rb.Push(RESULT_SUCCESS); 585 rb.Push(RESULT_SUCCESS);
556 LOG_WARNING(Service_HID, "(STUBBED) called");
557 } 586 }
558 587
559 void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { 588 void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
560 IPC::RequestParser rp{ctx}; 589 IPC::RequestParser rp{ctx};
561 auto mode = rp.PopRaw<u32>(); 590 auto mode = rp.PopRaw<u32>();
591 LOG_WARNING(Service_HID, "(STUBBED) called with mode={}", mode);
592
562 IPC::ResponseBuilder rb{ctx, 2}; 593 IPC::ResponseBuilder rb{ctx, 2};
563 rb.Push(RESULT_SUCCESS); 594 rb.Push(RESULT_SUCCESS);
564 LOG_WARNING(Service_HID, "(STUBBED) called");
565 } 595 }
566 596
567 void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { 597 void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
598 LOG_DEBUG(Service_HID, "called");
599
568 IPC::ResponseBuilder rb{ctx, 4}; 600 IPC::ResponseBuilder rb{ctx, 4};
569 rb.Push(RESULT_SUCCESS); 601 rb.Push(RESULT_SUCCESS);
570 rb.Push<u32>(1); 602 rb.Push<u32>(1);
571 rb.Push<u32>(0); 603 rb.Push<u32>(0);
572 LOG_DEBUG(Service_HID, "called");
573 } 604 }
574 605
575 void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { 606 void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
607 LOG_DEBUG(Service_HID, "called");
608
576 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 609 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
577 rb.Push(RESULT_SUCCESS); 610 rb.Push(RESULT_SUCCESS);
578 rb.PushIpcInterface<IActiveVibrationDeviceList>(); 611 rb.PushIpcInterface<IActiveVibrationDeviceList>();
579 LOG_DEBUG(Service_HID, "called");
580 } 612 }
581 613
582 void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { 614 void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
615 LOG_WARNING(Service_HID, "(STUBBED) called");
616
583 IPC::ResponseBuilder rb{ctx, 2}; 617 IPC::ResponseBuilder rb{ctx, 2};
584 rb.Push(RESULT_SUCCESS); 618 rb.Push(RESULT_SUCCESS);
585 LOG_WARNING(Service_HID, "(STUBBED) called");
586 } 619 }
587 620
588 void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { 621 void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
622 LOG_WARNING(Service_HID, "(STUBBED) called");
623
589 IPC::ResponseBuilder rb{ctx, 2}; 624 IPC::ResponseBuilder rb{ctx, 2};
590 rb.Push(RESULT_SUCCESS); 625 rb.Push(RESULT_SUCCESS);
591 LOG_WARNING(Service_HID, "(STUBBED) called");
592 } 626 }
593 627
594 void StopSixAxisSensor(Kernel::HLERequestContext& ctx) { 628 void StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
629 LOG_WARNING(Service_HID, "(STUBBED) called");
630
595 IPC::ResponseBuilder rb{ctx, 2}; 631 IPC::ResponseBuilder rb{ctx, 2};
596 rb.Push(RESULT_SUCCESS); 632 rb.Push(RESULT_SUCCESS);
633 }
634
635 void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) {
597 LOG_WARNING(Service_HID, "(STUBBED) called"); 636 LOG_WARNING(Service_HID, "(STUBBED) called");
637
638 IPC::ResponseBuilder rb{ctx, 2};
639 rb.Push(RESULT_SUCCESS);
640 }
641
642 void SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
643 LOG_WARNING(Service_HID, "(STUBBED) called");
644
645 IPC::ResponseBuilder rb{ctx, 2};
646 rb.Push(RESULT_SUCCESS);
598 } 647 }
599}; 648};
600 649
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp
index 872e3c344..3c7f8b1ee 100644
--- a/src/core/hle/service/hid/irs.cpp
+++ b/src/core/hle/service/hid/irs.cpp
@@ -44,115 +44,133 @@ IRS::IRS() : ServiceFramework{"irs"} {
44} 44}
45 45
46void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) { 46void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) {
47 LOG_WARNING(Service_IRS, "(STUBBED) called");
48
47 IPC::ResponseBuilder rb{ctx, 2}; 49 IPC::ResponseBuilder rb{ctx, 2};
48 rb.Push(RESULT_SUCCESS); 50 rb.Push(RESULT_SUCCESS);
49 LOG_WARNING(Service_IRS, "(STUBBED) called");
50} 51}
51 52
52void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) { 53void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) {
54 LOG_WARNING(Service_IRS, "(STUBBED) called");
55
53 IPC::ResponseBuilder rb{ctx, 2}; 56 IPC::ResponseBuilder rb{ctx, 2};
54 rb.Push(RESULT_SUCCESS); 57 rb.Push(RESULT_SUCCESS);
55 LOG_WARNING(Service_IRS, "(STUBBED) called");
56} 58}
57 59
58void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) { 60void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
61 LOG_DEBUG(Service_IRS, "called");
62
59 IPC::ResponseBuilder rb{ctx, 2, 1}; 63 IPC::ResponseBuilder rb{ctx, 2, 1};
60 rb.Push(RESULT_SUCCESS); 64 rb.Push(RESULT_SUCCESS);
61 rb.PushCopyObjects(shared_mem); 65 rb.PushCopyObjects(shared_mem);
62 LOG_DEBUG(Service_IRS, "called");
63} 66}
64 67
65void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { 68void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) {
69 LOG_WARNING(Service_IRS, "(STUBBED) called");
70
66 IPC::ResponseBuilder rb{ctx, 2}; 71 IPC::ResponseBuilder rb{ctx, 2};
67 rb.Push(RESULT_SUCCESS); 72 rb.Push(RESULT_SUCCESS);
68 LOG_WARNING(Service_IRS, "(STUBBED) called");
69} 73}
70 74
71void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) { 75void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) {
76 LOG_WARNING(Service_IRS, "(STUBBED) called");
77
72 IPC::ResponseBuilder rb{ctx, 2}; 78 IPC::ResponseBuilder rb{ctx, 2};
73 rb.Push(RESULT_SUCCESS); 79 rb.Push(RESULT_SUCCESS);
74 LOG_WARNING(Service_IRS, "(STUBBED) called");
75} 80}
76 81
77void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { 82void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) {
83 LOG_WARNING(Service_IRS, "(STUBBED) called");
84
78 IPC::ResponseBuilder rb{ctx, 2}; 85 IPC::ResponseBuilder rb{ctx, 2};
79 rb.Push(RESULT_SUCCESS); 86 rb.Push(RESULT_SUCCESS);
80 LOG_WARNING(Service_IRS, "(STUBBED) called");
81} 87}
82 88
83void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { 89void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) {
90 LOG_WARNING(Service_IRS, "(STUBBED) called");
91
84 IPC::ResponseBuilder rb{ctx, 2}; 92 IPC::ResponseBuilder rb{ctx, 2};
85 rb.Push(RESULT_SUCCESS); 93 rb.Push(RESULT_SUCCESS);
86 LOG_WARNING(Service_IRS, "(STUBBED) called");
87} 94}
88 95
89void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { 96void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
97 LOG_WARNING(Service_IRS, "(STUBBED) called");
98
90 IPC::ResponseBuilder rb{ctx, 5}; 99 IPC::ResponseBuilder rb{ctx, 5};
91 rb.Push(RESULT_SUCCESS); 100 rb.Push(RESULT_SUCCESS);
92 rb.PushRaw<u64>(CoreTiming::GetTicks()); 101 rb.PushRaw<u64>(CoreTiming::GetTicks());
93 rb.PushRaw<u32>(0); 102 rb.PushRaw<u32>(0);
94 LOG_WARNING(Service_IRS, "(STUBBED) called");
95} 103}
96 104
97void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) { 105void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) {
106 LOG_WARNING(Service_IRS, "(STUBBED) called");
107
98 IPC::ResponseBuilder rb{ctx, 2}; 108 IPC::ResponseBuilder rb{ctx, 2};
99 rb.Push(RESULT_SUCCESS); 109 rb.Push(RESULT_SUCCESS);
100 LOG_WARNING(Service_IRS, "(STUBBED) called");
101} 110}
102 111
103void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) { 112void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) {
113 LOG_WARNING(Service_IRS, "(STUBBED) called");
114
104 IPC::ResponseBuilder rb{ctx, 3}; 115 IPC::ResponseBuilder rb{ctx, 3};
105 rb.Push(RESULT_SUCCESS); 116 rb.Push(RESULT_SUCCESS);
106 rb.PushRaw<u32>(device_handle); 117 rb.PushRaw<u32>(device_handle);
107 LOG_WARNING(Service_IRS, "(STUBBED) called");
108} 118}
109 119
110void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) { 120void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) {
121 LOG_WARNING(Service_IRS, "(STUBBED) called");
122
111 IPC::ResponseBuilder rb{ctx, 2}; 123 IPC::ResponseBuilder rb{ctx, 2};
112 rb.Push(RESULT_SUCCESS); 124 rb.Push(RESULT_SUCCESS);
113 LOG_WARNING(Service_IRS, "(STUBBED) called");
114} 125}
115 126
116void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) { 127void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) {
128 LOG_WARNING(Service_IRS, "(STUBBED) called");
129
117 IPC::ResponseBuilder rb{ctx, 2}; 130 IPC::ResponseBuilder rb{ctx, 2};
118 rb.Push(RESULT_SUCCESS); 131 rb.Push(RESULT_SUCCESS);
119 LOG_WARNING(Service_IRS, "(STUBBED) called");
120} 132}
121 133
122void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) { 134void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) {
135 LOG_WARNING(Service_IRS, "(STUBBED) called");
136
123 IPC::ResponseBuilder rb{ctx, 2}; 137 IPC::ResponseBuilder rb{ctx, 2};
124 rb.Push(RESULT_SUCCESS); 138 rb.Push(RESULT_SUCCESS);
125 LOG_WARNING(Service_IRS, "(STUBBED) called");
126} 139}
127 140
128void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) { 141void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) {
142 LOG_WARNING(Service_IRS, "(STUBBED) called");
143
129 IPC::ResponseBuilder rb{ctx, 2}; 144 IPC::ResponseBuilder rb{ctx, 2};
130 rb.Push(RESULT_SUCCESS); 145 rb.Push(RESULT_SUCCESS);
131 LOG_WARNING(Service_IRS, "(STUBBED) called");
132} 146}
133 147
134void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) { 148void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) {
149 LOG_WARNING(Service_IRS, "(STUBBED) called");
150
135 IPC::ResponseBuilder rb{ctx, 2}; 151 IPC::ResponseBuilder rb{ctx, 2};
136 rb.Push(RESULT_SUCCESS); 152 rb.Push(RESULT_SUCCESS);
137 LOG_WARNING(Service_IRS, "(STUBBED) called");
138} 153}
139 154
140void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) { 155void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) {
156 LOG_WARNING(Service_IRS, "(STUBBED) called");
157
141 IPC::ResponseBuilder rb{ctx, 2}; 158 IPC::ResponseBuilder rb{ctx, 2};
142 rb.Push(RESULT_SUCCESS); 159 rb.Push(RESULT_SUCCESS);
143 LOG_WARNING(Service_IRS, "(STUBBED) called");
144} 160}
145 161
146void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) { 162void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) {
163 LOG_WARNING(Service_IRS, "(STUBBED) called");
164
147 IPC::ResponseBuilder rb{ctx, 2}; 165 IPC::ResponseBuilder rb{ctx, 2};
148 rb.Push(RESULT_SUCCESS); 166 rb.Push(RESULT_SUCCESS);
149 LOG_WARNING(Service_IRS, "(STUBBED) called");
150} 167}
151 168
152void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) { 169void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) {
170 LOG_WARNING(Service_IRS, "(STUBBED) called");
171
153 IPC::ResponseBuilder rb{ctx, 2}; 172 IPC::ResponseBuilder rb{ctx, 2};
154 rb.Push(RESULT_SUCCESS); 173 rb.Push(RESULT_SUCCESS);
155 LOG_WARNING(Service_IRS, "(STUBBED) called");
156} 174}
157 175
158IRS::~IRS() = default; 176IRS::~IRS() = default;
diff --git a/src/core/hle/service/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp
index 164c57e18..e8f9f2d29 100644
--- a/src/core/hle/service/lbl/lbl.cpp
+++ b/src/core/hle/service/lbl/lbl.cpp
@@ -55,29 +55,29 @@ public:
55 55
56private: 56private:
57 void EnableVrMode(Kernel::HLERequestContext& ctx) { 57 void EnableVrMode(Kernel::HLERequestContext& ctx) {
58 LOG_DEBUG(Service_LBL, "called");
59
58 IPC::ResponseBuilder rb{ctx, 2}; 60 IPC::ResponseBuilder rb{ctx, 2};
59 rb.Push(RESULT_SUCCESS); 61 rb.Push(RESULT_SUCCESS);
60 62
61 vr_mode_enabled = true; 63 vr_mode_enabled = true;
62
63 LOG_DEBUG(Service_LBL, "called");
64 } 64 }
65 65
66 void DisableVrMode(Kernel::HLERequestContext& ctx) { 66 void DisableVrMode(Kernel::HLERequestContext& ctx) {
67 LOG_DEBUG(Service_LBL, "called");
68
67 IPC::ResponseBuilder rb{ctx, 2}; 69 IPC::ResponseBuilder rb{ctx, 2};
68 rb.Push(RESULT_SUCCESS); 70 rb.Push(RESULT_SUCCESS);
69 71
70 vr_mode_enabled = false; 72 vr_mode_enabled = false;
71
72 LOG_DEBUG(Service_LBL, "called");
73 } 73 }
74 74
75 void IsVrModeEnabled(Kernel::HLERequestContext& ctx) { 75 void IsVrModeEnabled(Kernel::HLERequestContext& ctx) {
76 LOG_DEBUG(Service_LBL, "called");
77
76 IPC::ResponseBuilder rb{ctx, 3}; 78 IPC::ResponseBuilder rb{ctx, 3};
77 rb.Push(RESULT_SUCCESS); 79 rb.Push(RESULT_SUCCESS);
78 rb.Push(vr_mode_enabled); 80 rb.Push(vr_mode_enabled);
79
80 LOG_DEBUG(Service_LBL, "called");
81 } 81 }
82 82
83 bool vr_mode_enabled = false; 83 bool vr_mode_enabled = false;
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp
index 167f2c66a..e250595e3 100644
--- a/src/core/hle/service/ldn/ldn.cpp
+++ b/src/core/hle/service/ldn/ldn.cpp
@@ -44,11 +44,11 @@ public:
44 } 44 }
45 45
46 void CreateMonitorService(Kernel::HLERequestContext& ctx) { 46 void CreateMonitorService(Kernel::HLERequestContext& ctx) {
47 LOG_DEBUG(Service_LDN, "called");
48
47 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 49 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
48 rb.Push(RESULT_SUCCESS); 50 rb.Push(RESULT_SUCCESS);
49 rb.PushIpcInterface<IMonitorService>(); 51 rb.PushIpcInterface<IMonitorService>();
50
51 LOG_DEBUG(Service_LDN, "called");
52 } 52 }
53}; 53};
54 54
@@ -104,11 +104,11 @@ public:
104 } 104 }
105 105
106 void CreateSystemLocalCommunicationService(Kernel::HLERequestContext& ctx) { 106 void CreateSystemLocalCommunicationService(Kernel::HLERequestContext& ctx) {
107 LOG_DEBUG(Service_LDN, "called");
108
107 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 109 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
108 rb.Push(RESULT_SUCCESS); 110 rb.Push(RESULT_SUCCESS);
109 rb.PushIpcInterface<ILocalCommunicationService>("ISystemLocalCommunicationService"); 111 rb.PushIpcInterface<ILocalCommunicationService>("ISystemLocalCommunicationService");
110
111 LOG_DEBUG(Service_LDN, "called");
112 } 112 }
113}; 113};
114 114
@@ -125,11 +125,11 @@ public:
125 } 125 }
126 126
127 void CreateUserLocalCommunicationService(Kernel::HLERequestContext& ctx) { 127 void CreateUserLocalCommunicationService(Kernel::HLERequestContext& ctx) {
128 LOG_DEBUG(Service_LDN, "called");
129
128 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 130 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
129 rb.Push(RESULT_SUCCESS); 131 rb.Push(RESULT_SUCCESS);
130 rb.PushIpcInterface<ILocalCommunicationService>("IUserLocalCommunicationService"); 132 rb.PushIpcInterface<ILocalCommunicationService>("IUserLocalCommunicationService");
131
132 LOG_DEBUG(Service_LDN, "called");
133 } 133 }
134}; 134};
135 135
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index d607d985e..ca119dd3a 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -4,7 +4,10 @@
4 4
5#include <memory> 5#include <memory>
6#include <fmt/format.h> 6#include <fmt/format.h>
7#include <mbedtls/sha256.h>
7 8
9#include "common/alignment.h"
10#include "common/hex_util.h"
8#include "core/hle/ipc_helpers.h" 11#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/process.h" 12#include "core/hle/kernel/process.h"
10#include "core/hle/service/ldr/ldr.h" 13#include "core/hle/service/ldr/ldr.h"
@@ -13,6 +16,21 @@
13 16
14namespace Service::LDR { 17namespace Service::LDR {
15 18
19constexpr ResultCode ERROR_INVALID_MEMORY_STATE{ErrorModule::Loader, 51};
20constexpr ResultCode ERROR_INVALID_NRO{ErrorModule::Loader, 52};
21constexpr ResultCode ERROR_INVALID_NRR{ErrorModule::Loader, 53};
22constexpr ResultCode ERROR_MISSING_NRR_HASH{ErrorModule::Loader, 54};
23constexpr ResultCode ERROR_MAXIMUM_NRO{ErrorModule::Loader, 55};
24constexpr ResultCode ERROR_MAXIMUM_NRR{ErrorModule::Loader, 56};
25constexpr ResultCode ERROR_ALREADY_LOADED{ErrorModule::Loader, 57};
26constexpr ResultCode ERROR_INVALID_ALIGNMENT{ErrorModule::Loader, 81};
27constexpr ResultCode ERROR_INVALID_SIZE{ErrorModule::Loader, 82};
28constexpr ResultCode ERROR_INVALID_NRO_ADDRESS{ErrorModule::Loader, 84};
29constexpr ResultCode ERROR_INVALID_NRR_ADDRESS{ErrorModule::Loader, 85};
30constexpr ResultCode ERROR_NOT_INITIALIZED{ErrorModule::Loader, 87};
31
32constexpr u64 MAXIMUM_LOADED_RO = 0x40;
33
16class DebugMonitor final : public ServiceFramework<DebugMonitor> { 34class DebugMonitor final : public ServiceFramework<DebugMonitor> {
17public: 35public:
18 explicit DebugMonitor() : ServiceFramework{"ldr:dmnt"} { 36 explicit DebugMonitor() : ServiceFramework{"ldr:dmnt"} {
@@ -64,9 +82,9 @@ public:
64 // clang-format off 82 // clang-format off
65 static const FunctionInfo functions[] = { 83 static const FunctionInfo functions[] = {
66 {0, &RelocatableObject::LoadNro, "LoadNro"}, 84 {0, &RelocatableObject::LoadNro, "LoadNro"},
67 {1, nullptr, "UnloadNro"}, 85 {1, &RelocatableObject::UnloadNro, "UnloadNro"},
68 {2, &RelocatableObject::LoadNrr, "LoadNrr"}, 86 {2, &RelocatableObject::LoadNrr, "LoadNrr"},
69 {3, nullptr, "UnloadNrr"}, 87 {3, &RelocatableObject::UnloadNrr, "UnloadNrr"},
70 {4, &RelocatableObject::Initialize, "Initialize"}, 88 {4, &RelocatableObject::Initialize, "Initialize"},
71 }; 89 };
72 // clang-format on 90 // clang-format on
@@ -75,9 +93,126 @@ public:
75 } 93 }
76 94
77 void LoadNrr(Kernel::HLERequestContext& ctx) { 95 void LoadNrr(Kernel::HLERequestContext& ctx) {
96 IPC::RequestParser rp{ctx};
97 rp.Skip(2, false);
98 const VAddr nrr_addr{rp.Pop<VAddr>()};
99 const u64 nrr_size{rp.Pop<u64>()};
100 LOG_DEBUG(Service_LDR, "called with nrr_addr={:016X}, nrr_size={:016X}", nrr_addr,
101 nrr_size);
102
103 if (!initialized) {
104 LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
105 IPC::ResponseBuilder rb{ctx, 2};
106 rb.Push(ERROR_NOT_INITIALIZED);
107 return;
108 }
109
110 if (nrr.size() >= MAXIMUM_LOADED_RO) {
111 LOG_ERROR(Service_LDR, "Loading new NRR would exceed the maximum number of loaded NRRs "
112 "(0x40)! Failing...");
113 IPC::ResponseBuilder rb{ctx, 2};
114 rb.Push(ERROR_MAXIMUM_NRR);
115 return;
116 }
117
118 // NRR Address does not fall on 0x1000 byte boundary
119 if (!Common::Is4KBAligned(nrr_addr)) {
120 LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", nrr_addr);
121 IPC::ResponseBuilder rb{ctx, 2};
122 rb.Push(ERROR_INVALID_ALIGNMENT);
123 return;
124 }
125
126 // NRR Size is zero or causes overflow
127 if (nrr_addr + nrr_size <= nrr_addr || nrr_size == 0 || !Common::Is4KBAligned(nrr_size)) {
128 LOG_ERROR(Service_LDR, "NRR Size is invalid! (nrr_address={:016X}, nrr_size={:016X})",
129 nrr_addr, nrr_size);
130 IPC::ResponseBuilder rb{ctx, 2};
131 rb.Push(ERROR_INVALID_SIZE);
132 return;
133 }
134 // Read NRR data from memory
135 std::vector<u8> nrr_data(nrr_size);
136 Memory::ReadBlock(nrr_addr, nrr_data.data(), nrr_size);
137 NRRHeader header;
138 std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader));
139
140 if (header.magic != Common::MakeMagic('N', 'R', 'R', '0')) {
141 LOG_ERROR(Service_LDR, "NRR did not have magic 'NRR0' (actual {:08X})!", header.magic);
142 IPC::ResponseBuilder rb{ctx, 2};
143 rb.Push(ERROR_INVALID_NRR);
144 return;
145 }
146
147 if (header.size != nrr_size) {
148 LOG_ERROR(Service_LDR,
149 "NRR header reported size did not match LoadNrr parameter size! "
150 "(header_size={:016X}, loadnrr_size={:016X})",
151 header.size, nrr_size);
152 IPC::ResponseBuilder rb{ctx, 2};
153 rb.Push(ERROR_INVALID_SIZE);
154 return;
155 }
156
157 if (Core::CurrentProcess()->GetTitleID() != header.title_id) {
158 LOG_ERROR(Service_LDR,
159 "Attempting to load NRR with title ID other than current process. (actual "
160 "{:016X})!",
161 header.title_id);
162 IPC::ResponseBuilder rb{ctx, 2};
163 rb.Push(ERROR_INVALID_NRR);
164 return;
165 }
166
167 std::vector<SHA256Hash> hashes;
168
169 // Copy all hashes in the NRR (specified by hash count/hash offset) into vector.
170 for (std::size_t i = header.hash_offset;
171 i < (header.hash_offset + (header.hash_count * sizeof(SHA256Hash))); i += 8) {
172 SHA256Hash hash;
173 std::memcpy(hash.data(), nrr_data.data() + i, sizeof(SHA256Hash));
174 hashes.emplace_back(hash);
175 }
176
177 nrr.insert_or_assign(nrr_addr, std::move(hashes));
178
179 IPC::ResponseBuilder rb{ctx, 2};
180 rb.Push(RESULT_SUCCESS);
181 }
182
183 void UnloadNrr(Kernel::HLERequestContext& ctx) {
184 if (!initialized) {
185 LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
186 IPC::ResponseBuilder rb{ctx, 2};
187 rb.Push(ERROR_NOT_INITIALIZED);
188 return;
189 }
190
191 IPC::RequestParser rp{ctx};
192 rp.Skip(2, false);
193 const auto nrr_addr{rp.Pop<VAddr>()};
194 LOG_DEBUG(Service_LDR, "called with nrr_addr={:016X}", nrr_addr);
195
196 if (!Common::Is4KBAligned(nrr_addr)) {
197 LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", nrr_addr);
198 IPC::ResponseBuilder rb{ctx, 2};
199 rb.Push(ERROR_INVALID_ALIGNMENT);
200 return;
201 }
202
203 const auto iter = nrr.find(nrr_addr);
204 if (iter == nrr.end()) {
205 LOG_ERROR(Service_LDR,
206 "Attempting to unload NRR which has not been loaded! (addr={:016X})",
207 nrr_addr);
208 IPC::ResponseBuilder rb{ctx, 2};
209 rb.Push(ERROR_INVALID_NRR_ADDRESS);
210 return;
211 }
212
213 nrr.erase(iter);
78 IPC::ResponseBuilder rb{ctx, 2}; 214 IPC::ResponseBuilder rb{ctx, 2};
79 rb.Push(RESULT_SUCCESS); 215 rb.Push(RESULT_SUCCESS);
80 LOG_WARNING(Service_LDR, "(STUBBED) called");
81 } 216 }
82 217
83 void LoadNro(Kernel::HLERequestContext& ctx) { 218 void LoadNro(Kernel::HLERequestContext& ctx) {
@@ -87,33 +222,260 @@ public:
87 const u64 nro_size{rp.Pop<u64>()}; 222 const u64 nro_size{rp.Pop<u64>()};
88 const VAddr bss_addr{rp.Pop<VAddr>()}; 223 const VAddr bss_addr{rp.Pop<VAddr>()};
89 const u64 bss_size{rp.Pop<u64>()}; 224 const u64 bss_size{rp.Pop<u64>()};
225 LOG_DEBUG(
226 Service_LDR,
227 "called with nro_addr={:016X}, nro_size={:016X}, bss_addr={:016X}, bss_size={:016X}",
228 nro_addr, nro_size, bss_addr, bss_size);
229
230 if (!initialized) {
231 LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
232 IPC::ResponseBuilder rb{ctx, 2};
233 rb.Push(ERROR_NOT_INITIALIZED);
234 return;
235 }
236
237 if (nro.size() >= MAXIMUM_LOADED_RO) {
238 LOG_ERROR(Service_LDR, "Loading new NRO would exceed the maximum number of loaded NROs "
239 "(0x40)! Failing...");
240 IPC::ResponseBuilder rb{ctx, 2};
241 rb.Push(ERROR_MAXIMUM_NRO);
242 return;
243 }
244
245 // NRO Address does not fall on 0x1000 byte boundary
246 if (!Common::Is4KBAligned(nro_addr)) {
247 LOG_ERROR(Service_LDR, "NRO Address has invalid alignment (actual {:016X})!", nro_addr);
248 IPC::ResponseBuilder rb{ctx, 2};
249 rb.Push(ERROR_INVALID_ALIGNMENT);
250 return;
251 }
252
253 // NRO Size or BSS Size is zero or causes overflow
254 const auto nro_size_valid =
255 nro_size != 0 && nro_addr + nro_size > nro_addr && Common::Is4KBAligned(nro_size);
256 const auto bss_size_valid =
257 nro_size + bss_size >= nro_size && (bss_size == 0 || bss_addr + bss_size > bss_addr);
258
259 if (!nro_size_valid || !bss_size_valid) {
260 LOG_ERROR(Service_LDR,
261 "NRO Size or BSS Size is invalid! (nro_address={:016X}, nro_size={:016X}, "
262 "bss_address={:016X}, bss_size={:016X})",
263 nro_addr, nro_size, bss_addr, bss_size);
264 IPC::ResponseBuilder rb{ctx, 2};
265 rb.Push(ERROR_INVALID_SIZE);
266 return;
267 }
90 268
91 // Read NRO data from memory 269 // Read NRO data from memory
92 std::vector<u8> nro_data(nro_size); 270 std::vector<u8> nro_data(nro_size);
93 Memory::ReadBlock(nro_addr, nro_data.data(), nro_size); 271 Memory::ReadBlock(nro_addr, nro_data.data(), nro_size);
94 272
273 SHA256Hash hash{};
274 mbedtls_sha256(nro_data.data(), nro_data.size(), hash.data(), 0);
275
276 // NRO Hash is already loaded
277 if (std::any_of(nro.begin(), nro.end(), [&hash](const std::pair<VAddr, NROInfo>& info) {
278 return info.second.hash == hash;
279 })) {
280 LOG_ERROR(Service_LDR, "NRO is already loaded!");
281 IPC::ResponseBuilder rb{ctx, 2};
282 rb.Push(ERROR_ALREADY_LOADED);
283 return;
284 }
285
286 // NRO Hash is not in any loaded NRR
287 if (!IsValidNROHash(hash)) {
288 LOG_ERROR(Service_LDR,
289 "NRO hash is not present in any currently loaded NRRs (hash={})!",
290 Common::HexArrayToString(hash));
291 IPC::ResponseBuilder rb{ctx, 2};
292 rb.Push(ERROR_MISSING_NRR_HASH);
293 return;
294 }
295
296 NROHeader header;
297 std::memcpy(&header, nro_data.data(), sizeof(NROHeader));
298
299 if (!IsValidNRO(header, nro_size, bss_size)) {
300 LOG_ERROR(Service_LDR, "NRO was invalid!");
301 IPC::ResponseBuilder rb{ctx, 2};
302 rb.Push(ERROR_INVALID_NRO);
303 return;
304 }
305
95 // Load NRO as new executable module 306 // Load NRO as new executable module
96 const VAddr addr{*Core::CurrentProcess()->VMManager().FindFreeRegion(nro_size + bss_size)}; 307 auto* process = Core::CurrentProcess();
97 Loader::AppLoader_NRO::LoadNro(nro_data, fmt::format("nro-{:08x}", addr), addr); 308 auto& vm_manager = process->VMManager();
309 auto map_address = vm_manager.FindFreeRegion(nro_size + bss_size);
310
311 if (!map_address.Succeeded() ||
312 *map_address + nro_size + bss_size > vm_manager.GetAddressSpaceEndAddress()) {
313
314 LOG_ERROR(Service_LDR,
315 "General error while allocation memory or no available memory to allocate!");
316 IPC::ResponseBuilder rb{ctx, 2};
317 rb.Push(ERROR_INVALID_MEMORY_STATE);
318 return;
319 }
320
321 ASSERT(process->MirrorMemory(*map_address, nro_addr, nro_size,
322 Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS);
323 ASSERT(process->UnmapMemory(nro_addr, 0, nro_size) == RESULT_SUCCESS);
324
325 if (bss_size > 0) {
326 ASSERT(process->MirrorMemory(*map_address + nro_size, bss_addr, bss_size,
327 Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS);
328 ASSERT(process->UnmapMemory(bss_addr, 0, bss_size) == RESULT_SUCCESS);
329 }
98 330
99 // TODO(bunnei): This is an incomplete implementation. It was tested with Super Mario Party. 331 vm_manager.ReprotectRange(*map_address, header.text_size,
100 // It is currently missing: 332 Kernel::VMAPermission::ReadExecute);
101 // - Signature checks with LoadNRR 333 vm_manager.ReprotectRange(*map_address + header.ro_offset, header.ro_size,
102 // - Checking if a module has already been loaded 334 Kernel::VMAPermission::Read);
103 // - Using/validating BSS, etc. params (these are used from NRO header instead) 335 vm_manager.ReprotectRange(*map_address + header.rw_offset, header.rw_size,
104 // - Error checking 336 Kernel::VMAPermission::ReadWrite);
105 // - ...Probably other things 337
338 Core::System::GetInstance().ArmInterface(0).ClearInstructionCache();
339 Core::System::GetInstance().ArmInterface(1).ClearInstructionCache();
340 Core::System::GetInstance().ArmInterface(2).ClearInstructionCache();
341 Core::System::GetInstance().ArmInterface(3).ClearInstructionCache();
342
343 nro.insert_or_assign(*map_address, NROInfo{hash, nro_size + bss_size});
106 344
107 IPC::ResponseBuilder rb{ctx, 4}; 345 IPC::ResponseBuilder rb{ctx, 4};
108 rb.Push(RESULT_SUCCESS); 346 rb.Push(RESULT_SUCCESS);
109 rb.Push(addr); 347 rb.Push(*map_address);
110 LOG_WARNING(Service_LDR, "(STUBBED) called");
111 } 348 }
112 349
113 void Initialize(Kernel::HLERequestContext& ctx) { 350 void UnloadNro(Kernel::HLERequestContext& ctx) {
351 IPC::RequestParser rp{ctx};
352 rp.Skip(2, false);
353 const VAddr mapped_addr{rp.PopRaw<VAddr>()};
354 const VAddr heap_addr{rp.PopRaw<VAddr>()};
355 LOG_DEBUG(Service_LDR, "called with mapped_addr={:016X}, heap_addr={:016X}", mapped_addr,
356 heap_addr);
357
358 if (!initialized) {
359 LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
360 IPC::ResponseBuilder rb{ctx, 2};
361 rb.Push(ERROR_NOT_INITIALIZED);
362 return;
363 }
364
365 if (!Common::Is4KBAligned(mapped_addr) || !Common::Is4KBAligned(heap_addr)) {
366 LOG_ERROR(Service_LDR,
367 "NRO/BSS Address has invalid alignment (actual nro_addr={:016X}, "
368 "bss_addr={:016X})!",
369 mapped_addr, heap_addr);
370 IPC::ResponseBuilder rb{ctx, 2};
371 rb.Push(ERROR_INVALID_ALIGNMENT);
372 return;
373 }
374
375 const auto iter = nro.find(mapped_addr);
376 if (iter == nro.end()) {
377 LOG_ERROR(Service_LDR,
378 "The NRO attempting to unmap was not mapped or has an invalid address "
379 "(actual {:016X})!",
380 mapped_addr);
381 IPC::ResponseBuilder rb{ctx, 2};
382 rb.Push(ERROR_INVALID_NRO_ADDRESS);
383 return;
384 }
385
386 auto* process = Core::CurrentProcess();
387 auto& vm_manager = process->VMManager();
388 const auto& nro_size = iter->second.size;
389
390 ASSERT(process->MirrorMemory(heap_addr, mapped_addr, nro_size,
391 Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS);
392 ASSERT(process->UnmapMemory(mapped_addr, 0, nro_size) == RESULT_SUCCESS);
393
394 Core::System::GetInstance().ArmInterface(0).ClearInstructionCache();
395 Core::System::GetInstance().ArmInterface(1).ClearInstructionCache();
396 Core::System::GetInstance().ArmInterface(2).ClearInstructionCache();
397 Core::System::GetInstance().ArmInterface(3).ClearInstructionCache();
398
399 nro.erase(iter);
114 IPC::ResponseBuilder rb{ctx, 2}; 400 IPC::ResponseBuilder rb{ctx, 2};
115 rb.Push(RESULT_SUCCESS); 401 rb.Push(RESULT_SUCCESS);
402 }
403
404 void Initialize(Kernel::HLERequestContext& ctx) {
116 LOG_WARNING(Service_LDR, "(STUBBED) called"); 405 LOG_WARNING(Service_LDR, "(STUBBED) called");
406
407 initialized = true;
408
409 IPC::ResponseBuilder rb{ctx, 2};
410 rb.Push(RESULT_SUCCESS);
411 }
412
413private:
414 using SHA256Hash = std::array<u8, 0x20>;
415
416 struct NROHeader {
417 u32_le entrypoint_insn;
418 u32_le mod_offset;
419 INSERT_PADDING_WORDS(2);
420 u32_le magic;
421 INSERT_PADDING_WORDS(1);
422 u32_le nro_size;
423 INSERT_PADDING_WORDS(1);
424 u32_le text_offset;
425 u32_le text_size;
426 u32_le ro_offset;
427 u32_le ro_size;
428 u32_le rw_offset;
429 u32_le rw_size;
430 u32_le bss_size;
431 INSERT_PADDING_WORDS(1);
432 std::array<u8, 0x20> build_id;
433 INSERT_PADDING_BYTES(0x20);
434 };
435 static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size.");
436
437 struct NRRHeader {
438 u32_le magic;
439 INSERT_PADDING_BYTES(0x1C);
440 u64_le title_id_mask;
441 u64_le title_id_pattern;
442 std::array<u8, 0x100> modulus;
443 std::array<u8, 0x100> signature_1;
444 std::array<u8, 0x100> signature_2;
445 u64_le title_id;
446 u32_le size;
447 INSERT_PADDING_BYTES(4);
448 u32_le hash_offset;
449 u32_le hash_count;
450 INSERT_PADDING_BYTES(8);
451 };
452 static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has incorrect size.");
453
454 struct NROInfo {
455 SHA256Hash hash;
456 u64 size;
457 };
458
459 bool initialized = false;
460
461 std::map<VAddr, NROInfo> nro;
462 std::map<VAddr, std::vector<SHA256Hash>> nrr;
463
464 bool IsValidNROHash(const SHA256Hash& hash) {
465 return std::any_of(
466 nrr.begin(), nrr.end(), [&hash](const std::pair<VAddr, std::vector<SHA256Hash>>& p) {
467 return std::find(p.second.begin(), p.second.end(), hash) != p.second.end();
468 });
469 }
470
471 static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) {
472 return header.magic == Common::MakeMagic('N', 'R', 'O', '0') &&
473 header.nro_size == nro_size && header.bss_size == bss_size &&
474 header.ro_offset == header.text_offset + header.text_size &&
475 header.rw_offset == header.ro_offset + header.ro_size &&
476 nro_size == header.rw_offset + header.rw_size &&
477 Common::Is4KBAligned(header.text_size) && Common::Is4KBAligned(header.ro_size) &&
478 Common::Is4KBAligned(header.rw_size);
117 } 479 }
118}; 480};
119 481
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp
index c89157a4d..1f462e087 100644
--- a/src/core/hle/service/lm/lm.cpp
+++ b/src/core/hle/service/lm/lm.cpp
@@ -18,7 +18,7 @@ public:
18 ILogger() : ServiceFramework("ILogger") { 18 ILogger() : ServiceFramework("ILogger") {
19 static const FunctionInfo functions[] = { 19 static const FunctionInfo functions[] = {
20 {0x00000000, &ILogger::Initialize, "Initialize"}, 20 {0x00000000, &ILogger::Initialize, "Initialize"},
21 {0x00000001, nullptr, "SetDestination"}, 21 {0x00000001, &ILogger::SetDestination, "SetDestination"},
22 }; 22 };
23 RegisterHandlers(functions); 23 RegisterHandlers(functions);
24 } 24 }
@@ -178,6 +178,17 @@ private:
178 } 178 }
179 } 179 }
180 180
181 // This service function is intended to be used as a way to
182 // redirect logging output to different destinations, however,
183 // given we always want to see the logging output, it's sufficient
184 // to do nothing and return success here.
185 void SetDestination(Kernel::HLERequestContext& ctx) {
186 LOG_DEBUG(Service_LM, "called");
187
188 IPC::ResponseBuilder rb{ctx, 2};
189 rb.Push(RESULT_SUCCESS);
190 }
191
181 std::ostringstream log_stream; 192 std::ostringstream log_stream;
182}; 193};
183 194
@@ -198,11 +209,11 @@ public:
198 * 0: ResultCode 209 * 0: ResultCode
199 */ 210 */
200 void OpenLogger(Kernel::HLERequestContext& ctx) { 211 void OpenLogger(Kernel::HLERequestContext& ctx) {
212 LOG_DEBUG(Service_LM, "called");
213
201 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 214 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
202 rb.Push(RESULT_SUCCESS); 215 rb.Push(RESULT_SUCCESS);
203 rb.PushIpcInterface<ILogger>(); 216 rb.PushIpcInterface<ILogger>();
204
205 LOG_DEBUG(Service_LM, "called");
206 } 217 }
207}; 218};
208 219
diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp
index e1f17a926..def63dc8a 100644
--- a/src/core/hle/service/mm/mm_u.cpp
+++ b/src/core/hle/service/mm/mm_u.cpp
@@ -31,12 +31,14 @@ public:
31private: 31private:
32 void Initialize(Kernel::HLERequestContext& ctx) { 32 void Initialize(Kernel::HLERequestContext& ctx) {
33 LOG_WARNING(Service_MM, "(STUBBED) called"); 33 LOG_WARNING(Service_MM, "(STUBBED) called");
34
34 IPC::ResponseBuilder rb{ctx, 2}; 35 IPC::ResponseBuilder rb{ctx, 2};
35 rb.Push(RESULT_SUCCESS); 36 rb.Push(RESULT_SUCCESS);
36 } 37 }
37 38
38 void Finalize(Kernel::HLERequestContext& ctx) { 39 void Finalize(Kernel::HLERequestContext& ctx) {
39 LOG_WARNING(Service_MM, "(STUBBED) called"); 40 LOG_WARNING(Service_MM, "(STUBBED) called");
41
40 IPC::ResponseBuilder rb{ctx, 2}; 42 IPC::ResponseBuilder rb{ctx, 2};
41 rb.Push(RESULT_SUCCESS); 43 rb.Push(RESULT_SUCCESS);
42 } 44 }
@@ -45,15 +47,16 @@ private:
45 IPC::RequestParser rp{ctx}; 47 IPC::RequestParser rp{ctx};
46 min = rp.Pop<u32>(); 48 min = rp.Pop<u32>();
47 max = rp.Pop<u32>(); 49 max = rp.Pop<u32>();
48 current = min;
49
50 LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max); 50 LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max);
51
52 current = min;
51 IPC::ResponseBuilder rb{ctx, 2}; 53 IPC::ResponseBuilder rb{ctx, 2};
52 rb.Push(RESULT_SUCCESS); 54 rb.Push(RESULT_SUCCESS);
53 } 55 }
54 56
55 void Get(Kernel::HLERequestContext& ctx) { 57 void Get(Kernel::HLERequestContext& ctx) {
56 LOG_WARNING(Service_MM, "(STUBBED) called"); 58 LOG_WARNING(Service_MM, "(STUBBED) called");
59
57 IPC::ResponseBuilder rb{ctx, 3}; 60 IPC::ResponseBuilder rb{ctx, 3};
58 rb.Push(RESULT_SUCCESS); 61 rb.Push(RESULT_SUCCESS);
59 rb.Push(current); 62 rb.Push(current);
@@ -61,6 +64,7 @@ private:
61 64
62 void InitializeWithId(Kernel::HLERequestContext& ctx) { 65 void InitializeWithId(Kernel::HLERequestContext& ctx) {
63 LOG_WARNING(Service_MM, "(STUBBED) called"); 66 LOG_WARNING(Service_MM, "(STUBBED) called");
67
64 IPC::ResponseBuilder rb{ctx, 3}; 68 IPC::ResponseBuilder rb{ctx, 3};
65 rb.Push(RESULT_SUCCESS); 69 rb.Push(RESULT_SUCCESS);
66 rb.Push<u32>(id); // Any non zero value 70 rb.Push<u32>(id); // Any non zero value
@@ -68,6 +72,7 @@ private:
68 72
69 void FinalizeWithId(Kernel::HLERequestContext& ctx) { 73 void FinalizeWithId(Kernel::HLERequestContext& ctx) {
70 LOG_WARNING(Service_MM, "(STUBBED) called"); 74 LOG_WARNING(Service_MM, "(STUBBED) called");
75
71 IPC::ResponseBuilder rb{ctx, 2}; 76 IPC::ResponseBuilder rb{ctx, 2};
72 rb.Push(RESULT_SUCCESS); 77 rb.Push(RESULT_SUCCESS);
73 } 78 }
@@ -77,16 +82,17 @@ private:
77 u32 input_id = rp.Pop<u32>(); 82 u32 input_id = rp.Pop<u32>();
78 min = rp.Pop<u32>(); 83 min = rp.Pop<u32>();
79 max = rp.Pop<u32>(); 84 max = rp.Pop<u32>();
80 current = min;
81
82 LOG_WARNING(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}", 85 LOG_WARNING(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}",
83 input_id, min, max); 86 input_id, min, max);
87
88 current = min;
84 IPC::ResponseBuilder rb{ctx, 2}; 89 IPC::ResponseBuilder rb{ctx, 2};
85 rb.Push(RESULT_SUCCESS); 90 rb.Push(RESULT_SUCCESS);
86 } 91 }
87 92
88 void GetWithId(Kernel::HLERequestContext& ctx) { 93 void GetWithId(Kernel::HLERequestContext& ctx) {
89 LOG_WARNING(Service_MM, "(STUBBED) called"); 94 LOG_WARNING(Service_MM, "(STUBBED) called");
95
90 IPC::ResponseBuilder rb{ctx, 3}; 96 IPC::ResponseBuilder rb{ctx, 3};
91 rb.Push(RESULT_SUCCESS); 97 rb.Push(RESULT_SUCCESS);
92 rb.Push(current); 98 rb.Push(current);
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
index 30e542542..5c62d42ba 100644
--- a/src/core/hle/service/nfc/nfc.cpp
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -43,11 +43,11 @@ public:
43 43
44private: 44private:
45 void CreateAmInterface(Kernel::HLERequestContext& ctx) { 45 void CreateAmInterface(Kernel::HLERequestContext& ctx) {
46 LOG_DEBUG(Service_NFC, "called");
47
46 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 48 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
47 rb.Push(RESULT_SUCCESS); 49 rb.Push(RESULT_SUCCESS);
48 rb.PushIpcInterface<IAm>(); 50 rb.PushIpcInterface<IAm>();
49
50 LOG_DEBUG(Service_NFC, "called");
51 } 51 }
52}; 52};
53 53
@@ -91,11 +91,11 @@ public:
91 91
92private: 92private:
93 void CreateUserInterface(Kernel::HLERequestContext& ctx) { 93 void CreateUserInterface(Kernel::HLERequestContext& ctx) {
94 LOG_DEBUG(Service_NFC, "called");
95
94 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 96 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
95 rb.Push(RESULT_SUCCESS); 97 rb.Push(RESULT_SUCCESS);
96 rb.PushIpcInterface<MFIUser>(); 98 rb.PushIpcInterface<MFIUser>();
97
98 LOG_DEBUG(Service_NFC, "called");
99 } 99 }
100}; 100};
101 101
@@ -138,19 +138,19 @@ private:
138 }; 138 };
139 139
140 void InitializeOld(Kernel::HLERequestContext& ctx) { 140 void InitializeOld(Kernel::HLERequestContext& ctx) {
141 LOG_DEBUG(Service_NFC, "called");
142
141 IPC::ResponseBuilder rb{ctx, 2, 0}; 143 IPC::ResponseBuilder rb{ctx, 2, 0};
142 rb.Push(RESULT_SUCCESS); 144 rb.Push(RESULT_SUCCESS);
143
144 // We don't deal with hardware initialization so we can just stub this. 145 // We don't deal with hardware initialization so we can just stub this.
145 LOG_DEBUG(Service_NFC, "called");
146 } 146 }
147 147
148 void IsNfcEnabledOld(Kernel::HLERequestContext& ctx) { 148 void IsNfcEnabledOld(Kernel::HLERequestContext& ctx) {
149 LOG_DEBUG(Service_NFC, "IsNfcEnabledOld");
150
149 IPC::ResponseBuilder rb{ctx, 3}; 151 IPC::ResponseBuilder rb{ctx, 3};
150 rb.Push(RESULT_SUCCESS); 152 rb.Push(RESULT_SUCCESS);
151 rb.PushRaw<u8>(Settings::values.enable_nfc); 153 rb.PushRaw<u8>(Settings::values.enable_nfc);
152
153 LOG_DEBUG(Service_NFC, "IsNfcEnabledOld");
154 } 154 }
155 155
156 void GetStateOld(Kernel::HLERequestContext& ctx) { 156 void GetStateOld(Kernel::HLERequestContext& ctx) {
@@ -183,11 +183,11 @@ public:
183 183
184private: 184private:
185 void CreateUserInterface(Kernel::HLERequestContext& ctx) { 185 void CreateUserInterface(Kernel::HLERequestContext& ctx) {
186 LOG_DEBUG(Service_NFC, "called");
187
186 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 188 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
187 rb.Push(RESULT_SUCCESS); 189 rb.Push(RESULT_SUCCESS);
188 rb.PushIpcInterface<IUser>(); 190 rb.PushIpcInterface<IUser>();
189
190 LOG_DEBUG(Service_NFC, "called");
191 } 191 }
192}; 192};
193 193
@@ -241,11 +241,11 @@ public:
241 241
242private: 242private:
243 void CreateSystemInterface(Kernel::HLERequestContext& ctx) { 243 void CreateSystemInterface(Kernel::HLERequestContext& ctx) {
244 LOG_DEBUG(Service_NFC, "called");
245
244 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 246 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
245 rb.Push(RESULT_SUCCESS); 247 rb.Push(RESULT_SUCCESS);
246 rb.PushIpcInterface<ISystem>(); 248 rb.PushIpcInterface<ISystem>();
247
248 LOG_DEBUG(Service_NFC, "called");
249 } 249 }
250}; 250};
251 251
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index c1af878fe..d5df112a0 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -7,7 +7,9 @@
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
10#include "core/hle/kernel/event.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/readable_event.h"
12#include "core/hle/kernel/writable_event.h"
11#include "core/hle/lock.h" 13#include "core/hle/lock.h"
12#include "core/hle/service/hid/hid.h" 14#include "core/hle/service/hid/hid.h"
13#include "core/hle/service/nfp/nfp.h" 15#include "core/hle/service/nfp/nfp.h"
@@ -23,8 +25,8 @@ constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP,
23Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 25Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
24 : ServiceFramework(name), module(std::move(module)) { 26 : ServiceFramework(name), module(std::move(module)) {
25 auto& kernel = Core::System::GetInstance().Kernel(); 27 auto& kernel = Core::System::GetInstance().Kernel();
26 nfc_tag_load = 28 nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
27 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:NFCTagDetected"); 29 "IUser:NFCTagDetected");
28} 30}
29 31
30Module::Interface::~Interface() = default; 32Module::Interface::~Interface() = default;
@@ -63,10 +65,10 @@ public:
63 RegisterHandlers(functions); 65 RegisterHandlers(functions);
64 66
65 auto& kernel = Core::System::GetInstance().Kernel(); 67 auto& kernel = Core::System::GetInstance().Kernel();
66 deactivate_event = 68 deactivate_event = Kernel::WritableEvent::CreateEventPair(
67 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent"); 69 kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent");
68 availability_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, 70 availability_change_event = Kernel::WritableEvent::CreateEventPair(
69 "IUser:AvailabilityChangeEvent"); 71 kernel, Kernel::ResetType::OneShot, "IUser:AvailabilityChangeEvent");
70 } 72 }
71 73
72private: 74private:
@@ -108,30 +110,29 @@ private:
108 static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size"); 110 static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size");
109 111
110 void Initialize(Kernel::HLERequestContext& ctx) { 112 void Initialize(Kernel::HLERequestContext& ctx) {
113 LOG_DEBUG(Service_NFC, "called");
114
111 IPC::ResponseBuilder rb{ctx, 2, 0}; 115 IPC::ResponseBuilder rb{ctx, 2, 0};
112 rb.Push(RESULT_SUCCESS); 116 rb.Push(RESULT_SUCCESS);
113 117
114 state = State::Initialized; 118 state = State::Initialized;
115
116 LOG_DEBUG(Service_NFC, "called");
117 } 119 }
118 120
119 void GetState(Kernel::HLERequestContext& ctx) { 121 void GetState(Kernel::HLERequestContext& ctx) {
122 LOG_DEBUG(Service_NFC, "called");
123
120 IPC::ResponseBuilder rb{ctx, 3, 0}; 124 IPC::ResponseBuilder rb{ctx, 3, 0};
121 rb.Push(RESULT_SUCCESS); 125 rb.Push(RESULT_SUCCESS);
122 rb.PushRaw<u32>(static_cast<u32>(state)); 126 rb.PushRaw<u32>(static_cast<u32>(state));
123
124 LOG_DEBUG(Service_NFC, "called");
125 } 127 }
126 128
127 void ListDevices(Kernel::HLERequestContext& ctx) { 129 void ListDevices(Kernel::HLERequestContext& ctx) {
128 IPC::RequestParser rp{ctx}; 130 IPC::RequestParser rp{ctx};
129 const u32 array_size = rp.Pop<u32>(); 131 const u32 array_size = rp.Pop<u32>();
132 LOG_DEBUG(Service_NFP, "called, array_size={}", array_size);
130 133
131 ctx.WriteBuffer(&device_handle, sizeof(device_handle)); 134 ctx.WriteBuffer(&device_handle, sizeof(device_handle));
132 135
133 LOG_DEBUG(Service_NFP, "called, array_size={}", array_size);
134
135 IPC::ResponseBuilder rb{ctx, 3}; 136 IPC::ResponseBuilder rb{ctx, 3};
136 rb.Push(RESULT_SUCCESS); 137 rb.Push(RESULT_SUCCESS);
137 rb.Push<u32>(1); 138 rb.Push<u32>(1);
@@ -141,6 +142,7 @@ private:
141 IPC::RequestParser rp{ctx}; 142 IPC::RequestParser rp{ctx};
142 const u64 dev_handle = rp.Pop<u64>(); 143 const u64 dev_handle = rp.Pop<u64>();
143 LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); 144 LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
145
144 IPC::ResponseBuilder rb{ctx, 3}; 146 IPC::ResponseBuilder rb{ctx, 3};
145 rb.Push(RESULT_SUCCESS); 147 rb.Push(RESULT_SUCCESS);
146 rb.Push<u32>(npad_id); 148 rb.Push<u32>(npad_id);
@@ -150,6 +152,7 @@ private:
150 IPC::RequestParser rp{ctx}; 152 IPC::RequestParser rp{ctx};
151 const u64 dev_handle = rp.Pop<u64>(); 153 const u64 dev_handle = rp.Pop<u64>();
152 LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); 154 LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle);
155
153 IPC::ResponseBuilder rb{ctx, 2, 1}; 156 IPC::ResponseBuilder rb{ctx, 2, 1};
154 rb.Push(RESULT_SUCCESS); 157 rb.Push(RESULT_SUCCESS);
155 rb.PushCopyObjects(nfp_interface.GetNFCEvent()); 158 rb.PushCopyObjects(nfp_interface.GetNFCEvent());
@@ -163,15 +166,16 @@ private:
163 166
164 IPC::ResponseBuilder rb{ctx, 2, 1}; 167 IPC::ResponseBuilder rb{ctx, 2, 1};
165 rb.Push(RESULT_SUCCESS); 168 rb.Push(RESULT_SUCCESS);
166 rb.PushCopyObjects(deactivate_event); 169 rb.PushCopyObjects(deactivate_event.readable);
167 } 170 }
168 171
169 void StopDetection(Kernel::HLERequestContext& ctx) { 172 void StopDetection(Kernel::HLERequestContext& ctx) {
170 LOG_DEBUG(Service_NFP, "called"); 173 LOG_DEBUG(Service_NFP, "called");
174
171 switch (device_state) { 175 switch (device_state) {
172 case DeviceState::TagFound: 176 case DeviceState::TagFound:
173 case DeviceState::TagNearby: 177 case DeviceState::TagNearby:
174 deactivate_event->Signal(); 178 deactivate_event.writable->Signal();
175 device_state = DeviceState::Initialized; 179 device_state = DeviceState::Initialized;
176 break; 180 break;
177 case DeviceState::SearchingForTag: 181 case DeviceState::SearchingForTag:
@@ -185,6 +189,7 @@ private:
185 189
186 void GetDeviceState(Kernel::HLERequestContext& ctx) { 190 void GetDeviceState(Kernel::HLERequestContext& ctx) {
187 LOG_DEBUG(Service_NFP, "called"); 191 LOG_DEBUG(Service_NFP, "called");
192
188 auto nfc_event = nfp_interface.GetNFCEvent(); 193 auto nfc_event = nfp_interface.GetNFCEvent();
189 if (!nfc_event->ShouldWait(Kernel::GetCurrentThread()) && !has_attached_handle) { 194 if (!nfc_event->ShouldWait(Kernel::GetCurrentThread()) && !has_attached_handle) {
190 device_state = DeviceState::TagFound; 195 device_state = DeviceState::TagFound;
@@ -212,7 +217,7 @@ private:
212 IPC::ResponseBuilder rb{ctx, 2}; 217 IPC::ResponseBuilder rb{ctx, 2};
213 auto amiibo = nfp_interface.GetAmiiboBuffer(); 218 auto amiibo = nfp_interface.GetAmiiboBuffer();
214 TagInfo tag_info{}; 219 TagInfo tag_info{};
215 std::memcpy(tag_info.uuid.data(), amiibo.uuid.data(), sizeof(tag_info.uuid.size())); 220 tag_info.uuid = amiibo.uuid;
216 tag_info.uuid_length = static_cast<u8>(tag_info.uuid.size()); 221 tag_info.uuid_length = static_cast<u8>(tag_info.uuid.size());
217 222
218 tag_info.protocol = 1; // TODO(ogniK): Figure out actual values 223 tag_info.protocol = 1; // TODO(ogniK): Figure out actual values
@@ -261,7 +266,7 @@ private:
261 266
262 IPC::ResponseBuilder rb{ctx, 2, 1}; 267 IPC::ResponseBuilder rb{ctx, 2, 1};
263 rb.Push(RESULT_SUCCESS); 268 rb.Push(RESULT_SUCCESS);
264 rb.PushCopyObjects(availability_change_event); 269 rb.PushCopyObjects(availability_change_event.readable);
265 } 270 }
266 271
267 void GetRegisterInfo(Kernel::HLERequestContext& ctx) { 272 void GetRegisterInfo(Kernel::HLERequestContext& ctx) {
@@ -316,13 +321,14 @@ private:
316 const u32 npad_id{0}; // Player 1 controller 321 const u32 npad_id{0}; // Player 1 controller
317 State state{State::NonInitialized}; 322 State state{State::NonInitialized};
318 DeviceState device_state{DeviceState::Initialized}; 323 DeviceState device_state{DeviceState::Initialized};
319 Kernel::SharedPtr<Kernel::Event> deactivate_event; 324 Kernel::EventPair deactivate_event;
320 Kernel::SharedPtr<Kernel::Event> availability_change_event; 325 Kernel::EventPair availability_change_event;
321 const Module::Interface& nfp_interface; 326 const Module::Interface& nfp_interface;
322}; 327};
323 328
324void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { 329void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) {
325 LOG_DEBUG(Service_NFP, "called"); 330 LOG_DEBUG(Service_NFP, "called");
331
326 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 332 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
327 rb.Push(RESULT_SUCCESS); 333 rb.Push(RESULT_SUCCESS);
328 rb.PushIpcInterface<IUser>(*this); 334 rb.PushIpcInterface<IUser>(*this);
@@ -335,12 +341,14 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
335 } 341 }
336 342
337 std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); 343 std::memcpy(&amiibo, buffer.data(), sizeof(amiibo));
338 nfc_tag_load->Signal(); 344 nfc_tag_load.writable->Signal();
339 return true; 345 return true;
340} 346}
341const Kernel::SharedPtr<Kernel::Event>& Module::Interface::GetNFCEvent() const { 347
342 return nfc_tag_load; 348const Kernel::SharedPtr<Kernel::ReadableEvent>& Module::Interface::GetNFCEvent() const {
349 return nfc_tag_load.readable;
343} 350}
351
344const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const { 352const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const {
345 return amiibo; 353 return amiibo;
346} 354}
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h
index 5c0ae8a54..a1817e991 100644
--- a/src/core/hle/service/nfp/nfp.h
+++ b/src/core/hle/service/nfp/nfp.h
@@ -6,7 +6,8 @@
6 6
7#include <array> 7#include <array>
8#include <vector> 8#include <vector>
9#include "core/hle/kernel/event.h" 9#include "core/hle/kernel/readable_event.h"
10#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
11 12
12namespace Service::NFP { 13namespace Service::NFP {
@@ -33,11 +34,11 @@ public:
33 34
34 void CreateUserInterface(Kernel::HLERequestContext& ctx); 35 void CreateUserInterface(Kernel::HLERequestContext& ctx);
35 bool LoadAmiibo(const std::vector<u8>& buffer); 36 bool LoadAmiibo(const std::vector<u8>& buffer);
36 const Kernel::SharedPtr<Kernel::Event>& GetNFCEvent() const; 37 const Kernel::SharedPtr<Kernel::ReadableEvent>& GetNFCEvent() const;
37 const AmiiboFile& GetAmiiboBuffer() const; 38 const AmiiboFile& GetAmiiboBuffer() const;
38 39
39 private: 40 private:
40 Kernel::SharedPtr<Kernel::Event> nfc_tag_load{}; 41 Kernel::EventPair nfc_tag_load{};
41 AmiiboFile amiibo{}; 42 AmiiboFile amiibo{};
42 43
43 protected: 44 protected:
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 75dcd94a3..60479bb45 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -4,7 +4,9 @@
4 4
5#include "core/core.h" 5#include "core/core.h"
6#include "core/hle/ipc_helpers.h" 6#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/event.h" 7#include "core/hle/kernel/kernel.h"
8#include "core/hle/kernel/readable_event.h"
9#include "core/hle/kernel/writable_event.h"
8#include "core/hle/service/nifm/nifm.h" 10#include "core/hle/service/nifm/nifm.h"
9#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
10 12
@@ -56,19 +58,23 @@ public:
56 RegisterHandlers(functions); 58 RegisterHandlers(functions);
57 59
58 auto& kernel = Core::System::GetInstance().Kernel(); 60 auto& kernel = Core::System::GetInstance().Kernel();
59 event1 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event1"); 61 event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
60 event2 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event2"); 62 "IRequest:Event1");
63 event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
64 "IRequest:Event2");
61 } 65 }
62 66
63private: 67private:
64 void Submit(Kernel::HLERequestContext& ctx) { 68 void Submit(Kernel::HLERequestContext& ctx) {
65 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 69 LOG_WARNING(Service_NIFM, "(STUBBED) called");
70
66 IPC::ResponseBuilder rb{ctx, 2}; 71 IPC::ResponseBuilder rb{ctx, 2};
67 rb.Push(RESULT_SUCCESS); 72 rb.Push(RESULT_SUCCESS);
68 } 73 }
69 74
70 void GetRequestState(Kernel::HLERequestContext& ctx) { 75 void GetRequestState(Kernel::HLERequestContext& ctx) {
71 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 76 LOG_WARNING(Service_NIFM, "(STUBBED) called");
77
72 IPC::ResponseBuilder rb{ctx, 3}; 78 IPC::ResponseBuilder rb{ctx, 3};
73 rb.Push(RESULT_SUCCESS); 79 rb.Push(RESULT_SUCCESS);
74 rb.Push<u32>(0); 80 rb.Push<u32>(0);
@@ -76,30 +82,34 @@ private:
76 82
77 void GetResult(Kernel::HLERequestContext& ctx) { 83 void GetResult(Kernel::HLERequestContext& ctx) {
78 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 84 LOG_WARNING(Service_NIFM, "(STUBBED) called");
85
79 IPC::ResponseBuilder rb{ctx, 2}; 86 IPC::ResponseBuilder rb{ctx, 2};
80 rb.Push(RESULT_SUCCESS); 87 rb.Push(RESULT_SUCCESS);
81 } 88 }
82 89
83 void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) { 90 void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) {
84 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 91 LOG_WARNING(Service_NIFM, "(STUBBED) called");
92
85 IPC::ResponseBuilder rb{ctx, 2, 2}; 93 IPC::ResponseBuilder rb{ctx, 2, 2};
86 rb.Push(RESULT_SUCCESS); 94 rb.Push(RESULT_SUCCESS);
87 rb.PushCopyObjects(event1, event2); 95 rb.PushCopyObjects(event1.readable, event2.readable);
88 } 96 }
89 97
90 void Cancel(Kernel::HLERequestContext& ctx) { 98 void Cancel(Kernel::HLERequestContext& ctx) {
91 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 99 LOG_WARNING(Service_NIFM, "(STUBBED) called");
100
92 IPC::ResponseBuilder rb{ctx, 2}; 101 IPC::ResponseBuilder rb{ctx, 2};
93 rb.Push(RESULT_SUCCESS); 102 rb.Push(RESULT_SUCCESS);
94 } 103 }
95 104
96 void SetConnectionConfirmationOption(Kernel::HLERequestContext& ctx) { 105 void SetConnectionConfirmationOption(Kernel::HLERequestContext& ctx) {
97 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 106 LOG_WARNING(Service_NIFM, "(STUBBED) called");
107
98 IPC::ResponseBuilder rb{ctx, 2}; 108 IPC::ResponseBuilder rb{ctx, 2};
99 rb.Push(RESULT_SUCCESS); 109 rb.Push(RESULT_SUCCESS);
100 } 110 }
101 111
102 Kernel::SharedPtr<Kernel::Event> event1, event2; 112 Kernel::EventPair event1, event2;
103}; 113};
104 114
105class INetworkProfile final : public ServiceFramework<INetworkProfile> { 115class INetworkProfile final : public ServiceFramework<INetworkProfile> {
@@ -122,32 +132,36 @@ private:
122 void GetClientId(Kernel::HLERequestContext& ctx) { 132 void GetClientId(Kernel::HLERequestContext& ctx) {
123 static constexpr u32 client_id = 1; 133 static constexpr u32 client_id = 1;
124 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 134 LOG_WARNING(Service_NIFM, "(STUBBED) called");
135
125 IPC::ResponseBuilder rb{ctx, 4}; 136 IPC::ResponseBuilder rb{ctx, 4};
126 rb.Push(RESULT_SUCCESS); 137 rb.Push(RESULT_SUCCESS);
127 rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid 138 rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid
128 } 139 }
129 void CreateScanRequest(Kernel::HLERequestContext& ctx) { 140 void CreateScanRequest(Kernel::HLERequestContext& ctx) {
141 LOG_DEBUG(Service_NIFM, "called");
142
130 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 143 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
131 144
132 rb.Push(RESULT_SUCCESS); 145 rb.Push(RESULT_SUCCESS);
133 rb.PushIpcInterface<IScanRequest>(); 146 rb.PushIpcInterface<IScanRequest>();
134
135 LOG_DEBUG(Service_NIFM, "called");
136 } 147 }
137 void CreateRequest(Kernel::HLERequestContext& ctx) { 148 void CreateRequest(Kernel::HLERequestContext& ctx) {
149 LOG_DEBUG(Service_NIFM, "called");
150
138 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 151 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
139 152
140 rb.Push(RESULT_SUCCESS); 153 rb.Push(RESULT_SUCCESS);
141 rb.PushIpcInterface<IRequest>(); 154 rb.PushIpcInterface<IRequest>();
142
143 LOG_DEBUG(Service_NIFM, "called");
144 } 155 }
145 void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { 156 void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) {
146 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 157 LOG_WARNING(Service_NIFM, "(STUBBED) called");
158
147 IPC::ResponseBuilder rb{ctx, 2}; 159 IPC::ResponseBuilder rb{ctx, 2};
148 rb.Push(RESULT_SUCCESS); 160 rb.Push(RESULT_SUCCESS);
149 } 161 }
150 void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { 162 void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
163 LOG_DEBUG(Service_NIFM, "called");
164
151 ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, "NetworkProfileData is not the correct size"); 165 ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, "NetworkProfileData is not the correct size");
152 u128 uuid{}; 166 u128 uuid{};
153 auto buffer = ctx.ReadBuffer(); 167 auto buffer = ctx.ReadBuffer();
@@ -158,23 +172,24 @@ private:
158 rb.Push(RESULT_SUCCESS); 172 rb.Push(RESULT_SUCCESS);
159 rb.PushIpcInterface<INetworkProfile>(); 173 rb.PushIpcInterface<INetworkProfile>();
160 rb.PushRaw<u128>(uuid); 174 rb.PushRaw<u128>(uuid);
161
162 LOG_DEBUG(Service_NIFM, "called");
163 } 175 }
164 void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) { 176 void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) {
165 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 177 LOG_WARNING(Service_NIFM, "(STUBBED) called");
178
166 IPC::ResponseBuilder rb{ctx, 3}; 179 IPC::ResponseBuilder rb{ctx, 3};
167 rb.Push(RESULT_SUCCESS); 180 rb.Push(RESULT_SUCCESS);
168 rb.Push<u8>(0); 181 rb.Push<u8>(0);
169 } 182 }
170 void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) { 183 void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) {
171 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 184 LOG_WARNING(Service_NIFM, "(STUBBED) called");
185
172 IPC::ResponseBuilder rb{ctx, 3}; 186 IPC::ResponseBuilder rb{ctx, 3};
173 rb.Push(RESULT_SUCCESS); 187 rb.Push(RESULT_SUCCESS);
174 rb.Push<u8>(0); 188 rb.Push<u8>(0);
175 } 189 }
176 void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) { 190 void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
177 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 191 LOG_WARNING(Service_NIFM, "(STUBBED) called");
192
178 IPC::ResponseBuilder rb{ctx, 3}; 193 IPC::ResponseBuilder rb{ctx, 3};
179 rb.Push(RESULT_SUCCESS); 194 rb.Push(RESULT_SUCCESS);
180 rb.Push<u8>(0); 195 rb.Push<u8>(0);
@@ -235,17 +250,19 @@ public:
235 } 250 }
236 251
237 void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { 252 void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) {
253 LOG_DEBUG(Service_NIFM, "called");
254
238 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 255 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
239 rb.Push(RESULT_SUCCESS); 256 rb.Push(RESULT_SUCCESS);
240 rb.PushIpcInterface<IGeneralService>(); 257 rb.PushIpcInterface<IGeneralService>();
241 LOG_DEBUG(Service_NIFM, "called");
242 } 258 }
243 259
244 void CreateGeneralService(Kernel::HLERequestContext& ctx) { 260 void CreateGeneralService(Kernel::HLERequestContext& ctx) {
261 LOG_DEBUG(Service_NIFM, "called");
262
245 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 263 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
246 rb.Push(RESULT_SUCCESS); 264 rb.Push(RESULT_SUCCESS);
247 rb.PushIpcInterface<IGeneralService>(); 265 rb.PushIpcInterface<IGeneralService>();
248 LOG_DEBUG(Service_NIFM, "called");
249 } 266 }
250}; 267};
251 268
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index 18091c9bb..0dabcd23b 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.cpp
@@ -6,7 +6,9 @@
6#include <ctime> 6#include <ctime>
7#include "core/core.h" 7#include "core/core.h"
8#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/event.h" 9#include "core/hle/kernel/kernel.h"
10#include "core/hle/kernel/readable_event.h"
11#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/nim/nim.h" 12#include "core/hle/service/nim/nim.h"
11#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
12#include "core/hle/service/sm/sm.h" 14#include "core/hle/service/sm/sm.h"
@@ -138,57 +140,61 @@ public:
138 RegisterHandlers(functions); 140 RegisterHandlers(functions);
139 141
140 auto& kernel = Core::System::GetInstance().Kernel(); 142 auto& kernel = Core::System::GetInstance().Kernel();
141 finished_event = 143 finished_event = Kernel::WritableEvent::CreateEventPair(
142 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, 144 kernel, Kernel::ResetType::OneShot,
143 "IEnsureNetworkClockAvailabilityService:FinishEvent"); 145 "IEnsureNetworkClockAvailabilityService:FinishEvent");
144 } 146 }
145 147
146private: 148private:
147 Kernel::SharedPtr<Kernel::Event> finished_event; 149 Kernel::EventPair finished_event;
148 150
149 void StartTask(Kernel::HLERequestContext& ctx) { 151 void StartTask(Kernel::HLERequestContext& ctx) {
150 // No need to connect to the internet, just finish the task straight away. 152 // No need to connect to the internet, just finish the task straight away.
151 finished_event->Signal(); 153 LOG_DEBUG(Service_NIM, "called");
154 finished_event.writable->Signal();
152 IPC::ResponseBuilder rb{ctx, 2}; 155 IPC::ResponseBuilder rb{ctx, 2};
153 rb.Push(RESULT_SUCCESS); 156 rb.Push(RESULT_SUCCESS);
154 LOG_DEBUG(Service_NIM, "called");
155 } 157 }
156 158
157 void GetFinishNotificationEvent(Kernel::HLERequestContext& ctx) { 159 void GetFinishNotificationEvent(Kernel::HLERequestContext& ctx) {
160 LOG_DEBUG(Service_NIM, "called");
161
158 IPC::ResponseBuilder rb{ctx, 2, 1}; 162 IPC::ResponseBuilder rb{ctx, 2, 1};
159 rb.Push(RESULT_SUCCESS); 163 rb.Push(RESULT_SUCCESS);
160 rb.PushCopyObjects(finished_event); 164 rb.PushCopyObjects(finished_event.readable);
161 LOG_DEBUG(Service_NIM, "called");
162 } 165 }
163 166
164 void GetResult(Kernel::HLERequestContext& ctx) { 167 void GetResult(Kernel::HLERequestContext& ctx) {
168 LOG_DEBUG(Service_NIM, "called");
169
165 IPC::ResponseBuilder rb{ctx, 2}; 170 IPC::ResponseBuilder rb{ctx, 2};
166 rb.Push(RESULT_SUCCESS); 171 rb.Push(RESULT_SUCCESS);
167 LOG_DEBUG(Service_NIM, "called");
168 } 172 }
169 173
170 void Cancel(Kernel::HLERequestContext& ctx) { 174 void Cancel(Kernel::HLERequestContext& ctx) {
171 finished_event->Clear(); 175 LOG_DEBUG(Service_NIM, "called");
176 finished_event.writable->Clear();
172 IPC::ResponseBuilder rb{ctx, 2}; 177 IPC::ResponseBuilder rb{ctx, 2};
173 rb.Push(RESULT_SUCCESS); 178 rb.Push(RESULT_SUCCESS);
174 LOG_DEBUG(Service_NIM, "called");
175 } 179 }
176 180
177 void IsProcessing(Kernel::HLERequestContext& ctx) { 181 void IsProcessing(Kernel::HLERequestContext& ctx) {
182 LOG_DEBUG(Service_NIM, "called");
183
178 IPC::ResponseBuilder rb{ctx, 3}; 184 IPC::ResponseBuilder rb{ctx, 3};
179 rb.Push(RESULT_SUCCESS); 185 rb.Push(RESULT_SUCCESS);
180 rb.PushRaw<u32>(0); // We instantly process the request 186 rb.PushRaw<u32>(0); // We instantly process the request
181 LOG_DEBUG(Service_NIM, "called");
182 } 187 }
183 188
184 void GetServerTime(Kernel::HLERequestContext& ctx) { 189 void GetServerTime(Kernel::HLERequestContext& ctx) {
190 LOG_DEBUG(Service_NIM, "called");
191
185 const s64 server_time{std::chrono::duration_cast<std::chrono::seconds>( 192 const s64 server_time{std::chrono::duration_cast<std::chrono::seconds>(
186 std::chrono::system_clock::now().time_since_epoch()) 193 std::chrono::system_clock::now().time_since_epoch())
187 .count()}; 194 .count()};
188 IPC::ResponseBuilder rb{ctx, 4}; 195 IPC::ResponseBuilder rb{ctx, 4};
189 rb.Push(RESULT_SUCCESS); 196 rb.Push(RESULT_SUCCESS);
190 rb.PushRaw<s64>(server_time); 197 rb.PushRaw<s64>(server_time);
191 LOG_DEBUG(Service_NIM, "called");
192 } 198 }
193}; 199};
194 200
@@ -208,23 +214,26 @@ public:
208 214
209private: 215private:
210 void OpenEnsureNetworkClockAvailabilityService(Kernel::HLERequestContext& ctx) { 216 void OpenEnsureNetworkClockAvailabilityService(Kernel::HLERequestContext& ctx) {
217 LOG_DEBUG(Service_NIM, "called");
218
211 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 219 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
212 rb.Push(RESULT_SUCCESS); 220 rb.Push(RESULT_SUCCESS);
213 rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>(); 221 rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>();
214 LOG_DEBUG(Service_NIM, "called");
215 } 222 }
216 223
217 // TODO(ogniK): Do we need these? 224 // TODO(ogniK): Do we need these?
218 void SuspendAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) { 225 void SuspendAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) {
226 LOG_WARNING(Service_NIM, "(STUBBED) called");
227
219 IPC::ResponseBuilder rb{ctx, 2}; 228 IPC::ResponseBuilder rb{ctx, 2};
220 rb.Push(RESULT_SUCCESS); 229 rb.Push(RESULT_SUCCESS);
221 LOG_WARNING(Service_NIM, "(STUBBED) called");
222 } 230 }
223 231
224 void ResumeAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) { 232 void ResumeAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) {
233 LOG_WARNING(Service_NIM, "(STUBBED) called");
234
225 IPC::ResponseBuilder rb{ctx, 2}; 235 IPC::ResponseBuilder rb{ctx, 2};
226 rb.Push(RESULT_SUCCESS); 236 rb.Push(RESULT_SUCCESS);
227 LOG_WARNING(Service_NIM, "(STUBBED) called");
228 } 237 }
229}; 238};
230 239
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index 07c1381fe..2663f56b1 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -2,6 +2,9 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h"
6#include "core/file_sys/control_metadata.h"
7#include "core/file_sys/patch_manager.h"
5#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
6#include "core/hle/kernel/hle_ipc.h" 9#include "core/hle/kernel/hle_ipc.h"
7#include "core/hle/service/ns/ns.h" 10#include "core/hle/service/ns/ns.h"
@@ -118,7 +121,7 @@ public:
118 {305, nullptr, "TerminateSystemApplet"}, 121 {305, nullptr, "TerminateSystemApplet"},
119 {306, nullptr, "LaunchOverlayApplet"}, 122 {306, nullptr, "LaunchOverlayApplet"},
120 {307, nullptr, "TerminateOverlayApplet"}, 123 {307, nullptr, "TerminateOverlayApplet"},
121 {400, nullptr, "GetApplicationControlData"}, 124 {400, &IApplicationManagerInterface::GetApplicationControlData, "GetApplicationControlData"},
122 {401, nullptr, "InvalidateAllApplicationControlCache"}, 125 {401, nullptr, "InvalidateAllApplicationControlCache"},
123 {402, nullptr, "RequestDownloadApplicationControlData"}, 126 {402, nullptr, "RequestDownloadApplicationControlData"},
124 {403, nullptr, "GetMaxApplicationControlCacheCount"}, 127 {403, nullptr, "GetMaxApplicationControlCacheCount"},
@@ -243,6 +246,65 @@ public:
243 246
244 RegisterHandlers(functions); 247 RegisterHandlers(functions);
245 } 248 }
249
250 void GetApplicationControlData(Kernel::HLERequestContext& ctx) {
251 IPC::RequestParser rp{ctx};
252 const auto flag = rp.PopRaw<u64>();
253 LOG_DEBUG(Service_NS, "called with flag={:016X}", flag);
254
255 const auto title_id = rp.PopRaw<u64>();
256
257 const auto size = ctx.GetWriteBufferSize();
258
259 const FileSys::PatchManager pm{title_id};
260 const auto control = pm.GetControlMetadata();
261
262 std::vector<u8> out;
263
264 if (control.first != nullptr) {
265 if (size < 0x4000) {
266 LOG_ERROR(Service_NS,
267 "output buffer is too small! (actual={:016X}, expected_min=0x4000)",
268 size);
269 IPC::ResponseBuilder rb{ctx, 2};
270 // TODO(DarkLordZach): Find a better error code for this.
271 rb.Push(ResultCode(-1));
272 return;
273 }
274
275 out.resize(0x4000);
276 const auto bytes = control.first->GetRawBytes();
277 std::memcpy(out.data(), bytes.data(), bytes.size());
278 } else {
279 LOG_WARNING(Service_NS, "missing NACP data for title_id={:016X}, defaulting to zeros.",
280 title_id);
281 out.resize(std::min<u64>(0x4000, size));
282 }
283
284 if (control.second != nullptr) {
285 if (size < 0x4000 + control.second->GetSize()) {
286 LOG_ERROR(Service_NS,
287 "output buffer is too small! (actual={:016X}, expected_min={:016X})",
288 size, 0x4000 + control.second->GetSize());
289 IPC::ResponseBuilder rb{ctx, 2};
290 // TODO(DarkLordZach): Find a better error code for this.
291 rb.Push(ResultCode(-1));
292 return;
293 }
294
295 out.resize(0x4000 + control.second->GetSize());
296 control.second->Read(out.data() + 0x4000, control.second->GetSize());
297 } else {
298 LOG_WARNING(Service_NS, "missing icon data for title_id={:016X}, defaulting to zeros.",
299 title_id);
300 }
301
302 ctx.WriteBuffer(out);
303
304 IPC::ResponseBuilder rb{ctx, 3};
305 rb.Push(RESULT_SUCCESS);
306 rb.Push<u32>(static_cast<u32>(out.size()));
307 }
246}; 308};
247 309
248class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> { 310class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {
@@ -371,11 +433,11 @@ public:
371private: 433private:
372 template <typename T> 434 template <typename T>
373 void PushInterface(Kernel::HLERequestContext& ctx) { 435 void PushInterface(Kernel::HLERequestContext& ctx) {
436 LOG_DEBUG(Service_NS, "called");
437
374 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 438 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
375 rb.Push(RESULT_SUCCESS); 439 rb.Push(RESULT_SUCCESS);
376 rb.PushIpcInterface<T>(); 440 rb.PushIpcInterface<T>();
377
378 LOG_DEBUG(Service_NS, "called");
379 } 441 }
380}; 442};
381 443
@@ -464,11 +526,11 @@ public:
464 526
465private: 527private:
466 void OpenSystemUpdateControl(Kernel::HLERequestContext& ctx) { 528 void OpenSystemUpdateControl(Kernel::HLERequestContext& ctx) {
529 LOG_DEBUG(Service_NS, "called");
530
467 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 531 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
468 rb.Push(RESULT_SUCCESS); 532 rb.Push(RESULT_SUCCESS);
469 rb.PushIpcInterface<ISystemUpdateControl>(); 533 rb.PushIpcInterface<ISystemUpdateControl>();
470
471 LOG_DEBUG(Service_NS, "called");
472 } 534 }
473}; 535};
474 536
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index 44accecb7..ad176f89d 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -281,6 +281,7 @@ void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) {
281 const u32 shared_font_type{rp.Pop<u32>()}; 281 const u32 shared_font_type{rp.Pop<u32>()};
282 // Games don't call this so all fonts should be loaded 282 // Games don't call this so all fonts should be loaded
283 LOG_DEBUG(Service_NS, "called, shared_font_type={}", shared_font_type); 283 LOG_DEBUG(Service_NS, "called, shared_font_type={}", shared_font_type);
284
284 IPC::ResponseBuilder rb{ctx, 2}; 285 IPC::ResponseBuilder rb{ctx, 2};
285 rb.Push(RESULT_SUCCESS); 286 rb.Push(RESULT_SUCCESS);
286} 287}
@@ -288,8 +289,8 @@ void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) {
288void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) { 289void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) {
289 IPC::RequestParser rp{ctx}; 290 IPC::RequestParser rp{ctx};
290 const u32 font_id{rp.Pop<u32>()}; 291 const u32 font_id{rp.Pop<u32>()};
291
292 LOG_DEBUG(Service_NS, "called, font_id={}", font_id); 292 LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
293
293 IPC::ResponseBuilder rb{ctx, 3}; 294 IPC::ResponseBuilder rb{ctx, 3};
294 rb.Push(RESULT_SUCCESS); 295 rb.Push(RESULT_SUCCESS);
295 rb.Push<u32>(static_cast<u32>(LoadState::Done)); 296 rb.Push<u32>(static_cast<u32>(LoadState::Done));
@@ -298,8 +299,8 @@ void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) {
298void PL_U::GetSize(Kernel::HLERequestContext& ctx) { 299void PL_U::GetSize(Kernel::HLERequestContext& ctx) {
299 IPC::RequestParser rp{ctx}; 300 IPC::RequestParser rp{ctx};
300 const u32 font_id{rp.Pop<u32>()}; 301 const u32 font_id{rp.Pop<u32>()};
301
302 LOG_DEBUG(Service_NS, "called, font_id={}", font_id); 302 LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
303
303 IPC::ResponseBuilder rb{ctx, 3}; 304 IPC::ResponseBuilder rb{ctx, 3};
304 rb.Push(RESULT_SUCCESS); 305 rb.Push(RESULT_SUCCESS);
305 rb.Push<u32>(impl->GetSharedFontRegion(font_id).size); 306 rb.Push<u32>(impl->GetSharedFontRegion(font_id).size);
@@ -308,8 +309,8 @@ void PL_U::GetSize(Kernel::HLERequestContext& ctx) {
308void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { 309void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
309 IPC::RequestParser rp{ctx}; 310 IPC::RequestParser rp{ctx};
310 const u32 font_id{rp.Pop<u32>()}; 311 const u32 font_id{rp.Pop<u32>()};
311
312 LOG_DEBUG(Service_NS, "called, font_id={}", font_id); 312 LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
313
313 IPC::ResponseBuilder rb{ctx, 3}; 314 IPC::ResponseBuilder rb{ctx, 3};
314 rb.Push(RESULT_SUCCESS); 315 rb.Push(RESULT_SUCCESS);
315 rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset); 316 rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset);
@@ -317,6 +318,7 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
317 318
318void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { 319void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
319 // Map backing memory for the font data 320 // Map backing memory for the font data
321 LOG_DEBUG(Service_NS, "called");
320 Core::CurrentProcess()->VMManager().MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0, 322 Core::CurrentProcess()->VMManager().MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0,
321 SHARED_FONT_MEM_SIZE, 323 SHARED_FONT_MEM_SIZE,
322 Kernel::MemoryState::Shared); 324 Kernel::MemoryState::Shared);
@@ -328,7 +330,6 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
328 Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, 330 Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE,
329 "PL_U:shared_font_mem"); 331 "PL_U:shared_font_mem");
330 332
331 LOG_DEBUG(Service_NS, "called");
332 IPC::ResponseBuilder rb{ctx, 2, 1}; 333 IPC::ResponseBuilder rb{ctx, 2, 1};
333 rb.Push(RESULT_SUCCESS); 334 rb.Push(RESULT_SUCCESS);
334 rb.PushCopyObjects(impl->shared_font_mem); 335 rb.PushCopyObjects(impl->shared_font_mem);
@@ -338,6 +339,7 @@ void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) {
338 IPC::RequestParser rp{ctx}; 339 IPC::RequestParser rp{ctx};
339 const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for 340 const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for
340 LOG_DEBUG(Service_NS, "called, language_code={:X}", language_code); 341 LOG_DEBUG(Service_NS, "called, language_code={:X}", language_code);
342
341 IPC::ResponseBuilder rb{ctx, 4}; 343 IPC::ResponseBuilder rb{ctx, 4};
342 std::vector<u32> font_codes; 344 std::vector<u32> font_codes;
343 std::vector<u32> font_offsets; 345 std::vector<u32> font_offsets;
@@ -351,6 +353,14 @@ void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) {
351 font_sizes.push_back(region.size); 353 font_sizes.push_back(region.size);
352 } 354 }
353 355
356 // Resize buffers if game requests smaller size output.
357 font_codes.resize(
358 std::min<std::size_t>(font_codes.size(), ctx.GetWriteBufferSize(0) / sizeof(u32)));
359 font_offsets.resize(
360 std::min<std::size_t>(font_offsets.size(), ctx.GetWriteBufferSize(1) / sizeof(u32)));
361 font_sizes.resize(
362 std::min<std::size_t>(font_sizes.size(), ctx.GetWriteBufferSize(2) / sizeof(u32)));
363
354 ctx.WriteBuffer(font_codes, 0); 364 ctx.WriteBuffer(font_codes, 0);
355 ctx.WriteBuffer(font_offsets, 1); 365 ctx.WriteBuffer(font_offsets, 1);
356 ctx.WriteBuffer(font_sizes, 2); 366 ctx.WriteBuffer(font_sizes, 2);
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 c41ef7058..466db7ccd 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -54,6 +54,7 @@ u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& ou
54 IoctlInitalizeEx params{}; 54 IoctlInitalizeEx params{};
55 std::memcpy(&params, input.data(), input.size()); 55 std::memcpy(&params, input.data(), input.size());
56 LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); 56 LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size);
57
57 return 0; 58 return 0;
58} 59}
59 60
@@ -191,6 +192,7 @@ u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& ou
191 IoctlBindChannel params{}; 192 IoctlBindChannel params{};
192 std::memcpy(&params, input.data(), input.size()); 193 std::memcpy(&params, input.data(), input.size());
193 LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); 194 LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
195
194 channel = params.fd; 196 channel = params.fd;
195 return 0; 197 return 0;
196} 198}
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index 7a88ae029..d57a54ee8 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -5,6 +5,8 @@
5#include <cstring> 5#include <cstring>
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/core_timing.h"
9#include "core/core_timing_util.h"
8#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" 10#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
9 11
10namespace Service::Nvidia::Devices { 12namespace Service::Nvidia::Devices {
@@ -33,6 +35,8 @@ u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vec
33 return ZBCQueryTable(input, output); 35 return ZBCQueryTable(input, output);
34 case IoctlCommand::IocFlushL2: 36 case IoctlCommand::IocFlushL2:
35 return FlushL2(input, output); 37 return FlushL2(input, output);
38 case IoctlCommand::IocGetGpuTime:
39 return GetGpuTime(input, output);
36 } 40 }
37 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 41 UNIMPLEMENTED_MSG("Unimplemented ioctl");
38 return 0; 42 return 0;
@@ -99,6 +103,7 @@ u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>&
99 103
100u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { 104u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) {
101 LOG_DEBUG(Service_NVDRV, "called"); 105 LOG_DEBUG(Service_NVDRV, "called");
106
102 IoctlActiveSlotMask params{}; 107 IoctlActiveSlotMask params{};
103 if (input.size() > 0) { 108 if (input.size() > 0) {
104 std::memcpy(&params, input.data(), input.size()); 109 std::memcpy(&params, input.data(), input.size());
@@ -111,6 +116,7 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector
111 116
112u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { 117u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) {
113 LOG_DEBUG(Service_NVDRV, "called"); 118 LOG_DEBUG(Service_NVDRV, "called");
119
114 IoctlZcullGetCtxSize params{}; 120 IoctlZcullGetCtxSize params{};
115 if (input.size() > 0) { 121 if (input.size() > 0) {
116 std::memcpy(&params, input.data(), input.size()); 122 std::memcpy(&params, input.data(), input.size());
@@ -122,6 +128,7 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u
122 128
123u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { 129u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) {
124 LOG_DEBUG(Service_NVDRV, "called"); 130 LOG_DEBUG(Service_NVDRV, "called");
131
125 IoctlNvgpuGpuZcullGetInfoArgs params{}; 132 IoctlNvgpuGpuZcullGetInfoArgs params{};
126 133
127 if (input.size() > 0) { 134 if (input.size() > 0) {
@@ -144,6 +151,7 @@ u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>&
144 151
145u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { 152u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) {
146 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 153 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
154
147 IoctlZbcSetTable params{}; 155 IoctlZbcSetTable params{};
148 std::memcpy(&params, input.data(), input.size()); 156 std::memcpy(&params, input.data(), input.size());
149 // TODO(ogniK): What does this even actually do? 157 // TODO(ogniK): What does this even actually do?
@@ -153,6 +161,7 @@ u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>&
153 161
154u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { 162u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) {
155 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 163 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
164
156 IoctlZbcQueryTable params{}; 165 IoctlZbcQueryTable params{};
157 std::memcpy(&params, input.data(), input.size()); 166 std::memcpy(&params, input.data(), input.size());
158 // TODO : To implement properly 167 // TODO : To implement properly
@@ -162,6 +171,7 @@ u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>
162 171
163u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { 172u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) {
164 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 173 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
174
165 IoctlFlushL2 params{}; 175 IoctlFlushL2 params{};
166 std::memcpy(&params, input.data(), input.size()); 176 std::memcpy(&params, input.data(), input.size());
167 // TODO : To implement properly 177 // TODO : To implement properly
@@ -169,4 +179,14 @@ u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& outp
169 return 0; 179 return 0;
170} 180}
171 181
182u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) {
183 LOG_DEBUG(Service_NVDRV, "called");
184
185 IoctlGetGpuTime params{};
186 std::memcpy(&params, input.data(), input.size());
187 params.gpu_time = CoreTiming::cyclesToNs(CoreTiming::GetTicks());
188 std::memcpy(output.data(), &params, output.size());
189 return 0;
190}
191
172} // namespace Service::Nvidia::Devices 192} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
index 3bbf028ad..240435eea 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
@@ -156,6 +156,11 @@ private:
156 }; 156 };
157 static_assert(sizeof(IoctlFlushL2) == 8, "IoctlFlushL2 is incorrect size"); 157 static_assert(sizeof(IoctlFlushL2) == 8, "IoctlFlushL2 is incorrect size");
158 158
159 struct IoctlGetGpuTime {
160 u64_le gpu_time;
161 };
162 static_assert(sizeof(IoctlGetGpuTime) == 8, "IoctlGetGpuTime is incorrect size");
163
159 u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output); 164 u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output);
160 u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output); 165 u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output);
161 u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); 166 u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output);
@@ -164,6 +169,7 @@ private:
164 u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); 169 u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output);
165 u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); 170 u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output);
166 u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output); 171 u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output);
172 u32 GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output);
167}; 173};
168 174
169} // namespace Service::Nvidia::Devices 175} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index 874d5e1c3..3bfce0110 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -8,7 +8,6 @@
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/service/nvdrv/devices/nvhost_gpu.h" 9#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
10#include "core/memory.h" 10#include "core/memory.h"
11#include "video_core/command_processor.h"
12#include "video_core/gpu.h" 11#include "video_core/gpu.h"
13#include "video_core/memory_manager.h" 12#include "video_core/memory_manager.h"
14 13
@@ -61,12 +60,14 @@ u32 nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output
61 IoctlSetNvmapFD params{}; 60 IoctlSetNvmapFD params{};
62 std::memcpy(&params, input.data(), input.size()); 61 std::memcpy(&params, input.data(), input.size());
63 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 62 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
63
64 nvmap_fd = params.nvmap_fd; 64 nvmap_fd = params.nvmap_fd;
65 return 0; 65 return 0;
66} 66}
67 67
68u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { 68u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
69 LOG_DEBUG(Service_NVDRV, "called"); 69 LOG_DEBUG(Service_NVDRV, "called");
70
70 IoctlClientData params{}; 71 IoctlClientData params{};
71 std::memcpy(&params, input.data(), input.size()); 72 std::memcpy(&params, input.data(), input.size());
72 user_data = params.data; 73 user_data = params.data;
@@ -75,6 +76,7 @@ u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& out
75 76
76u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { 77u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
77 LOG_DEBUG(Service_NVDRV, "called"); 78 LOG_DEBUG(Service_NVDRV, "called");
79
78 IoctlClientData params{}; 80 IoctlClientData params{};
79 std::memcpy(&params, input.data(), input.size()); 81 std::memcpy(&params, input.data(), input.size());
80 params.data = user_data; 82 params.data = user_data;
@@ -86,6 +88,7 @@ u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output)
86 std::memcpy(&zcull_params, input.data(), input.size()); 88 std::memcpy(&zcull_params, input.data(), input.size());
87 LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, 89 LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va,
88 zcull_params.mode); 90 zcull_params.mode);
91
89 std::memcpy(output.data(), &zcull_params, output.size()); 92 std::memcpy(output.data(), &zcull_params, output.size());
90 return 0; 93 return 0;
91} 94}
@@ -95,6 +98,7 @@ u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>&
95 std::memcpy(&params, input.data(), input.size()); 98 std::memcpy(&params, input.data(), input.size());
96 LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, 99 LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,
97 params.size, params.mem); 100 params.size, params.mem);
101
98 std::memcpy(output.data(), &params, output.size()); 102 std::memcpy(output.data(), &params, output.size());
99 return 0; 103 return 0;
100} 104}
@@ -102,6 +106,7 @@ u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>&
102u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { 106u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) {
103 std::memcpy(&channel_priority, input.data(), input.size()); 107 std::memcpy(&channel_priority, input.data(), input.size());
104 LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); 108 LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority);
109
105 return 0; 110 return 0;
106} 111}
107 112
@@ -113,6 +118,7 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou
113 "unk1={:X}, unk2={:X}, unk3={:X}", 118 "unk1={:X}, unk2={:X}, unk3={:X}",
114 params.num_entries, params.flags, params.unk0, params.unk1, params.unk2, 119 params.num_entries, params.flags, params.unk0, params.unk1, params.unk2,
115 params.unk3); 120 params.unk3);
121
116 params.fence_out.id = 0; 122 params.fence_out.id = 0;
117 params.fence_out.value = 0; 123 params.fence_out.value = 0;
118 std::memcpy(output.data(), &params, output.size()); 124 std::memcpy(output.data(), &params, output.size());
@@ -124,11 +130,18 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<
124 std::memcpy(&params, input.data(), input.size()); 130 std::memcpy(&params, input.data(), input.size());
125 LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, 131 LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num,
126 params.flags); 132 params.flags);
133
127 params.obj_id = 0x0; 134 params.obj_id = 0x0;
128 std::memcpy(output.data(), &params, output.size()); 135 std::memcpy(output.data(), &params, output.size());
129 return 0; 136 return 0;
130} 137}
131 138
139static void PushGPUEntries(Tegra::CommandList&& entries) {
140 auto& dma_pusher{Core::System::GetInstance().GPU().DmaPusher()};
141 dma_pusher.Push(std::move(entries));
142 dma_pusher.DispatchCalls();
143}
144
132u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { 145u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) {
133 if (input.size() < sizeof(IoctlSubmitGpfifo)) { 146 if (input.size() < sizeof(IoctlSubmitGpfifo)) {
134 UNIMPLEMENTED(); 147 UNIMPLEMENTED();
@@ -142,11 +155,11 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp
142 params.num_entries * sizeof(Tegra::CommandListHeader), 155 params.num_entries * sizeof(Tegra::CommandListHeader),
143 "Incorrect input size"); 156 "Incorrect input size");
144 157
145 std::vector<Tegra::CommandListHeader> entries(params.num_entries); 158 Tegra::CommandList entries(params.num_entries);
146 std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)], 159 std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)],
147 params.num_entries * sizeof(Tegra::CommandListHeader)); 160 params.num_entries * sizeof(Tegra::CommandListHeader));
148 161
149 Core::System::GetInstance().GPU().ProcessCommandLists(entries); 162 PushGPUEntries(std::move(entries));
150 163
151 params.fence_out.id = 0; 164 params.fence_out.id = 0;
152 params.fence_out.value = 0; 165 params.fence_out.value = 0;
@@ -163,11 +176,11 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output)
163 LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", 176 LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}",
164 params.address, params.num_entries, params.flags); 177 params.address, params.num_entries, params.flags);
165 178
166 std::vector<Tegra::CommandListHeader> entries(params.num_entries); 179 Tegra::CommandList entries(params.num_entries);
167 Memory::ReadBlock(params.address, entries.data(), 180 Memory::ReadBlock(params.address, entries.data(),
168 params.num_entries * sizeof(Tegra::CommandListHeader)); 181 params.num_entries * sizeof(Tegra::CommandListHeader));
169 182
170 Core::System::GetInstance().GPU().ProcessCommandLists(entries); 183 PushGPUEntries(std::move(entries));
171 184
172 params.fence_out.id = 0; 185 params.fence_out.id = 0;
173 params.fence_out.value = 0; 186 params.fence_out.value = 0;
@@ -179,6 +192,7 @@ u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& outpu
179 IoctlGetWaitbase params{}; 192 IoctlGetWaitbase params{};
180 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase)); 193 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
181 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); 194 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
195
182 params.value = 0; // Seems to be hard coded at 0 196 params.value = 0; // Seems to be hard coded at 0
183 std::memcpy(output.data(), &params, output.size()); 197 std::memcpy(output.data(), &params, output.size());
184 return 0; 198 return 0;
@@ -188,6 +202,7 @@ u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>&
188 IoctlChannelSetTimeout params{}; 202 IoctlChannelSetTimeout params{};
189 std::memcpy(&params, input.data(), sizeof(IoctlChannelSetTimeout)); 203 std::memcpy(&params, input.data(), sizeof(IoctlChannelSetTimeout));
190 LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); 204 LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout);
205
191 return 0; 206 return 0;
192} 207}
193 208
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index 46dbbc37c..f5e8ea7c3 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -30,6 +30,7 @@ u32 nvhost_nvdec::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& outp
30 IoctlSetNvmapFD params{}; 30 IoctlSetNvmapFD params{};
31 std::memcpy(&params, input.data(), input.size()); 31 std::memcpy(&params, input.data(), input.size());
32 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 32 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
33
33 nvmap_fd = params.nvmap_fd; 34 nvmap_fd = params.nvmap_fd;
34 return 0; 35 return 0;
35} 36}
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
index c67f934f6..3e0951ab0 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
@@ -30,6 +30,7 @@ u32 nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& outp
30 IoctlSetNvmapFD params{}; 30 IoctlSetNvmapFD params{};
31 std::memcpy(&params, input.data(), input.size()); 31 std::memcpy(&params, input.data(), input.size());
32 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 32 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
33
33 nvmap_fd = params.nvmap_fd; 34 nvmap_fd = params.nvmap_fd;
34 return 0; 35 return 0;
35} 36}
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index 727b9fee4..d544f0f31 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -30,6 +30,7 @@ u32 nvhost_vic::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output
30 IoctlSetNvmapFD params{}; 30 IoctlSetNvmapFD params{};
31 std::memcpy(&params, input.data(), input.size()); 31 std::memcpy(&params, input.data(), input.size());
32 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 32 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
33
33 nvmap_fd = params.nvmap_fd; 34 nvmap_fd = params.nvmap_fd;
34 return 0; 35 return 0;
35} 36}
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index 43651d8a6..1ec796fc6 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -54,6 +54,7 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
54 LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); 54 LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size);
55 55
56 if (!params.size) { 56 if (!params.size) {
57 LOG_ERROR(Service_NVDRV, "Size is 0");
57 return static_cast<u32>(NvErrCodes::InvalidValue); 58 return static_cast<u32>(NvErrCodes::InvalidValue);
58 } 59 }
59 // Create a new nvmap object and obtain a handle to it. 60 // Create a new nvmap object and obtain a handle to it.
@@ -78,10 +79,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
78 LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); 79 LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr);
79 80
80 if (!params.handle) { 81 if (!params.handle) {
82 LOG_ERROR(Service_NVDRV, "Handle is 0");
81 return static_cast<u32>(NvErrCodes::InvalidValue); 83 return static_cast<u32>(NvErrCodes::InvalidValue);
82 } 84 }
83 85
84 if ((params.align - 1) & params.align) { 86 if ((params.align - 1) & params.align) {
87 LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align);
85 return static_cast<u32>(NvErrCodes::InvalidValue); 88 return static_cast<u32>(NvErrCodes::InvalidValue);
86 } 89 }
87 90
@@ -92,10 +95,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
92 95
93 auto object = GetObject(params.handle); 96 auto object = GetObject(params.handle);
94 if (!object) { 97 if (!object) {
98 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
95 return static_cast<u32>(NvErrCodes::InvalidValue); 99 return static_cast<u32>(NvErrCodes::InvalidValue);
96 } 100 }
97 101
98 if (object->status == Object::Status::Allocated) { 102 if (object->status == Object::Status::Allocated) {
103 LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle);
99 return static_cast<u32>(NvErrCodes::OperationNotPermitted); 104 return static_cast<u32>(NvErrCodes::OperationNotPermitted);
100 } 105 }
101 106
@@ -116,11 +121,13 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
116 LOG_WARNING(Service_NVDRV, "called"); 121 LOG_WARNING(Service_NVDRV, "called");
117 122
118 if (!params.handle) { 123 if (!params.handle) {
124 LOG_ERROR(Service_NVDRV, "Handle is zero");
119 return static_cast<u32>(NvErrCodes::InvalidValue); 125 return static_cast<u32>(NvErrCodes::InvalidValue);
120 } 126 }
121 127
122 auto object = GetObject(params.handle); 128 auto object = GetObject(params.handle);
123 if (!object) { 129 if (!object) {
130 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
124 return static_cast<u32>(NvErrCodes::OperationNotPermitted); 131 return static_cast<u32>(NvErrCodes::OperationNotPermitted);
125 } 132 }
126 133
@@ -139,11 +146,13 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
139 auto itr = std::find_if(handles.begin(), handles.end(), 146 auto itr = std::find_if(handles.begin(), handles.end(),
140 [&](const auto& entry) { return entry.second->id == params.id; }); 147 [&](const auto& entry) { return entry.second->id == params.id; });
141 if (itr == handles.end()) { 148 if (itr == handles.end()) {
149 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
142 return static_cast<u32>(NvErrCodes::InvalidValue); 150 return static_cast<u32>(NvErrCodes::InvalidValue);
143 } 151 }
144 152
145 auto& object = itr->second; 153 auto& object = itr->second;
146 if (object->status != Object::Status::Allocated) { 154 if (object->status != Object::Status::Allocated) {
155 LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
147 return static_cast<u32>(NvErrCodes::InvalidValue); 156 return static_cast<u32>(NvErrCodes::InvalidValue);
148 } 157 }
149 158
@@ -166,10 +175,12 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
166 175
167 auto object = GetObject(params.handle); 176 auto object = GetObject(params.handle);
168 if (!object) { 177 if (!object) {
178 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
169 return static_cast<u32>(NvErrCodes::InvalidValue); 179 return static_cast<u32>(NvErrCodes::InvalidValue);
170 } 180 }
171 181
172 if (object->status != Object::Status::Allocated) { 182 if (object->status != Object::Status::Allocated) {
183 LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
173 return static_cast<u32>(NvErrCodes::OperationNotPermitted); 184 return static_cast<u32>(NvErrCodes::OperationNotPermitted);
174 } 185 }
175 186
@@ -209,9 +220,14 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
209 220
210 auto itr = handles.find(params.handle); 221 auto itr = handles.find(params.handle);
211 if (itr == handles.end()) { 222 if (itr == handles.end()) {
223 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
212 return static_cast<u32>(NvErrCodes::InvalidValue); 224 return static_cast<u32>(NvErrCodes::InvalidValue);
213 } 225 }
214 if (!itr->second->refcount) { 226 if (!itr->second->refcount) {
227 LOG_ERROR(
228 Service_NVDRV,
229 "There is no references to this object. The object is already freed. handle={:08X}",
230 params.handle);
215 return static_cast<u32>(NvErrCodes::InvalidValue); 231 return static_cast<u32>(NvErrCodes::InvalidValue);
216 } 232 }
217 233
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index ac3859353..3b9ab4b14 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -6,7 +6,9 @@
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/event.h" 9#include "core/hle/kernel/kernel.h"
10#include "core/hle/kernel/readable_event.h"
11#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/nvdrv/interface.h" 12#include "core/hle/service/nvdrv/interface.h"
11#include "core/hle/service/nvdrv/nvdrv.h" 13#include "core/hle/service/nvdrv/nvdrv.h"
12 14
@@ -55,6 +57,7 @@ void NVDRV::Close(Kernel::HLERequestContext& ctx) {
55 57
56void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { 58void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {
57 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 59 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
60
58 IPC::ResponseBuilder rb{ctx, 3}; 61 IPC::ResponseBuilder rb{ctx, 3};
59 rb.Push(RESULT_SUCCESS); 62 rb.Push(RESULT_SUCCESS);
60 rb.Push<u32>(0); 63 rb.Push<u32>(0);
@@ -68,15 +71,15 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
68 71
69 IPC::ResponseBuilder rb{ctx, 3, 1}; 72 IPC::ResponseBuilder rb{ctx, 3, 1};
70 rb.Push(RESULT_SUCCESS); 73 rb.Push(RESULT_SUCCESS);
71 rb.PushCopyObjects(query_event); 74 rb.PushCopyObjects(query_event.readable);
72 rb.Push<u32>(0); 75 rb.Push<u32>(0);
73} 76}
74 77
75void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) { 78void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {
76 IPC::RequestParser rp{ctx}; 79 IPC::RequestParser rp{ctx};
77 pid = rp.Pop<u64>(); 80 pid = rp.Pop<u64>();
78
79 LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid); 81 LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid);
82
80 IPC::ResponseBuilder rb{ctx, 3}; 83 IPC::ResponseBuilder rb{ctx, 3};
81 rb.Push(RESULT_SUCCESS); 84 rb.Push(RESULT_SUCCESS);
82 rb.Push<u32>(0); 85 rb.Push<u32>(0);
@@ -84,6 +87,23 @@ void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) {
84 87
85void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) { 88void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) {
86 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 89 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
90
91 IPC::ResponseBuilder rb{ctx, 2};
92 rb.Push(RESULT_SUCCESS);
93}
94
95void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) {
96 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
97
98 IPC::ResponseBuilder rb{ctx, 2};
99 rb.Push(RESULT_SUCCESS);
100}
101
102void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
103 // According to SwitchBrew, this has no inputs and no outputs, so effectively does nothing on
104 // retail hardware.
105 LOG_DEBUG(Service_NVDRV, "called");
106
87 IPC::ResponseBuilder rb{ctx, 2}; 107 IPC::ResponseBuilder rb{ctx, 2};
88 rb.Push(RESULT_SUCCESS); 108 rb.Push(RESULT_SUCCESS);
89} 109}
@@ -97,10 +117,10 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
97 {3, &NVDRV::Initialize, "Initialize"}, 117 {3, &NVDRV::Initialize, "Initialize"},
98 {4, &NVDRV::QueryEvent, "QueryEvent"}, 118 {4, &NVDRV::QueryEvent, "QueryEvent"},
99 {5, nullptr, "MapSharedMem"}, 119 {5, nullptr, "MapSharedMem"},
100 {6, nullptr, "GetStatus"}, 120 {6, &NVDRV::GetStatus, "GetStatus"},
101 {7, nullptr, "ForceSetClientPID"}, 121 {7, nullptr, "ForceSetClientPID"},
102 {8, &NVDRV::SetClientPID, "SetClientPID"}, 122 {8, &NVDRV::SetClientPID, "SetClientPID"},
103 {9, nullptr, "DumpGraphicsMemoryInfo"}, 123 {9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"},
104 {10, nullptr, "InitializeDevtools"}, 124 {10, nullptr, "InitializeDevtools"},
105 {11, &NVDRV::Ioctl, "Ioctl2"}, 125 {11, &NVDRV::Ioctl, "Ioctl2"},
106 {12, nullptr, "Ioctl3"}, 126 {12, nullptr, "Ioctl3"},
@@ -109,7 +129,8 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
109 RegisterHandlers(functions); 129 RegisterHandlers(functions);
110 130
111 auto& kernel = Core::System::GetInstance().Kernel(); 131 auto& kernel = Core::System::GetInstance().Kernel();
112 query_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "NVDRV::query_event"); 132 query_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
133 "NVDRV::query_event");
113} 134}
114 135
115NVDRV::~NVDRV() = default; 136NVDRV::~NVDRV() = default;
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h
index d340893c2..fe311b069 100644
--- a/src/core/hle/service/nvdrv/interface.h
+++ b/src/core/hle/service/nvdrv/interface.h
@@ -5,10 +5,13 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include "core/hle/kernel/event.h"
9#include "core/hle/service/nvdrv/nvdrv.h" 8#include "core/hle/service/nvdrv/nvdrv.h"
10#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
11 10
11namespace Kernel {
12class WritableEvent;
13}
14
12namespace Service::Nvidia { 15namespace Service::Nvidia {
13 16
14class NVDRV final : public ServiceFramework<NVDRV> { 17class NVDRV final : public ServiceFramework<NVDRV> {
@@ -24,12 +27,14 @@ private:
24 void QueryEvent(Kernel::HLERequestContext& ctx); 27 void QueryEvent(Kernel::HLERequestContext& ctx);
25 void SetClientPID(Kernel::HLERequestContext& ctx); 28 void SetClientPID(Kernel::HLERequestContext& ctx);
26 void FinishInitialize(Kernel::HLERequestContext& ctx); 29 void FinishInitialize(Kernel::HLERequestContext& ctx);
30 void GetStatus(Kernel::HLERequestContext& ctx);
31 void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx);
27 32
28 std::shared_ptr<Module> nvdrv; 33 std::shared_ptr<Module> nvdrv;
29 34
30 u64 pid{}; 35 u64 pid{};
31 36
32 Kernel::SharedPtr<Kernel::Event> query_event; 37 Kernel::EventPair query_event;
33}; 38};
34 39
35} // namespace Service::Nvidia 40} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index 630ebbfc7..fc07d9bb8 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -7,28 +7,31 @@
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/readable_event.h"
12#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/nvflinger/buffer_queue.h" 13#include "core/hle/service/nvflinger/buffer_queue.h"
11 14
12namespace Service::NVFlinger { 15namespace Service::NVFlinger {
13 16
14BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { 17BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
15 auto& kernel = Core::System::GetInstance().Kernel(); 18 auto& kernel = Core::System::GetInstance().Kernel();
16 buffer_wait_event = 19 buffer_wait_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
17 Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "BufferQueue NativeHandle"); 20 "BufferQueue NativeHandle");
18} 21}
19 22
20BufferQueue::~BufferQueue() = default; 23BufferQueue::~BufferQueue() = default;
21 24
22void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) { 25void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) {
26 LOG_WARNING(Service, "Adding graphics buffer {}", slot);
27
23 Buffer buffer{}; 28 Buffer buffer{};
24 buffer.slot = slot; 29 buffer.slot = slot;
25 buffer.igbp_buffer = igbp_buffer; 30 buffer.igbp_buffer = igbp_buffer;
26 buffer.status = Buffer::Status::Free; 31 buffer.status = Buffer::Status::Free;
27 32
28 LOG_WARNING(Service, "Adding graphics buffer {}", slot);
29
30 queue.emplace_back(buffer); 33 queue.emplace_back(buffer);
31 buffer_wait_event->Signal(); 34 buffer_wait_event.writable->Signal();
32} 35}
33 36
34std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) { 37std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
@@ -87,11 +90,12 @@ void BufferQueue::ReleaseBuffer(u32 slot) {
87 ASSERT(itr->status == Buffer::Status::Acquired); 90 ASSERT(itr->status == Buffer::Status::Acquired);
88 itr->status = Buffer::Status::Free; 91 itr->status = Buffer::Status::Free;
89 92
90 buffer_wait_event->Signal(); 93 buffer_wait_event.writable->Signal();
91} 94}
92 95
93u32 BufferQueue::Query(QueryType type) { 96u32 BufferQueue::Query(QueryType type) {
94 LOG_WARNING(Service, "(STUBBED) called type={}", static_cast<u32>(type)); 97 LOG_WARNING(Service, "(STUBBED) called type={}", static_cast<u32>(type));
98
95 switch (type) { 99 switch (type) {
96 case QueryType::NativeWindowFormat: 100 case QueryType::NativeWindowFormat:
97 // TODO(Subv): Use an enum for this 101 // TODO(Subv): Use an enum for this
@@ -103,4 +107,12 @@ u32 BufferQueue::Query(QueryType type) {
103 return 0; 107 return 0;
104} 108}
105 109
110Kernel::SharedPtr<Kernel::WritableEvent> BufferQueue::GetWritableBufferWaitEvent() const {
111 return buffer_wait_event.writable;
112}
113
114Kernel::SharedPtr<Kernel::ReadableEvent> BufferQueue::GetBufferWaitEvent() const {
115 return buffer_wait_event.readable;
116}
117
106} // namespace Service::NVFlinger 118} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 8cff5eb71..b171f256c 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -10,7 +10,8 @@
10#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11#include "common/math_util.h" 11#include "common/math_util.h"
12#include "common/swap.h" 12#include "common/swap.h"
13#include "core/hle/kernel/event.h" 13#include "core/hle/kernel/object.h"
14#include "core/hle/kernel/writable_event.h"
14 15
15namespace CoreTiming { 16namespace CoreTiming {
16struct EventType; 17struct EventType;
@@ -86,16 +87,16 @@ public:
86 return id; 87 return id;
87 } 88 }
88 89
89 Kernel::SharedPtr<Kernel::Event> GetBufferWaitEvent() const { 90 Kernel::SharedPtr<Kernel::WritableEvent> GetWritableBufferWaitEvent() const;
90 return buffer_wait_event; 91
91 } 92 Kernel::SharedPtr<Kernel::ReadableEvent> GetBufferWaitEvent() const;
92 93
93private: 94private:
94 u32 id; 95 u32 id;
95 u64 layer_id; 96 u64 layer_id;
96 97
97 std::vector<Buffer> queue; 98 std::vector<Buffer> queue;
98 Kernel::SharedPtr<Kernel::Event> buffer_wait_event; 99 Kernel::EventPair buffer_wait_event;
99}; 100};
100 101
101} // namespace Service::NVFlinger 102} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 214e6d1b3..05af2d593 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -13,6 +13,9 @@
13#include "core/core.h" 13#include "core/core.h"
14#include "core/core_timing.h" 14#include "core/core_timing.h"
15#include "core/core_timing_util.h" 15#include "core/core_timing_util.h"
16#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/readable_event.h"
18#include "core/hle/kernel/writable_event.h"
16#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" 19#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
17#include "core/hle/service/nvdrv/nvdrv.h" 20#include "core/hle/service/nvdrv/nvdrv.h"
18#include "core/hle/service/nvflinger/buffer_queue.h" 21#include "core/hle/service/nvflinger/buffer_queue.h"
@@ -83,9 +86,8 @@ u32 NVFlinger::GetBufferQueueId(u64 display_id, u64 layer_id) {
83 return layer.buffer_queue->GetId(); 86 return layer.buffer_queue->GetId();
84} 87}
85 88
86Kernel::SharedPtr<Kernel::Event> NVFlinger::GetVsyncEvent(u64 display_id) { 89Kernel::SharedPtr<Kernel::ReadableEvent> NVFlinger::GetVsyncEvent(u64 display_id) {
87 const auto& display = GetDisplay(display_id); 90 return GetDisplay(display_id).vsync_event.readable;
88 return display.vsync_event;
89} 91}
90 92
91std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) const { 93std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) const {
@@ -117,7 +119,7 @@ Layer& NVFlinger::GetLayer(u64 display_id, u64 layer_id) {
117void NVFlinger::Compose() { 119void NVFlinger::Compose() {
118 for (auto& display : displays) { 120 for (auto& display : displays) {
119 // Trigger vsync for this display at the end of drawing 121 // Trigger vsync for this display at the end of drawing
120 SCOPE_EXIT({ display.vsync_event->Signal(); }); 122 SCOPE_EXIT({ display.vsync_event.writable->Signal(); });
121 123
122 // Don't do anything for displays without layers. 124 // Don't do anything for displays without layers.
123 if (display.layers.empty()) 125 if (display.layers.empty())
@@ -164,7 +166,8 @@ Layer::~Layer() = default;
164 166
165Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) { 167Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) {
166 auto& kernel = Core::System::GetInstance().Kernel(); 168 auto& kernel = Core::System::GetInstance().Kernel();
167 vsync_event = Kernel::Event::Create(kernel, Kernel::ResetType::Pulse, "Display VSync Event"); 169 vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Pulse,
170 fmt::format("Display VSync Event {}", id));
168} 171}
169 172
170Display::~Display() = default; 173Display::~Display() = default;
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 3dc69e69b..9abba555b 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -10,12 +10,17 @@
10#include <vector> 10#include <vector>
11 11
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "core/hle/kernel/event.h" 13#include "core/hle/kernel/object.h"
14 14
15namespace CoreTiming { 15namespace CoreTiming {
16struct EventType; 16struct EventType;
17} 17}
18 18
19namespace Kernel {
20class ReadableEvent;
21class WritableEvent;
22} // namespace Kernel
23
19namespace Service::Nvidia { 24namespace Service::Nvidia {
20class Module; 25class Module;
21} 26}
@@ -40,7 +45,7 @@ struct Display {
40 std::string name; 45 std::string name;
41 46
42 std::vector<Layer> layers; 47 std::vector<Layer> layers;
43 Kernel::SharedPtr<Kernel::Event> vsync_event; 48 Kernel::EventPair vsync_event;
44}; 49};
45 50
46class NVFlinger final { 51class NVFlinger final {
@@ -61,7 +66,7 @@ public:
61 u32 GetBufferQueueId(u64 display_id, u64 layer_id); 66 u32 GetBufferQueueId(u64 display_id, u64 layer_id);
62 67
63 /// Gets the vsync event for the specified display. 68 /// Gets the vsync event for the specified display.
64 Kernel::SharedPtr<Kernel::Event> GetVsyncEvent(u64 display_id); 69 Kernel::SharedPtr<Kernel::ReadableEvent> GetVsyncEvent(u64 display_id);
65 70
66 /// Obtains a buffer queue identified by the id. 71 /// Obtains a buffer queue identified by the id.
67 std::shared_ptr<BufferQueue> GetBufferQueue(u32 id) const; 72 std::shared_ptr<BufferQueue> GetBufferQueue(u32 id) const;
diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp
index 4fd185f69..6081f41e1 100644
--- a/src/core/hle/service/pctl/module.cpp
+++ b/src/core/hle/service/pctl/module.cpp
@@ -114,29 +114,33 @@ public:
114private: 114private:
115 void Initialize(Kernel::HLERequestContext& ctx) { 115 void Initialize(Kernel::HLERequestContext& ctx) {
116 LOG_WARNING(Service_PCTL, "(STUBBED) called"); 116 LOG_WARNING(Service_PCTL, "(STUBBED) called");
117
117 IPC::ResponseBuilder rb{ctx, 2, 0, 0}; 118 IPC::ResponseBuilder rb{ctx, 2, 0, 0};
118 rb.Push(RESULT_SUCCESS); 119 rb.Push(RESULT_SUCCESS);
119 } 120 }
120 121
121 void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) { 122 void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) {
122 LOG_WARNING(Service_PCTL, "(STUBBED) called"); 123 LOG_WARNING(Service_PCTL, "(STUBBED) called");
124
123 IPC::ResponseBuilder rb{ctx, 2}; 125 IPC::ResponseBuilder rb{ctx, 2};
124 rb.Push(RESULT_SUCCESS); 126 rb.Push(RESULT_SUCCESS);
125 } 127 }
126}; 128};
127 129
128void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { 130void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
131 LOG_DEBUG(Service_PCTL, "called");
132
129 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 133 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
130 rb.Push(RESULT_SUCCESS); 134 rb.Push(RESULT_SUCCESS);
131 rb.PushIpcInterface<IParentalControlService>(); 135 rb.PushIpcInterface<IParentalControlService>();
132 LOG_DEBUG(Service_PCTL, "called");
133} 136}
134 137
135void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) { 138void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) {
139 LOG_DEBUG(Service_PCTL, "called");
140
136 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 141 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
137 rb.Push(RESULT_SUCCESS); 142 rb.Push(RESULT_SUCCESS);
138 rb.PushIpcInterface<IParentalControlService>(); 143 rb.PushIpcInterface<IParentalControlService>();
139 LOG_DEBUG(Service_PCTL, "called");
140} 144}
141 145
142Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 146Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp
index 6ec35ca60..53e7da9c3 100644
--- a/src/core/hle/service/pm/pm.cpp
+++ b/src/core/hle/service/pm/pm.cpp
@@ -20,11 +20,11 @@ public:
20 20
21private: 21private:
22 void GetBootMode(Kernel::HLERequestContext& ctx) { 22 void GetBootMode(Kernel::HLERequestContext& ctx) {
23 LOG_DEBUG(Service_PM, "called");
24
23 IPC::ResponseBuilder rb{ctx, 3}; 25 IPC::ResponseBuilder rb{ctx, 3};
24 rb.Push(RESULT_SUCCESS); 26 rb.Push(RESULT_SUCCESS);
25 rb.Push<u32>(static_cast<u32>(SystemBootMode::Normal)); // Normal boot mode 27 rb.Push<u32>(static_cast<u32>(SystemBootMode::Normal)); // Normal boot mode
26
27 LOG_DEBUG(Service_PM, "called");
28 } 28 }
29}; 29};
30 30
diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp
index bbad870a2..0ba0a4076 100644
--- a/src/core/hle/service/psc/psc.cpp
+++ b/src/core/hle/service/psc/psc.cpp
@@ -61,11 +61,11 @@ public:
61 61
62private: 62private:
63 void GetPmModule(Kernel::HLERequestContext& ctx) { 63 void GetPmModule(Kernel::HLERequestContext& ctx) {
64 LOG_DEBUG(Service_PSC, "called");
65
64 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 66 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
65 rb.Push(RESULT_SUCCESS); 67 rb.Push(RESULT_SUCCESS);
66 rb.PushIpcInterface<IPmModule>(); 68 rb.PushIpcInterface<IPmModule>();
67
68 LOG_DEBUG(Service_PSC, "called");
69 } 69 }
70}; 70};
71 71
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index a4cf45267..1ec340466 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -80,8 +80,8 @@ namespace Service {
80 * Creates a function string for logging, complete with the name (or header code, depending 80 * Creates a function string for logging, complete with the name (or header code, depending
81 * on what's passed in) the port name, and all the cmd_buff arguments. 81 * on what's passed in) the port name, and all the cmd_buff arguments.
82 */ 82 */
83static std::string MakeFunctionString(const char* name, const char* port_name, 83[[maybe_unused]] static std::string MakeFunctionString(const char* name, const char* port_name,
84 const u32* cmd_buff) { 84 const u32* cmd_buff) {
85 // Number of params == bits 0-5 + bits 6-11 85 // Number of params == bits 0-5 + bits 6-11
86 int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F); 86 int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
87 87
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index 9e5af7839..1afc43f75 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -35,6 +35,8 @@ constexpr std::array<LanguageCode, 17> available_language_codes = {{
35constexpr std::size_t pre4_0_0_max_entries = 0xF; 35constexpr std::size_t pre4_0_0_max_entries = 0xF;
36constexpr std::size_t post4_0_0_max_entries = 0x40; 36constexpr std::size_t post4_0_0_max_entries = 0x40;
37 37
38constexpr ResultCode ERR_INVALID_LANGUAGE{ErrorModule::Settings, 625};
39
38LanguageCode GetLanguageCodeFromIndex(std::size_t index) { 40LanguageCode GetLanguageCodeFromIndex(std::size_t index) {
39 return available_language_codes.at(index); 41 return available_language_codes.at(index);
40} 42}
@@ -49,38 +51,54 @@ static std::array<LanguageCode, size> MakeLanguageCodeSubset() {
49static void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t max_size) { 51static void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t max_size) {
50 IPC::ResponseBuilder rb{ctx, 3}; 52 IPC::ResponseBuilder rb{ctx, 3};
51 rb.Push(RESULT_SUCCESS); 53 rb.Push(RESULT_SUCCESS);
52 if (available_language_codes.size() > max_size) 54 if (available_language_codes.size() > max_size) {
53 rb.Push(static_cast<u32>(max_size)); 55 rb.Push(static_cast<u32>(max_size));
54 else 56 } else {
55 rb.Push(static_cast<u32>(available_language_codes.size())); 57 rb.Push(static_cast<u32>(available_language_codes.size()));
58 }
56} 59}
57 60
58void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { 61void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) {
59 if (available_language_codes.size() > pre4_0_0_max_entries) 62 LOG_DEBUG(Service_SET, "called");
63
64 if (available_language_codes.size() > pre4_0_0_max_entries) {
60 ctx.WriteBuffer(MakeLanguageCodeSubset<pre4_0_0_max_entries>()); 65 ctx.WriteBuffer(MakeLanguageCodeSubset<pre4_0_0_max_entries>());
61 else 66 } else {
62 ctx.WriteBuffer(available_language_codes); 67 ctx.WriteBuffer(available_language_codes);
63 68 }
64 PushResponseLanguageCode(ctx, pre4_0_0_max_entries); 69 PushResponseLanguageCode(ctx, pre4_0_0_max_entries);
70}
65 71
66 LOG_DEBUG(Service_SET, "called"); 72void SET::MakeLanguageCode(Kernel::HLERequestContext& ctx) {
73 IPC::RequestParser rp{ctx};
74 const auto index = rp.Pop<u32>();
75
76 if (index >= available_language_codes.size()) {
77 IPC::ResponseBuilder rb{ctx, 2};
78 rb.Push(ERR_INVALID_LANGUAGE);
79 return;
80 }
81
82 IPC::ResponseBuilder rb{ctx, 4};
83 rb.Push(RESULT_SUCCESS);
84 rb.PushEnum(available_language_codes[index]);
67} 85}
68 86
69void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) { 87void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) {
70 if (available_language_codes.size() > post4_0_0_max_entries) 88 LOG_DEBUG(Service_SET, "called");
89
90 if (available_language_codes.size() > post4_0_0_max_entries) {
71 ctx.WriteBuffer(MakeLanguageCodeSubset<post4_0_0_max_entries>()); 91 ctx.WriteBuffer(MakeLanguageCodeSubset<post4_0_0_max_entries>());
72 else 92 } else {
73 ctx.WriteBuffer(available_language_codes); 93 ctx.WriteBuffer(available_language_codes);
74 94 }
75 PushResponseLanguageCode(ctx, post4_0_0_max_entries); 95 PushResponseLanguageCode(ctx, post4_0_0_max_entries);
76
77 LOG_DEBUG(Service_SET, "called");
78} 96}
79 97
80void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) { 98void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) {
81 PushResponseLanguageCode(ctx, pre4_0_0_max_entries);
82
83 LOG_DEBUG(Service_SET, "called"); 99 LOG_DEBUG(Service_SET, "called");
100
101 PushResponseLanguageCode(ctx, pre4_0_0_max_entries);
84} 102}
85 103
86void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) { 104void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) {
@@ -90,18 +108,18 @@ void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) {
90} 108}
91 109
92void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) { 110void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
111 LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index);
112
93 IPC::ResponseBuilder rb{ctx, 4}; 113 IPC::ResponseBuilder rb{ctx, 4};
94 rb.Push(RESULT_SUCCESS); 114 rb.Push(RESULT_SUCCESS);
95 rb.Push(static_cast<u64>(available_language_codes[Settings::values.language_index])); 115 rb.PushEnum(available_language_codes[Settings::values.language_index]);
96
97 LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index);
98} 116}
99 117
100SET::SET() : ServiceFramework("set") { 118SET::SET() : ServiceFramework("set") {
101 static const FunctionInfo functions[] = { 119 static const FunctionInfo functions[] = {
102 {0, &SET::GetLanguageCode, "GetLanguageCode"}, 120 {0, &SET::GetLanguageCode, "GetLanguageCode"},
103 {1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"}, 121 {1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"},
104 {2, nullptr, "MakeLanguageCode"}, 122 {2, &SET::MakeLanguageCode, "MakeLanguageCode"},
105 {3, &SET::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount"}, 123 {3, &SET::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount"},
106 {4, nullptr, "GetRegionCode"}, 124 {4, nullptr, "GetRegionCode"},
107 {5, &SET::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"}, 125 {5, &SET::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"},
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h
index 266f13e46..31f9cb296 100644
--- a/src/core/hle/service/set/set.h
+++ b/src/core/hle/service/set/set.h
@@ -38,6 +38,7 @@ public:
38private: 38private:
39 void GetLanguageCode(Kernel::HLERequestContext& ctx); 39 void GetLanguageCode(Kernel::HLERequestContext& ctx);
40 void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx); 40 void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx);
41 void MakeLanguageCode(Kernel::HLERequestContext& ctx);
41 void GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx); 42 void GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx);
42 void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx); 43 void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx);
43 void GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx); 44 void GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp
index 41efca31c..c9b4da5b0 100644
--- a/src/core/hle/service/set/set_sys.cpp
+++ b/src/core/hle/service/set/set_sys.cpp
@@ -10,22 +10,22 @@
10namespace Service::Set { 10namespace Service::Set {
11 11
12void SET_SYS::GetColorSetId(Kernel::HLERequestContext& ctx) { 12void SET_SYS::GetColorSetId(Kernel::HLERequestContext& ctx) {
13 LOG_DEBUG(Service_SET, "called");
14
13 IPC::ResponseBuilder rb{ctx, 3}; 15 IPC::ResponseBuilder rb{ctx, 3};
14 16
15 rb.Push(RESULT_SUCCESS); 17 rb.Push(RESULT_SUCCESS);
16 rb.PushEnum(color_set); 18 rb.PushEnum(color_set);
17
18 LOG_DEBUG(Service_SET, "called");
19} 19}
20 20
21void SET_SYS::SetColorSetId(Kernel::HLERequestContext& ctx) { 21void SET_SYS::SetColorSetId(Kernel::HLERequestContext& ctx) {
22 LOG_DEBUG(Service_SET, "called");
23
22 IPC::RequestParser rp{ctx}; 24 IPC::RequestParser rp{ctx};
23 color_set = rp.PopEnum<ColorSet>(); 25 color_set = rp.PopEnum<ColorSet>();
24 26
25 IPC::ResponseBuilder rb{ctx, 2}; 27 IPC::ResponseBuilder rb{ctx, 2};
26 rb.Push(RESULT_SUCCESS); 28 rb.Push(RESULT_SUCCESS);
27
28 LOG_DEBUG(Service_SET, "called");
29} 29}
30 30
31SET_SYS::SET_SYS() : ServiceFramework("set:sys") { 31SET_SYS::SET_SYS() : ServiceFramework("set:sys") {
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp
index 98f6e4111..74da4d5e6 100644
--- a/src/core/hle/service/sm/controller.cpp
+++ b/src/core/hle/service/sm/controller.cpp
@@ -14,25 +14,26 @@ namespace Service::SM {
14 14
15void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) { 15void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) {
16 ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain"); 16 ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain");
17 LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId());
17 ctx.Session()->ConvertToDomain(); 18 ctx.Session()->ConvertToDomain();
18 19
19 IPC::ResponseBuilder rb{ctx, 3}; 20 IPC::ResponseBuilder rb{ctx, 3};
20 rb.Push(RESULT_SUCCESS); 21 rb.Push(RESULT_SUCCESS);
21 rb.Push<u32>(1); // Converted sessions start with 1 request handler 22 rb.Push<u32>(1); // Converted sessions start with 1 request handler
22
23 LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId());
24} 23}
25 24
26void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { 25void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) {
27 // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong 26 // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong
28 // and that we probably want to actually make an entirely new Session, but we still need to 27 // and that we probably want to actually make an entirely new Session, but we still need to
29 // verify this on hardware. 28 // verify this on hardware.
29 LOG_DEBUG(Service, "called");
30
30 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; 31 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
31 rb.Push(RESULT_SUCCESS); 32 rb.Push(RESULT_SUCCESS);
32 Kernel::SharedPtr<Kernel::ClientSession> session{ctx.Session()->parent->client}; 33 Kernel::SharedPtr<Kernel::ClientSession> session{ctx.Session()->parent->client};
33 rb.PushMoveObjects(session); 34 rb.PushMoveObjects(session);
34 35
35 LOG_DEBUG(Service, "called, session={}", session->GetObjectId()); 36 LOG_DEBUG(Service, "session={}", session->GetObjectId());
36} 37}
37 38
38void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) { 39void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {
@@ -42,11 +43,11 @@ void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {
42} 43}
43 44
44void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { 45void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) {
46 LOG_WARNING(Service, "(STUBBED) called");
47
45 IPC::ResponseBuilder rb{ctx, 3}; 48 IPC::ResponseBuilder rb{ctx, 3};
46 rb.Push(RESULT_SUCCESS); 49 rb.Push(RESULT_SUCCESS);
47 rb.Push<u16>(0x500); 50 rb.Push<u16>(0x500);
48
49 LOG_WARNING(Service, "(STUBBED) called");
50} 51}
51 52
52Controller::Controller() : ServiceFramework("IpcController") { 53Controller::Controller() : ServiceFramework("IpcController") {
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 464e79d01..0d0f63a78 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -63,6 +63,17 @@ ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService
63 return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port)); 63 return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port));
64} 64}
65 65
66ResultCode ServiceManager::UnregisterService(const std::string& name) {
67 CASCADE_CODE(ValidateServiceName(name));
68
69 const auto iter = registered_services.find(name);
70 if (iter == registered_services.end())
71 return ERR_SERVICE_NOT_REGISTERED;
72
73 registered_services.erase(iter);
74 return RESULT_SUCCESS;
75}
76
66ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort( 77ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort(
67 const std::string& name) { 78 const std::string& name) {
68 79
@@ -92,9 +103,10 @@ SM::~SM() = default;
92 * 0: ResultCode 103 * 0: ResultCode
93 */ 104 */
94void SM::Initialize(Kernel::HLERequestContext& ctx) { 105void SM::Initialize(Kernel::HLERequestContext& ctx) {
106 LOG_DEBUG(Service_SM, "called");
107
95 IPC::ResponseBuilder rb{ctx, 2}; 108 IPC::ResponseBuilder rb{ctx, 2};
96 rb.Push(RESULT_SUCCESS); 109 rb.Push(RESULT_SUCCESS);
97 LOG_DEBUG(Service_SM, "called");
98} 110}
99 111
100void SM::GetService(Kernel::HLERequestContext& ctx) { 112void SM::GetService(Kernel::HLERequestContext& ctx) {
@@ -127,13 +139,53 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
127 } 139 }
128} 140}
129 141
142void SM::RegisterService(Kernel::HLERequestContext& ctx) {
143 IPC::RequestParser rp{ctx};
144
145 const auto name_buf = rp.PopRaw<std::array<char, 8>>();
146 const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
147
148 const std::string name(name_buf.begin(), end);
149
150 const auto unk_bool = static_cast<bool>(rp.PopRaw<u32>());
151 const auto session_count = rp.PopRaw<u32>();
152
153 LOG_DEBUG(Service_SM, "called with unk_bool={}", unk_bool);
154
155 auto handle = service_manager->RegisterService(name, session_count);
156 if (handle.Failed()) {
157 LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}",
158 handle.Code().raw);
159 IPC::ResponseBuilder rb{ctx, 2};
160 rb.Push(handle.Code());
161 return;
162 }
163
164 IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
165 rb.Push(handle.Code());
166 rb.PushMoveObjects(std::move(handle).Unwrap());
167}
168
169void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
170 IPC::RequestParser rp{ctx};
171
172 const auto name_buf = rp.PopRaw<std::array<char, 8>>();
173 const auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
174
175 const std::string name(name_buf.begin(), end);
176 LOG_DEBUG(Service_SM, "called with name={}", name);
177
178 IPC::ResponseBuilder rb{ctx, 2};
179 rb.Push(service_manager->UnregisterService(name));
180}
181
130SM::SM(std::shared_ptr<ServiceManager> service_manager) 182SM::SM(std::shared_ptr<ServiceManager> service_manager)
131 : ServiceFramework("sm:", 4), service_manager(std::move(service_manager)) { 183 : ServiceFramework("sm:", 4), service_manager(std::move(service_manager)) {
132 static const FunctionInfo functions[] = { 184 static const FunctionInfo functions[] = {
133 {0x00000000, &SM::Initialize, "Initialize"}, 185 {0x00000000, &SM::Initialize, "Initialize"},
134 {0x00000001, &SM::GetService, "GetService"}, 186 {0x00000001, &SM::GetService, "GetService"},
135 {0x00000002, nullptr, "RegisterService"}, 187 {0x00000002, &SM::RegisterService, "RegisterService"},
136 {0x00000003, nullptr, "UnregisterService"}, 188 {0x00000003, &SM::UnregisterService, "UnregisterService"},
137 }; 189 };
138 RegisterHandlers(functions); 190 RegisterHandlers(functions);
139} 191}
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index 4f8145dda..bef25433e 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -35,6 +35,8 @@ public:
35private: 35private:
36 void Initialize(Kernel::HLERequestContext& ctx); 36 void Initialize(Kernel::HLERequestContext& ctx);
37 void GetService(Kernel::HLERequestContext& ctx); 37 void GetService(Kernel::HLERequestContext& ctx);
38 void RegisterService(Kernel::HLERequestContext& ctx);
39 void UnregisterService(Kernel::HLERequestContext& ctx);
38 40
39 std::shared_ptr<ServiceManager> service_manager; 41 std::shared_ptr<ServiceManager> service_manager;
40}; 42};
@@ -48,6 +50,7 @@ public:
48 50
49 ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name, 51 ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name,
50 unsigned int max_sessions); 52 unsigned int max_sessions);
53 ResultCode UnregisterService(const std::string& name);
51 ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name); 54 ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name);
52 ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name); 55 ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name);
53 56
diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp
index 44a6717d0..8db0c2f13 100644
--- a/src/core/hle/service/spl/module.cpp
+++ b/src/core/hle/service/spl/module.cpp
@@ -3,34 +3,41 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <chrono>
6#include <cstdlib> 7#include <cstdlib>
8#include <ctime>
9#include <functional>
7#include <vector> 10#include <vector>
8#include "common/logging/log.h" 11#include "common/logging/log.h"
9#include "core/hle/ipc_helpers.h" 12#include "core/hle/ipc_helpers.h"
10#include "core/hle/service/spl/csrng.h" 13#include "core/hle/service/spl/csrng.h"
11#include "core/hle/service/spl/module.h" 14#include "core/hle/service/spl/module.h"
12#include "core/hle/service/spl/spl.h" 15#include "core/hle/service/spl/spl.h"
16#include "core/settings.h"
13 17
14namespace Service::SPL { 18namespace Service::SPL {
15 19
16Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 20Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
17 : ServiceFramework(name), module(std::move(module)) {} 21 : ServiceFramework(name), module(std::move(module)),
22 rng(Settings::values.rng_seed.value_or(std::time(nullptr))) {}
18 23
19Module::Interface::~Interface() = default; 24Module::Interface::~Interface() = default;
20 25
21void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { 26void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) {
27 LOG_DEBUG(Service_SPL, "called");
28
22 IPC::RequestParser rp{ctx}; 29 IPC::RequestParser rp{ctx};
23 30
24 std::size_t size = ctx.GetWriteBufferSize(); 31 std::size_t size = ctx.GetWriteBufferSize();
25 32
33 std::uniform_int_distribution<u16> distribution(0, std::numeric_limits<u8>::max());
26 std::vector<u8> data(size); 34 std::vector<u8> data(size);
27 std::generate(data.begin(), data.end(), std::rand); 35 std::generate(data.begin(), data.end(), [&] { return static_cast<u8>(distribution(rng)); });
28 36
29 ctx.WriteBuffer(data); 37 ctx.WriteBuffer(data);
30 38
31 IPC::ResponseBuilder rb{ctx, 2}; 39 IPC::ResponseBuilder rb{ctx, 2};
32 rb.Push(RESULT_SUCCESS); 40 rb.Push(RESULT_SUCCESS);
33 LOG_DEBUG(Service_SPL, "called");
34} 41}
35 42
36void InstallInterfaces(SM::ServiceManager& service_manager) { 43void InstallInterfaces(SM::ServiceManager& service_manager) {
diff --git a/src/core/hle/service/spl/module.h b/src/core/hle/service/spl/module.h
index 48fda6099..afa1f0295 100644
--- a/src/core/hle/service/spl/module.h
+++ b/src/core/hle/service/spl/module.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <random>
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8 9
9namespace Service::SPL { 10namespace Service::SPL {
@@ -19,6 +20,9 @@ public:
19 20
20 protected: 21 protected:
21 std::shared_ptr<Module> module; 22 std::shared_ptr<Module> module;
23
24 private:
25 std::mt19937 rng;
22 }; 26 };
23}; 27};
24 28
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index bc4f7a437..af40a1815 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -69,6 +69,7 @@ public:
69private: 69private:
70 void SetOption(Kernel::HLERequestContext& ctx) { 70 void SetOption(Kernel::HLERequestContext& ctx) {
71 LOG_WARNING(Service_SSL, "(STUBBED) called"); 71 LOG_WARNING(Service_SSL, "(STUBBED) called");
72
72 IPC::RequestParser rp{ctx}; 73 IPC::RequestParser rp{ctx};
73 74
74 IPC::ResponseBuilder rb{ctx, 2}; 75 IPC::ResponseBuilder rb{ctx, 2};
@@ -114,6 +115,7 @@ private:
114 115
115 void SetInterfaceVersion(Kernel::HLERequestContext& ctx) { 116 void SetInterfaceVersion(Kernel::HLERequestContext& ctx) {
116 LOG_DEBUG(Service_SSL, "called"); 117 LOG_DEBUG(Service_SSL, "called");
118
117 IPC::RequestParser rp{ctx}; 119 IPC::RequestParser rp{ctx};
118 ssl_version = rp.Pop<u32>(); 120 ssl_version = rp.Pop<u32>();
119 121
diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp
index 18a5d71d5..b3a196f65 100644
--- a/src/core/hle/service/time/interface.cpp
+++ b/src/core/hle/service/time/interface.cpp
@@ -21,9 +21,10 @@ Time::Time(std::shared_ptr<Module> time, const char* name)
21 {102, nullptr, "GetStandardUserSystemClockInitialYear"}, 21 {102, nullptr, "GetStandardUserSystemClockInitialYear"},
22 {200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"}, 22 {200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"},
23 {300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"}, 23 {300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"},
24 {400, nullptr, "GetClockSnapshot"}, 24 {400, &Time::GetClockSnapshot, "GetClockSnapshot"},
25 {401, nullptr, "GetClockSnapshotFromSystemClockContext"}, 25 {401, nullptr, "GetClockSnapshotFromSystemClockContext"},
26 {500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"}, 26 {500, &Time::CalculateStandardUserSystemClockDifferenceByUser,
27 "CalculateStandardUserSystemClockDifferenceByUser"},
27 {501, nullptr, "CalculateSpanBetween"}, 28 {501, nullptr, "CalculateSpanBetween"},
28 }; 29 };
29 RegisterHandlers(functions); 30 RegisterHandlers(functions);
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 28fd8debc..60b201d06 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -15,6 +15,44 @@
15 15
16namespace Service::Time { 16namespace Service::Time {
17 17
18static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time,
19 CalendarAdditionalInfo& additional_info,
20 [[maybe_unused]] const TimeZoneRule& /*rule*/) {
21 const std::time_t time(posix_time);
22 const std::tm* tm = std::localtime(&time);
23 if (tm == nullptr) {
24 calendar_time = {};
25 additional_info = {};
26 return;
27 }
28 calendar_time.year = tm->tm_year + 1900;
29 calendar_time.month = tm->tm_mon + 1;
30 calendar_time.day = tm->tm_mday;
31 calendar_time.hour = tm->tm_hour;
32 calendar_time.minute = tm->tm_min;
33 calendar_time.second = tm->tm_sec;
34
35 additional_info.day_of_week = tm->tm_wday;
36 additional_info.day_of_year = tm->tm_yday;
37 std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC"));
38 additional_info.utc_offset = 0;
39}
40
41static u64 CalendarToPosix(const CalendarTime& calendar_time,
42 [[maybe_unused]] const TimeZoneRule& /*rule*/) {
43 std::tm time{};
44 time.tm_year = calendar_time.year - 1900;
45 time.tm_mon = calendar_time.month - 1;
46 time.tm_mday = calendar_time.day;
47
48 time.tm_hour = calendar_time.hour;
49 time.tm_min = calendar_time.minute;
50 time.tm_sec = calendar_time.second;
51
52 std::time_t epoch_time = std::mktime(&time);
53 return static_cast<u64>(epoch_time);
54}
55
18class ISystemClock final : public ServiceFramework<ISystemClock> { 56class ISystemClock final : public ServiceFramework<ISystemClock> {
19public: 57public:
20 ISystemClock() : ServiceFramework("ISystemClock") { 58 ISystemClock() : ServiceFramework("ISystemClock") {
@@ -34,6 +72,7 @@ private:
34 std::chrono::system_clock::now().time_since_epoch()) 72 std::chrono::system_clock::now().time_since_epoch())
35 .count()}; 73 .count()};
36 LOG_DEBUG(Service_Time, "called"); 74 LOG_DEBUG(Service_Time, "called");
75
37 IPC::ResponseBuilder rb{ctx, 4}; 76 IPC::ResponseBuilder rb{ctx, 4};
38 rb.Push(RESULT_SUCCESS); 77 rb.Push(RESULT_SUCCESS);
39 rb.Push<u64>(time_since_epoch); 78 rb.Push<u64>(time_since_epoch);
@@ -41,6 +80,7 @@ private:
41 80
42 void GetSystemClockContext(Kernel::HLERequestContext& ctx) { 81 void GetSystemClockContext(Kernel::HLERequestContext& ctx) {
43 LOG_WARNING(Service_Time, "(STUBBED) called"); 82 LOG_WARNING(Service_Time, "(STUBBED) called");
83
44 SystemClockContext system_clock_ontext{}; 84 SystemClockContext system_clock_ontext{};
45 IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2}; 85 IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2};
46 rb.Push(RESULT_SUCCESS); 86 rb.Push(RESULT_SUCCESS);
@@ -60,6 +100,7 @@ public:
60private: 100private:
61 void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) { 101 void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
62 LOG_DEBUG(Service_Time, "called"); 102 LOG_DEBUG(Service_Time, "called");
103
63 SteadyClockTimePoint steady_clock_time_point{ 104 SteadyClockTimePoint steady_clock_time_point{
64 CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000}; 105 CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000};
65 IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2}; 106 IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2};
@@ -80,8 +121,8 @@ public:
80 {5, nullptr, "GetTimeZoneRuleVersion"}, 121 {5, nullptr, "GetTimeZoneRuleVersion"},
81 {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"}, 122 {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
82 {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, 123 {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
83 {201, nullptr, "ToPosixTime"}, 124 {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"},
84 {202, nullptr, "ToPosixTimeWithMyRule"}, 125 {202, &ITimeZoneService::ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"},
85 }; 126 };
86 RegisterHandlers(functions); 127 RegisterHandlers(functions);
87 } 128 }
@@ -92,6 +133,7 @@ private:
92 133
93 void GetDeviceLocationName(Kernel::HLERequestContext& ctx) { 134 void GetDeviceLocationName(Kernel::HLERequestContext& ctx) {
94 LOG_DEBUG(Service_Time, "called"); 135 LOG_DEBUG(Service_Time, "called");
136
95 IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2}; 137 IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2};
96 rb.Push(RESULT_SUCCESS); 138 rb.Push(RESULT_SUCCESS);
97 rb.PushRaw(location_name); 139 rb.PushRaw(location_name);
@@ -99,6 +141,7 @@ private:
99 141
100 void GetTotalLocationNameCount(Kernel::HLERequestContext& ctx) { 142 void GetTotalLocationNameCount(Kernel::HLERequestContext& ctx) {
101 LOG_WARNING(Service_Time, "(STUBBED) called"); 143 LOG_WARNING(Service_Time, "(STUBBED) called");
144
102 IPC::ResponseBuilder rb{ctx, 3}; 145 IPC::ResponseBuilder rb{ctx, 3};
103 rb.Push(RESULT_SUCCESS); 146 rb.Push(RESULT_SUCCESS);
104 rb.Push<u32>(0); 147 rb.Push<u32>(0);
@@ -116,7 +159,6 @@ private:
116 void ToCalendarTime(Kernel::HLERequestContext& ctx) { 159 void ToCalendarTime(Kernel::HLERequestContext& ctx) {
117 IPC::RequestParser rp{ctx}; 160 IPC::RequestParser rp{ctx};
118 const u64 posix_time = rp.Pop<u64>(); 161 const u64 posix_time = rp.Pop<u64>();
119
120 LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); 162 LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time);
121 163
122 TimeZoneRule time_zone_rule{}; 164 TimeZoneRule time_zone_rule{};
@@ -137,7 +179,6 @@ private:
137 void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) { 179 void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) {
138 IPC::RequestParser rp{ctx}; 180 IPC::RequestParser rp{ctx};
139 const u64 posix_time = rp.Pop<u64>(); 181 const u64 posix_time = rp.Pop<u64>();
140
141 LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); 182 LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time);
142 183
143 CalendarTime calendar_time{2018, 1, 1, 0, 0, 0}; 184 CalendarTime calendar_time{2018, 1, 1, 0, 0, 0};
@@ -151,60 +192,137 @@ private:
151 rb.PushRaw(additional_info); 192 rb.PushRaw(additional_info);
152 } 193 }
153 194
154 void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time, 195 void ToPosixTime(Kernel::HLERequestContext& ctx) {
155 CalendarAdditionalInfo& additional_info, const TimeZoneRule& /*rule*/) { 196 // TODO(ogniK): Figure out how to handle multiple times
156 std::time_t t(posix_time); 197 LOG_WARNING(Service_Time, "(STUBBED) called");
157 std::tm* tm = std::localtime(&t); 198
158 if (!tm) { 199 IPC::RequestParser rp{ctx};
159 return; 200 auto calendar_time = rp.PopRaw<CalendarTime>();
160 } 201 auto posix_time = CalendarToPosix(calendar_time, {});
161 calendar_time.year = tm->tm_year + 1900; 202
162 calendar_time.month = tm->tm_mon + 1; 203 IPC::ResponseBuilder rb{ctx, 3};
163 calendar_time.day = tm->tm_mday; 204 rb.Push(RESULT_SUCCESS);
164 calendar_time.hour = tm->tm_hour; 205 rb.PushRaw<u32>(1); // Amount of times we're returning
165 calendar_time.minute = tm->tm_min; 206 ctx.WriteBuffer(&posix_time, sizeof(u64));
166 calendar_time.second = tm->tm_sec; 207 }
167 208
168 additional_info.day_of_week = tm->tm_wday; 209 void ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) {
169 additional_info.day_of_year = tm->tm_yday; 210 LOG_WARNING(Service_Time, "(STUBBED) called");
170 std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC")); 211
171 additional_info.utc_offset = 0; 212 IPC::RequestParser rp{ctx};
213 auto calendar_time = rp.PopRaw<CalendarTime>();
214 auto posix_time = CalendarToPosix(calendar_time, {});
215
216 IPC::ResponseBuilder rb{ctx, 3};
217 rb.Push(RESULT_SUCCESS);
218 rb.PushRaw<u32>(1); // Amount of times we're returning
219 ctx.WriteBuffer(&posix_time, sizeof(u64));
172 } 220 }
173}; 221};
174 222
175void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) { 223void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) {
224 LOG_DEBUG(Service_Time, "called");
225
176 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 226 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
177 rb.Push(RESULT_SUCCESS); 227 rb.Push(RESULT_SUCCESS);
178 rb.PushIpcInterface<ISystemClock>(); 228 rb.PushIpcInterface<ISystemClock>();
179 LOG_DEBUG(Service_Time, "called");
180} 229}
181 230
182void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) { 231void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) {
232 LOG_DEBUG(Service_Time, "called");
233
183 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 234 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
184 rb.Push(RESULT_SUCCESS); 235 rb.Push(RESULT_SUCCESS);
185 rb.PushIpcInterface<ISystemClock>(); 236 rb.PushIpcInterface<ISystemClock>();
186 LOG_DEBUG(Service_Time, "called");
187} 237}
188 238
189void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) { 239void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
240 LOG_DEBUG(Service_Time, "called");
241
190 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 242 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
191 rb.Push(RESULT_SUCCESS); 243 rb.Push(RESULT_SUCCESS);
192 rb.PushIpcInterface<ISteadyClock>(); 244 rb.PushIpcInterface<ISteadyClock>();
193 LOG_DEBUG(Service_Time, "called");
194} 245}
195 246
196void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { 247void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
248 LOG_DEBUG(Service_Time, "called");
249
197 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 250 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
198 rb.Push(RESULT_SUCCESS); 251 rb.Push(RESULT_SUCCESS);
199 rb.PushIpcInterface<ITimeZoneService>(); 252 rb.PushIpcInterface<ITimeZoneService>();
200 LOG_DEBUG(Service_Time, "called");
201} 253}
202 254
203void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { 255void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) {
256 LOG_DEBUG(Service_Time, "called");
257
204 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 258 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
205 rb.Push(RESULT_SUCCESS); 259 rb.Push(RESULT_SUCCESS);
206 rb.PushIpcInterface<ISystemClock>(); 260 rb.PushIpcInterface<ISystemClock>();
261}
262
263void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
207 LOG_DEBUG(Service_Time, "called"); 264 LOG_DEBUG(Service_Time, "called");
265
266 IPC::RequestParser rp{ctx};
267 auto unknown_u8 = rp.PopRaw<u8>();
268
269 ClockSnapshot clock_snapshot{};
270
271 const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>(
272 std::chrono::system_clock::now().time_since_epoch())
273 .count()};
274 CalendarTime calendar_time{};
275 const std::time_t time(time_since_epoch);
276 const std::tm* tm = std::localtime(&time);
277 if (tm == nullptr) {
278 LOG_ERROR(Service_Time, "tm is a nullptr");
279 IPC::ResponseBuilder rb{ctx, 2};
280 rb.Push(ResultCode(-1)); // TODO(ogniK): Find appropriate error code
281 return;
282 }
283 SteadyClockTimePoint steady_clock_time_point{CoreTiming::cyclesToMs(CoreTiming::GetTicks()) /
284 1000};
285
286 LocationName location_name{"UTC"};
287 calendar_time.year = tm->tm_year + 1900;
288 calendar_time.month = tm->tm_mon + 1;
289 calendar_time.day = tm->tm_mday;
290 calendar_time.hour = tm->tm_hour;
291 calendar_time.minute = tm->tm_min;
292 calendar_time.second = tm->tm_sec;
293 clock_snapshot.system_posix_time = time_since_epoch;
294 clock_snapshot.network_posix_time = time_since_epoch;
295 clock_snapshot.system_calendar_time = calendar_time;
296 clock_snapshot.network_calendar_time = calendar_time;
297
298 CalendarAdditionalInfo additional_info{};
299 PosixToCalendar(time_since_epoch, calendar_time, additional_info, {});
300
301 clock_snapshot.system_calendar_info = additional_info;
302 clock_snapshot.network_calendar_info = additional_info;
303
304 clock_snapshot.steady_clock_timepoint = steady_clock_time_point;
305 clock_snapshot.location_name = location_name;
306 clock_snapshot.clock_auto_adjustment_enabled = 1;
307 clock_snapshot.ipc_u8 = unknown_u8;
308 IPC::ResponseBuilder rb{ctx, 2};
309 rb.Push(RESULT_SUCCESS);
310 ctx.WriteBuffer(&clock_snapshot, sizeof(ClockSnapshot));
311}
312
313void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(
314 Kernel::HLERequestContext& ctx) {
315 LOG_DEBUG(Service_Time, "called");
316
317 IPC::RequestParser rp{ctx};
318 const auto snapshot_a = rp.PopRaw<ClockSnapshot>();
319 const auto snapshot_b = rp.PopRaw<ClockSnapshot>();
320 const u64 difference =
321 snapshot_b.user_clock_context.offset - snapshot_a.user_clock_context.offset;
322
323 IPC::ResponseBuilder rb{ctx, 4};
324 rb.Push(RESULT_SUCCESS);
325 rb.PushRaw<u64>(difference);
208} 326}
209 327
210Module::Interface::Interface(std::shared_ptr<Module> time, const char* name) 328Module::Interface::Interface(std::shared_ptr<Module> time, const char* name)
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index 5659ecad3..ea43fbea7 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include "common/common_funcs.h"
8#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
9 10
10namespace Service::Time { 11namespace Service::Time {
@@ -53,6 +54,23 @@ struct SystemClockContext {
53static_assert(sizeof(SystemClockContext) == 0x20, 54static_assert(sizeof(SystemClockContext) == 0x20,
54 "SystemClockContext structure has incorrect size"); 55 "SystemClockContext structure has incorrect size");
55 56
57struct ClockSnapshot {
58 SystemClockContext user_clock_context;
59 SystemClockContext network_clock_context;
60 s64_le system_posix_time;
61 s64_le network_posix_time;
62 CalendarTime system_calendar_time;
63 CalendarTime network_calendar_time;
64 CalendarAdditionalInfo system_calendar_info;
65 CalendarAdditionalInfo network_calendar_info;
66 SteadyClockTimePoint steady_clock_timepoint;
67 LocationName location_name;
68 u8 clock_auto_adjustment_enabled;
69 u8 ipc_u8;
70 INSERT_PADDING_BYTES(2);
71};
72static_assert(sizeof(ClockSnapshot) == 0xd0, "ClockSnapshot is an invalid size");
73
56class Module final { 74class Module final {
57public: 75public:
58 class Interface : public ServiceFramework<Interface> { 76 class Interface : public ServiceFramework<Interface> {
@@ -65,6 +83,8 @@ public:
65 void GetStandardSteadyClock(Kernel::HLERequestContext& ctx); 83 void GetStandardSteadyClock(Kernel::HLERequestContext& ctx);
66 void GetTimeZoneService(Kernel::HLERequestContext& ctx); 84 void GetTimeZoneService(Kernel::HLERequestContext& ctx);
67 void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx); 85 void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx);
86 void GetClockSnapshot(Kernel::HLERequestContext& ctx);
87 void CalculateStandardUserSystemClockDifferenceByUser(Kernel::HLERequestContext& ctx);
68 88
69 protected: 89 protected:
70 std::shared_ptr<Module> time; 90 std::shared_ptr<Module> time;
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp
index f0a831d45..58a9845fc 100644
--- a/src/core/hle/service/usb/usb.cpp
+++ b/src/core/hle/service/usb/usb.cpp
@@ -73,7 +73,7 @@ public:
73 {3, nullptr, "Populate"}, 73 {3, nullptr, "Populate"},
74 {4, nullptr, "PostBufferAsync"}, 74 {4, nullptr, "PostBufferAsync"},
75 {5, nullptr, "GetXferReport"}, 75 {5, nullptr, "GetXferReport"},
76 {6, nullptr, "Unknown2"}, 76 {6, nullptr, "PostBufferMultiAsync"},
77 {7, nullptr, "Unknown3"}, 77 {7, nullptr, "Unknown3"},
78 {8, nullptr, "Unknown4"}, 78 {8, nullptr, "Unknown4"},
79 }; 79 };
@@ -159,11 +159,11 @@ public:
159 159
160private: 160private:
161 void GetPdSession(Kernel::HLERequestContext& ctx) { 161 void GetPdSession(Kernel::HLERequestContext& ctx) {
162 LOG_DEBUG(Service_USB, "called");
163
162 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 164 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
163 rb.Push(RESULT_SUCCESS); 165 rb.Push(RESULT_SUCCESS);
164 rb.PushIpcInterface<IPdSession>(); 166 rb.PushIpcInterface<IPdSession>();
165
166 LOG_DEBUG(Service_USB, "called");
167 } 167 }
168}; 168};
169 169
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index d764b2406..311b0c765 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -18,7 +18,8 @@
18#include "common/swap.h" 18#include "common/swap.h"
19#include "core/core_timing.h" 19#include "core/core_timing.h"
20#include "core/hle/ipc_helpers.h" 20#include "core/hle/ipc_helpers.h"
21#include "core/hle/kernel/event.h" 21#include "core/hle/kernel/readable_event.h"
22#include "core/hle/kernel/writable_event.h"
22#include "core/hle/service/nvdrv/nvdrv.h" 23#include "core/hle/service/nvdrv/nvdrv.h"
23#include "core/hle/service/nvflinger/buffer_queue.h" 24#include "core/hle/service/nvflinger/buffer_queue.h"
24#include "core/hle/service/nvflinger/nvflinger.h" 25#include "core/hle/service/nvflinger/nvflinger.h"
@@ -237,6 +238,22 @@ private:
237 Data data{}; 238 Data data{};
238}; 239};
239 240
241/// Represents a parcel containing one int '0' as its data
242/// Used by DetachBuffer and Disconnect
243class IGBPEmptyResponseParcel : public Parcel {
244protected:
245 void SerializeData() override {
246 Write(data);
247 }
248
249private:
250 struct Data {
251 u32_le unk_0;
252 };
253
254 Data data{};
255};
256
240class IGBPSetPreallocatedBufferRequestParcel : public Parcel { 257class IGBPSetPreallocatedBufferRequestParcel : public Parcel {
241public: 258public:
242 explicit IGBPSetPreallocatedBufferRequestParcel(std::vector<u8> buffer) 259 explicit IGBPSetPreallocatedBufferRequestParcel(std::vector<u8> buffer)
@@ -488,13 +505,17 @@ private:
488 u32 id = rp.Pop<u32>(); 505 u32 id = rp.Pop<u32>();
489 auto transaction = static_cast<TransactionId>(rp.Pop<u32>()); 506 auto transaction = static_cast<TransactionId>(rp.Pop<u32>());
490 u32 flags = rp.Pop<u32>(); 507 u32 flags = rp.Pop<u32>();
491 auto buffer_queue = nv_flinger->GetBufferQueue(id);
492
493 LOG_DEBUG(Service_VI, "called, transaction={:X}", static_cast<u32>(transaction)); 508 LOG_DEBUG(Service_VI, "called, transaction={:X}", static_cast<u32>(transaction));
494 509
510 auto buffer_queue = nv_flinger->GetBufferQueue(id);
511
495 if (transaction == TransactionId::Connect) { 512 if (transaction == TransactionId::Connect) {
496 IGBPConnectRequestParcel request{ctx.ReadBuffer()}; 513 IGBPConnectRequestParcel request{ctx.ReadBuffer()};
497 IGBPConnectResponseParcel response{1280, 720}; 514 IGBPConnectResponseParcel response{
515 static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedWidth) *
516 Settings::values.resolution_factor),
517 static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedHeight) *
518 Settings::values.resolution_factor)};
498 ctx.WriteBuffer(response.Serialize()); 519 ctx.WriteBuffer(response.Serialize());
499 } else if (transaction == TransactionId::SetPreallocatedBuffer) { 520 } else if (transaction == TransactionId::SetPreallocatedBuffer) {
500 IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()}; 521 IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()};
@@ -522,12 +543,14 @@ private:
522 // Repeat TransactParcel DequeueBuffer when a buffer is available 543 // Repeat TransactParcel DequeueBuffer when a buffer is available
523 auto buffer_queue = nv_flinger->GetBufferQueue(id); 544 auto buffer_queue = nv_flinger->GetBufferQueue(id);
524 std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height); 545 std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
546 ASSERT_MSG(slot != std::nullopt, "Could not dequeue buffer.");
547
525 IGBPDequeueBufferResponseParcel response{*slot}; 548 IGBPDequeueBufferResponseParcel response{*slot};
526 ctx.WriteBuffer(response.Serialize()); 549 ctx.WriteBuffer(response.Serialize());
527 IPC::ResponseBuilder rb{ctx, 2}; 550 IPC::ResponseBuilder rb{ctx, 2};
528 rb.Push(RESULT_SUCCESS); 551 rb.Push(RESULT_SUCCESS);
529 }, 552 },
530 buffer_queue->GetBufferWaitEvent()); 553 buffer_queue->GetWritableBufferWaitEvent());
531 } 554 }
532 } else if (transaction == TransactionId::RequestBuffer) { 555 } else if (transaction == TransactionId::RequestBuffer) {
533 IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()}; 556 IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()};
@@ -554,6 +577,12 @@ private:
554 ctx.WriteBuffer(response.Serialize()); 577 ctx.WriteBuffer(response.Serialize());
555 } else if (transaction == TransactionId::CancelBuffer) { 578 } else if (transaction == TransactionId::CancelBuffer) {
556 LOG_CRITICAL(Service_VI, "(STUBBED) called, transaction=CancelBuffer"); 579 LOG_CRITICAL(Service_VI, "(STUBBED) called, transaction=CancelBuffer");
580 } else if (transaction == TransactionId::Disconnect ||
581 transaction == TransactionId::DetachBuffer) {
582 const auto buffer = ctx.ReadBuffer();
583
584 IGBPEmptyResponseParcel response{};
585 ctx.WriteBuffer(response.Serialize());
557 } else { 586 } else {
558 ASSERT_MSG(false, "Unimplemented"); 587 ASSERT_MSG(false, "Unimplemented");
559 } 588 }
@@ -567,9 +596,9 @@ private:
567 u32 id = rp.Pop<u32>(); 596 u32 id = rp.Pop<u32>();
568 s32 addval = rp.PopRaw<s32>(); 597 s32 addval = rp.PopRaw<s32>();
569 u32 type = rp.Pop<u32>(); 598 u32 type = rp.Pop<u32>();
570
571 LOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={:08X}, type={:08X}", id, addval, 599 LOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={:08X}, type={:08X}", id, addval,
572 type); 600 type);
601
573 IPC::ResponseBuilder rb{ctx, 2}; 602 IPC::ResponseBuilder rb{ctx, 2};
574 rb.Push(RESULT_SUCCESS); 603 rb.Push(RESULT_SUCCESS);
575 } 604 }
@@ -578,12 +607,11 @@ private:
578 IPC::RequestParser rp{ctx}; 607 IPC::RequestParser rp{ctx};
579 u32 id = rp.Pop<u32>(); 608 u32 id = rp.Pop<u32>();
580 u32 unknown = rp.Pop<u32>(); 609 u32 unknown = rp.Pop<u32>();
610 LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
581 611
582 auto buffer_queue = nv_flinger->GetBufferQueue(id); 612 auto buffer_queue = nv_flinger->GetBufferQueue(id);
583 613
584 // TODO(Subv): Find out what this actually is. 614 // TODO(Subv): Find out what this actually is.
585
586 LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown);
587 IPC::ResponseBuilder rb{ctx, 2, 1}; 615 IPC::ResponseBuilder rb{ctx, 2, 1};
588 rb.Push(RESULT_SUCCESS); 616 rb.Push(RESULT_SUCCESS);
589 rb.PushCopyObjects(buffer_queue->GetBufferWaitEvent()); 617 rb.PushCopyObjects(buffer_queue->GetBufferWaitEvent());
@@ -647,6 +675,7 @@ public:
647private: 675private:
648 void SetLayerZ(Kernel::HLERequestContext& ctx) { 676 void SetLayerZ(Kernel::HLERequestContext& ctx) {
649 LOG_WARNING(Service_VI, "(STUBBED) called"); 677 LOG_WARNING(Service_VI, "(STUBBED) called");
678
650 IPC::RequestParser rp{ctx}; 679 IPC::RequestParser rp{ctx};
651 u64 layer_id = rp.Pop<u64>(); 680 u64 layer_id = rp.Pop<u64>();
652 u64 z_value = rp.Pop<u64>(); 681 u64 z_value = rp.Pop<u64>();
@@ -659,28 +688,33 @@ private:
659 IPC::RequestParser rp{ctx}; 688 IPC::RequestParser rp{ctx};
660 u64 layer_id = rp.Pop<u64>(); 689 u64 layer_id = rp.Pop<u64>();
661 bool visibility = rp.Pop<bool>(); 690 bool visibility = rp.Pop<bool>();
662 IPC::ResponseBuilder rb{ctx, 2};
663 rb.Push(RESULT_SUCCESS);
664 LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id, 691 LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id,
665 visibility); 692 visibility);
693
694 IPC::ResponseBuilder rb{ctx, 2};
695 rb.Push(RESULT_SUCCESS);
666 } 696 }
667 697
668 void GetDisplayMode(Kernel::HLERequestContext& ctx) { 698 void GetDisplayMode(Kernel::HLERequestContext& ctx) {
699 LOG_WARNING(Service_VI, "(STUBBED) called");
700
669 IPC::ResponseBuilder rb{ctx, 6}; 701 IPC::ResponseBuilder rb{ctx, 6};
670 rb.Push(RESULT_SUCCESS); 702 rb.Push(RESULT_SUCCESS);
671 703
672 if (Settings::values.use_docked_mode) { 704 if (Settings::values.use_docked_mode) {
673 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth)); 705 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
674 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); 706 static_cast<u32>(Settings::values.resolution_factor));
707 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
708 static_cast<u32>(Settings::values.resolution_factor));
675 } else { 709 } else {
676 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth)); 710 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) *
677 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight)); 711 static_cast<u32>(Settings::values.resolution_factor));
712 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) *
713 static_cast<u32>(Settings::values.resolution_factor));
678 } 714 }
679 715
680 rb.PushRaw<float>(60.0f); 716 rb.PushRaw<float>(60.0f); // This wouldn't seem to be correct for 30 fps games.
681 rb.Push<u32>(0); 717 rb.Push<u32>(0);
682
683 LOG_DEBUG(Service_VI, "called");
684 } 718 }
685}; 719};
686 720
@@ -763,6 +797,7 @@ public:
763private: 797private:
764 void CloseDisplay(Kernel::HLERequestContext& ctx) { 798 void CloseDisplay(Kernel::HLERequestContext& ctx) {
765 LOG_WARNING(Service_VI, "(STUBBED) called"); 799 LOG_WARNING(Service_VI, "(STUBBED) called");
800
766 IPC::RequestParser rp{ctx}; 801 IPC::RequestParser rp{ctx};
767 u64 display = rp.Pop<u64>(); 802 u64 display = rp.Pop<u64>();
768 803
@@ -772,6 +807,7 @@ private:
772 807
773 void CreateManagedLayer(Kernel::HLERequestContext& ctx) { 808 void CreateManagedLayer(Kernel::HLERequestContext& ctx) {
774 LOG_WARNING(Service_VI, "(STUBBED) called"); 809 LOG_WARNING(Service_VI, "(STUBBED) called");
810
775 IPC::RequestParser rp{ctx}; 811 IPC::RequestParser rp{ctx};
776 u32 unknown = rp.Pop<u32>(); 812 u32 unknown = rp.Pop<u32>();
777 rp.Skip(1, false); 813 rp.Skip(1, false);
@@ -787,6 +823,7 @@ private:
787 823
788 void AddToLayerStack(Kernel::HLERequestContext& ctx) { 824 void AddToLayerStack(Kernel::HLERequestContext& ctx) {
789 LOG_WARNING(Service_VI, "(STUBBED) called"); 825 LOG_WARNING(Service_VI, "(STUBBED) called");
826
790 IPC::RequestParser rp{ctx}; 827 IPC::RequestParser rp{ctx};
791 u32 stack = rp.Pop<u32>(); 828 u32 stack = rp.Pop<u32>();
792 u64 layer_id = rp.Pop<u64>(); 829 u64 layer_id = rp.Pop<u64>();
@@ -799,10 +836,11 @@ private:
799 IPC::RequestParser rp{ctx}; 836 IPC::RequestParser rp{ctx};
800 u64 layer_id = rp.Pop<u64>(); 837 u64 layer_id = rp.Pop<u64>();
801 bool visibility = rp.Pop<bool>(); 838 bool visibility = rp.Pop<bool>();
802 IPC::ResponseBuilder rb{ctx, 2};
803 rb.Push(RESULT_SUCCESS);
804 LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id, 839 LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id,
805 visibility); 840 visibility);
841
842 IPC::ResponseBuilder rb{ctx, 2};
843 rb.Push(RESULT_SUCCESS);
806 } 844 }
807 845
808 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; 846 std::shared_ptr<NVFlinger::NVFlinger> nv_flinger;
@@ -848,6 +886,7 @@ private:
848 886
849 void OpenDisplay(Kernel::HLERequestContext& ctx) { 887 void OpenDisplay(Kernel::HLERequestContext& ctx) {
850 LOG_WARNING(Service_VI, "(STUBBED) called"); 888 LOG_WARNING(Service_VI, "(STUBBED) called");
889
851 IPC::RequestParser rp{ctx}; 890 IPC::RequestParser rp{ctx};
852 auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); 891 auto name_buf = rp.PopRaw<std::array<u8, 0x40>>();
853 auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); 892 auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
@@ -863,6 +902,7 @@ private:
863 902
864 void CloseDisplay(Kernel::HLERequestContext& ctx) { 903 void CloseDisplay(Kernel::HLERequestContext& ctx) {
865 LOG_WARNING(Service_VI, "(STUBBED) called"); 904 LOG_WARNING(Service_VI, "(STUBBED) called");
905
866 IPC::RequestParser rp{ctx}; 906 IPC::RequestParser rp{ctx};
867 u64 display_id = rp.Pop<u64>(); 907 u64 display_id = rp.Pop<u64>();
868 908
@@ -872,6 +912,7 @@ private:
872 912
873 void GetDisplayResolution(Kernel::HLERequestContext& ctx) { 913 void GetDisplayResolution(Kernel::HLERequestContext& ctx) {
874 LOG_WARNING(Service_VI, "(STUBBED) called"); 914 LOG_WARNING(Service_VI, "(STUBBED) called");
915
875 IPC::RequestParser rp{ctx}; 916 IPC::RequestParser rp{ctx};
876 u64 display_id = rp.Pop<u64>(); 917 u64 display_id = rp.Pop<u64>();
877 918
@@ -879,16 +920,21 @@ private:
879 rb.Push(RESULT_SUCCESS); 920 rb.Push(RESULT_SUCCESS);
880 921
881 if (Settings::values.use_docked_mode) { 922 if (Settings::values.use_docked_mode) {
882 rb.Push(static_cast<u64>(DisplayResolution::DockedWidth)); 923 rb.Push(static_cast<u64>(DisplayResolution::DockedWidth) *
883 rb.Push(static_cast<u64>(DisplayResolution::DockedHeight)); 924 static_cast<u32>(Settings::values.resolution_factor));
925 rb.Push(static_cast<u64>(DisplayResolution::DockedHeight) *
926 static_cast<u32>(Settings::values.resolution_factor));
884 } else { 927 } else {
885 rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth)); 928 rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth) *
886 rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight)); 929 static_cast<u32>(Settings::values.resolution_factor));
930 rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight) *
931 static_cast<u32>(Settings::values.resolution_factor));
887 } 932 }
888 } 933 }
889 934
890 void SetLayerScalingMode(Kernel::HLERequestContext& ctx) { 935 void SetLayerScalingMode(Kernel::HLERequestContext& ctx) {
891 LOG_WARNING(Service_VI, "(STUBBED) called"); 936 LOG_WARNING(Service_VI, "(STUBBED) called");
937
892 IPC::RequestParser rp{ctx}; 938 IPC::RequestParser rp{ctx};
893 u32 scaling_mode = rp.Pop<u32>(); 939 u32 scaling_mode = rp.Pop<u32>();
894 u64 unknown = rp.Pop<u64>(); 940 u64 unknown = rp.Pop<u64>();
@@ -898,17 +944,21 @@ private:
898 } 944 }
899 945
900 void ListDisplays(Kernel::HLERequestContext& ctx) { 946 void ListDisplays(Kernel::HLERequestContext& ctx) {
947 LOG_WARNING(Service_VI, "(STUBBED) called");
948
901 IPC::RequestParser rp{ctx}; 949 IPC::RequestParser rp{ctx};
902 DisplayInfo display_info; 950 DisplayInfo display_info;
951 display_info.width *= static_cast<u64>(Settings::values.resolution_factor);
952 display_info.height *= static_cast<u64>(Settings::values.resolution_factor);
903 ctx.WriteBuffer(&display_info, sizeof(DisplayInfo)); 953 ctx.WriteBuffer(&display_info, sizeof(DisplayInfo));
904 IPC::ResponseBuilder rb{ctx, 4}; 954 IPC::ResponseBuilder rb{ctx, 4};
905 rb.Push(RESULT_SUCCESS); 955 rb.Push(RESULT_SUCCESS);
906 rb.Push<u64>(1); 956 rb.Push<u64>(1);
907 LOG_WARNING(Service_VI, "(STUBBED) called");
908 } 957 }
909 958
910 void OpenLayer(Kernel::HLERequestContext& ctx) { 959 void OpenLayer(Kernel::HLERequestContext& ctx) {
911 LOG_DEBUG(Service_VI, "called"); 960 LOG_DEBUG(Service_VI, "called");
961
912 IPC::RequestParser rp{ctx}; 962 IPC::RequestParser rp{ctx};
913 auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); 963 auto name_buf = rp.PopRaw<std::array<u8, 0x40>>();
914 auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); 964 auto end = std::find(name_buf.begin(), name_buf.end(), '\0');
@@ -959,6 +1009,7 @@ private:
959 1009
960 void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) { 1010 void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) {
961 LOG_WARNING(Service_VI, "(STUBBED) called"); 1011 LOG_WARNING(Service_VI, "(STUBBED) called");
1012
962 IPC::RequestParser rp{ctx}; 1013 IPC::RequestParser rp{ctx};
963 u64 display_id = rp.Pop<u64>(); 1014 u64 display_id = rp.Pop<u64>();
964 1015
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 8518dddcb..ac04d72d7 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -7,7 +7,6 @@
7#include "common/common_funcs.h" 7#include "common/common_funcs.h"
8#include "common/file_util.h" 8#include "common/file_util.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "core/core.h"
11#include "core/file_sys/content_archive.h" 10#include "core/file_sys/content_archive.h"
12#include "core/file_sys/control_metadata.h" 11#include "core/file_sys/control_metadata.h"
13#include "core/file_sys/patch_manager.h" 12#include "core/file_sys/patch_manager.h"
@@ -146,7 +145,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process)
146 const VAddr load_addr = next_load_addr; 145 const VAddr load_addr = next_load_addr;
147 const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; 146 const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
148 const auto tentative_next_load_addr = 147 const auto tentative_next_load_addr =
149 AppLoader_NSO::LoadModule(*module_file, load_addr, should_pass_arguments, pm); 148 AppLoader_NSO::LoadModule(process, *module_file, load_addr, should_pass_arguments, pm);
150 if (!tentative_next_load_addr) { 149 if (!tentative_next_load_addr) {
151 return ResultStatus::ErrorLoadingNSO; 150 return ResultStatus::ErrorLoadingNSO;
152 } 151 }
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index bc8e402a8..4fad0c0dd 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -10,12 +10,13 @@
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 "common/swap.h" 12#include "common/swap.h"
13#include "core/core.h"
14#include "core/file_sys/control_metadata.h" 13#include "core/file_sys/control_metadata.h"
14#include "core/file_sys/romfs_factory.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/process.h" 17#include "core/hle/kernel/process.h"
18#include "core/hle/kernel/vm_manager.h" 18#include "core/hle/kernel/vm_manager.h"
19#include "core/hle/service/filesystem/filesystem.h"
19#include "core/loader/nro.h" 20#include "core/loader/nro.h"
20#include "core/loader/nso.h" 21#include "core/loader/nso.h"
21#include "core/memory.h" 22#include "core/memory.h"
@@ -127,9 +128,8 @@ static constexpr u32 PageAlignSize(u32 size) {
127 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; 128 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
128} 129}
129 130
130/*static*/ bool AppLoader_NRO::LoadNro(const std::vector<u8>& data, const std::string& name, 131static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data,
131 VAddr load_base) { 132 const std::string& name, VAddr load_base) {
132
133 if (data.size() < sizeof(NroHeader)) { 133 if (data.size() < sizeof(NroHeader)) {
134 return {}; 134 return {};
135 } 135 }
@@ -168,23 +168,26 @@ static constexpr u32 PageAlignSize(u32 size) {
168 arg_data.size()); 168 arg_data.size());
169 } 169 }
170 170
171 // Read MOD header
172 ModHeader mod_header{};
173 // Default .bss to NRO header bss size if MOD0 section doesn't exist 171 // Default .bss to NRO header bss size if MOD0 section doesn't exist
174 u32 bss_size{PageAlignSize(nro_header.bss_size)}; 172 u32 bss_size{PageAlignSize(nro_header.bss_size)};
173
174 // Read MOD header
175 ModHeader mod_header{};
175 std::memcpy(&mod_header, program_image.data() + nro_header.module_header_offset, 176 std::memcpy(&mod_header, program_image.data() + nro_header.module_header_offset,
176 sizeof(ModHeader)); 177 sizeof(ModHeader));
178
177 const bool has_mod_header{mod_header.magic == Common::MakeMagic('M', 'O', 'D', '0')}; 179 const bool has_mod_header{mod_header.magic == Common::MakeMagic('M', 'O', 'D', '0')};
178 if (has_mod_header) { 180 if (has_mod_header) {
179 // Resize program image to include .bss section and page align each section 181 // Resize program image to include .bss section and page align each section
180 bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset); 182 bss_size = PageAlignSize(mod_header.bss_end_offset - mod_header.bss_start_offset);
181 } 183 }
184
182 codeset.DataSegment().size += bss_size; 185 codeset.DataSegment().size += bss_size;
183 program_image.resize(static_cast<u32>(program_image.size()) + bss_size); 186 program_image.resize(static_cast<u32>(program_image.size()) + bss_size);
184 187
185 // Load codeset for current process 188 // Load codeset for current process
186 codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image)); 189 codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image));
187 Core::CurrentProcess()->LoadModule(std::move(codeset), load_base); 190 process.LoadModule(std::move(codeset), load_base);
188 191
189 // Register module with GDBStub 192 // Register module with GDBStub
190 GDBStub::RegisterModule(name, load_base, load_base); 193 GDBStub::RegisterModule(name, load_base, load_base);
@@ -192,8 +195,9 @@ static constexpr u32 PageAlignSize(u32 size) {
192 return true; 195 return true;
193} 196}
194 197
195bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) { 198bool AppLoader_NRO::LoadNro(Kernel::Process& process, const FileSys::VfsFile& file,
196 return AppLoader_NRO::LoadNro(file.ReadAllBytes(), file.GetName(), load_base); 199 VAddr load_base) {
200 return LoadNroImpl(process, file.ReadAllBytes(), file.GetName(), load_base);
197} 201}
198 202
199ResultStatus AppLoader_NRO::Load(Kernel::Process& process) { 203ResultStatus AppLoader_NRO::Load(Kernel::Process& process) {
@@ -204,10 +208,13 @@ ResultStatus AppLoader_NRO::Load(Kernel::Process& process) {
204 // Load NRO 208 // Load NRO
205 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); 209 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
206 210
207 if (!LoadNro(*file, base_address)) { 211 if (!LoadNro(process, *file, base_address)) {
208 return ResultStatus::ErrorLoadingNRO; 212 return ResultStatus::ErrorLoadingNRO;
209 } 213 }
210 214
215 if (romfs != nullptr)
216 Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this));
217
211 process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE); 218 process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
212 219
213 is_loaded = true; 220 is_loaded = true;
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index 3e6959302..6deff3a51 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -14,6 +14,10 @@ namespace FileSys {
14class NACP; 14class NACP;
15} 15}
16 16
17namespace Kernel {
18class Process;
19}
20
17namespace Loader { 21namespace Loader {
18 22
19/// Loads an NRO file 23/// Loads an NRO file
@@ -41,10 +45,8 @@ public:
41 ResultStatus ReadTitle(std::string& title) override; 45 ResultStatus ReadTitle(std::string& title) override;
42 bool IsRomFSUpdatable() const override; 46 bool IsRomFSUpdatable() const override;
43 47
44 static bool LoadNro(const std::vector<u8>& data, const std::string& name, VAddr load_base);
45
46private: 48private:
47 bool LoadNro(const FileSys::VfsFile& file, VAddr load_base); 49 bool LoadNro(Kernel::Process& process, const FileSys::VfsFile& file, VAddr load_base);
48 50
49 std::vector<u8> icon_data; 51 std::vector<u8> icon_data;
50 std::unique_ptr<FileSys::NACP> nacp; 52 std::unique_ptr<FileSys::NACP> nacp;
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 68efca5c0..6ded0b707 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -9,7 +9,6 @@
9#include "common/file_util.h" 9#include "common/file_util.h"
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "common/swap.h" 11#include "common/swap.h"
12#include "core/core.h"
13#include "core/file_sys/patch_manager.h" 12#include "core/file_sys/patch_manager.h"
14#include "core/gdbstub/gdbstub.h" 13#include "core/gdbstub/gdbstub.h"
15#include "core/hle/kernel/process.h" 14#include "core/hle/kernel/process.h"
@@ -93,7 +92,8 @@ static constexpr u32 PageAlignSize(u32 size) {
93 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; 92 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
94} 93}
95 94
96std::optional<VAddr> AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAddr load_base, 95std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
96 const FileSys::VfsFile& file, VAddr load_base,
97 bool should_pass_arguments, 97 bool should_pass_arguments,
98 std::optional<FileSys::PatchManager> pm) { 98 std::optional<FileSys::PatchManager> pm) {
99 if (file.GetSize() < sizeof(NsoHeader)) 99 if (file.GetSize() < sizeof(NsoHeader))
@@ -154,7 +154,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAd
154 program_image.resize(image_size); 154 program_image.resize(image_size);
155 155
156 // Apply patches if necessary 156 // Apply patches if necessary
157 if (pm && pm->HasNSOPatch(nso_header.build_id)) { 157 if (pm && (pm->HasNSOPatch(nso_header.build_id) || Settings::values.dump_nso)) {
158 std::vector<u8> pi_header(program_image.size() + 0x100); 158 std::vector<u8> pi_header(program_image.size() + 0x100);
159 std::memcpy(pi_header.data(), &nso_header, sizeof(NsoHeader)); 159 std::memcpy(pi_header.data(), &nso_header, sizeof(NsoHeader));
160 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());
@@ -166,7 +166,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAd
166 166
167 // Load codeset for current process 167 // Load codeset for current process
168 codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image)); 168 codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image));
169 Core::CurrentProcess()->LoadModule(std::move(codeset), load_base); 169 process.LoadModule(std::move(codeset), load_base);
170 170
171 // Register module with GDBStub 171 // Register module with GDBStub
172 GDBStub::RegisterModule(file.GetName(), load_base, load_base); 172 GDBStub::RegisterModule(file.GetName(), load_base, load_base);
@@ -181,7 +181,7 @@ ResultStatus AppLoader_NSO::Load(Kernel::Process& process) {
181 181
182 // Load module 182 // Load module
183 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); 183 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
184 if (!LoadModule(*file, base_address, true)) { 184 if (!LoadModule(process, *file, base_address, true)) {
185 return ResultStatus::ErrorLoadingNSO; 185 return ResultStatus::ErrorLoadingNSO;
186 } 186 }
187 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); 187 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address);
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h
index 433306139..0c1defbb6 100644
--- a/src/core/loader/nso.h
+++ b/src/core/loader/nso.h
@@ -10,6 +10,10 @@
10#include "core/loader/linker.h" 10#include "core/loader/linker.h"
11#include "core/loader/loader.h" 11#include "core/loader/loader.h"
12 12
13namespace Kernel {
14class Process;
15}
16
13namespace Loader { 17namespace Loader {
14 18
15constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000; 19constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000;
@@ -37,8 +41,8 @@ public:
37 return IdentifyType(file); 41 return IdentifyType(file);
38 } 42 }
39 43
40 static std::optional<VAddr> LoadModule(const FileSys::VfsFile& file, VAddr load_base, 44 static std::optional<VAddr> LoadModule(Kernel::Process& process, const FileSys::VfsFile& file,
41 bool should_pass_arguments, 45 VAddr load_base, bool should_pass_arguments,
42 std::optional<FileSys::PatchManager> pm = {}); 46 std::optional<FileSys::PatchManager> pm = {});
43 47
44 ResultStatus Load(Kernel::Process& process) override; 48 ResultStatus Load(Kernel::Process& process) override;
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 0da159559..26fcd3405 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -10,6 +10,56 @@
10 10
11namespace Settings { 11namespace Settings {
12 12
13namespace NativeButton {
14const std::array<const char*, NumButtons> mapping = {{
15 "button_a",
16 "button_b",
17 "button_x",
18 "button_y",
19 "button_lstick",
20 "button_rstick",
21 "button_l",
22 "button_r",
23 "button_zl",
24 "button_zr",
25 "button_plus",
26 "button_minus",
27 "button_dleft",
28 "button_dup",
29 "button_dright",
30 "button_ddown",
31 "button_lstick_left",
32 "button_lstick_up",
33 "button_lstick_right",
34 "button_lstick_down",
35 "button_rstick_left",
36 "button_rstick_up",
37 "button_rstick_right",
38 "button_rstick_down",
39 "button_sl",
40 "button_sr",
41 "button_home",
42 "button_screenshot",
43}};
44}
45
46namespace NativeAnalog {
47const std::array<const char*, NumAnalogs> mapping = {{
48 "lstick",
49 "rstick",
50}};
51}
52
53namespace NativeMouseButton {
54const std::array<const char*, NumMouseButtons> mapping = {{
55 "left",
56 "right",
57 "middle",
58 "forward",
59 "back",
60}};
61}
62
13Values values = {}; 63Values values = {};
14 64
15void Apply() { 65void Apply() {
diff --git a/src/core/settings.h b/src/core/settings.h
index a8954647f..a0c5fd447 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -6,6 +6,7 @@
6 6
7#include <array> 7#include <array>
8#include <atomic> 8#include <atomic>
9#include <optional>
9#include <string> 10#include <string>
10#include "common/common_types.h" 11#include "common/common_types.h"
11 12
@@ -59,36 +60,7 @@ constexpr int BUTTON_NS_END = NumButtons;
59constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN; 60constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN;
60constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN; 61constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN;
61 62
62static const std::array<const char*, NumButtons> mapping = {{ 63extern const std::array<const char*, NumButtons> mapping;
63 "button_a",
64 "button_b",
65 "button_x",
66 "button_y",
67 "button_lstick",
68 "button_rstick",
69 "button_l",
70 "button_r",
71 "button_zl",
72 "button_zr",
73 "button_plus",
74 "button_minus",
75 "button_dleft",
76 "button_dup",
77 "button_dright",
78 "button_ddown",
79 "button_lstick_left",
80 "button_lstick_up",
81 "button_lstick_right",
82 "button_lstick_down",
83 "button_rstick_left",
84 "button_rstick_up",
85 "button_rstick_right",
86 "button_rstick_down",
87 "button_sl",
88 "button_sr",
89 "button_home",
90 "button_screenshot",
91}};
92 64
93} // namespace NativeButton 65} // namespace NativeButton
94 66
@@ -104,24 +76,298 @@ constexpr int STICK_HID_BEGIN = LStick;
104constexpr int STICK_HID_END = NumAnalogs; 76constexpr int STICK_HID_END = NumAnalogs;
105constexpr int NUM_STICKS_HID = NumAnalogs; 77constexpr int NUM_STICKS_HID = NumAnalogs;
106 78
107static const std::array<const char*, NumAnalogs> mapping = {{ 79extern const std::array<const char*, NumAnalogs> mapping;
108 "lstick",
109 "rstick",
110}};
111} // namespace NativeAnalog 80} // namespace NativeAnalog
112 81
82namespace NativeMouseButton {
83enum Values {
84 Left,
85 Right,
86 Middle,
87 Forward,
88 Back,
89
90 NumMouseButtons,
91};
92
93constexpr int MOUSE_HID_BEGIN = Left;
94constexpr int MOUSE_HID_END = NumMouseButtons;
95constexpr int NUM_MOUSE_HID = NumMouseButtons;
96
97extern const std::array<const char*, NumMouseButtons> mapping;
98} // namespace NativeMouseButton
99
100namespace NativeKeyboard {
101enum Keys {
102 None,
103 Error,
104
105 A = 4,
106 B,
107 C,
108 D,
109 E,
110 F,
111 G,
112 H,
113 I,
114 J,
115 K,
116 L,
117 M,
118 N,
119 O,
120 P,
121 Q,
122 R,
123 S,
124 T,
125 U,
126 V,
127 W,
128 X,
129 Y,
130 Z,
131 N1,
132 N2,
133 N3,
134 N4,
135 N5,
136 N6,
137 N7,
138 N8,
139 N9,
140 N0,
141 Enter,
142 Escape,
143 Backspace,
144 Tab,
145 Space,
146 Minus,
147 Equal,
148 LeftBrace,
149 RightBrace,
150 Backslash,
151 Tilde,
152 Semicolon,
153 Apostrophe,
154 Grave,
155 Comma,
156 Dot,
157 Slash,
158 CapsLockKey,
159
160 F1,
161 F2,
162 F3,
163 F4,
164 F5,
165 F6,
166 F7,
167 F8,
168 F9,
169 F10,
170 F11,
171 F12,
172
173 SystemRequest,
174 ScrollLockKey,
175 Pause,
176 Insert,
177 Home,
178 PageUp,
179 Delete,
180 End,
181 PageDown,
182 Right,
183 Left,
184 Down,
185 Up,
186
187 NumLockKey,
188 KPSlash,
189 KPAsterisk,
190 KPMinus,
191 KPPlus,
192 KPEnter,
193 KP1,
194 KP2,
195 KP3,
196 KP4,
197 KP5,
198 KP6,
199 KP7,
200 KP8,
201 KP9,
202 KP0,
203 KPDot,
204
205 Key102,
206 Compose,
207 Power,
208 KPEqual,
209
210 F13,
211 F14,
212 F15,
213 F16,
214 F17,
215 F18,
216 F19,
217 F20,
218 F21,
219 F22,
220 F23,
221 F24,
222
223 Open,
224 Help,
225 Properties,
226 Front,
227 Stop,
228 Repeat,
229 Undo,
230 Cut,
231 Copy,
232 Paste,
233 Find,
234 Mute,
235 VolumeUp,
236 VolumeDown,
237 CapsLockActive,
238 NumLockActive,
239 ScrollLockActive,
240 KPComma,
241
242 KPLeftParenthesis,
243 KPRightParenthesis,
244
245 LeftControlKey = 0xE0,
246 LeftShiftKey,
247 LeftAltKey,
248 LeftMetaKey,
249 RightControlKey,
250 RightShiftKey,
251 RightAltKey,
252 RightMetaKey,
253
254 MediaPlayPause,
255 MediaStopCD,
256 MediaPrevious,
257 MediaNext,
258 MediaEject,
259 MediaVolumeUp,
260 MediaVolumeDown,
261 MediaMute,
262 MediaWebsite,
263 MediaBack,
264 MediaForward,
265 MediaStop,
266 MediaFind,
267 MediaScrollUp,
268 MediaScrollDown,
269 MediaEdit,
270 MediaSleep,
271 MediaCoffee,
272 MediaRefresh,
273 MediaCalculator,
274
275 NumKeyboardKeys,
276};
277
278static_assert(NumKeyboardKeys == 0xFC, "Incorrect number of keyboard keys.");
279
280enum Modifiers {
281 LeftControl,
282 LeftShift,
283 LeftAlt,
284 LeftMeta,
285 RightControl,
286 RightShift,
287 RightAlt,
288 RightMeta,
289 CapsLock,
290 ScrollLock,
291 NumLock,
292
293 NumKeyboardMods,
294};
295
296constexpr int KEYBOARD_KEYS_HID_BEGIN = None;
297constexpr int KEYBOARD_KEYS_HID_END = NumKeyboardKeys;
298constexpr int NUM_KEYBOARD_KEYS_HID = NumKeyboardKeys;
299
300constexpr int KEYBOARD_MODS_HID_BEGIN = LeftControl;
301constexpr int KEYBOARD_MODS_HID_END = NumKeyboardMods;
302constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods;
303
304} // namespace NativeKeyboard
305
306using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>;
307using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>;
308using MouseButtonsRaw = std::array<std::string, NativeMouseButton::NumMouseButtons>;
309using KeyboardKeysRaw = std::array<std::string, NativeKeyboard::NumKeyboardKeys>;
310using KeyboardModsRaw = std::array<std::string, NativeKeyboard::NumKeyboardMods>;
311
312constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;
313constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A;
314constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6;
315constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E;
316
317enum class ControllerType {
318 ProController,
319 DualJoycon,
320 RightJoycon,
321 LeftJoycon,
322};
323
324struct PlayerInput {
325 bool connected;
326 ControllerType type;
327 ButtonsRaw buttons;
328 AnalogsRaw analogs;
329
330 u32 body_color_right;
331 u32 button_color_right;
332 u32 body_color_left;
333 u32 button_color_left;
334};
335
336struct TouchscreenInput {
337 bool enabled;
338 std::string device;
339
340 u32 finger;
341 u32 diameter_x;
342 u32 diameter_y;
343 u32 rotation_angle;
344};
345
113struct Values { 346struct Values {
114 // System 347 // System
115 bool use_docked_mode; 348 bool use_docked_mode;
116 bool enable_nfc; 349 bool enable_nfc;
350 std::optional<u32> rng_seed;
117 s32 current_user; 351 s32 current_user;
118 s32 language_index; 352 s32 language_index;
119 353
120 // Controls 354 // Controls
121 std::array<std::string, NativeButton::NumButtons> buttons; 355 std::array<PlayerInput, 10> players;
122 std::array<std::string, NativeAnalog::NumAnalogs> analogs; 356
357 bool mouse_enabled;
358 std::string mouse_device;
359 MouseButtonsRaw mouse_buttons;
360
361 bool keyboard_enabled;
362 KeyboardKeysRaw keyboard_keys;
363 KeyboardModsRaw keyboard_mods;
364
365 bool debug_pad_enabled;
366 ButtonsRaw debug_pad_buttons;
367 AnalogsRaw debug_pad_analogs;
368
123 std::string motion_device; 369 std::string motion_device;
124 std::string touch_device; 370 TouchscreenInput touchscreen;
125 std::atomic_bool is_device_reload_pending{true}; 371 std::atomic_bool is_device_reload_pending{true};
126 372
127 // Core 373 // Core
@@ -157,6 +403,8 @@ struct Values {
157 bool use_gdbstub; 403 bool use_gdbstub;
158 u16 gdbstub_port; 404 u16 gdbstub_port;
159 std::string program_args; 405 std::string program_args;
406 bool dump_exefs;
407 bool dump_nso;
160 408
161 // WebService 409 // WebService
162 bool enable_telemetry; 410 bool enable_telemetry;