summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp1
-rw-r--r--src/core/debugger/debugger.cpp161
-rw-r--r--src/core/debugger/gdbstub.cpp151
-rw-r--r--src/core/debugger/gdbstub.h1
-rw-r--r--src/core/frontend/applets/cabinet.cpp20
-rw-r--r--src/core/frontend/applets/cabinet.h37
-rw-r--r--src/core/hid/emulated_console.cpp94
-rw-r--r--src/core/hid/emulated_console.h15
-rw-r--r--src/core/hid/input_converter.cpp3
-rw-r--r--src/core/hle/kernel/init/init_slab_setup.cpp1
-rw-r--r--src/core/hle/kernel/k_page_table.cpp3
-rw-r--r--src/core/hle/kernel/k_page_table.h3
-rw-r--r--src/core/hle/kernel/k_process.cpp1
-rw-r--r--src/core/hle/kernel/svc.cpp26
-rw-r--r--src/core/hle/kernel/svc_wrap.h8
-rw-r--r--src/core/hle/result.h76
-rw-r--r--src/core/hle/service/am/applets/applet_cabinet.cpp177
-rw-r--r--src/core/hle/service/am/applets/applet_cabinet.h104
-rw-r--r--src/core/hle/service/am/applets/applet_error.cpp1
-rw-r--r--src/core/hle/service/am/applets/applet_general_backend.cpp2
-rw-r--r--src/core/hle/service/am/applets/applets.cpp20
-rw-r--r--src/core/hle/service/am/applets/applets.h12
-rw-r--r--src/core/hle/service/hid/hid.cpp32
-rw-r--r--src/core/hle/service/hid/hid.h4
-rw-r--r--src/core/hle/service/nfp/nfp_device.cpp35
-rw-r--r--src/core/hle/service/nfp/nfp_device.h6
-rw-r--r--src/core/hle/service/nfp/nfp_types.h17
-rw-r--r--src/core/hle/service/nfp/nfp_user.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp5
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_core.cpp6
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_core.h5
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_producer.cpp14
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue_producer.h3
-rw-r--r--src/core/hle/service/service.cpp1
-rw-r--r--src/core/hle/service/time/time_zone_manager.cpp1
-rw-r--r--src/core/memory.cpp65
-rw-r--r--src/core/memory.h34
39 files changed, 1010 insertions, 146 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 705667080..5629980d9 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -120,6 +120,8 @@ add_library(core STATIC
120 file_sys/vfs_vector.h 120 file_sys/vfs_vector.h
121 file_sys/xts_archive.cpp 121 file_sys/xts_archive.cpp
122 file_sys/xts_archive.h 122 file_sys/xts_archive.h
123 frontend/applets/cabinet.cpp
124 frontend/applets/cabinet.h
123 frontend/applets/controller.cpp 125 frontend/applets/controller.cpp
124 frontend/applets/controller.h 126 frontend/applets/controller.h
125 frontend/applets/error.cpp 127 frontend/applets/error.cpp
@@ -312,6 +314,8 @@ add_library(core STATIC
312 hle/service/am/applet_ae.h 314 hle/service/am/applet_ae.h
313 hle/service/am/applet_oe.cpp 315 hle/service/am/applet_oe.cpp
314 hle/service/am/applet_oe.h 316 hle/service/am/applet_oe.h
317 hle/service/am/applets/applet_cabinet.cpp
318 hle/service/am/applets/applet_cabinet.h
315 hle/service/am/applets/applet_controller.cpp 319 hle/service/am/applets/applet_controller.cpp
316 hle/service/am/applets/applet_controller.h 320 hle/service/am/applets/applet_controller.h
317 hle/service/am/applets/applet_error.cpp 321 hle/service/am/applets/applet_error.cpp
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index afb7fb3a0..cb53d64ba 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -348,7 +348,6 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
348 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) { 348 if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) {
349 config.unsafe_optimizations = true; 349 config.unsafe_optimizations = true;
350 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; 350 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
351 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
352 config.fastmem_address_space_bits = 64; 351 config.fastmem_address_space_bits = 64;
353 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; 352 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
354 } 353 }
diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp
index 339f971e6..1a8e02e6a 100644
--- a/src/core/debugger/debugger.cpp
+++ b/src/core/debugger/debugger.cpp
@@ -27,12 +27,21 @@ static void AsyncReceiveInto(Readable& r, Buffer& buffer, Callback&& c) {
27 const u8* buffer_start = reinterpret_cast<const u8*>(&buffer); 27 const u8* buffer_start = reinterpret_cast<const u8*>(&buffer);
28 std::span<const u8> received_data{buffer_start, buffer_start + bytes_read}; 28 std::span<const u8> received_data{buffer_start, buffer_start + bytes_read};
29 c(received_data); 29 c(received_data);
30 AsyncReceiveInto(r, buffer, c);
30 } 31 }
31
32 AsyncReceiveInto(r, buffer, c);
33 }); 32 });
34} 33}
35 34
35template <typename Callback>
36static void AsyncAccept(boost::asio::ip::tcp::acceptor& acceptor, Callback&& c) {
37 acceptor.async_accept([&, c](const boost::system::error_code& error, auto&& peer_socket) {
38 if (!error.failed()) {
39 c(peer_socket);
40 AsyncAccept(acceptor, c);
41 }
42 });
43}
44
36template <typename Readable, typename Buffer> 45template <typename Readable, typename Buffer>
37static std::span<const u8> ReceiveInto(Readable& r, Buffer& buffer) { 46static std::span<const u8> ReceiveInto(Readable& r, Buffer& buffer) {
38 static_assert(std::is_trivial_v<Buffer>); 47 static_assert(std::is_trivial_v<Buffer>);
@@ -59,9 +68,7 @@ namespace Core {
59 68
60class DebuggerImpl : public DebuggerBackend { 69class DebuggerImpl : public DebuggerBackend {
61public: 70public:
62 explicit DebuggerImpl(Core::System& system_, u16 port) 71 explicit DebuggerImpl(Core::System& system_, u16 port) : system{system_} {
63 : system{system_}, signal_pipe{io_context}, client_socket{io_context} {
64 frontend = std::make_unique<GDBStub>(*this, system);
65 InitializeServer(port); 72 InitializeServer(port);
66 } 73 }
67 74
@@ -70,39 +77,42 @@ public:
70 } 77 }
71 78
72 bool SignalDebugger(SignalInfo signal_info) { 79 bool SignalDebugger(SignalInfo signal_info) {
73 { 80 std::scoped_lock lk{connection_lock};
74 std::scoped_lock lk{connection_lock};
75 81
76 if (stopped) { 82 if (stopped || !state) {
77 // Do not notify the debugger about another event. 83 // Do not notify the debugger about another event.
78 // It should be ignored. 84 // It should be ignored.
79 return false; 85 return false;
80 }
81
82 // Set up the state.
83 stopped = true;
84 info = signal_info;
85 } 86 }
86 87
88 // Set up the state.
89 stopped = true;
90 state->info = signal_info;
91
87 // Write a single byte into the pipe to wake up the debug interface. 92 // Write a single byte into the pipe to wake up the debug interface.
88 boost::asio::write(signal_pipe, boost::asio::buffer(&stopped, sizeof(stopped))); 93 boost::asio::write(state->signal_pipe, boost::asio::buffer(&stopped, sizeof(stopped)));
94
89 return true; 95 return true;
90 } 96 }
91 97
98 // These functions are callbacks from the frontend, and the lock will be held.
99 // There is no need to relock it.
100
92 std::span<const u8> ReadFromClient() override { 101 std::span<const u8> ReadFromClient() override {
93 return ReceiveInto(client_socket, client_data); 102 return ReceiveInto(state->client_socket, state->client_data);
94 } 103 }
95 104
96 void WriteToClient(std::span<const u8> data) override { 105 void WriteToClient(std::span<const u8> data) override {
97 boost::asio::write(client_socket, boost::asio::buffer(data.data(), data.size_bytes())); 106 boost::asio::write(state->client_socket,
107 boost::asio::buffer(data.data(), data.size_bytes()));
98 } 108 }
99 109
100 void SetActiveThread(Kernel::KThread* thread) override { 110 void SetActiveThread(Kernel::KThread* thread) override {
101 active_thread = thread; 111 state->active_thread = thread;
102 } 112 }
103 113
104 Kernel::KThread* GetActiveThread() override { 114 Kernel::KThread* GetActiveThread() override {
105 return active_thread; 115 return state->active_thread;
106 } 116 }
107 117
108private: 118private:
@@ -113,65 +123,78 @@ private:
113 123
114 // Run the connection thread. 124 // Run the connection thread.
115 connection_thread = std::jthread([&, port](std::stop_token stop_token) { 125 connection_thread = std::jthread([&, port](std::stop_token stop_token) {
126 Common::SetCurrentThreadName("Debugger");
127
116 try { 128 try {
117 // Initialize the listening socket and accept a new client. 129 // Initialize the listening socket and accept a new client.
118 tcp::endpoint endpoint{boost::asio::ip::address_v4::any(), port}; 130 tcp::endpoint endpoint{boost::asio::ip::address_v4::any(), port};
119 tcp::acceptor acceptor{io_context, endpoint}; 131 tcp::acceptor acceptor{io_context, endpoint};
120 132
121 acceptor.async_accept(client_socket, [](const auto&) {}); 133 AsyncAccept(acceptor, [&](auto&& peer) { AcceptConnection(std::move(peer)); });
122 io_context.run_one();
123 io_context.restart();
124 134
125 if (stop_token.stop_requested()) { 135 while (!stop_token.stop_requested() && io_context.run()) {
126 return;
127 } 136 }
128
129 ThreadLoop(stop_token);
130 } catch (const std::exception& ex) { 137 } catch (const std::exception& ex) {
131 LOG_CRITICAL(Debug_GDBStub, "Stopping server: {}", ex.what()); 138 LOG_CRITICAL(Debug_GDBStub, "Stopping server: {}", ex.what());
132 } 139 }
133 }); 140 });
134 } 141 }
135 142
136 void ShutdownServer() { 143 void AcceptConnection(boost::asio::ip::tcp::socket&& peer) {
137 connection_thread.request_stop(); 144 LOG_INFO(Debug_GDBStub, "Accepting new peer connection");
138 io_context.stop();
139 connection_thread.join();
140 }
141 145
142 void ThreadLoop(std::stop_token stop_token) { 146 std::scoped_lock lk{connection_lock};
143 Common::SetCurrentThreadName("Debugger"); 147
148 // Ensure everything is stopped.
149 PauseEmulation();
150
151 // Set up the new frontend.
152 frontend = std::make_unique<GDBStub>(*this, system);
153
154 // Set the new state. This will tear down any existing state.
155 state = ConnectionState{
156 .client_socket{std::move(peer)},
157 .signal_pipe{io_context},
158 .info{},
159 .active_thread{},
160 .client_data{},
161 .pipe_data{},
162 };
144 163
145 // Set up the client signals for new data. 164 // Set up the client signals for new data.
146 AsyncReceiveInto(signal_pipe, pipe_data, [&](auto d) { PipeData(d); }); 165 AsyncReceiveInto(state->signal_pipe, state->pipe_data, [&](auto d) { PipeData(d); });
147 AsyncReceiveInto(client_socket, client_data, [&](auto d) { ClientData(d); }); 166 AsyncReceiveInto(state->client_socket, state->client_data, [&](auto d) { ClientData(d); });
148 167
149 // Set the active thread. 168 // Set the active thread.
150 UpdateActiveThread(); 169 UpdateActiveThread();
151 170
152 // Set up the frontend. 171 // Set up the frontend.
153 frontend->Connected(); 172 frontend->Connected();
173 }
154 174
155 // Main event loop. 175 void ShutdownServer() {
156 while (!stop_token.stop_requested() && io_context.run()) { 176 connection_thread.request_stop();
157 } 177 io_context.stop();
178 connection_thread.join();
158 } 179 }
159 180
160 void PipeData(std::span<const u8> data) { 181 void PipeData(std::span<const u8> data) {
161 switch (info.type) { 182 std::scoped_lock lk{connection_lock};
183
184 switch (state->info.type) {
162 case SignalType::Stopped: 185 case SignalType::Stopped:
163 case SignalType::Watchpoint: 186 case SignalType::Watchpoint:
164 // Stop emulation. 187 // Stop emulation.
165 PauseEmulation(); 188 PauseEmulation();
166 189
167 // Notify the client. 190 // Notify the client.
168 active_thread = info.thread; 191 state->active_thread = state->info.thread;
169 UpdateActiveThread(); 192 UpdateActiveThread();
170 193
171 if (info.type == SignalType::Watchpoint) { 194 if (state->info.type == SignalType::Watchpoint) {
172 frontend->Watchpoint(active_thread, *info.watchpoint); 195 frontend->Watchpoint(state->active_thread, *state->info.watchpoint);
173 } else { 196 } else {
174 frontend->Stopped(active_thread); 197 frontend->Stopped(state->active_thread);
175 } 198 }
176 199
177 break; 200 break;
@@ -179,8 +202,8 @@ private:
179 frontend->ShuttingDown(); 202 frontend->ShuttingDown();
180 203
181 // Wait for emulation to shut down gracefully now. 204 // Wait for emulation to shut down gracefully now.
182 signal_pipe.close(); 205 state->signal_pipe.close();
183 client_socket.shutdown(boost::asio::socket_base::shutdown_both); 206 state->client_socket.shutdown(boost::asio::socket_base::shutdown_both);
184 LOG_INFO(Debug_GDBStub, "Shut down server"); 207 LOG_INFO(Debug_GDBStub, "Shut down server");
185 208
186 break; 209 break;
@@ -188,17 +211,16 @@ private:
188 } 211 }
189 212
190 void ClientData(std::span<const u8> data) { 213 void ClientData(std::span<const u8> data) {
214 std::scoped_lock lk{connection_lock};
215
191 const auto actions{frontend->ClientData(data)}; 216 const auto actions{frontend->ClientData(data)};
192 for (const auto action : actions) { 217 for (const auto action : actions) {
193 switch (action) { 218 switch (action) {
194 case DebuggerAction::Interrupt: { 219 case DebuggerAction::Interrupt: {
195 { 220 stopped = true;
196 std::scoped_lock lk{connection_lock};
197 stopped = true;
198 }
199 PauseEmulation(); 221 PauseEmulation();
200 UpdateActiveThread(); 222 UpdateActiveThread();
201 frontend->Stopped(active_thread); 223 frontend->Stopped(state->active_thread);
202 break; 224 break;
203 } 225 }
204 case DebuggerAction::Continue: 226 case DebuggerAction::Continue:
@@ -206,15 +228,15 @@ private:
206 break; 228 break;
207 case DebuggerAction::StepThreadUnlocked: 229 case DebuggerAction::StepThreadUnlocked:
208 MarkResumed([&] { 230 MarkResumed([&] {
209 active_thread->SetStepState(Kernel::StepState::StepPending); 231 state->active_thread->SetStepState(Kernel::StepState::StepPending);
210 active_thread->Resume(Kernel::SuspendType::Debug); 232 state->active_thread->Resume(Kernel::SuspendType::Debug);
211 ResumeEmulation(active_thread); 233 ResumeEmulation(state->active_thread);
212 }); 234 });
213 break; 235 break;
214 case DebuggerAction::StepThreadLocked: { 236 case DebuggerAction::StepThreadLocked: {
215 MarkResumed([&] { 237 MarkResumed([&] {
216 active_thread->SetStepState(Kernel::StepState::StepPending); 238 state->active_thread->SetStepState(Kernel::StepState::StepPending);
217 active_thread->Resume(Kernel::SuspendType::Debug); 239 state->active_thread->Resume(Kernel::SuspendType::Debug);
218 }); 240 });
219 break; 241 break;
220 } 242 }
@@ -254,15 +276,14 @@ private:
254 template <typename Callback> 276 template <typename Callback>
255 void MarkResumed(Callback&& cb) { 277 void MarkResumed(Callback&& cb) {
256 Kernel::KScopedSchedulerLock sl{system.Kernel()}; 278 Kernel::KScopedSchedulerLock sl{system.Kernel()};
257 std::scoped_lock cl{connection_lock};
258 stopped = false; 279 stopped = false;
259 cb(); 280 cb();
260 } 281 }
261 282
262 void UpdateActiveThread() { 283 void UpdateActiveThread() {
263 const auto& threads{ThreadList()}; 284 const auto& threads{ThreadList()};
264 if (std::find(threads.begin(), threads.end(), active_thread) == threads.end()) { 285 if (std::find(threads.begin(), threads.end(), state->active_thread) == threads.end()) {
265 active_thread = threads[0]; 286 state->active_thread = threads[0];
266 } 287 }
267 } 288 }
268 289
@@ -274,18 +295,22 @@ private:
274 System& system; 295 System& system;
275 std::unique_ptr<DebuggerFrontend> frontend; 296 std::unique_ptr<DebuggerFrontend> frontend;
276 297
298 boost::asio::io_context io_context;
277 std::jthread connection_thread; 299 std::jthread connection_thread;
278 std::mutex connection_lock; 300 std::mutex connection_lock;
279 boost::asio::io_context io_context;
280 boost::process::async_pipe signal_pipe;
281 boost::asio::ip::tcp::socket client_socket;
282 301
283 SignalInfo info; 302 struct ConnectionState {
284 Kernel::KThread* active_thread; 303 boost::asio::ip::tcp::socket client_socket;
285 bool pipe_data; 304 boost::process::async_pipe signal_pipe;
286 bool stopped; 305
306 SignalInfo info;
307 Kernel::KThread* active_thread;
308 std::array<u8, 4096> client_data;
309 bool pipe_data;
310 };
287 311
288 std::array<u8, 4096> client_data; 312 std::optional<ConnectionState> state{};
313 bool stopped{};
289}; 314};
290 315
291Debugger::Debugger(Core::System& system, u16 port) { 316Debugger::Debugger(Core::System& system, u16 port) {
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp
index 884229c77..a64a9ac64 100644
--- a/src/core/debugger/gdbstub.cpp
+++ b/src/core/debugger/gdbstub.cpp
@@ -606,6 +606,8 @@ void GDBStub::HandleQuery(std::string_view command) {
606 } else if (command.starts_with("StartNoAckMode")) { 606 } else if (command.starts_with("StartNoAckMode")) {
607 no_ack = true; 607 no_ack = true;
608 SendReply(GDB_STUB_REPLY_OK); 608 SendReply(GDB_STUB_REPLY_OK);
609 } else if (command.starts_with("Rcmd,")) {
610 HandleRcmd(Common::HexStringToVector(command.substr(5), false));
609 } else { 611 } else {
610 SendReply(GDB_STUB_REPLY_EMPTY); 612 SendReply(GDB_STUB_REPLY_EMPTY);
611 } 613 }
@@ -645,6 +647,155 @@ void GDBStub::HandleVCont(std::string_view command, std::vector<DebuggerAction>&
645 } 647 }
646} 648}
647 649
650constexpr std::array<std::pair<const char*, Kernel::Svc::MemoryState>, 22> MemoryStateNames{{
651 {"----- Free -----", Kernel::Svc::MemoryState::Free},
652 {"Io ", Kernel::Svc::MemoryState::Io},
653 {"Static ", Kernel::Svc::MemoryState::Static},
654 {"Code ", Kernel::Svc::MemoryState::Code},
655 {"CodeData ", Kernel::Svc::MemoryState::CodeData},
656 {"Normal ", Kernel::Svc::MemoryState::Normal},
657 {"Shared ", Kernel::Svc::MemoryState::Shared},
658 {"AliasCode ", Kernel::Svc::MemoryState::AliasCode},
659 {"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData},
660 {"Ipc ", Kernel::Svc::MemoryState::Ipc},
661 {"Stack ", Kernel::Svc::MemoryState::Stack},
662 {"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal},
663 {"Transfered ", Kernel::Svc::MemoryState::Transfered},
664 {"SharedTransfered", Kernel::Svc::MemoryState::SharedTransfered},
665 {"SharedCode ", Kernel::Svc::MemoryState::SharedCode},
666 {"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible},
667 {"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc},
668 {"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc},
669 {"Kernel ", Kernel::Svc::MemoryState::Kernel},
670 {"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode},
671 {"CodeOut ", Kernel::Svc::MemoryState::CodeOut},
672 {"Coverage ", Kernel::Svc::MemoryState::Coverage},
673}};
674
675static constexpr const char* GetMemoryStateName(Kernel::Svc::MemoryState state) {
676 for (size_t i = 0; i < MemoryStateNames.size(); i++) {
677 if (std::get<1>(MemoryStateNames[i]) == state) {
678 return std::get<0>(MemoryStateNames[i]);
679 }
680 }
681 return "Unknown ";
682}
683
684static constexpr const char* GetMemoryPermissionString(const Kernel::Svc::MemoryInfo& info) {
685 if (info.state == Kernel::Svc::MemoryState::Free) {
686 return " ";
687 }
688
689 switch (info.permission) {
690 case Kernel::Svc::MemoryPermission::ReadExecute:
691 return "r-x";
692 case Kernel::Svc::MemoryPermission::Read:
693 return "r--";
694 case Kernel::Svc::MemoryPermission::ReadWrite:
695 return "rw-";
696 default:
697 return "---";
698 }
699}
700
701static VAddr GetModuleEnd(Kernel::KPageTable& page_table, VAddr base) {
702 Kernel::Svc::MemoryInfo mem_info;
703 VAddr cur_addr{base};
704
705 // Expect: r-x Code (.text)
706 mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo();
707 cur_addr = mem_info.base_address + mem_info.size;
708 if (mem_info.state != Kernel::Svc::MemoryState::Code ||
709 mem_info.permission != Kernel::Svc::MemoryPermission::ReadExecute) {
710 return cur_addr - 1;
711 }
712
713 // Expect: r-- Code (.rodata)
714 mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo();
715 cur_addr = mem_info.base_address + mem_info.size;
716 if (mem_info.state != Kernel::Svc::MemoryState::Code ||
717 mem_info.permission != Kernel::Svc::MemoryPermission::Read) {
718 return cur_addr - 1;
719 }
720
721 // Expect: rw- CodeData (.data)
722 mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo();
723 cur_addr = mem_info.base_address + mem_info.size;
724 return cur_addr - 1;
725}
726
727void GDBStub::HandleRcmd(const std::vector<u8>& command) {
728 std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()};
729 std::string reply;
730
731 auto* process = system.CurrentProcess();
732 auto& page_table = process->PageTable();
733
734 if (command_str == "get info") {
735 Loader::AppLoader::Modules modules;
736 system.GetAppLoader().ReadNSOModules(modules);
737
738 reply = fmt::format("Process: {:#x} ({})\n"
739 "Program Id: {:#018x}\n",
740 process->GetProcessID(), process->GetName(), process->GetProgramID());
741 reply +=
742 fmt::format("Layout:\n"
743 " Alias: {:#012x} - {:#012x}\n"
744 " Heap: {:#012x} - {:#012x}\n"
745 " Aslr: {:#012x} - {:#012x}\n"
746 " Stack: {:#012x} - {:#012x}\n"
747 "Modules:\n",
748 page_table.GetAliasRegionStart(), page_table.GetAliasRegionEnd(),
749 page_table.GetHeapRegionStart(), page_table.GetHeapRegionEnd(),
750 page_table.GetAliasCodeRegionStart(), page_table.GetAliasCodeRegionEnd(),
751 page_table.GetStackRegionStart(), page_table.GetStackRegionEnd());
752
753 for (const auto& [vaddr, name] : modules) {
754 reply += fmt::format(" {:#012x} - {:#012x} {}\n", vaddr,
755 GetModuleEnd(page_table, vaddr), name);
756 }
757 } else if (command_str == "get mappings") {
758 reply = "Mappings:\n";
759 VAddr cur_addr = 0;
760
761 while (true) {
762 using MemoryAttribute = Kernel::Svc::MemoryAttribute;
763
764 auto mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo();
765
766 if (mem_info.state != Kernel::Svc::MemoryState::Inaccessible ||
767 mem_info.base_address + mem_info.size - 1 != std::numeric_limits<u64>::max()) {
768 const char* state = GetMemoryStateName(mem_info.state);
769 const char* perm = GetMemoryPermissionString(mem_info);
770
771 const char l = True(mem_info.attribute & MemoryAttribute::Locked) ? 'L' : '-';
772 const char i = True(mem_info.attribute & MemoryAttribute::IpcLocked) ? 'I' : '-';
773 const char d = True(mem_info.attribute & MemoryAttribute::DeviceShared) ? 'D' : '-';
774 const char u = True(mem_info.attribute & MemoryAttribute::Uncached) ? 'U' : '-';
775
776 reply +=
777 fmt::format(" {:#012x} - {:#012x} {} {} {}{}{}{} [{}, {}]\n",
778 mem_info.base_address, mem_info.base_address + mem_info.size - 1,
779 perm, state, l, i, d, u, mem_info.ipc_count, mem_info.device_count);
780 }
781
782 const uintptr_t next_address = mem_info.base_address + mem_info.size;
783 if (next_address <= cur_addr) {
784 break;
785 }
786
787 cur_addr = next_address;
788 }
789 } else if (command_str == "help") {
790 reply = "Commands:\n get info\n get mappings\n";
791 } else {
792 reply = "Unknown command.\nCommands:\n get info\n get mappings\n";
793 }
794
795 std::span<const u8> reply_span{reinterpret_cast<u8*>(&reply.front()), reply.size()};
796 SendReply(Common::HexToString(reply_span, false));
797}
798
648Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { 799Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) {
649 const auto& threads{system.GlobalSchedulerContext().GetThreadList()}; 800 const auto& threads{system.GlobalSchedulerContext().GetThreadList()};
650 for (auto* thread : threads) { 801 for (auto* thread : threads) {
diff --git a/src/core/debugger/gdbstub.h b/src/core/debugger/gdbstub.h
index 0b0f56e4b..368197920 100644
--- a/src/core/debugger/gdbstub.h
+++ b/src/core/debugger/gdbstub.h
@@ -32,6 +32,7 @@ private:
32 void ExecuteCommand(std::string_view packet, std::vector<DebuggerAction>& actions); 32 void ExecuteCommand(std::string_view packet, std::vector<DebuggerAction>& actions);
33 void HandleVCont(std::string_view command, std::vector<DebuggerAction>& actions); 33 void HandleVCont(std::string_view command, std::vector<DebuggerAction>& actions);
34 void HandleQuery(std::string_view command); 34 void HandleQuery(std::string_view command);
35 void HandleRcmd(const std::vector<u8>& command);
35 void HandleBreakpointInsert(std::string_view command); 36 void HandleBreakpointInsert(std::string_view command);
36 void HandleBreakpointRemove(std::string_view command); 37 void HandleBreakpointRemove(std::string_view command);
37 std::vector<char>::const_iterator CommandEnd() const; 38 std::vector<char>::const_iterator CommandEnd() const;
diff --git a/src/core/frontend/applets/cabinet.cpp b/src/core/frontend/applets/cabinet.cpp
new file mode 100644
index 000000000..26c7fefe3
--- /dev/null
+++ b/src/core/frontend/applets/cabinet.cpp
@@ -0,0 +1,20 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/logging/log.h"
5#include "core/frontend/applets/cabinet.h"
6
7#include <thread>
8
9namespace Core::Frontend {
10
11CabinetApplet::~CabinetApplet() = default;
12
13void DefaultCabinetApplet::ShowCabinetApplet(
14 const CabinetCallback& callback, const CabinetParameters& parameters,
15 std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const {
16 LOG_WARNING(Service_AM, "(STUBBED) called");
17 callback(false, {});
18}
19
20} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/cabinet.h b/src/core/frontend/applets/cabinet.h
new file mode 100644
index 000000000..c28a235c1
--- /dev/null
+++ b/src/core/frontend/applets/cabinet.h
@@ -0,0 +1,37 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <functional>
7#include "core/hle/service/nfp/nfp_types.h"
8
9namespace Service::NFP {
10class NfpDevice;
11} // namespace Service::NFP
12
13namespace Core::Frontend {
14
15struct CabinetParameters {
16 Service::NFP::TagInfo tag_info;
17 Service::NFP::RegisterInfo register_info;
18 Service::NFP::CabinetMode mode;
19};
20
21using CabinetCallback = std::function<void(bool, const std::string&)>;
22
23class CabinetApplet {
24public:
25 virtual ~CabinetApplet();
26 virtual void ShowCabinetApplet(const CabinetCallback& callback,
27 const CabinetParameters& parameters,
28 std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const = 0;
29};
30
31class DefaultCabinetApplet final : public CabinetApplet {
32public:
33 void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters,
34 std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override;
35};
36
37} // namespace Core::Frontend
diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp
index aac45907d..fb7e5802a 100644
--- a/src/core/hid/emulated_console.cpp
+++ b/src/core/hid/emulated_console.cpp
@@ -19,27 +19,26 @@ void EmulatedConsole::ReloadFromSettings() {
19} 19}
20 20
21void EmulatedConsole::SetTouchParams() { 21void EmulatedConsole::SetTouchParams() {
22 // TODO(german77): Support any number of fingers
23 std::size_t index = 0; 22 std::size_t index = 0;
24 23
25 // Hardcode mouse, touchscreen and cemuhook parameters 24 // We can't use mouse as touch if native mouse is enabled
26 if (!Settings::values.mouse_enabled) { 25 if (!Settings::values.mouse_enabled) {
27 // We can't use mouse as touch if native mouse is enabled
28 touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; 26 touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"};
29 } 27 }
30 28
31 touch_params[index++] = 29 touch_params[index++] =
32 Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0,touch_id:0"}; 30 Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536"};
33 touch_params[index++] = 31 touch_params[index++] =
34 Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1,touch_id:1"}; 32 Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072"};
35 touch_params[index++] = 33
36 Common::ParamPackage{"engine:touch,axis_x:4,axis_y:5,button:2,touch_id:2"}; 34 for (int i = 0; i < static_cast<int>(MaxActiveTouchInputs); i++) {
37 touch_params[index++] = 35 Common::ParamPackage touchscreen_param{};
38 Common::ParamPackage{"engine:touch,axis_x:6,axis_y:7,button:3,touch_id:3"}; 36 touchscreen_param.Set("engine", "touch");
39 touch_params[index++] = 37 touchscreen_param.Set("axis_x", i * 2);
40 Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536,touch_id:0"}; 38 touchscreen_param.Set("axis_y", (i * 2) + 1);
41 touch_params[index++] = 39 touchscreen_param.Set("button", i);
42 Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072,touch_id:1"}; 40 touch_params[index++] = touchscreen_param;
41 }
43 42
44 const auto button_index = 43 const auto button_index =
45 static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue()); 44 static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());
@@ -47,7 +46,7 @@ void EmulatedConsole::SetTouchParams() {
47 46
48 // Map the rest of the fingers from touch from button configuration 47 // Map the rest of the fingers from touch from button configuration
49 for (const auto& config_entry : touch_buttons) { 48 for (const auto& config_entry : touch_buttons) {
50 if (index >= touch_params.size()) { 49 if (index >= MaxTouchDevices) {
51 continue; 50 continue;
52 } 51 }
53 Common::ParamPackage params{config_entry}; 52 Common::ParamPackage params{config_entry};
@@ -60,7 +59,6 @@ void EmulatedConsole::SetTouchParams() {
60 touch_button_params.Set("button", params.Serialize()); 59 touch_button_params.Set("button", params.Serialize());
61 touch_button_params.Set("x", x); 60 touch_button_params.Set("x", x);
62 touch_button_params.Set("y", y); 61 touch_button_params.Set("y", y);
63 touch_button_params.Set("touch_id", static_cast<int>(index));
64 touch_params[index] = touch_button_params; 62 touch_params[index] = touch_button_params;
65 index++; 63 index++;
66 } 64 }
@@ -178,12 +176,38 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
178} 176}
179 177
180void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) { 178void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) {
181 if (index >= console.touch_values.size()) { 179 if (index >= MaxTouchDevices) {
182 return; 180 return;
183 } 181 }
184 std::unique_lock lock{mutex}; 182 std::unique_lock lock{mutex};
185 183
186 console.touch_values[index] = TransformToTouch(callback); 184 const auto touch_input = TransformToTouch(callback);
185 auto touch_index = GetIndexFromFingerId(index);
186 bool is_new_input = false;
187
188 if (!touch_index.has_value() && touch_input.pressed.value) {
189 touch_index = GetNextFreeIndex();
190 is_new_input = true;
191 }
192
193 // No free entries or invalid state. Ignore input
194 if (!touch_index.has_value()) {
195 return;
196 }
197
198 auto& touch_value = console.touch_values[touch_index.value()];
199
200 if (is_new_input) {
201 touch_value.pressed.value = true;
202 touch_value.id = static_cast<u32>(index);
203 }
204
205 touch_value.x = touch_input.x;
206 touch_value.y = touch_input.y;
207
208 if (!touch_input.pressed.value) {
209 touch_value.pressed.value = false;
210 }
187 211
188 if (is_configuring) { 212 if (is_configuring) {
189 lock.unlock(); 213 lock.unlock();
@@ -191,11 +215,15 @@ void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, st
191 return; 215 return;
192 } 216 }
193 217
194 // TODO(german77): Remap touch id in sequential order 218 // Touch outside allowed range. Ignore input
195 console.touch_state[index] = { 219 if (touch_index.value() >= MaxActiveTouchInputs) {
196 .position = {console.touch_values[index].x.value, console.touch_values[index].y.value}, 220 return;
197 .id = static_cast<u32>(console.touch_values[index].id), 221 }
198 .pressed = console.touch_values[index].pressed.value, 222
223 console.touch_state[touch_index.value()] = {
224 .position = {touch_value.x.value, touch_value.y.value},
225 .id = static_cast<u32>(touch_index.value()),
226 .pressed = touch_input.pressed.value,
199 }; 227 };
200 228
201 lock.unlock(); 229 lock.unlock();
@@ -222,6 +250,28 @@ TouchFingerState EmulatedConsole::GetTouch() const {
222 return console.touch_state; 250 return console.touch_state;
223} 251}
224 252
253std::optional<std::size_t> EmulatedConsole::GetIndexFromFingerId(std::size_t finger_id) const {
254 for (std::size_t index = 0; index < MaxTouchDevices; ++index) {
255 const auto& finger = console.touch_values[index];
256 if (!finger.pressed.value) {
257 continue;
258 }
259 if (finger.id == static_cast<int>(finger_id)) {
260 return index;
261 }
262 }
263 return std::nullopt;
264}
265
266std::optional<std::size_t> EmulatedConsole::GetNextFreeIndex() const {
267 for (std::size_t index = 0; index < MaxTouchDevices; ++index) {
268 if (!console.touch_values[index].pressed.value) {
269 return index;
270 }
271 }
272 return std::nullopt;
273}
274
225void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) { 275void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {
226 std::scoped_lock lock{callback_mutex}; 276 std::scoped_lock lock{callback_mutex};
227 for (const auto& poller_pair : callback_list) { 277 for (const auto& poller_pair : callback_list) {
diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h
index 1c510cd19..697ecd2d6 100644
--- a/src/core/hid/emulated_console.h
+++ b/src/core/hid/emulated_console.h
@@ -7,6 +7,7 @@
7#include <functional> 7#include <functional>
8#include <memory> 8#include <memory>
9#include <mutex> 9#include <mutex>
10#include <optional>
10#include <unordered_map> 11#include <unordered_map>
11 12
12#include "common/common_funcs.h" 13#include "common/common_funcs.h"
@@ -20,6 +21,8 @@
20#include "core/hid/motion_input.h" 21#include "core/hid/motion_input.h"
21 22
22namespace Core::HID { 23namespace Core::HID {
24static constexpr std::size_t MaxTouchDevices = 32;
25static constexpr std::size_t MaxActiveTouchInputs = 16;
23 26
24struct ConsoleMotionInfo { 27struct ConsoleMotionInfo {
25 Common::Input::MotionStatus raw_status{}; 28 Common::Input::MotionStatus raw_status{};
@@ -27,13 +30,13 @@ struct ConsoleMotionInfo {
27}; 30};
28 31
29using ConsoleMotionDevices = std::unique_ptr<Common::Input::InputDevice>; 32using ConsoleMotionDevices = std::unique_ptr<Common::Input::InputDevice>;
30using TouchDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, 16>; 33using TouchDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, MaxTouchDevices>;
31 34
32using ConsoleMotionParams = Common::ParamPackage; 35using ConsoleMotionParams = Common::ParamPackage;
33using TouchParams = std::array<Common::ParamPackage, 16>; 36using TouchParams = std::array<Common::ParamPackage, MaxTouchDevices>;
34 37
35using ConsoleMotionValues = ConsoleMotionInfo; 38using ConsoleMotionValues = ConsoleMotionInfo;
36using TouchValues = std::array<Common::Input::TouchStatus, 16>; 39using TouchValues = std::array<Common::Input::TouchStatus, MaxTouchDevices>;
37 40
38struct TouchFinger { 41struct TouchFinger {
39 u64 last_touch{}; 42 u64 last_touch{};
@@ -55,7 +58,7 @@ struct ConsoleMotion {
55 bool is_at_rest{}; 58 bool is_at_rest{};
56}; 59};
57 60
58using TouchFingerState = std::array<TouchFinger, 16>; 61using TouchFingerState = std::array<TouchFinger, MaxActiveTouchInputs>;
59 62
60struct ConsoleStatus { 63struct ConsoleStatus {
61 // Data from input_common 64 // Data from input_common
@@ -166,6 +169,10 @@ private:
166 */ 169 */
167 void SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index); 170 void SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index);
168 171
172 std::optional<std::size_t> GetIndexFromFingerId(std::size_t finger_id) const;
173
174 std::optional<std::size_t> GetNextFreeIndex() const;
175
169 /** 176 /**
170 * Triggers a callback that something has changed on the console status 177 * Triggers a callback that something has changed on the console status
171 * @param type Input type of the event to trigger 178 * @param type Input type of the event to trigger
diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp
index 5d8b75b50..502692875 100644
--- a/src/core/hid/input_converter.cpp
+++ b/src/core/hid/input_converter.cpp
@@ -200,9 +200,6 @@ Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus&
200 x = std::clamp(x, 0.0f, 1.0f); 200 x = std::clamp(x, 0.0f, 1.0f);
201 y = std::clamp(y, 0.0f, 1.0f); 201 y = std::clamp(y, 0.0f, 1.0f);
202 202
203 // Limit id to maximum number of fingers
204 status.id = std::clamp(status.id, 0, 16);
205
206 if (status.pressed.inverted) { 203 if (status.pressed.inverted) {
207 status.pressed.value = !status.pressed.value; 204 status.pressed.value = !status.pressed.value;
208 } 205 }
diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp
index bda098511..7b363eb1e 100644
--- a/src/core/hle/kernel/init/init_slab_setup.cpp
+++ b/src/core/hle/kernel/init/init_slab_setup.cpp
@@ -243,6 +243,7 @@ void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) {
243 // If we somehow get an invalid type, abort. 243 // If we somehow get an invalid type, abort.
244 default: 244 default:
245 ASSERT_MSG(false, "Unknown slab type: {}", slab_types[i]); 245 ASSERT_MSG(false, "Unknown slab type: {}", slab_types[i]);
246 break;
246 } 247 }
247 248
248 // If we've hit the end of a gap, free it. 249 // If we've hit the end of a gap, free it.
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index 5387bf5fe..612fc76fa 100644
--- a/src/core/hle/kernel/k_page_table.cpp
+++ b/src/core/hle/kernel/k_page_table.cpp
@@ -2301,6 +2301,7 @@ Result KPageTable::SetProcessMemoryPermission(VAddr addr, size_t size,
2301 break; 2301 break;
2302 default: 2302 default:
2303 ASSERT(false); 2303 ASSERT(false);
2304 break;
2304 } 2305 }
2305 } 2306 }
2306 2307
@@ -2803,6 +2804,7 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, const KPageGroup& page_
2803 break; 2804 break;
2804 default: 2805 default:
2805 ASSERT(false); 2806 ASSERT(false);
2807 break;
2806 } 2808 }
2807 2809
2808 addr += size; 2810 addr += size;
@@ -2838,6 +2840,7 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, KMemoryPermission perm,
2838 break; 2840 break;
2839 default: 2841 default:
2840 ASSERT(false); 2842 ASSERT(false);
2843 break;
2841 } 2844 }
2842 R_SUCCEED(); 2845 R_SUCCEED();
2843} 2846}
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h
index 950850291..f1ca785d7 100644
--- a/src/core/hle/kernel/k_page_table.h
+++ b/src/core/hle/kernel/k_page_table.h
@@ -320,6 +320,9 @@ public:
320 constexpr VAddr GetAliasCodeRegionStart() const { 320 constexpr VAddr GetAliasCodeRegionStart() const {
321 return m_alias_code_region_start; 321 return m_alias_code_region_start;
322 } 322 }
323 constexpr VAddr GetAliasCodeRegionEnd() const {
324 return m_alias_code_region_end;
325 }
323 constexpr VAddr GetAliasCodeRegionSize() const { 326 constexpr VAddr GetAliasCodeRegionSize() const {
324 return m_alias_code_region_end - m_alias_code_region_start; 327 return m_alias_code_region_end - m_alias_code_region_start;
325 } 328 }
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 55a9c5fae..d1dc62401 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -395,6 +395,7 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
395 395
396 default: 396 default:
397 ASSERT(false); 397 ASSERT(false);
398 break;
398 } 399 }
399 400
400 // Create TLS region 401 // Create TLS region
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 9962ad171..e520cab47 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -2701,14 +2701,24 @@ static Result GetThreadList(Core::System& system, u32* out_num_threads, VAddr ou
2701 return ResultSuccess; 2701 return ResultSuccess;
2702} 2702}
2703 2703
2704static Result FlushProcessDataCache32([[maybe_unused]] Core::System& system, 2704static Result FlushProcessDataCache32(Core::System& system, Handle process_handle, u64 address,
2705 [[maybe_unused]] Handle handle, [[maybe_unused]] u32 address, 2705 u64 size) {
2706 [[maybe_unused]] u32 size) { 2706 // Validate address/size.
2707 // Note(Blinkhawk): For emulation purposes of the data cache this is mostly a no-op, 2707 R_UNLESS(size > 0, ResultInvalidSize);
2708 // as all emulation is done in the same cache level in host architecture, thus data cache 2708 R_UNLESS(address == static_cast<uintptr_t>(address), ResultInvalidCurrentMemory);
2709 // does not need flushing. 2709 R_UNLESS(size == static_cast<size_t>(size), ResultInvalidCurrentMemory);
2710 LOG_DEBUG(Kernel_SVC, "called"); 2710
2711 return ResultSuccess; 2711 // Get the process from its handle.
2712 KScopedAutoObject process =
2713 system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KProcess>(process_handle);
2714 R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
2715
2716 // Verify the region is within range.
2717 auto& page_table = process->PageTable();
2718 R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
2719
2720 // Perform the operation.
2721 R_RETURN(system.Memory().FlushDataCache(*process, address, size));
2712} 2722}
2713 2723
2714namespace { 2724namespace {
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index 272c54cf7..3730937fe 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -722,4 +722,12 @@ void SvcWrap32(Core::System& system) {
722 FuncReturn(system, retval); 722 FuncReturn(system, retval);
723} 723}
724 724
725// Used by Invalidate/Store/FlushProcessDataCache32
726template <Result func(Core::System&, Handle, u64, u64)>
727void SvcWrap32(Core::System& system) {
728 const u64 address = (Param(system, 3) << 32) | Param(system, 2);
729 const u64 size = (Param(system, 4) << 32) | Param(system, 1);
730 FuncReturn32(system, func(system, Param32(system, 0), address, size).raw);
731}
732
725} // namespace Kernel 733} // namespace Kernel
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 56c990728..240f06689 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -28,30 +28,49 @@ enum class ErrorModule : u32 {
28 Loader = 9, 28 Loader = 9,
29 CMIF = 10, 29 CMIF = 10,
30 HIPC = 11, 30 HIPC = 11,
31 TMA = 12,
32 DMNT = 13,
33 GDS = 14,
31 PM = 15, 34 PM = 15,
32 NS = 16, 35 NS = 16,
36 BSDSockets = 17,
33 HTC = 18, 37 HTC = 18,
38 TSC = 19,
34 NCMContent = 20, 39 NCMContent = 20,
35 SM = 21, 40 SM = 21,
36 RO = 22, 41 RO = 22,
42 GC = 23,
37 SDMMC = 24, 43 SDMMC = 24,
38 OVLN = 25, 44 OVLN = 25,
39 SPL = 26, 45 SPL = 26,
46 Socket = 27,
47 HTCLOW = 29,
48 DDSF = 30,
49 HTCFS = 31,
50 Async = 32,
51 Util = 33,
52 TIPC = 35,
53 ANIF = 37,
40 ETHC = 100, 54 ETHC = 100,
41 I2C = 101, 55 I2C = 101,
42 GPIO = 102, 56 GPIO = 102,
43 UART = 103, 57 UART = 103,
58 CPAD = 104,
44 Settings = 105, 59 Settings = 105,
60 FTM = 106,
45 WLAN = 107, 61 WLAN = 107,
46 XCD = 108, 62 XCD = 108,
63 TMP451 = 109,
47 NIFM = 110, 64 NIFM = 110,
48 Hwopus = 111, 65 Hwopus = 111,
66 LSM6DS3 = 112,
49 Bluetooth = 113, 67 Bluetooth = 113,
50 VI = 114, 68 VI = 114,
51 NFP = 115, 69 NFP = 115,
52 Time = 116, 70 Time = 116,
53 FGM = 117, 71 FGM = 117,
54 OE = 118, 72 OE = 118,
73 BH1730FVC = 119,
55 PCIe = 120, 74 PCIe = 120,
56 Friends = 121, 75 Friends = 121,
57 BCAT = 122, 76 BCAT = 122,
@@ -65,7 +84,7 @@ enum class ErrorModule : u32 {
65 AHID = 130, 84 AHID = 130,
66 Qlaunch = 132, 85 Qlaunch = 132,
67 PCV = 133, 86 PCV = 133,
68 OMM = 134, 87 USBPD = 134,
69 BPC = 135, 88 BPC = 135,
70 PSM = 136, 89 PSM = 136,
71 NIM = 137, 90 NIM = 137,
@@ -75,18 +94,22 @@ enum class ErrorModule : u32 {
75 NSD = 141, 94 NSD = 141,
76 PCTL = 142, 95 PCTL = 142,
77 BTM = 143, 96 BTM = 143,
97 LA = 144,
78 ETicket = 145, 98 ETicket = 145,
79 NGC = 146, 99 NGC = 146,
80 ERPT = 147, 100 ERPT = 147,
81 APM = 148, 101 APM = 148,
102 CEC = 149,
82 Profiler = 150, 103 Profiler = 150,
83 ErrorUpload = 151, 104 ErrorUpload = 151,
105 LIDBE = 152,
84 Audio = 153, 106 Audio = 153,
85 NPNS = 154, 107 NPNS = 154,
86 NPNSHTTPSTREAM = 155, 108 NPNSHTTPSTREAM = 155,
87 ARP = 157, 109 ARP = 157,
88 SWKBD = 158, 110 SWKBD = 158,
89 BOOT = 159, 111 BOOT = 159,
112 NetDiag = 160,
90 NFCMifare = 161, 113 NFCMifare = 161,
91 UserlandAssert = 162, 114 UserlandAssert = 162,
92 Fatal = 163, 115 Fatal = 163,
@@ -94,17 +117,68 @@ enum class ErrorModule : u32 {
94 SPSM = 165, 117 SPSM = 165,
95 BGTC = 167, 118 BGTC = 167,
96 UserlandCrash = 168, 119 UserlandCrash = 168,
120 SASBUS = 169,
121 PI = 170,
122 AudioCtrl = 172,
123 LBL = 173,
124 JIT = 175,
125 HDCP = 176,
126 OMM = 177,
127 PDM = 178,
128 OLSC = 179,
97 SREPO = 180, 129 SREPO = 180,
98 Dauth = 181, 130 Dauth = 181,
131 STDFU = 182,
132 DBG = 183,
133 DHCPS = 186,
134 SPI = 187,
135 AVM = 188,
136 PWM = 189,
137 RTC = 191,
138 Regulator = 192,
139 LED = 193,
140 SIO = 195,
141 PCM = 196,
142 CLKRST = 197,
143 POWCTL = 198,
144 AudioOld = 201,
99 HID = 202, 145 HID = 202,
100 LDN = 203, 146 LDN = 203,
147 CS = 204,
101 Irsensor = 205, 148 Irsensor = 205,
102 Capture = 206, 149 Capture = 206,
103 Manu = 208, 150 Manu = 208,
104 ATK = 209, 151 ATK = 209,
152 WEB = 210,
153 LCS = 211,
105 GRC = 212, 154 GRC = 212,
155 Repair = 213,
156 Album = 214,
157 RID = 215,
106 Migration = 216, 158 Migration = 216,
107 MigrationLdcServ = 217, 159 MigrationLdcServ = 217,
160 HIDBUS = 218,
161 ENS = 219,
162 WebSocket = 223,
163 DCDMTP = 227,
164 PGL = 228,
165 Notification = 229,
166 INS = 230,
167 LP2P = 231,
168 RCD = 232,
169 LCM40607 = 233,
170 PRC = 235,
171 TMAHTC = 237,
172 ECTX = 238,
173 MNPP = 239,
174 HSHL = 240,
175 CAPMTP = 242,
176 DP2HDMI = 244,
177 Cradle = 245,
178 SProfile = 246,
179 NDRM = 250,
180 TSPM = 499,
181 DevMenu = 500,
108 GeneralWebApplet = 800, 182 GeneralWebApplet = 800,
109 WifiWebAuthApplet = 809, 183 WifiWebAuthApplet = 809,
110 WhitelistedApplet = 810, 184 WhitelistedApplet = 810,
diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp
new file mode 100644
index 000000000..d0969b0f1
--- /dev/null
+++ b/src/core/hle/service/am/applets/applet_cabinet.cpp
@@ -0,0 +1,177 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/assert.h"
5#include "common/logging/log.h"
6#include "core/core.h"
7#include "core/frontend/applets/cabinet.h"
8#include "core/hid/hid_core.h"
9#include "core/hle/kernel/k_event.h"
10#include "core/hle/kernel/k_readable_event.h"
11#include "core/hle/service/am/am.h"
12#include "core/hle/service/am/applets/applet_cabinet.h"
13#include "core/hle/service/mii/mii_manager.h"
14#include "core/hle/service/nfp/nfp_device.h"
15
16namespace Service::AM::Applets {
17
18Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_,
19 const Core::Frontend::CabinetApplet& frontend_)
20 : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, service_context{
21 system_,
22 "CabinetApplet"} {
23
24 availability_change_event =
25 service_context.CreateEvent("CabinetApplet:AvailabilityChangeEvent");
26}
27
28Cabinet::~Cabinet() = default;
29
30void Cabinet::Initialize() {
31 Applet::Initialize();
32
33 LOG_INFO(Service_HID, "Initializing Cabinet Applet.");
34
35 LOG_DEBUG(Service_HID,
36 "Initializing Applet with common_args: arg_version={}, lib_version={}, "
37 "play_startup_sound={}, size={}, system_tick={}, theme_color={}",
38 common_args.arguments_version, common_args.library_version,
39 common_args.play_startup_sound, common_args.size, common_args.system_tick,
40 common_args.theme_color);
41
42 const auto storage = broker.PopNormalDataToApplet();
43 ASSERT(storage != nullptr);
44
45 const auto applet_input_data = storage->GetData();
46 ASSERT(applet_input_data.size() >= sizeof(StartParamForAmiiboSettings));
47
48 std::memcpy(&applet_input_common, applet_input_data.data(),
49 sizeof(StartParamForAmiiboSettings));
50}
51
52bool Cabinet::TransactionComplete() const {
53 return is_complete;
54}
55
56Result Cabinet::GetStatus() const {
57 return ResultSuccess;
58}
59
60void Cabinet::ExecuteInteractive() {
61 ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet.");
62}
63
64void Cabinet::Execute() {
65 if (is_complete) {
66 return;
67 }
68
69 const auto callback = [this](bool apply_changes, const std::string& amiibo_name) {
70 DisplayCompleted(apply_changes, amiibo_name);
71 };
72
73 // TODO: listen on all controllers
74 if (nfp_device == nullptr) {
75 nfp_device = std::make_shared<Service::NFP::NfpDevice>(
76 system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event);
77 nfp_device->Initialize();
78 nfp_device->StartDetection(Service::NFP::TagProtocol::All);
79 }
80
81 const Core::Frontend::CabinetParameters parameters{
82 .tag_info = applet_input_common.tag_info,
83 .register_info = applet_input_common.register_info,
84 .mode = applet_input_common.applet_mode,
85 };
86
87 switch (applet_input_common.applet_mode) {
88 case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings:
89 case Service::NFP::CabinetMode::StartGameDataEraser:
90 case Service::NFP::CabinetMode::StartRestorer:
91 case Service::NFP::CabinetMode::StartFormatter:
92 frontend.ShowCabinetApplet(callback, parameters, nfp_device);
93 break;
94 default:
95 UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode);
96 DisplayCompleted(false, {});
97 break;
98 }
99}
100
101void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) {
102 Service::Mii::MiiManager manager;
103 ReturnValueForAmiiboSettings applet_output{};
104
105 if (!apply_changes) {
106 Cancel();
107 }
108
109 if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound &&
110 nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) {
111 Cancel();
112 }
113
114 if (nfp_device->GetCurrentState() == Service::NFP::DeviceState::TagFound) {
115 nfp_device->Mount(Service::NFP::MountTarget::All);
116 }
117
118 switch (applet_input_common.applet_mode) {
119 case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: {
120 Service::NFP::AmiiboName name{};
121 std::memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1));
122 nfp_device->SetNicknameAndOwner(name);
123 break;
124 }
125 case Service::NFP::CabinetMode::StartGameDataEraser:
126 nfp_device->DeleteApplicationArea();
127 break;
128 case Service::NFP::CabinetMode::StartRestorer:
129 nfp_device->RestoreAmiibo();
130 break;
131 case Service::NFP::CabinetMode::StartFormatter:
132 nfp_device->DeleteAllData();
133 break;
134 default:
135 UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode);
136 break;
137 }
138
139 applet_output.device_handle = applet_input_common.device_handle;
140 applet_output.result = CabinetResult::Cancel;
141 const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info);
142 const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info);
143 nfp_device->Finalize();
144
145 if (reg_result.IsSuccess()) {
146 applet_output.result |= CabinetResult::RegisterInfo;
147 }
148
149 if (tag_result.IsSuccess()) {
150 applet_output.result |= CabinetResult::TagInfo;
151 }
152
153 std::vector<u8> out_data(sizeof(ReturnValueForAmiiboSettings));
154 std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings));
155
156 is_complete = true;
157
158 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
159 broker.SignalStateChanged();
160}
161
162void Cabinet::Cancel() {
163 ReturnValueForAmiiboSettings applet_output{};
164 applet_output.device_handle = applet_input_common.device_handle;
165 applet_output.result = CabinetResult::Cancel;
166 nfp_device->Finalize();
167
168 std::vector<u8> out_data(sizeof(ReturnValueForAmiiboSettings));
169 std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings));
170
171 is_complete = true;
172
173 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
174 broker.SignalStateChanged();
175}
176
177} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applet_cabinet.h b/src/core/hle/service/am/applets/applet_cabinet.h
new file mode 100644
index 000000000..84197a807
--- /dev/null
+++ b/src/core/hle/service/am/applets/applet_cabinet.h
@@ -0,0 +1,104 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "core/hle/result.h"
9#include "core/hle/service/am/applets/applets.h"
10#include "core/hle/service/kernel_helpers.h"
11#include "core/hle/service/nfp/nfp_types.h"
12
13namespace Kernel {
14class KEvent;
15class KReadableEvent;
16} // namespace Kernel
17
18namespace Core {
19class System;
20} // namespace Core
21
22namespace Service::NFP {
23class NfpDevice;
24}
25
26namespace Service::AM::Applets {
27
28enum class CabinetAppletVersion : u32 {
29 Version1 = 0x1,
30};
31
32enum class CabinetResult : u8 {
33 Cancel = 0,
34 TagInfo = 1 << 1,
35 RegisterInfo = 1 << 2,
36 All = TagInfo | RegisterInfo,
37};
38DECLARE_ENUM_FLAG_OPERATORS(CabinetResult)
39
40// This is nn::nfp::AmiiboSettingsStartParam
41struct AmiiboSettingsStartParam {
42 u64 device_handle;
43 std::array<u8, 0x20> param_1;
44 u8 param_2;
45};
46static_assert(sizeof(AmiiboSettingsStartParam) == 0x30,
47 "AmiiboSettingsStartParam is an invalid size");
48
49#pragma pack(push, 1)
50// This is nn::nfp::StartParamForAmiiboSettings
51struct StartParamForAmiiboSettings {
52 u8 param_1;
53 Service::NFP::CabinetMode applet_mode;
54 u8 flags;
55 u8 amiibo_settings_1;
56 u64 device_handle;
57 Service::NFP::TagInfo tag_info;
58 Service::NFP::RegisterInfo register_info;
59 std::array<u8, 0x20> amiibo_settings_3;
60 INSERT_PADDING_BYTES(0x24);
61};
62static_assert(sizeof(StartParamForAmiiboSettings) == 0x1A8,
63 "StartParamForAmiiboSettings is an invalid size");
64
65// This is nn::nfp::ReturnValueForAmiiboSettings
66struct ReturnValueForAmiiboSettings {
67 CabinetResult result;
68 INSERT_PADDING_BYTES(0x3);
69 u64 device_handle;
70 Service::NFP::TagInfo tag_info;
71 Service::NFP::RegisterInfo register_info;
72 INSERT_PADDING_BYTES(0x24);
73};
74static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188,
75 "ReturnValueForAmiiboSettings is an invalid size");
76#pragma pack(pop)
77
78class Cabinet final : public Applet {
79public:
80 explicit Cabinet(Core::System& system_, LibraryAppletMode applet_mode_,
81 const Core::Frontend::CabinetApplet& frontend_);
82 ~Cabinet() override;
83
84 void Initialize() override;
85
86 bool TransactionComplete() const override;
87 Result GetStatus() const override;
88 void ExecuteInteractive() override;
89 void Execute() override;
90 void DisplayCompleted(bool apply_changes, std::string_view amiibo_name);
91 void Cancel();
92
93private:
94 const Core::Frontend::CabinetApplet& frontend;
95 Core::System& system;
96
97 bool is_complete{false};
98 std::shared_ptr<Service::NFP::NfpDevice> nfp_device;
99 Kernel::KEvent* availability_change_event;
100 KernelHelpers::ServiceContext service_context;
101 StartParamForAmiiboSettings applet_input_common{};
102};
103
104} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/applets/applet_error.cpp
index fcf34bf7e..bae0d99a6 100644
--- a/src/core/hle/service/am/applets/applet_error.cpp
+++ b/src/core/hle/service/am/applets/applet_error.cpp
@@ -144,6 +144,7 @@ void Error::Initialize() {
144 break; 144 break;
145 default: 145 default:
146 UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode); 146 UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode);
147 break;
147 } 148 }
148} 149}
149 150
diff --git a/src/core/hle/service/am/applets/applet_general_backend.cpp b/src/core/hle/service/am/applets/applet_general_backend.cpp
index c34ef08b3..e50acdaf6 100644
--- a/src/core/hle/service/am/applets/applet_general_backend.cpp
+++ b/src/core/hle/service/am/applets/applet_general_backend.cpp
@@ -129,6 +129,7 @@ void Auth::Execute() {
129 } 129 }
130 default: 130 default:
131 unimplemented_log(); 131 unimplemented_log();
132 break;
132 } 133 }
133} 134}
134 135
@@ -192,6 +193,7 @@ void PhotoViewer::Execute() {
192 break; 193 break;
193 default: 194 default:
194 UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", mode); 195 UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", mode);
196 break;
195 } 197 }
196} 198}
197 199
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index 7062df21c..10afbc2da 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -5,6 +5,7 @@
5 5
6#include "common/assert.h" 6#include "common/assert.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/frontend/applets/cabinet.h"
8#include "core/frontend/applets/controller.h" 9#include "core/frontend/applets/controller.h"
9#include "core/frontend/applets/error.h" 10#include "core/frontend/applets/error.h"
10#include "core/frontend/applets/general_frontend.h" 11#include "core/frontend/applets/general_frontend.h"
@@ -16,6 +17,7 @@
16#include "core/hle/service/am/am.h" 17#include "core/hle/service/am/am.h"
17#include "core/hle/service/am/applet_ae.h" 18#include "core/hle/service/am/applet_ae.h"
18#include "core/hle/service/am/applet_oe.h" 19#include "core/hle/service/am/applet_oe.h"
20#include "core/hle/service/am/applets/applet_cabinet.h"
19#include "core/hle/service/am/applets/applet_controller.h" 21#include "core/hle/service/am/applets/applet_controller.h"
20#include "core/hle/service/am/applets/applet_error.h" 22#include "core/hle/service/am/applets/applet_error.h"
21#include "core/hle/service/am/applets/applet_general_backend.h" 23#include "core/hle/service/am/applets/applet_general_backend.h"
@@ -171,13 +173,15 @@ void Applet::Initialize() {
171 173
172AppletFrontendSet::AppletFrontendSet() = default; 174AppletFrontendSet::AppletFrontendSet() = default;
173 175
174AppletFrontendSet::AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet, 176AppletFrontendSet::AppletFrontendSet(CabinetApplet cabinet_applet,
177 ControllerApplet controller_applet, ErrorApplet error_applet,
175 MiiEdit mii_edit_, 178 MiiEdit mii_edit_,
176 ParentalControlsApplet parental_controls_applet, 179 ParentalControlsApplet parental_controls_applet,
177 PhotoViewer photo_viewer_, ProfileSelect profile_select_, 180 PhotoViewer photo_viewer_, ProfileSelect profile_select_,
178 SoftwareKeyboard software_keyboard_, WebBrowser web_browser_) 181 SoftwareKeyboard software_keyboard_, WebBrowser web_browser_)
179 : controller{std::move(controller_applet)}, error{std::move(error_applet)}, 182 : cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)},
180 mii_edit{std::move(mii_edit_)}, parental_controls{std::move(parental_controls_applet)}, 183 error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)},
184 parental_controls{std::move(parental_controls_applet)},
181 photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)}, 185 photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)},
182 software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {} 186 software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {}
183 187
@@ -196,6 +200,10 @@ const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const {
196} 200}
197 201
198void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { 202void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
203 if (set.cabinet != nullptr) {
204 frontend.cabinet = std::move(set.cabinet);
205 }
206
199 if (set.controller != nullptr) { 207 if (set.controller != nullptr) {
200 frontend.controller = std::move(set.controller); 208 frontend.controller = std::move(set.controller);
201 } 209 }
@@ -235,6 +243,10 @@ void AppletManager::SetDefaultAppletFrontendSet() {
235} 243}
236 244
237void AppletManager::SetDefaultAppletsIfMissing() { 245void AppletManager::SetDefaultAppletsIfMissing() {
246 if (frontend.cabinet == nullptr) {
247 frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>();
248 }
249
238 if (frontend.controller == nullptr) { 250 if (frontend.controller == nullptr) {
239 frontend.controller = 251 frontend.controller =
240 std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore()); 252 std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore());
@@ -279,6 +291,8 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode
279 switch (id) { 291 switch (id) {
280 case AppletId::Auth: 292 case AppletId::Auth:
281 return std::make_shared<Auth>(system, mode, *frontend.parental_controls); 293 return std::make_shared<Auth>(system, mode, *frontend.parental_controls);
294 case AppletId::Cabinet:
295 return std::make_shared<Cabinet>(system, mode, *frontend.cabinet);
282 case AppletId::Controller: 296 case AppletId::Controller:
283 return std::make_shared<Controller>(system, mode, *frontend.controller); 297 return std::make_shared<Controller>(system, mode, *frontend.controller);
284 case AppletId::Error: 298 case AppletId::Error:
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index 12c6a5b1a..a22eb62a8 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -16,6 +16,7 @@ class System;
16} 16}
17 17
18namespace Core::Frontend { 18namespace Core::Frontend {
19class CabinetApplet;
19class ControllerApplet; 20class ControllerApplet;
20class ECommerceApplet; 21class ECommerceApplet;
21class ErrorApplet; 22class ErrorApplet;
@@ -176,6 +177,7 @@ protected:
176}; 177};
177 178
178struct AppletFrontendSet { 179struct AppletFrontendSet {
180 using CabinetApplet = std::unique_ptr<Core::Frontend::CabinetApplet>;
179 using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>; 181 using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
180 using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>; 182 using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
181 using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>; 183 using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>;
@@ -186,10 +188,11 @@ struct AppletFrontendSet {
186 using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; 188 using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
187 189
188 AppletFrontendSet(); 190 AppletFrontendSet();
189 AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet, 191 AppletFrontendSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet,
190 MiiEdit mii_edit_, ParentalControlsApplet parental_controls_applet, 192 ErrorApplet error_applet, MiiEdit mii_edit_,
191 PhotoViewer photo_viewer_, ProfileSelect profile_select_, 193 ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_,
192 SoftwareKeyboard software_keyboard_, WebBrowser web_browser_); 194 ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_,
195 WebBrowser web_browser_);
193 ~AppletFrontendSet(); 196 ~AppletFrontendSet();
194 197
195 AppletFrontendSet(const AppletFrontendSet&) = delete; 198 AppletFrontendSet(const AppletFrontendSet&) = delete;
@@ -198,6 +201,7 @@ struct AppletFrontendSet {
198 AppletFrontendSet(AppletFrontendSet&&) noexcept; 201 AppletFrontendSet(AppletFrontendSet&&) noexcept;
199 AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; 202 AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
200 203
204 CabinetApplet cabinet;
201 ControllerApplet controller; 205 ControllerApplet controller;
202 ErrorApplet error; 206 ErrorApplet error;
203 MiiEdit mii_edit; 207 MiiEdit mii_edit;
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 79375bd2f..bf28440c6 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -36,8 +36,9 @@ namespace Service::HID {
36 36
37// Updating period for each HID device. 37// Updating period for each HID device.
38// Period time is obtained by measuring the number of samples in a second on HW using a homebrew 38// Period time is obtained by measuring the number of samples in a second on HW using a homebrew
39// Correct pad_update_ns is 4ms this is overclocked to lower input lag 39// Correct npad_update_ns is 4ms this is overclocked to lower input lag
40constexpr auto pad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz) 40constexpr auto npad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz)
41constexpr auto default_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 1000Hz)
41constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) 42constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)
42constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) 43constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)
43 44
@@ -75,11 +76,19 @@ IAppletResource::IAppletResource(Core::System& system_,
75 GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00); 76 GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00);
76 77
77 // Register update callbacks 78 // Register update callbacks
78 pad_update_event = Core::Timing::CreateEvent( 79 npad_update_event = Core::Timing::CreateEvent(
79 "HID::UpdatePadCallback", 80 "HID::UpdatePadCallback",
80 [this](std::uintptr_t user_data, s64 time, 81 [this](std::uintptr_t user_data, s64 time,
81 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { 82 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
82 const auto guard = LockService(); 83 const auto guard = LockService();
84 UpdateNpad(user_data, ns_late);
85 return std::nullopt;
86 });
87 default_update_event = Core::Timing::CreateEvent(
88 "HID::UpdateDefaultCallback",
89 [this](std::uintptr_t user_data, s64 time,
90 std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
91 const auto guard = LockService();
83 UpdateControllers(user_data, ns_late); 92 UpdateControllers(user_data, ns_late);
84 return std::nullopt; 93 return std::nullopt;
85 }); 94 });
@@ -100,7 +109,9 @@ IAppletResource::IAppletResource(Core::System& system_,
100 return std::nullopt; 109 return std::nullopt;
101 }); 110 });
102 111
103 system.CoreTiming().ScheduleLoopingEvent(pad_update_ns, pad_update_ns, pad_update_event); 112 system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event);
113 system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns,
114 default_update_event);
104 system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns, 115 system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns,
105 mouse_keyboard_update_event); 116 mouse_keyboard_update_event);
106 system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns, 117 system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns,
@@ -118,7 +129,8 @@ void IAppletResource::DeactivateController(HidController controller) {
118} 129}
119 130
120IAppletResource::~IAppletResource() { 131IAppletResource::~IAppletResource() {
121 system.CoreTiming().UnscheduleEvent(pad_update_event, 0); 132 system.CoreTiming().UnscheduleEvent(npad_update_event, 0);
133 system.CoreTiming().UnscheduleEvent(default_update_event, 0);
122 system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0); 134 system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0);
123 system.CoreTiming().UnscheduleEvent(motion_update_event, 0); 135 system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
124} 136}
@@ -144,10 +156,20 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
144 if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) { 156 if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) {
145 continue; 157 continue;
146 } 158 }
159 // Npad has it's own update event
160 if (controller == controllers[static_cast<size_t>(HidController::NPad)]) {
161 continue;
162 }
147 controller->OnUpdate(core_timing); 163 controller->OnUpdate(core_timing);
148 } 164 }
149} 165}
150 166
167void IAppletResource::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
168 auto& core_timing = system.CoreTiming();
169
170 controllers[static_cast<size_t>(HidController::NPad)]->OnUpdate(core_timing);
171}
172
151void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, 173void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data,
152 std::chrono::nanoseconds ns_late) { 174 std::chrono::nanoseconds ns_late) {
153 auto& core_timing = system.CoreTiming(); 175 auto& core_timing = system.CoreTiming();
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 340d26fdc..b7c2a23ef 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -71,12 +71,14 @@ private:
71 71
72 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); 72 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
73 void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 73 void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
74 void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
74 void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 75 void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
75 void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 76 void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
76 77
77 KernelHelpers::ServiceContext& service_context; 78 KernelHelpers::ServiceContext& service_context;
78 79
79 std::shared_ptr<Core::Timing::EventType> pad_update_event; 80 std::shared_ptr<Core::Timing::EventType> npad_update_event;
81 std::shared_ptr<Core::Timing::EventType> default_update_event;
80 std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event; 82 std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
81 std::shared_ptr<Core::Timing::EventType> motion_update_event; 83 std::shared_ptr<Core::Timing::EventType> motion_update_event;
82 84
diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp
index 296603764..c860fd1a1 100644
--- a/src/core/hle/service/nfp/nfp_device.cpp
+++ b/src/core/hle/service/nfp/nfp_device.cpp
@@ -75,6 +75,9 @@ void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
75 LoadAmiibo(nfc_status.data); 75 LoadAmiibo(nfc_status.data);
76 break; 76 break;
77 case Common::Input::NfcState::AmiiboRemoved: 77 case Common::Input::NfcState::AmiiboRemoved:
78 if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
79 break;
80 }
78 if (device_state != DeviceState::SearchingForTag) { 81 if (device_state != DeviceState::SearchingForTag) {
79 CloseAmiibo(); 82 CloseAmiibo();
80 } 83 }
@@ -95,6 +98,8 @@ bool NfpDevice::LoadAmiibo(std::span<const u8> data) {
95 return false; 98 return false;
96 } 99 }
97 100
101 // TODO: Filter by allowed_protocols here
102
98 memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File)); 103 memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File));
99 104
100 device_state = DeviceState::TagFound; 105 device_state = DeviceState::TagFound;
@@ -141,7 +146,7 @@ void NfpDevice::Finalize() {
141 device_state = DeviceState::Unavailable; 146 device_state = DeviceState::Unavailable;
142} 147}
143 148
144Result NfpDevice::StartDetection(s32 protocol_) { 149Result NfpDevice::StartDetection(TagProtocol allowed_protocol) {
145 if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) { 150 if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) {
146 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 151 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
147 return WrongDeviceState; 152 return WrongDeviceState;
@@ -153,7 +158,7 @@ Result NfpDevice::StartDetection(s32 protocol_) {
153 } 158 }
154 159
155 device_state = DeviceState::SearchingForTag; 160 device_state = DeviceState::SearchingForTag;
156 protocol = protocol_; 161 allowed_protocols = allowed_protocol;
157 return ResultSuccess; 162 return ResultSuccess;
158} 163}
159 164
@@ -467,6 +472,32 @@ Result NfpDevice::OpenApplicationArea(u32 access_id) {
467 return ResultSuccess; 472 return ResultSuccess;
468} 473}
469 474
475Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const {
476 application_area_id = {};
477
478 if (device_state != DeviceState::TagMounted) {
479 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
480 if (device_state == DeviceState::TagRemoved) {
481 return TagRemoved;
482 }
483 return WrongDeviceState;
484 }
485
486 if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
487 LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
488 return WrongDeviceState;
489 }
490
491 if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
492 LOG_WARNING(Service_NFP, "Application area is not initialized");
493 return ApplicationAreaIsNotInitialized;
494 }
495
496 application_area_id = tag_data.application_area_id;
497
498 return ResultSuccess;
499}
500
470Result NfpDevice::GetApplicationArea(std::vector<u8>& data) const { 501Result NfpDevice::GetApplicationArea(std::vector<u8>& data) const {
471 if (device_state != DeviceState::TagMounted) { 502 if (device_state != DeviceState::TagMounted) {
472 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); 503 LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h
index 6d8fc1099..b6a46f2ac 100644
--- a/src/core/hle/service/nfp/nfp_device.h
+++ b/src/core/hle/service/nfp/nfp_device.h
@@ -3,6 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <span>
6#include <vector> 7#include <vector>
7 8
8#include "common/common_types.h" 9#include "common/common_types.h"
@@ -36,7 +37,7 @@ public:
36 void Initialize(); 37 void Initialize();
37 void Finalize(); 38 void Finalize();
38 39
39 Result StartDetection(s32 protocol_); 40 Result StartDetection(TagProtocol allowed_protocol);
40 Result StopDetection(); 41 Result StopDetection();
41 Result Mount(MountTarget mount_target); 42 Result Mount(MountTarget mount_target);
42 Result Unmount(); 43 Result Unmount();
@@ -52,6 +53,7 @@ public:
52 Result DeleteAllData(); 53 Result DeleteAllData();
53 54
54 Result OpenApplicationArea(u32 access_id); 55 Result OpenApplicationArea(u32 access_id);
56 Result GetApplicationAreaId(u32& application_area_id) const;
55 Result GetApplicationArea(std::vector<u8>& data) const; 57 Result GetApplicationArea(std::vector<u8>& data) const;
56 Result SetApplicationArea(std::span<const u8> data); 58 Result SetApplicationArea(std::span<const u8> data);
57 Result CreateApplicationArea(u32 access_id, std::span<const u8> data); 59 Result CreateApplicationArea(u32 access_id, std::span<const u8> data);
@@ -87,7 +89,7 @@ private:
87 89
88 bool is_data_moddified{}; 90 bool is_data_moddified{};
89 bool is_app_area_open{}; 91 bool is_app_area_open{};
90 s32 protocol{}; 92 TagProtocol allowed_protocols{};
91 s64 current_posix_time{}; 93 s64 current_posix_time{};
92 MountTarget mount_target{MountTarget::None}; 94 MountTarget mount_target{MountTarget::None};
93 DeviceState device_state{DeviceState::Unavailable}; 95 DeviceState device_state{DeviceState::Unavailable};
diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h
index 63d5917cb..69858096a 100644
--- a/src/core/hle/service/nfp/nfp_types.h
+++ b/src/core/hle/service/nfp/nfp_types.h
@@ -88,11 +88,22 @@ enum class PackedTagType : u8 {
88 Type5, // ISO15693 RW/RO 540 bytes 106kbit/s 88 Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
89}; 89};
90 90
91// Verify this enum. It might be completely wrong default protocol is 0x48
91enum class TagProtocol : u32 { 92enum class TagProtocol : u32 {
92 None, 93 None,
93 TypeA, // ISO14443A 94 TypeA = 1U << 0, // ISO14443A
94 TypeB, // ISO14443B 95 TypeB = 1U << 1, // ISO14443B
95 TypeF, // Sony Felica 96 TypeF = 1U << 2, // Sony Felica
97 Unknown1 = 1U << 3,
98 Unknown2 = 1U << 5,
99 All = 0xFFFFFFFFU,
100};
101
102enum class CabinetMode : u8 {
103 StartNicknameAndOwnerSettings,
104 StartGameDataEraser,
105 StartRestorer,
106 StartFormatter,
96}; 107};
97 108
98using UniqueSerialNumber = std::array<u8, 7>; 109using UniqueSerialNumber = std::array<u8, 7>;
diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp
index 3f7f17598..2fe3c0ea0 100644
--- a/src/core/hle/service/nfp/nfp_user.cpp
+++ b/src/core/hle/service/nfp/nfp_user.cpp
@@ -131,7 +131,7 @@ void IUser::ListDevices(Kernel::HLERequestContext& ctx) {
131void IUser::StartDetection(Kernel::HLERequestContext& ctx) { 131void IUser::StartDetection(Kernel::HLERequestContext& ctx) {
132 IPC::RequestParser rp{ctx}; 132 IPC::RequestParser rp{ctx};
133 const auto device_handle{rp.Pop<u64>()}; 133 const auto device_handle{rp.Pop<u64>()};
134 const auto nfp_protocol{rp.Pop<s32>()}; 134 const auto nfp_protocol{rp.PopEnum<TagProtocol>()};
135 LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); 135 LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol);
136 136
137 if (state == State::NonInitialized) { 137 if (state == State::NonInitialized) {
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 ced57dfe6..b97813fbc 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -300,11 +300,10 @@ Kernel::KEvent* nvhost_ctrl_gpu::QueryEvent(u32 event_id) {
300 return error_notifier_event; 300 return error_notifier_event;
301 case 2: 301 case 2:
302 return unknown_event; 302 return unknown_event;
303 default: { 303 default:
304 LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id); 304 LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id);
305 return nullptr;
305 } 306 }
306 }
307 return nullptr;
308} 307}
309 308
310} // namespace Service::Nvidia::Devices 309} // 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 45a759fa8..e123564c6 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -364,11 +364,10 @@ Kernel::KEvent* nvhost_gpu::QueryEvent(u32 event_id) {
364 return sm_exception_breakpoint_pause_report_event; 364 return sm_exception_breakpoint_pause_report_event;
365 case 3: 365 case 3:
366 return error_notifier_event; 366 return error_notifier_event;
367 default: { 367 default:
368 LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id); 368 LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id);
369 return nullptr;
369 } 370 }
370 }
371 return nullptr;
372} 371}
373 372
374} // namespace Service::Nvidia::Devices 373} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp
index ea4a14ea4..3d1338e66 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_core.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp
@@ -23,15 +23,17 @@ void BufferQueueCore::NotifyShutdown() {
23} 23}
24 24
25void BufferQueueCore::SignalDequeueCondition() { 25void BufferQueueCore::SignalDequeueCondition() {
26 dequeue_possible.store(true);
26 dequeue_condition.notify_all(); 27 dequeue_condition.notify_all();
27} 28}
28 29
29bool BufferQueueCore::WaitForDequeueCondition() { 30bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk) {
30 if (is_shutting_down) { 31 if (is_shutting_down) {
31 return false; 32 return false;
32 } 33 }
33 34
34 dequeue_condition.wait(mutex); 35 dequeue_condition.wait(lk, [&] { return dequeue_possible.load(); });
36 dequeue_possible.store(false);
35 37
36 return true; 38 return true;
37} 39}
diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.h b/src/core/hle/service/nvflinger/buffer_queue_core.h
index ca6baefaf..85b3bc4c1 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_core.h
+++ b/src/core/hle/service/nvflinger/buffer_queue_core.h
@@ -38,7 +38,7 @@ public:
38 38
39private: 39private:
40 void SignalDequeueCondition(); 40 void SignalDequeueCondition();
41 bool WaitForDequeueCondition(); 41 bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk);
42 42
43 s32 GetMinUndequeuedBufferCountLocked(bool async) const; 43 s32 GetMinUndequeuedBufferCountLocked(bool async) const;
44 s32 GetMinMaxBufferCountLocked(bool async) const; 44 s32 GetMinMaxBufferCountLocked(bool async) const;
@@ -60,7 +60,8 @@ private:
60 BufferQueueDefs::SlotsType slots{}; 60 BufferQueueDefs::SlotsType slots{};
61 std::vector<BufferItem> queue; 61 std::vector<BufferItem> queue;
62 s32 override_max_buffer_count{}; 62 s32 override_max_buffer_count{};
63 mutable std::condition_variable_any dequeue_condition; 63 std::condition_variable dequeue_condition;
64 std::atomic<bool> dequeue_possible{};
64 const bool use_async_buffer{}; // This is always disabled on HOS 65 const bool use_async_buffer{}; // This is always disabled on HOS
65 bool dequeue_buffer_cannot_block{}; 66 bool dequeue_buffer_cannot_block{};
66 PixelFormat default_buffer_format{PixelFormat::Rgba8888}; 67 PixelFormat default_buffer_format{PixelFormat::Rgba8888};
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
index 41ba44b21..e601b5da1 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp
@@ -121,8 +121,8 @@ Status BufferQueueProducer::SetBufferCount(s32 buffer_count) {
121 return Status::NoError; 121 return Status::NoError;
122} 122}
123 123
124Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, 124Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags,
125 Status* return_flags) const { 125 std::unique_lock<std::mutex>& lk) const {
126 bool try_again = true; 126 bool try_again = true;
127 127
128 while (try_again) { 128 while (try_again) {
@@ -214,7 +214,7 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found,
214 return Status::WouldBlock; 214 return Status::WouldBlock;
215 } 215 }
216 216
217 if (!core->WaitForDequeueCondition()) { 217 if (!core->WaitForDequeueCondition(lk)) {
218 // We are no longer running 218 // We are no longer running
219 return Status::NoError; 219 return Status::NoError;
220 } 220 }
@@ -237,7 +237,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool
237 Status return_flags = Status::NoError; 237 Status return_flags = Status::NoError;
238 bool attached_by_consumer = false; 238 bool attached_by_consumer = false;
239 { 239 {
240 std::scoped_lock lock{core->mutex}; 240 std::unique_lock lock{core->mutex};
241 core->WaitWhileAllocatingLocked(); 241 core->WaitWhileAllocatingLocked();
242 242
243 if (format == PixelFormat::NoFormat) { 243 if (format == PixelFormat::NoFormat) {
@@ -248,7 +248,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool
248 usage |= core->consumer_usage_bit; 248 usage |= core->consumer_usage_bit;
249 249
250 s32 found{}; 250 s32 found{};
251 Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags); 251 Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags, lock);
252 if (status != Status::NoError) { 252 if (status != Status::NoError) {
253 return status; 253 return status;
254 } 254 }
@@ -400,13 +400,13 @@ Status BufferQueueProducer::AttachBuffer(s32* out_slot,
400 return Status::BadValue; 400 return Status::BadValue;
401 } 401 }
402 402
403 std::scoped_lock lock{core->mutex}; 403 std::unique_lock lock{core->mutex};
404 core->WaitWhileAllocatingLocked(); 404 core->WaitWhileAllocatingLocked();
405 405
406 Status return_flags = Status::NoError; 406 Status return_flags = Status::NoError;
407 s32 found{}; 407 s32 found{};
408 408
409 const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags); 409 const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags, lock);
410 if (status != Status::NoError) { 410 if (status != Status::NoError) {
411 return status; 411 return status;
412 } 412 }
diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.h b/src/core/hle/service/nvflinger/buffer_queue_producer.h
index 7526bf8ec..1d380480f 100644
--- a/src/core/hle/service/nvflinger/buffer_queue_producer.h
+++ b/src/core/hle/service/nvflinger/buffer_queue_producer.h
@@ -70,7 +70,8 @@ public:
70private: 70private:
71 BufferQueueProducer(const BufferQueueProducer&) = delete; 71 BufferQueueProducer(const BufferQueueProducer&) = delete;
72 72
73 Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags) const; 73 Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags,
74 std::unique_lock<std::mutex>& lk) const;
74 75
75 Kernel::KEvent* buffer_wait_event{}; 76 Kernel::KEvent* buffer_wait_event{};
76 Service::KernelHelpers::ServiceContext& service_context; 77 Service::KernelHelpers::ServiceContext& service_context;
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 5ab41c0c4..0de67f1e1 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -228,6 +228,7 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session,
228 } 228 }
229 229
230 UNIMPLEMENTED_MSG("command_type={}", ctx.GetCommandType()); 230 UNIMPLEMENTED_MSG("command_type={}", ctx.GetCommandType());
231 break;
231 } 232 }
232 233
233 // If emulation was shutdown, we are closing service threads, do not write the response back to 234 // If emulation was shutdown, we are closing service threads, do not write the response back to
diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp
index 2aa675df9..f9ada7c93 100644
--- a/src/core/hle/service/time/time_zone_manager.cpp
+++ b/src/core/hle/service/time/time_zone_manager.cpp
@@ -280,6 +280,7 @@ static constexpr int TransitionTime(int year, Rule rule, int offset) {
280 } 280 }
281 default: 281 default:
282 ASSERT(false); 282 ASSERT(false);
283 break;
283 } 284 }
284 return value + rule.transition_time + offset; 285 return value + rule.transition_time + offset;
285} 286}
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 3ca80c8ff..3141122f1 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -6,6 +6,7 @@
6 6
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/atomic_ops.h" 8#include "common/atomic_ops.h"
9#include "common/cache_management.h"
9#include "common/common_types.h" 10#include "common/common_types.h"
10#include "common/logging/log.h" 11#include "common/logging/log.h"
11#include "common/page_table.h" 12#include "common/page_table.h"
@@ -329,6 +330,55 @@ struct Memory::Impl {
329 }); 330 });
330 } 331 }
331 332
333 template <typename Callback>
334 Result PerformCacheOperation(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size,
335 Callback&& cb) {
336 class InvalidMemoryException : public std::exception {};
337
338 try {
339 WalkBlock(
340 process, dest_addr, size,
341 [&](const std::size_t block_size, const VAddr current_vaddr) {
342 LOG_ERROR(HW_Memory, "Unmapped cache maintenance @ {:#018X}", current_vaddr);
343 throw InvalidMemoryException();
344 },
345 [&](const std::size_t block_size, u8* const host_ptr) { cb(block_size, host_ptr); },
346 [&](const VAddr current_vaddr, const std::size_t block_size, u8* const host_ptr) {
347 system.GPU().FlushRegion(current_vaddr, block_size);
348 cb(block_size, host_ptr);
349 },
350 [](const std::size_t block_size) {});
351 } catch (InvalidMemoryException&) {
352 return Kernel::ResultInvalidCurrentMemory;
353 }
354
355 return ResultSuccess;
356 }
357
358 Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) {
359 auto perform = [&](const std::size_t block_size, u8* const host_ptr) {
360 // Do nothing; this operation (dc ivac) cannot be supported
361 // from EL0
362 };
363 return PerformCacheOperation(process, dest_addr, size, perform);
364 }
365
366 Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) {
367 auto perform = [&](const std::size_t block_size, u8* const host_ptr) {
368 // dc cvac: Store to point of coherency
369 Common::DataCacheLineCleanByVAToPoC(host_ptr, block_size);
370 };
371 return PerformCacheOperation(process, dest_addr, size, perform);
372 }
373
374 Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) {
375 auto perform = [&](const std::size_t block_size, u8* const host_ptr) {
376 // dc civac: Store to point of coherency, and invalidate from cache
377 Common::DataCacheLineCleanAndInvalidateByVAToPoC(host_ptr, block_size);
378 };
379 return PerformCacheOperation(process, dest_addr, size, perform);
380 }
381
332 void MarkRegionDebug(VAddr vaddr, u64 size, bool debug) { 382 void MarkRegionDebug(VAddr vaddr, u64 size, bool debug) {
333 if (vaddr == 0) { 383 if (vaddr == 0) {
334 return; 384 return;
@@ -786,6 +836,21 @@ void Memory::ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, const s
786 impl->ZeroBlock(process, dest_addr, size); 836 impl->ZeroBlock(process, dest_addr, size);
787} 837}
788 838
839Result Memory::InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr,
840 const std::size_t size) {
841 return impl->InvalidateDataCache(process, dest_addr, size);
842}
843
844Result Memory::StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr,
845 const std::size_t size) {
846 return impl->StoreDataCache(process, dest_addr, size);
847}
848
849Result Memory::FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr,
850 const std::size_t size) {
851 return impl->FlushDataCache(process, dest_addr, size);
852}
853
789void Memory::RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) { 854void Memory::RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
790 impl->RasterizerMarkRegionCached(vaddr, size, cached); 855 impl->RasterizerMarkRegionCached(vaddr, size, cached);
791} 856}
diff --git a/src/core/memory.h b/src/core/memory.h
index 81eac448b..31fe699d8 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -7,6 +7,7 @@
7#include <memory> 7#include <memory>
8#include <string> 8#include <string>
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/hle/result.h"
10 11
11namespace Common { 12namespace Common {
12struct PageTable; 13struct PageTable;
@@ -450,6 +451,39 @@ public:
450 void ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); 451 void ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size);
451 452
452 /** 453 /**
454 * Invalidates a range of bytes within the current process' address space at the specified
455 * virtual address.
456 *
457 * @param process The process that will have data invalidated within its address space.
458 * @param dest_addr The destination virtual address to invalidate the data from.
459 * @param size The size of the range to invalidate, in bytes.
460 *
461 */
462 Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size);
463
464 /**
465 * Stores a range of bytes within the current process' address space at the specified
466 * virtual address.
467 *
468 * @param process The process that will have data stored within its address space.
469 * @param dest_addr The destination virtual address to store the data from.
470 * @param size The size of the range to store, in bytes.
471 *
472 */
473 Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size);
474
475 /**
476 * Flushes a range of bytes within the current process' address space at the specified
477 * virtual address.
478 *
479 * @param process The process that will have data flushed within its address space.
480 * @param dest_addr The destination virtual address to flush the data from.
481 * @param size The size of the range to flush, in bytes.
482 *
483 */
484 Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size);
485
486 /**
453 * Marks each page within the specified address range as cached or uncached. 487 * Marks each page within the specified address range as cached or uncached.
454 * 488 *
455 * @param vaddr The virtual address indicating the start of the address range. 489 * @param vaddr The virtual address indicating the start of the address range.