summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt21
-rw-r--r--src/core/announce_multiplayer_session.cpp164
-rw-r--r--src/core/announce_multiplayer_session.h98
-rw-r--r--src/core/arm/arm_interface.h11
-rw-r--r--src/core/arm/cpu_interrupt_handler.cpp24
-rw-r--r--src/core/arm/cpu_interrupt_handler.h39
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp51
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.h5
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp34
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.h6
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_cp15.cpp31
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_cp15.h2
-rw-r--r--src/core/core.cpp13
-rw-r--r--src/core/core_timing.cpp14
-rw-r--r--src/core/core_timing.h6
-rw-r--r--src/core/debugger/debugger.cpp9
-rw-r--r--src/core/file_sys/ips_layer.cpp7
-rw-r--r--src/core/file_sys/patch_manager.cpp14
-rw-r--r--src/core/file_sys/system_archive/shared_font.cpp2
-rw-r--r--src/core/hid/emulated_controller.cpp80
-rw-r--r--src/core/hid/emulated_controller.h8
-rw-r--r--src/core/hid/hid_types.h12
-rw-r--r--src/core/hid/input_converter.cpp3
-rw-r--r--src/core/hle/kernel/kernel.cpp41
-rw-r--r--src/core/hle/kernel/kernel.h8
-rw-r--r--src/core/hle/kernel/physical_core.cpp29
-rw-r--r--src/core/hle/kernel/physical_core.h17
-rw-r--r--src/core/hle/result.h2
-rw-r--r--src/core/hle/service/acc/acc.cpp2
-rw-r--r--src/core/hle/service/am/am.cpp2
-rw-r--r--src/core/hle/service/am/applets/applet_web_browser.cpp2
-rw-r--r--src/core/hle/service/apm/apm_controller.cpp2
-rw-r--r--src/core/hle/service/audio/audout_u.cpp3
-rw-r--r--src/core/hle/service/audio/audren_u.cpp31
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp77
-rw-r--r--src/core/hle/service/hid/hid.cpp20
-rw-r--r--src/core/hle/service/ldn/errors.h12
-rw-r--r--src/core/hle/service/ldn/ldn.cpp436
-rw-r--r--src/core/hle/service/ldn/ldn.h6
-rw-r--r--src/core/hle/service/ldn/ldn_results.h27
-rw-r--r--src/core/hle/service/ldn/ldn_types.h292
-rw-r--r--src/core/hle/service/mm/mm_u.cpp10
-rw-r--r--src/core/hle/service/nifm/nifm.cpp342
-rw-r--r--src/core/hle/service/nifm/nifm.h27
-rw-r--r--src/core/hle/service/ns/iplatform_service_manager.cpp (renamed from src/core/hle/service/ns/pl_u.cpp)34
-rw-r--r--src/core/hle/service/ns/iplatform_service_manager.h (renamed from src/core/hle/service/ns/pl_u.h)6
-rw-r--r--src/core/hle/service/ns/ns.cpp5
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp7
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp4
-rw-r--r--src/core/hle/service/pcv/pcv.cpp93
-rw-r--r--src/core/hle/service/pcv/pcv.h91
-rw-r--r--src/core/hle/service/sockets/bsd.cpp46
-rw-r--r--src/core/hle/service/sockets/bsd.h13
-rw-r--r--src/core/hle/service/sockets/sockets.h6
-rw-r--r--src/core/hle/service/sockets/sockets_translate.cpp2
-rw-r--r--src/core/internal_network/network.cpp62
-rw-r--r--src/core/internal_network/network.h43
-rw-r--r--src/core/internal_network/socket_proxy.cpp290
-rw-r--r--src/core/internal_network/socket_proxy.h97
-rw-r--r--src/core/internal_network/sockets.h132
-rw-r--r--src/core/loader/kip.cpp2
-rw-r--r--src/core/loader/nro.cpp2
-rw-r--r--src/core/loader/nso.cpp2
-rw-r--r--src/core/memory.cpp81
-rw-r--r--src/core/memory.h6
66 files changed, 2133 insertions, 936 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 9dbe5bdca..405a2f993 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -2,18 +2,8 @@
2# SPDX-License-Identifier: GPL-2.0-or-later 2# SPDX-License-Identifier: GPL-2.0-or-later
3 3
4add_library(core STATIC 4add_library(core STATIC
5 announce_multiplayer_session.cpp
6 announce_multiplayer_session.h
7 arm/arm_interface.h 5 arm/arm_interface.h
8 arm/arm_interface.cpp 6 arm/arm_interface.cpp
9 arm/cpu_interrupt_handler.cpp
10 arm/cpu_interrupt_handler.h
11 arm/dynarmic/arm_dynarmic_32.cpp
12 arm/dynarmic/arm_dynarmic_32.h
13 arm/dynarmic/arm_dynarmic_64.cpp
14 arm/dynarmic/arm_dynarmic_64.h
15 arm/dynarmic/arm_dynarmic_cp15.cpp
16 arm/dynarmic/arm_dynarmic_cp15.h
17 arm/dynarmic/arm_exclusive_monitor.cpp 7 arm/dynarmic/arm_exclusive_monitor.cpp
18 arm/dynarmic/arm_exclusive_monitor.h 8 arm/dynarmic/arm_exclusive_monitor.h
19 arm/exclusive_monitor.cpp 9 arm/exclusive_monitor.cpp
@@ -504,9 +494,10 @@ add_library(core STATIC
504 hle/service/jit/jit.h 494 hle/service/jit/jit.h
505 hle/service/lbl/lbl.cpp 495 hle/service/lbl/lbl.cpp
506 hle/service/lbl/lbl.h 496 hle/service/lbl/lbl.h
507 hle/service/ldn/errors.h 497 hle/service/ldn/ldn_results.h
508 hle/service/ldn/ldn.cpp 498 hle/service/ldn/ldn.cpp
509 hle/service/ldn/ldn.h 499 hle/service/ldn/ldn.h
500 hle/service/ldn/ldn_types.h
510 hle/service/ldr/ldr.cpp 501 hle/service/ldr/ldr.cpp
511 hle/service/ldr/ldr.h 502 hle/service/ldr/ldr.h
512 hle/service/lm/lm.cpp 503 hle/service/lm/lm.cpp
@@ -541,14 +532,14 @@ add_library(core STATIC
541 hle/service/npns/npns.cpp 532 hle/service/npns/npns.cpp
542 hle/service/npns/npns.h 533 hle/service/npns/npns.h
543 hle/service/ns/errors.h 534 hle/service/ns/errors.h
535 hle/service/ns/iplatform_service_manager.cpp
536 hle/service/ns/iplatform_service_manager.h
544 hle/service/ns/language.cpp 537 hle/service/ns/language.cpp
545 hle/service/ns/language.h 538 hle/service/ns/language.h
546 hle/service/ns/ns.cpp 539 hle/service/ns/ns.cpp
547 hle/service/ns/ns.h 540 hle/service/ns/ns.h
548 hle/service/ns/pdm_qry.cpp 541 hle/service/ns/pdm_qry.cpp
549 hle/service/ns/pdm_qry.h 542 hle/service/ns/pdm_qry.h
550 hle/service/ns/pl_u.cpp
551 hle/service/ns/pl_u.h
552 hle/service/nvdrv/devices/nvdevice.h 543 hle/service/nvdrv/devices/nvdevice.h
553 hle/service/nvdrv/devices/nvdisp_disp0.cpp 544 hle/service/nvdrv/devices/nvdisp_disp0.cpp
554 hle/service/nvdrv/devices/nvdisp_disp0.h 545 hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -725,6 +716,8 @@ add_library(core STATIC
725 internal_network/network_interface.cpp 716 internal_network/network_interface.cpp
726 internal_network/network_interface.h 717 internal_network/network_interface.h
727 internal_network/sockets.h 718 internal_network/sockets.h
719 internal_network/socket_proxy.cpp
720 internal_network/socket_proxy.h
728 loader/deconstructed_rom_directory.cpp 721 loader/deconstructed_rom_directory.cpp
729 loader/deconstructed_rom_directory.h 722 loader/deconstructed_rom_directory.h
730 loader/kip.cpp 723 loader/kip.cpp
@@ -785,7 +778,7 @@ endif()
785create_target_directory_groups(core) 778create_target_directory_groups(core)
786 779
787target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core) 780target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core)
788target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::Opus) 781target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::opus)
789if (MINGW) 782if (MINGW)
790 target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY}) 783 target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY})
791endif() 784endif()
diff --git a/src/core/announce_multiplayer_session.cpp b/src/core/announce_multiplayer_session.cpp
deleted file mode 100644
index d73a488cf..000000000
--- a/src/core/announce_multiplayer_session.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <chrono>
5#include <future>
6#include <vector>
7#include "announce_multiplayer_session.h"
8#include "common/announce_multiplayer_room.h"
9#include "common/assert.h"
10#include "common/settings.h"
11#include "network/network.h"
12
13#ifdef ENABLE_WEB_SERVICE
14#include "web_service/announce_room_json.h"
15#endif
16
17namespace Core {
18
19// Time between room is announced to web_service
20static constexpr std::chrono::seconds announce_time_interval(15);
21
22AnnounceMultiplayerSession::AnnounceMultiplayerSession(Network::RoomNetwork& room_network_)
23 : room_network{room_network_} {
24#ifdef ENABLE_WEB_SERVICE
25 backend = std::make_unique<WebService::RoomJson>(Settings::values.web_api_url.GetValue(),
26 Settings::values.yuzu_username.GetValue(),
27 Settings::values.yuzu_token.GetValue());
28#else
29 backend = std::make_unique<AnnounceMultiplayerRoom::NullBackend>();
30#endif
31}
32
33WebService::WebResult AnnounceMultiplayerSession::Register() {
34 std::shared_ptr<Network::Room> room = room_network.GetRoom().lock();
35 if (!room) {
36 return WebService::WebResult{WebService::WebResult::Code::LibError,
37 "Network is not initialized", ""};
38 }
39 if (room->GetState() != Network::Room::State::Open) {
40 return WebService::WebResult{WebService::WebResult::Code::LibError, "Room is not open", ""};
41 }
42 UpdateBackendData(room);
43 WebService::WebResult result = backend->Register();
44 if (result.result_code != WebService::WebResult::Code::Success) {
45 return result;
46 }
47 LOG_INFO(WebService, "Room has been registered");
48 room->SetVerifyUID(result.returned_data);
49 registered = true;
50 return WebService::WebResult{WebService::WebResult::Code::Success, "", ""};
51}
52
53void AnnounceMultiplayerSession::Start() {
54 if (announce_multiplayer_thread) {
55 Stop();
56 }
57 shutdown_event.Reset();
58 announce_multiplayer_thread =
59 std::make_unique<std::thread>(&AnnounceMultiplayerSession::AnnounceMultiplayerLoop, this);
60}
61
62void AnnounceMultiplayerSession::Stop() {
63 if (announce_multiplayer_thread) {
64 shutdown_event.Set();
65 announce_multiplayer_thread->join();
66 announce_multiplayer_thread.reset();
67 backend->Delete();
68 registered = false;
69 }
70}
71
72AnnounceMultiplayerSession::CallbackHandle AnnounceMultiplayerSession::BindErrorCallback(
73 std::function<void(const WebService::WebResult&)> function) {
74 std::lock_guard lock(callback_mutex);
75 auto handle = std::make_shared<std::function<void(const WebService::WebResult&)>>(function);
76 error_callbacks.insert(handle);
77 return handle;
78}
79
80void AnnounceMultiplayerSession::UnbindErrorCallback(CallbackHandle handle) {
81 std::lock_guard lock(callback_mutex);
82 error_callbacks.erase(handle);
83}
84
85AnnounceMultiplayerSession::~AnnounceMultiplayerSession() {
86 Stop();
87}
88
89void AnnounceMultiplayerSession::UpdateBackendData(std::shared_ptr<Network::Room> room) {
90 Network::RoomInformation room_information = room->GetRoomInformation();
91 std::vector<AnnounceMultiplayerRoom::Member> memberlist = room->GetRoomMemberList();
92 backend->SetRoomInformation(room_information.name, room_information.description,
93 room_information.port, room_information.member_slots,
94 Network::network_version, room->HasPassword(),
95 room_information.preferred_game);
96 backend->ClearPlayers();
97 for (const auto& member : memberlist) {
98 backend->AddPlayer(member);
99 }
100}
101
102void AnnounceMultiplayerSession::AnnounceMultiplayerLoop() {
103 // Invokes all current bound error callbacks.
104 const auto ErrorCallback = [this](WebService::WebResult result) {
105 std::lock_guard<std::mutex> lock(callback_mutex);
106 for (auto callback : error_callbacks) {
107 (*callback)(result);
108 }
109 };
110
111 if (!registered) {
112 WebService::WebResult result = Register();
113 if (result.result_code != WebService::WebResult::Code::Success) {
114 ErrorCallback(result);
115 return;
116 }
117 }
118
119 auto update_time = std::chrono::steady_clock::now();
120 std::future<WebService::WebResult> future;
121 while (!shutdown_event.WaitUntil(update_time)) {
122 update_time += announce_time_interval;
123 std::shared_ptr<Network::Room> room = room_network.GetRoom().lock();
124 if (!room) {
125 break;
126 }
127 if (room->GetState() != Network::Room::State::Open) {
128 break;
129 }
130 UpdateBackendData(room);
131 WebService::WebResult result = backend->Update();
132 if (result.result_code != WebService::WebResult::Code::Success) {
133 ErrorCallback(result);
134 }
135 if (result.result_string == "404") {
136 registered = false;
137 // Needs to register the room again
138 WebService::WebResult register_result = Register();
139 if (register_result.result_code != WebService::WebResult::Code::Success) {
140 ErrorCallback(register_result);
141 }
142 }
143 }
144}
145
146AnnounceMultiplayerRoom::RoomList AnnounceMultiplayerSession::GetRoomList() {
147 return backend->GetRoomList();
148}
149
150bool AnnounceMultiplayerSession::IsRunning() const {
151 return announce_multiplayer_thread != nullptr;
152}
153
154void AnnounceMultiplayerSession::UpdateCredentials() {
155 ASSERT_MSG(!IsRunning(), "Credentials can only be updated when session is not running");
156
157#ifdef ENABLE_WEB_SERVICE
158 backend = std::make_unique<WebService::RoomJson>(Settings::values.web_api_url.GetValue(),
159 Settings::values.yuzu_username.GetValue(),
160 Settings::values.yuzu_token.GetValue());
161#endif
162}
163
164} // namespace Core
diff --git a/src/core/announce_multiplayer_session.h b/src/core/announce_multiplayer_session.h
deleted file mode 100644
index db790f7d2..000000000
--- a/src/core/announce_multiplayer_session.h
+++ /dev/null
@@ -1,98 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <atomic>
7#include <functional>
8#include <memory>
9#include <mutex>
10#include <set>
11#include <thread>
12#include "common/announce_multiplayer_room.h"
13#include "common/common_types.h"
14#include "common/thread.h"
15
16namespace Network {
17class Room;
18class RoomNetwork;
19} // namespace Network
20
21namespace Core {
22
23/**
24 * Instruments AnnounceMultiplayerRoom::Backend.
25 * Creates a thread that regularly updates the room information and submits them
26 * An async get of room information is also possible
27 */
28class AnnounceMultiplayerSession {
29public:
30 using CallbackHandle = std::shared_ptr<std::function<void(const WebService::WebResult&)>>;
31 AnnounceMultiplayerSession(Network::RoomNetwork& room_network_);
32 ~AnnounceMultiplayerSession();
33
34 /**
35 * Allows to bind a function that will get called if the announce encounters an error
36 * @param function The function that gets called
37 * @return A handle that can be used the unbind the function
38 */
39 CallbackHandle BindErrorCallback(std::function<void(const WebService::WebResult&)> function);
40
41 /**
42 * Unbind a function from the error callbacks
43 * @param handle The handle for the function that should get unbind
44 */
45 void UnbindErrorCallback(CallbackHandle handle);
46
47 /**
48 * Registers a room to web services
49 * @return The result of the registration attempt.
50 */
51 WebService::WebResult Register();
52
53 /**
54 * Starts the announce of a room to web services
55 */
56 void Start();
57
58 /**
59 * Stops the announce to web services
60 */
61 void Stop();
62
63 /**
64 * Returns a list of all room information the backend got
65 * @param func A function that gets executed when the async get finished, e.g. a signal
66 * @return a list of rooms received from the web service
67 */
68 AnnounceMultiplayerRoom::RoomList GetRoomList();
69
70 /**
71 * Whether the announce session is still running
72 */
73 bool IsRunning() const;
74
75 /**
76 * Recreates the backend, updating the credentials.
77 * This can only be used when the announce session is not running.
78 */
79 void UpdateCredentials();
80
81private:
82 void UpdateBackendData(std::shared_ptr<Network::Room> room);
83 void AnnounceMultiplayerLoop();
84
85 Common::Event shutdown_event;
86 std::mutex callback_mutex;
87 std::set<CallbackHandle> error_callbacks;
88 std::unique_ptr<std::thread> announce_multiplayer_thread;
89
90 /// Backend interface that logs fields
91 std::unique_ptr<AnnounceMultiplayerRoom::Backend> backend;
92
93 std::atomic_bool registered = false; ///< Whether the room has been registered
94
95 Network::RoomNetwork& room_network;
96};
97
98} // namespace Core
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 73f259525..7d62d030e 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -27,7 +27,6 @@ namespace Core {
27class System; 27class System;
28class CPUInterruptHandler; 28class CPUInterruptHandler;
29 29
30using CPUInterrupts = std::array<CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>;
31using WatchpointArray = std::array<Kernel::DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>; 30using WatchpointArray = std::array<Kernel::DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>;
32 31
33/// Generic ARMv8 CPU interface 32/// Generic ARMv8 CPU interface
@@ -36,10 +35,8 @@ public:
36 YUZU_NON_COPYABLE(ARM_Interface); 35 YUZU_NON_COPYABLE(ARM_Interface);
37 YUZU_NON_MOVEABLE(ARM_Interface); 36 YUZU_NON_MOVEABLE(ARM_Interface);
38 37
39 explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers_, 38 explicit ARM_Interface(System& system_, bool uses_wall_clock_)
40 bool uses_wall_clock_) 39 : system{system_}, uses_wall_clock{uses_wall_clock_} {}
41 : system{system_}, interrupt_handlers{interrupt_handlers_}, uses_wall_clock{
42 uses_wall_clock_} {}
43 virtual ~ARM_Interface() = default; 40 virtual ~ARM_Interface() = default;
44 41
45 struct ThreadContext32 { 42 struct ThreadContext32 {
@@ -181,6 +178,9 @@ public:
181 /// Signal an interrupt and ask the core to halt as soon as possible. 178 /// Signal an interrupt and ask the core to halt as soon as possible.
182 virtual void SignalInterrupt() = 0; 179 virtual void SignalInterrupt() = 0;
183 180
181 /// Clear a previous interrupt.
182 virtual void ClearInterrupt() = 0;
183
184 struct BacktraceEntry { 184 struct BacktraceEntry {
185 std::string module; 185 std::string module;
186 u64 address; 186 u64 address;
@@ -208,7 +208,6 @@ public:
208protected: 208protected:
209 /// System context that this ARM interface is running under. 209 /// System context that this ARM interface is running under.
210 System& system; 210 System& system;
211 CPUInterrupts& interrupt_handlers;
212 const WatchpointArray* watchpoints; 211 const WatchpointArray* watchpoints;
213 bool uses_wall_clock; 212 bool uses_wall_clock;
214 213
diff --git a/src/core/arm/cpu_interrupt_handler.cpp b/src/core/arm/cpu_interrupt_handler.cpp
deleted file mode 100644
index 77b6194d7..000000000
--- a/src/core/arm/cpu_interrupt_handler.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/thread.h"
5#include "core/arm/cpu_interrupt_handler.h"
6
7namespace Core {
8
9CPUInterruptHandler::CPUInterruptHandler() : interrupt_event{std::make_unique<Common::Event>()} {}
10
11CPUInterruptHandler::~CPUInterruptHandler() = default;
12
13void CPUInterruptHandler::SetInterrupt(bool is_interrupted_) {
14 if (is_interrupted_) {
15 interrupt_event->Set();
16 }
17 is_interrupted = is_interrupted_;
18}
19
20void CPUInterruptHandler::AwaitInterrupt() {
21 interrupt_event->Wait();
22}
23
24} // namespace Core
diff --git a/src/core/arm/cpu_interrupt_handler.h b/src/core/arm/cpu_interrupt_handler.h
deleted file mode 100644
index 286e12e53..000000000
--- a/src/core/arm/cpu_interrupt_handler.h
+++ /dev/null
@@ -1,39 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <atomic>
7#include <memory>
8
9namespace Common {
10class Event;
11}
12
13namespace Core {
14
15class CPUInterruptHandler {
16public:
17 CPUInterruptHandler();
18 ~CPUInterruptHandler();
19
20 CPUInterruptHandler(const CPUInterruptHandler&) = delete;
21 CPUInterruptHandler& operator=(const CPUInterruptHandler&) = delete;
22
23 CPUInterruptHandler(CPUInterruptHandler&&) = delete;
24 CPUInterruptHandler& operator=(CPUInterruptHandler&&) = delete;
25
26 bool IsInterrupted() const {
27 return is_interrupted;
28 }
29
30 void SetInterrupt(bool is_interrupted);
31
32 void AwaitInterrupt();
33
34private:
35 std::unique_ptr<Common::Event> interrupt_event;
36 std::atomic_bool is_interrupted{false};
37};
38
39} // namespace Core
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index b8d2ce224..d1e70f19d 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -11,7 +11,6 @@
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/page_table.h" 12#include "common/page_table.h"
13#include "common/settings.h" 13#include "common/settings.h"
14#include "core/arm/cpu_interrupt_handler.h"
15#include "core/arm/dynarmic/arm_dynarmic_32.h" 14#include "core/arm/dynarmic/arm_dynarmic_32.h"
16#include "core/arm/dynarmic/arm_dynarmic_cp15.h" 15#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
17#include "core/arm/dynarmic/arm_exclusive_monitor.h" 16#include "core/arm/dynarmic/arm_exclusive_monitor.h"
@@ -125,7 +124,9 @@ public:
125 } 124 }
126 125
127 void AddTicks(u64 ticks) override { 126 void AddTicks(u64 ticks) override {
128 ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled"); 127 if (parent.uses_wall_clock) {
128 return;
129 }
129 130
130 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a 131 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
131 // rough approximation of the amount of executed ticks in the system, it may be thrown off 132 // rough approximation of the amount of executed ticks in the system, it may be thrown off
@@ -142,7 +143,12 @@ public:
142 } 143 }
143 144
144 u64 GetTicksRemaining() override { 145 u64 GetTicksRemaining() override {
145 ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled"); 146 if (parent.uses_wall_clock) {
147 if (!IsInterrupted()) {
148 return minimum_run_cycles;
149 }
150 return 0U;
151 }
146 152
147 return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0); 153 return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
148 } 154 }
@@ -168,11 +174,15 @@ public:
168 parent.jit.load()->HaltExecution(hr); 174 parent.jit.load()->HaltExecution(hr);
169 } 175 }
170 176
177 bool IsInterrupted() {
178 return parent.system.Kernel().PhysicalCore(parent.core_index).IsInterrupted();
179 }
180
171 ARM_Dynarmic_32& parent; 181 ARM_Dynarmic_32& parent;
172 Core::Memory::Memory& memory; 182 Core::Memory::Memory& memory;
173 std::size_t num_interpreted_instructions{}; 183 std::size_t num_interpreted_instructions{};
174 bool debugger_enabled{}; 184 bool debugger_enabled{};
175 static constexpr u64 minimum_run_cycles = 1000U; 185 static constexpr u64 minimum_run_cycles = 10000U;
176}; 186};
177 187
178std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* page_table) const { 188std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* page_table) const {
@@ -180,19 +190,21 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
180 config.callbacks = cb.get(); 190 config.callbacks = cb.get();
181 config.coprocessors[15] = cp15; 191 config.coprocessors[15] = cp15;
182 config.define_unpredictable_behaviour = true; 192 config.define_unpredictable_behaviour = true;
183 static constexpr std::size_t PAGE_BITS = 12; 193 static constexpr std::size_t YUZU_PAGEBITS = 12;
184 static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - PAGE_BITS); 194 static constexpr std::size_t NUM_PAGE_TABLE_ENTRIES = 1 << (32 - YUZU_PAGEBITS);
185 if (page_table) { 195 if (page_table) {
186 config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>( 196 config.page_table = reinterpret_cast<std::array<std::uint8_t*, NUM_PAGE_TABLE_ENTRIES>*>(
187 page_table->pointers.data()); 197 page_table->pointers.data());
198 config.absolute_offset_page_table = true;
199 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
200 config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
201 config.only_detect_misalignment_via_page_table_on_page_boundary = true;
202
188 config.fastmem_pointer = page_table->fastmem_arena; 203 config.fastmem_pointer = page_table->fastmem_arena;
204
205 config.fastmem_exclusive_access = config.fastmem_pointer != nullptr;
206 config.recompile_on_exclusive_fastmem_failure = true;
189 } 207 }
190 config.absolute_offset_page_table = true;
191 config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
192 config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
193 config.only_detect_misalignment_via_page_table_on_page_boundary = true;
194 config.fastmem_exclusive_access = true;
195 config.recompile_on_exclusive_fastmem_failure = true;
196 208
197 // Multi-process state 209 // Multi-process state
198 config.processor_id = core_index; 210 config.processor_id = core_index;
@@ -200,7 +212,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
200 212
201 // Timing 213 // Timing
202 config.wall_clock_cntpct = uses_wall_clock; 214 config.wall_clock_cntpct = uses_wall_clock;
203 config.enable_cycle_counting = !uses_wall_clock; 215 config.enable_cycle_counting = true;
204 216
205 // Code cache size 217 // Code cache size
206 config.code_cache_size = 512_MiB; 218 config.code_cache_size = 512_MiB;
@@ -244,6 +256,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
244 } 256 }
245 if (!Settings::values.cpuopt_fastmem) { 257 if (!Settings::values.cpuopt_fastmem) {
246 config.fastmem_pointer = nullptr; 258 config.fastmem_pointer = nullptr;
259 config.fastmem_exclusive_access = false;
247 } 260 }
248 if (!Settings::values.cpuopt_fastmem_exclusives) { 261 if (!Settings::values.cpuopt_fastmem_exclusives) {
249 config.fastmem_exclusive_access = false; 262 config.fastmem_exclusive_access = false;
@@ -311,11 +324,9 @@ void ARM_Dynarmic_32::RewindBreakpointInstruction() {
311 LoadContext(breakpoint_context); 324 LoadContext(breakpoint_context);
312} 325}
313 326
314ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, 327ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, bool uses_wall_clock_,
315 bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_, 328 ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_)
316 std::size_t core_index_) 329 : ARM_Interface{system_, uses_wall_clock_}, cb(std::make_unique<DynarmicCallbacks32>(*this)),
317 : ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_},
318 cb(std::make_unique<DynarmicCallbacks32>(*this)),
319 cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index_}, 330 cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index_},
320 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)}, 331 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)},
321 null_jit{MakeJit(nullptr)}, jit{null_jit.get()} {} 332 null_jit{MakeJit(nullptr)}, jit{null_jit.get()} {}
@@ -394,6 +405,10 @@ void ARM_Dynarmic_32::SignalInterrupt() {
394 jit.load()->HaltExecution(break_loop); 405 jit.load()->HaltExecution(break_loop);
395} 406}
396 407
408void ARM_Dynarmic_32::ClearInterrupt() {
409 jit.load()->ClearHalt(break_loop);
410}
411
397void ARM_Dynarmic_32::ClearInstructionCache() { 412void ARM_Dynarmic_32::ClearInstructionCache() {
398 jit.load()->ClearCache(); 413 jit.load()->ClearCache();
399} 414}
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h
index 346e9abf8..d24ba2289 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.h
@@ -28,8 +28,8 @@ class System;
28 28
29class ARM_Dynarmic_32 final : public ARM_Interface { 29class ARM_Dynarmic_32 final : public ARM_Interface {
30public: 30public:
31 ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_, 31 ARM_Dynarmic_32(System& system_, bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
32 ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_); 32 std::size_t core_index_);
33 ~ARM_Dynarmic_32() override; 33 ~ARM_Dynarmic_32() override;
34 34
35 void SetPC(u64 pc) override; 35 void SetPC(u64 pc) override;
@@ -56,6 +56,7 @@ public:
56 void LoadContext(const ThreadContext64& ctx) override {} 56 void LoadContext(const ThreadContext64& ctx) override {}
57 57
58 void SignalInterrupt() override; 58 void SignalInterrupt() override;
59 void ClearInterrupt() override;
59 void ClearExclusiveState() override; 60 void ClearExclusiveState() override;
60 61
61 void ClearInstructionCache() override; 62 void ClearInstructionCache() override;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index 1a4d37cbc..1d46f6d40 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -10,7 +10,6 @@
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "common/page_table.h" 11#include "common/page_table.h"
12#include "common/settings.h" 12#include "common/settings.h"
13#include "core/arm/cpu_interrupt_handler.h"
14#include "core/arm/dynarmic/arm_dynarmic_64.h" 13#include "core/arm/dynarmic/arm_dynarmic_64.h"
15#include "core/arm/dynarmic/arm_exclusive_monitor.h" 14#include "core/arm/dynarmic/arm_exclusive_monitor.h"
16#include "core/core.h" 15#include "core/core.h"
@@ -166,7 +165,9 @@ public:
166 } 165 }
167 166
168 void AddTicks(u64 ticks) override { 167 void AddTicks(u64 ticks) override {
169 ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled"); 168 if (parent.uses_wall_clock) {
169 return;
170 }
170 171
171 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a 172 // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
172 // rough approximation of the amount of executed ticks in the system, it may be thrown off 173 // rough approximation of the amount of executed ticks in the system, it may be thrown off
@@ -181,7 +182,12 @@ public:
181 } 182 }
182 183
183 u64 GetTicksRemaining() override { 184 u64 GetTicksRemaining() override {
184 ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled"); 185 if (parent.uses_wall_clock) {
186 if (!IsInterrupted()) {
187 return minimum_run_cycles;
188 }
189 return 0U;
190 }
185 191
186 return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0); 192 return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
187 } 193 }
@@ -211,12 +217,16 @@ public:
211 parent.jit.load()->HaltExecution(hr); 217 parent.jit.load()->HaltExecution(hr);
212 } 218 }
213 219
220 bool IsInterrupted() {
221 return parent.system.Kernel().PhysicalCore(parent.core_index).IsInterrupted();
222 }
223
214 ARM_Dynarmic_64& parent; 224 ARM_Dynarmic_64& parent;
215 Core::Memory::Memory& memory; 225 Core::Memory::Memory& memory;
216 u64 tpidrro_el0 = 0; 226 u64 tpidrro_el0 = 0;
217 u64 tpidr_el0 = 0; 227 u64 tpidr_el0 = 0;
218 bool debugger_enabled{}; 228 bool debugger_enabled{};
219 static constexpr u64 minimum_run_cycles = 1000U; 229 static constexpr u64 minimum_run_cycles = 10000U;
220}; 230};
221 231
222std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* page_table, 232std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* page_table,
@@ -240,7 +250,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
240 config.fastmem_address_space_bits = address_space_bits; 250 config.fastmem_address_space_bits = address_space_bits;
241 config.silently_mirror_fastmem = false; 251 config.silently_mirror_fastmem = false;
242 252
243 config.fastmem_exclusive_access = true; 253 config.fastmem_exclusive_access = config.fastmem_pointer != nullptr;
244 config.recompile_on_exclusive_fastmem_failure = true; 254 config.recompile_on_exclusive_fastmem_failure = true;
245 } 255 }
246 256
@@ -260,7 +270,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
260 270
261 // Timing 271 // Timing
262 config.wall_clock_cntpct = uses_wall_clock; 272 config.wall_clock_cntpct = uses_wall_clock;
263 config.enable_cycle_counting = !uses_wall_clock; 273 config.enable_cycle_counting = true;
264 274
265 // Code cache size 275 // Code cache size
266 config.code_cache_size = 512_MiB; 276 config.code_cache_size = 512_MiB;
@@ -304,6 +314,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
304 } 314 }
305 if (!Settings::values.cpuopt_fastmem) { 315 if (!Settings::values.cpuopt_fastmem) {
306 config.fastmem_pointer = nullptr; 316 config.fastmem_pointer = nullptr;
317 config.fastmem_exclusive_access = false;
307 } 318 }
308 if (!Settings::values.cpuopt_fastmem_exclusives) { 319 if (!Settings::values.cpuopt_fastmem_exclusives) {
309 config.fastmem_exclusive_access = false; 320 config.fastmem_exclusive_access = false;
@@ -371,10 +382,9 @@ void ARM_Dynarmic_64::RewindBreakpointInstruction() {
371 LoadContext(breakpoint_context); 382 LoadContext(breakpoint_context);
372} 383}
373 384
374ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, 385ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, bool uses_wall_clock_,
375 bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_, 386 ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_)
376 std::size_t core_index_) 387 : ARM_Interface{system_, uses_wall_clock_},
377 : ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_},
378 cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index_}, 388 cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index_},
379 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)}, 389 exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)},
380 null_jit{MakeJit(nullptr, 48)}, jit{null_jit.get()} {} 390 null_jit{MakeJit(nullptr, 48)}, jit{null_jit.get()} {}
@@ -461,6 +471,10 @@ void ARM_Dynarmic_64::SignalInterrupt() {
461 jit.load()->HaltExecution(break_loop); 471 jit.load()->HaltExecution(break_loop);
462} 472}
463 473
474void ARM_Dynarmic_64::ClearInterrupt() {
475 jit.load()->ClearHalt(break_loop);
476}
477
464void ARM_Dynarmic_64::ClearInstructionCache() { 478void ARM_Dynarmic_64::ClearInstructionCache() {
465 jit.load()->ClearCache(); 479 jit.load()->ClearCache();
466} 480}
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h
index c77a83ad7..ed1a5eb96 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.h
@@ -20,14 +20,13 @@ class Memory;
20namespace Core { 20namespace Core {
21 21
22class DynarmicCallbacks64; 22class DynarmicCallbacks64;
23class CPUInterruptHandler;
24class DynarmicExclusiveMonitor; 23class DynarmicExclusiveMonitor;
25class System; 24class System;
26 25
27class ARM_Dynarmic_64 final : public ARM_Interface { 26class ARM_Dynarmic_64 final : public ARM_Interface {
28public: 27public:
29 ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_, 28 ARM_Dynarmic_64(System& system_, bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
30 ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_); 29 std::size_t core_index_);
31 ~ARM_Dynarmic_64() override; 30 ~ARM_Dynarmic_64() override;
32 31
33 void SetPC(u64 pc) override; 32 void SetPC(u64 pc) override;
@@ -50,6 +49,7 @@ public:
50 void LoadContext(const ThreadContext64& ctx) override; 49 void LoadContext(const ThreadContext64& ctx) override;
51 50
52 void SignalInterrupt() override; 51 void SignalInterrupt() override;
52 void ClearInterrupt() override;
53 void ClearExclusiveState() override; 53 void ClearExclusiveState() override;
54 54
55 void ClearInstructionCache() override; 55 void ClearInstructionCache() override;
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
index e9123c13d..200efe4db 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.cpp
@@ -8,6 +8,10 @@
8#include "core/core.h" 8#include "core/core.h"
9#include "core/core_timing.h" 9#include "core/core_timing.h"
10 10
11#ifdef _MSC_VER
12#include <intrin.h>
13#endif
14
11using Callback = Dynarmic::A32::Coprocessor::Callback; 15using Callback = Dynarmic::A32::Coprocessor::Callback;
12using CallbackOrAccessOneWord = Dynarmic::A32::Coprocessor::CallbackOrAccessOneWord; 16using CallbackOrAccessOneWord = Dynarmic::A32::Coprocessor::CallbackOrAccessOneWord;
13using CallbackOrAccessTwoWords = Dynarmic::A32::Coprocessor::CallbackOrAccessTwoWords; 17using CallbackOrAccessTwoWords = Dynarmic::A32::Coprocessor::CallbackOrAccessTwoWords;
@@ -47,12 +51,31 @@ CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1
47 switch (opc2) { 51 switch (opc2) {
48 case 4: 52 case 4:
49 // CP15_DATA_SYNC_BARRIER 53 // CP15_DATA_SYNC_BARRIER
50 // This is a dummy write, we ignore the value written here. 54 return Callback{
51 return &dummy_value; 55 [](Dynarmic::A32::Jit*, void*, std::uint32_t, std::uint32_t) -> std::uint64_t {
56#ifdef _MSC_VER
57 _mm_mfence();
58 _mm_lfence();
59#else
60 asm volatile("mfence\n\tlfence\n\t" : : : "memory");
61#endif
62 return 0;
63 },
64 std::nullopt,
65 };
52 case 5: 66 case 5:
53 // CP15_DATA_MEMORY_BARRIER 67 // CP15_DATA_MEMORY_BARRIER
54 // This is a dummy write, we ignore the value written here. 68 return Callback{
55 return &dummy_value; 69 [](Dynarmic::A32::Jit*, void*, std::uint32_t, std::uint32_t) -> std::uint64_t {
70#ifdef _MSC_VER
71 _mm_mfence();
72#else
73 asm volatile("mfence\n\t" : : : "memory");
74#endif
75 return 0;
76 },
77 std::nullopt,
78 };
56 } 79 }
57 } 80 }
58 81
diff --git a/src/core/arm/dynarmic/arm_dynarmic_cp15.h b/src/core/arm/dynarmic/arm_dynarmic_cp15.h
index 5b2a51636..d90b3e568 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_cp15.h
+++ b/src/core/arm/dynarmic/arm_dynarmic_cp15.h
@@ -35,6 +35,8 @@ public:
35 ARM_Dynarmic_32& parent; 35 ARM_Dynarmic_32& parent;
36 u32 uprw = 0; 36 u32 uprw = 0;
37 u32 uro = 0; 37 u32 uro = 0;
38
39 friend class ARM_Dynarmic_32;
38}; 40};
39 41
40} // namespace Core 42} // namespace Core
diff --git a/src/core/core.cpp b/src/core/core.cpp
index ea32a4a8d..121092868 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -141,8 +141,6 @@ struct System::Impl {
141 core_timing.SyncPause(false); 141 core_timing.SyncPause(false);
142 is_paused = false; 142 is_paused = false;
143 143
144 audio_core->PauseSinks(false);
145
146 return status; 144 return status;
147 } 145 }
148 146
@@ -150,8 +148,6 @@ struct System::Impl {
150 std::unique_lock<std::mutex> lk(suspend_guard); 148 std::unique_lock<std::mutex> lk(suspend_guard);
151 status = SystemResultStatus::Success; 149 status = SystemResultStatus::Success;
152 150
153 audio_core->PauseSinks(true);
154
155 core_timing.SyncPause(true); 151 core_timing.SyncPause(true);
156 kernel.Suspend(true); 152 kernel.Suspend(true);
157 is_paused = true; 153 is_paused = true;
@@ -319,10 +315,19 @@ struct System::Impl {
319 if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) { 315 if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) {
320 LOG_ERROR(Core, "Failed to read title for ROM (Error {})", load_result); 316 LOG_ERROR(Core, "Failed to read title for ROM (Error {})", load_result);
321 } 317 }
318
319 std::string title_version;
320 const FileSys::PatchManager pm(program_id, system.GetFileSystemController(),
321 system.GetContentProvider());
322 const auto metadata = pm.GetControlMetadata();
323 if (metadata.first != nullptr) {
324 title_version = metadata.first->GetVersionString();
325 }
322 if (auto room_member = room_network.GetRoomMember().lock()) { 326 if (auto room_member = room_network.GetRoomMember().lock()) {
323 Network::GameInfo game_info; 327 Network::GameInfo game_info;
324 game_info.name = name; 328 game_info.name = name;
325 game_info.id = program_id; 329 game_info.id = program_id;
330 game_info.version = title_version;
326 room_member->SendGameInfo(game_info); 331 room_member->SendGameInfo(game_info);
327 } 332 }
328 333
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 8d1ee3b51..f6c4567ba 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -73,7 +73,6 @@ void CoreTiming::Shutdown() {
73 if (timer_thread) { 73 if (timer_thread) {
74 timer_thread->join(); 74 timer_thread->join();
75 } 75 }
76 pause_callbacks.clear();
77 ClearPendingEvents(); 76 ClearPendingEvents();
78 timer_thread.reset(); 77 timer_thread.reset();
79 has_started = false; 78 has_started = false;
@@ -86,10 +85,6 @@ void CoreTiming::Pause(bool is_paused) {
86 if (!is_paused) { 85 if (!is_paused) {
87 pause_end_time = GetGlobalTimeNs().count(); 86 pause_end_time = GetGlobalTimeNs().count();
88 } 87 }
89
90 for (auto& cb : pause_callbacks) {
91 cb(is_paused);
92 }
93} 88}
94 89
95void CoreTiming::SyncPause(bool is_paused) { 90void CoreTiming::SyncPause(bool is_paused) {
@@ -110,10 +105,6 @@ void CoreTiming::SyncPause(bool is_paused) {
110 if (!is_paused) { 105 if (!is_paused) {
111 pause_end_time = GetGlobalTimeNs().count(); 106 pause_end_time = GetGlobalTimeNs().count();
112 } 107 }
113
114 for (auto& cb : pause_callbacks) {
115 cb(is_paused);
116 }
117} 108}
118 109
119bool CoreTiming::IsRunning() const { 110bool CoreTiming::IsRunning() const {
@@ -223,11 +214,6 @@ void CoreTiming::RemoveEvent(const std::shared_ptr<EventType>& event_type) {
223 } 214 }
224} 215}
225 216
226void CoreTiming::RegisterPauseCallback(PauseCallback&& callback) {
227 std::scoped_lock lock{basic_lock};
228 pause_callbacks.emplace_back(std::move(callback));
229}
230
231std::optional<s64> CoreTiming::Advance() { 217std::optional<s64> CoreTiming::Advance() {
232 std::scoped_lock lock{advance_lock, basic_lock}; 218 std::scoped_lock lock{advance_lock, basic_lock};
233 global_timer = GetGlobalTimeNs().count(); 219 global_timer = GetGlobalTimeNs().count();
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 6aa3ae923..3259397b2 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -22,7 +22,6 @@ namespace Core::Timing {
22/// A callback that may be scheduled for a particular core timing event. 22/// A callback that may be scheduled for a particular core timing event.
23using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>( 23using TimedCallback = std::function<std::optional<std::chrono::nanoseconds>(
24 std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)>; 24 std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late)>;
25using PauseCallback = std::function<void(bool paused)>;
26 25
27/// Contains the characteristics of a particular event. 26/// Contains the characteristics of a particular event.
28struct EventType { 27struct EventType {
@@ -134,9 +133,6 @@ public:
134 /// Checks for events manually and returns time in nanoseconds for next event, threadsafe. 133 /// Checks for events manually and returns time in nanoseconds for next event, threadsafe.
135 std::optional<s64> Advance(); 134 std::optional<s64> Advance();
136 135
137 /// Register a callback function to be called when coretiming pauses.
138 void RegisterPauseCallback(PauseCallback&& callback);
139
140private: 136private:
141 struct Event; 137 struct Event;
142 138
@@ -176,8 +172,6 @@ private:
176 /// Cycle timing 172 /// Cycle timing
177 u64 ticks{}; 173 u64 ticks{};
178 s64 downcount{}; 174 s64 downcount{};
179
180 std::vector<PauseCallback> pause_callbacks{};
181}; 175};
182 176
183/// Creates a core timing event with the given name and callback. 177/// Creates a core timing event with the given name and callback.
diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp
index ac64d2f9d..e42bdd17d 100644
--- a/src/core/debugger/debugger.cpp
+++ b/src/core/debugger/debugger.cpp
@@ -15,6 +15,7 @@
15#include "core/debugger/debugger_interface.h" 15#include "core/debugger/debugger_interface.h"
16#include "core/debugger/gdbstub.h" 16#include "core/debugger/gdbstub.h"
17#include "core/hle/kernel/global_scheduler_context.h" 17#include "core/hle/kernel/global_scheduler_context.h"
18#include "core/hle/kernel/k_scheduler.h"
18 19
19template <typename Readable, typename Buffer, typename Callback> 20template <typename Readable, typename Buffer, typename Callback>
20static void AsyncReceiveInto(Readable& r, Buffer& buffer, Callback&& c) { 21static void AsyncReceiveInto(Readable& r, Buffer& buffer, Callback&& c) {
@@ -230,13 +231,12 @@ private:
230 } 231 }
231 232
232 void PauseEmulation() { 233 void PauseEmulation() {
234 Kernel::KScopedSchedulerLock sl{system.Kernel()};
235
233 // Put all threads to sleep on next scheduler round. 236 // Put all threads to sleep on next scheduler round.
234 for (auto* thread : ThreadList()) { 237 for (auto* thread : ThreadList()) {
235 thread->RequestSuspend(Kernel::SuspendType::Debug); 238 thread->RequestSuspend(Kernel::SuspendType::Debug);
236 } 239 }
237
238 // Signal an interrupt so that scheduler will fire.
239 system.Kernel().InterruptAllPhysicalCores();
240 } 240 }
241 241
242 void ResumeEmulation(Kernel::KThread* except = nullptr) { 242 void ResumeEmulation(Kernel::KThread* except = nullptr) {
@@ -253,7 +253,8 @@ private:
253 253
254 template <typename Callback> 254 template <typename Callback>
255 void MarkResumed(Callback&& cb) { 255 void MarkResumed(Callback&& cb) {
256 std::scoped_lock lk{connection_lock}; 256 Kernel::KScopedSchedulerLock sl{system.Kernel()};
257 std::scoped_lock cl{connection_lock};
257 stopped = false; 258 stopped = false;
258 cb(); 259 cb();
259 } 260 }
diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp
index 4b35ca82f..5aab428bb 100644
--- a/src/core/file_sys/ips_layer.cpp
+++ b/src/core/file_sys/ips_layer.cpp
@@ -217,9 +217,7 @@ void IPSwitchCompiler::Parse() {
217 break; 217 break;
218 } else if (StartsWith(line, "@nsobid-")) { 218 } else if (StartsWith(line, "@nsobid-")) {
219 // NSO Build ID Specifier 219 // NSO Build ID Specifier
220 auto raw_build_id = line.substr(8); 220 const auto raw_build_id = fmt::format("{:0<64}", line.substr(8));
221 if (raw_build_id.size() != 0x40)
222 raw_build_id.resize(0x40, '0');
223 nso_build_id = Common::HexStringToArray<0x20>(raw_build_id); 221 nso_build_id = Common::HexStringToArray<0x20>(raw_build_id);
224 } else if (StartsWith(line, "#")) { 222 } else if (StartsWith(line, "#")) {
225 // Mandatory Comment 223 // Mandatory Comment
@@ -287,7 +285,8 @@ void IPSwitchCompiler::Parse() {
287 std::copy(value.begin(), value.end(), std::back_inserter(replace)); 285 std::copy(value.begin(), value.end(), std::back_inserter(replace));
288 } else { 286 } else {
289 // hex replacement 287 // hex replacement
290 const auto value = patch_line.substr(9); 288 const auto value =
289 patch_line.substr(9, patch_line.find_first_of(" /\r\n", 9) - 9);
291 replace = Common::HexStringToVector(value, is_little_endian); 290 replace = Common::HexStringToVector(value, is_little_endian);
292 } 291 }
293 292
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index bd525b26c..4c80e13a9 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -191,6 +191,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
191std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualDir>& patch_dirs, 191std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualDir>& patch_dirs,
192 const std::string& build_id) const { 192 const std::string& build_id) const {
193 const auto& disabled = Settings::values.disabled_addons[title_id]; 193 const auto& disabled = Settings::values.disabled_addons[title_id];
194 const auto nso_build_id = fmt::format("{:0<64}", build_id);
194 195
195 std::vector<VirtualFile> out; 196 std::vector<VirtualFile> out;
196 out.reserve(patch_dirs.size()); 197 out.reserve(patch_dirs.size());
@@ -203,21 +204,18 @@ std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualD
203 for (const auto& file : exefs_dir->GetFiles()) { 204 for (const auto& file : exefs_dir->GetFiles()) {
204 if (file->GetExtension() == "ips") { 205 if (file->GetExtension() == "ips") {
205 auto name = file->GetName(); 206 auto name = file->GetName();
206 const auto p1 = name.substr(0, name.find('.'));
207 const auto this_build_id = p1.substr(0, p1.find_last_not_of('0') + 1);
208 207
209 if (build_id == this_build_id) 208 const auto this_build_id =
209 fmt::format("{:0<64}", name.substr(0, name.find('.')));
210 if (nso_build_id == this_build_id)
210 out.push_back(file); 211 out.push_back(file);
211 } else if (file->GetExtension() == "pchtxt") { 212 } else if (file->GetExtension() == "pchtxt") {
212 IPSwitchCompiler compiler{file}; 213 IPSwitchCompiler compiler{file};
213 if (!compiler.IsValid()) 214 if (!compiler.IsValid())
214 continue; 215 continue;
215 216
216 auto this_build_id = Common::HexToString(compiler.GetBuildID()); 217 const auto this_build_id = Common::HexToString(compiler.GetBuildID());
217 this_build_id = 218 if (nso_build_id == this_build_id)
218 this_build_id.substr(0, this_build_id.find_last_not_of('0') + 1);
219
220 if (build_id == this_build_id)
221 out.push_back(file); 219 out.push_back(file);
222 } 220 }
223 } 221 }
diff --git a/src/core/file_sys/system_archive/shared_font.cpp b/src/core/file_sys/system_archive/shared_font.cpp
index f841988ff..3210583f0 100644
--- a/src/core/file_sys/system_archive/shared_font.cpp
+++ b/src/core/file_sys/system_archive/shared_font.cpp
@@ -9,7 +9,7 @@
9#include "core/file_sys/system_archive/data/font_standard.h" 9#include "core/file_sys/system_archive/data/font_standard.h"
10#include "core/file_sys/system_archive/shared_font.h" 10#include "core/file_sys/system_archive/shared_font.h"
11#include "core/file_sys/vfs_vector.h" 11#include "core/file_sys/vfs_vector.h"
12#include "core/hle/service/ns/pl_u.h" 12#include "core/hle/service/ns/iplatform_service_manager.h"
13 13
14namespace FileSys::SystemArchive { 14namespace FileSys::SystemArchive {
15 15
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index 8c3895937..01c43be93 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "common/thread.h"
4#include "core/hid/emulated_controller.h" 5#include "core/hid/emulated_controller.h"
5#include "core/hid/input_converter.h" 6#include "core/hid/input_converter.h"
6 7
@@ -84,23 +85,26 @@ void EmulatedController::ReloadFromSettings() {
84 motion_params[index] = Common::ParamPackage(player.motions[index]); 85 motion_params[index] = Common::ParamPackage(player.motions[index]);
85 } 86 }
86 87
88 controller.colors_state.fullkey = {
89 .body = GetNpadColor(player.body_color_left),
90 .button = GetNpadColor(player.button_color_left),
91 };
87 controller.colors_state.left = { 92 controller.colors_state.left = {
88 .body = player.body_color_left, 93 .body = GetNpadColor(player.body_color_left),
89 .button = player.button_color_left, 94 .button = GetNpadColor(player.button_color_left),
90 }; 95 };
91 96 controller.colors_state.left = {
92 controller.colors_state.right = { 97 .body = GetNpadColor(player.body_color_right),
93 .body = player.body_color_right, 98 .button = GetNpadColor(player.button_color_right),
94 .button = player.button_color_right,
95 }; 99 };
96 100
97 controller.colors_state.fullkey = controller.colors_state.left;
98
99 // Other or debug controller should always be a pro controller 101 // Other or debug controller should always be a pro controller
100 if (npad_id_type != NpadIdType::Other) { 102 if (npad_id_type != NpadIdType::Other) {
101 SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type)); 103 SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type));
104 original_npad_type = npad_type;
102 } else { 105 } else {
103 SetNpadStyleIndex(NpadStyleIndex::ProController); 106 SetNpadStyleIndex(NpadStyleIndex::ProController);
107 original_npad_type = npad_type;
104 } 108 }
105 109
106 if (player.connected) { 110 if (player.connected) {
@@ -352,6 +356,7 @@ void EmulatedController::DisableConfiguration() {
352 Disconnect(); 356 Disconnect();
353 } 357 }
354 SetNpadStyleIndex(tmp_npad_type); 358 SetNpadStyleIndex(tmp_npad_type);
359 original_npad_type = tmp_npad_type;
355 } 360 }
356 361
357 // Apply temporary connected status to the real controller 362 // Apply temporary connected status to the real controller
@@ -557,6 +562,16 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
557 return; 562 return;
558 } 563 }
559 564
565 // GC controllers have triggers not buttons
566 if (npad_type == NpadStyleIndex::GameCube) {
567 if (index == Settings::NativeButton::ZR) {
568 return;
569 }
570 if (index == Settings::NativeButton::ZL) {
571 return;
572 }
573 }
574
560 switch (index) { 575 switch (index) {
561 case Settings::NativeButton::A: 576 case Settings::NativeButton::A:
562 controller.npad_button_state.a.Assign(current_status.value); 577 controller.npad_button_state.a.Assign(current_status.value);
@@ -733,6 +748,11 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
733 return; 748 return;
734 } 749 }
735 750
751 // Only GC controllers have analog triggers
752 if (npad_type != NpadStyleIndex::GameCube) {
753 return;
754 }
755
736 const auto& trigger = controller.trigger_values[index]; 756 const auto& trigger = controller.trigger_values[index];
737 757
738 switch (index) { 758 switch (index) {
@@ -949,6 +969,9 @@ bool EmulatedController::TestVibration(std::size_t device_index) {
949 // Send a slight vibration to test for rumble support 969 // Send a slight vibration to test for rumble support
950 output_devices[device_index]->SetVibration(test_vibration); 970 output_devices[device_index]->SetVibration(test_vibration);
951 971
972 // Wait for about 15ms to ensure the controller is ready for the stop command
973 std::this_thread::sleep_for(std::chrono::milliseconds(15));
974
952 // Stop any vibration and return the result 975 // Stop any vibration and return the result
953 return output_devices[device_index]->SetVibration(zero_vibration) == 976 return output_devices[device_index]->SetVibration(zero_vibration) ==
954 Common::Input::VibrationError::None; 977 Common::Input::VibrationError::None;
@@ -999,13 +1022,27 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles)
999 if (!is_connected) { 1022 if (!is_connected) {
1000 return; 1023 return;
1001 } 1024 }
1025
1026 // Attempt to reconnect with the original type
1027 if (npad_type != original_npad_type) {
1028 Disconnect();
1029 const auto current_npad_type = npad_type;
1030 SetNpadStyleIndex(original_npad_type);
1031 if (IsControllerSupported()) {
1032 Connect();
1033 return;
1034 }
1035 SetNpadStyleIndex(current_npad_type);
1036 Connect();
1037 }
1038
1002 if (IsControllerSupported()) { 1039 if (IsControllerSupported()) {
1003 return; 1040 return;
1004 } 1041 }
1005 1042
1006 Disconnect(); 1043 Disconnect();
1007 1044
1008 // Fallback fullkey controllers to Pro controllers 1045 // Fallback Fullkey controllers to Pro controllers
1009 if (IsControllerFullkey() && supported_style_tag.fullkey) { 1046 if (IsControllerFullkey() && supported_style_tag.fullkey) {
1010 LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type); 1047 LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type);
1011 SetNpadStyleIndex(NpadStyleIndex::ProController); 1048 SetNpadStyleIndex(NpadStyleIndex::ProController);
@@ -1013,6 +1050,22 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles)
1013 return; 1050 return;
1014 } 1051 }
1015 1052
1053 // Fallback Dual joycon controllers to Pro controllers
1054 if (npad_type == NpadStyleIndex::JoyconDual && supported_style_tag.fullkey) {
1055 LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type);
1056 SetNpadStyleIndex(NpadStyleIndex::ProController);
1057 Connect();
1058 return;
1059 }
1060
1061 // Fallback Pro controllers to Dual joycon
1062 if (npad_type == NpadStyleIndex::ProController && supported_style_tag.joycon_dual) {
1063 LOG_WARNING(Service_HID, "Reconnecting controller type {} as Dual Joycons", npad_type);
1064 SetNpadStyleIndex(NpadStyleIndex::JoyconDual);
1065 Connect();
1066 return;
1067 }
1068
1016 LOG_ERROR(Service_HID, "Controller type {} is not supported. Disconnecting controller", 1069 LOG_ERROR(Service_HID, "Controller type {} is not supported. Disconnecting controller",
1017 npad_type); 1070 npad_type);
1018} 1071}
@@ -1310,6 +1363,15 @@ const CameraState& EmulatedController::GetCamera() const {
1310 return controller.camera_state; 1363 return controller.camera_state;
1311} 1364}
1312 1365
1366NpadColor EmulatedController::GetNpadColor(u32 color) {
1367 return {
1368 .r = static_cast<u8>((color >> 16) & 0xFF),
1369 .g = static_cast<u8>((color >> 8) & 0xFF),
1370 .b = static_cast<u8>(color & 0xFF),
1371 .a = 0xff,
1372 };
1373}
1374
1313void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) { 1375void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) {
1314 std::scoped_lock lock{callback_mutex}; 1376 std::scoped_lock lock{callback_mutex};
1315 for (const auto& poller_pair : callback_list) { 1377 for (const auto& poller_pair : callback_list) {
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index 823c1700c..c3aa8f9d3 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -425,6 +425,13 @@ private:
425 void SetCamera(const Common::Input::CallbackStatus& callback); 425 void SetCamera(const Common::Input::CallbackStatus& callback);
426 426
427 /** 427 /**
428 * Converts a color format from bgra to rgba
429 * @param color in bgra format
430 * @return NpadColor in rgba format
431 */
432 NpadColor GetNpadColor(u32 color);
433
434 /**
428 * Triggers a callback that something has changed on the controller status 435 * Triggers a callback that something has changed on the controller status
429 * @param type Input type of the event to trigger 436 * @param type Input type of the event to trigger
430 * @param is_service_update indicates if this event should only be sent to HID services 437 * @param is_service_update indicates if this event should only be sent to HID services
@@ -433,6 +440,7 @@ private:
433 440
434 const NpadIdType npad_id_type; 441 const NpadIdType npad_id_type;
435 NpadStyleIndex npad_type{NpadStyleIndex::None}; 442 NpadStyleIndex npad_type{NpadStyleIndex::None};
443 NpadStyleIndex original_npad_type{NpadStyleIndex::None};
436 NpadStyleTag supported_style_tag{NpadStyleSet::All}; 444 NpadStyleTag supported_style_tag{NpadStyleSet::All};
437 bool is_connected{false}; 445 bool is_connected{false};
438 bool is_configuring{false}; 446 bool is_configuring{false};
diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h
index e49223016..e3b1cfbc6 100644
--- a/src/core/hid/hid_types.h
+++ b/src/core/hid/hid_types.h
@@ -327,10 +327,18 @@ struct TouchState {
327}; 327};
328static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size"); 328static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
329 329
330struct NpadColor {
331 u8 r{};
332 u8 g{};
333 u8 b{};
334 u8 a{};
335};
336static_assert(sizeof(NpadColor) == 4, "NpadColor is an invalid size");
337
330// This is nn::hid::NpadControllerColor 338// This is nn::hid::NpadControllerColor
331struct NpadControllerColor { 339struct NpadControllerColor {
332 u32 body{}; 340 NpadColor body{};
333 u32 button{}; 341 NpadColor button{};
334}; 342};
335static_assert(sizeof(NpadControllerColor) == 8, "NpadControllerColor is an invalid size"); 343static_assert(sizeof(NpadControllerColor) == 8, "NpadControllerColor is an invalid size");
336 344
diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp
index 68d143a01..52fb69e9c 100644
--- a/src/core/hid/input_converter.cpp
+++ b/src/core/hid/input_converter.cpp
@@ -52,6 +52,9 @@ Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatu
52 Common::Input::ButtonStatus status{}; 52 Common::Input::ButtonStatus status{};
53 switch (callback.type) { 53 switch (callback.type) {
54 case Common::Input::InputType::Analog: 54 case Common::Input::InputType::Analog:
55 status.value = TransformToTrigger(callback).pressed.value;
56 status.toggle = callback.analog_status.properties.toggle;
57 break;
55 case Common::Input::InputType::Trigger: 58 case Common::Input::InputType::Trigger:
56 status.value = TransformToTrigger(callback).pressed.value; 59 status.value = TransformToTrigger(callback).pressed.value;
57 break; 60 break;
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index f4072e1c3..ce7fa8275 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -17,7 +17,6 @@
17#include "common/thread.h" 17#include "common/thread.h"
18#include "common/thread_worker.h" 18#include "common/thread_worker.h"
19#include "core/arm/arm_interface.h" 19#include "core/arm/arm_interface.h"
20#include "core/arm/cpu_interrupt_handler.h"
21#include "core/arm/exclusive_monitor.h" 20#include "core/arm/exclusive_monitor.h"
22#include "core/core.h" 21#include "core/core.h"
23#include "core/core_timing.h" 22#include "core/core_timing.h"
@@ -82,7 +81,7 @@ struct KernelCore::Impl {
82 81
83 void InitializeCores() { 82 void InitializeCores() {
84 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { 83 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
85 cores[core_id].Initialize((*current_process).Is64BitProcess()); 84 cores[core_id]->Initialize((*current_process).Is64BitProcess());
86 system.Memory().SetCurrentPageTable(*current_process, core_id); 85 system.Memory().SetCurrentPageTable(*current_process, core_id);
87 } 86 }
88 } 87 }
@@ -100,7 +99,9 @@ struct KernelCore::Impl {
100 next_user_process_id = KProcess::ProcessIDMin; 99 next_user_process_id = KProcess::ProcessIDMin;
101 next_thread_id = 1; 100 next_thread_id = 1;
102 101
103 cores.clear(); 102 for (auto& core : cores) {
103 core = nullptr;
104 }
104 105
105 global_handle_table->Finalize(); 106 global_handle_table->Finalize();
106 global_handle_table.reset(); 107 global_handle_table.reset();
@@ -199,7 +200,7 @@ struct KernelCore::Impl {
199 const s32 core{static_cast<s32>(i)}; 200 const s32 core{static_cast<s32>(i)};
200 201
201 schedulers[i] = std::make_unique<Kernel::KScheduler>(system.Kernel()); 202 schedulers[i] = std::make_unique<Kernel::KScheduler>(system.Kernel());
202 cores.emplace_back(i, system, *schedulers[i], interrupts); 203 cores[i] = std::make_unique<Kernel::PhysicalCore>(i, system, *schedulers[i]);
203 204
204 auto* main_thread{Kernel::KThread::Create(system.Kernel())}; 205 auto* main_thread{Kernel::KThread::Create(system.Kernel())};
205 main_thread->SetName(fmt::format("MainThread:{}", core)); 206 main_thread->SetName(fmt::format("MainThread:{}", core));
@@ -761,7 +762,7 @@ struct KernelCore::Impl {
761 std::unordered_set<KAutoObject*> registered_in_use_objects; 762 std::unordered_set<KAutoObject*> registered_in_use_objects;
762 763
763 std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; 764 std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
764 std::vector<Kernel::PhysicalCore> cores; 765 std::array<std::unique_ptr<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores;
765 766
766 // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others 767 // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
767 std::atomic<u32> next_host_thread_id{Core::Hardware::NUM_CPU_CORES}; 768 std::atomic<u32> next_host_thread_id{Core::Hardware::NUM_CPU_CORES};
@@ -785,7 +786,6 @@ struct KernelCore::Impl {
785 Common::ThreadWorker service_threads_manager; 786 Common::ThreadWorker service_threads_manager;
786 787
787 std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads; 788 std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads;
788 std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
789 std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; 789 std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
790 790
791 bool is_multicore{}; 791 bool is_multicore{};
@@ -874,11 +874,11 @@ const Kernel::KScheduler& KernelCore::Scheduler(std::size_t id) const {
874} 874}
875 875
876Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) { 876Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) {
877 return impl->cores[id]; 877 return *impl->cores[id];
878} 878}
879 879
880const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const { 880const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const {
881 return impl->cores[id]; 881 return *impl->cores[id];
882} 882}
883 883
884size_t KernelCore::CurrentPhysicalCoreIndex() const { 884size_t KernelCore::CurrentPhysicalCoreIndex() const {
@@ -890,11 +890,11 @@ size_t KernelCore::CurrentPhysicalCoreIndex() const {
890} 890}
891 891
892Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() { 892Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() {
893 return impl->cores[CurrentPhysicalCoreIndex()]; 893 return *impl->cores[CurrentPhysicalCoreIndex()];
894} 894}
895 895
896const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const { 896const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const {
897 return impl->cores[CurrentPhysicalCoreIndex()]; 897 return *impl->cores[CurrentPhysicalCoreIndex()];
898} 898}
899 899
900Kernel::KScheduler* KernelCore::CurrentScheduler() { 900Kernel::KScheduler* KernelCore::CurrentScheduler() {
@@ -906,15 +906,6 @@ Kernel::KScheduler* KernelCore::CurrentScheduler() {
906 return impl->schedulers[core_id].get(); 906 return impl->schedulers[core_id].get();
907} 907}
908 908
909std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& KernelCore::Interrupts() {
910 return impl->interrupts;
911}
912
913const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& KernelCore::Interrupts()
914 const {
915 return impl->interrupts;
916}
917
918Kernel::TimeManager& KernelCore::TimeManager() { 909Kernel::TimeManager& KernelCore::TimeManager() {
919 return impl->time_manager; 910 return impl->time_manager;
920} 911}
@@ -939,24 +930,18 @@ const KAutoObjectWithListContainer& KernelCore::ObjectListContainer() const {
939 return *impl->global_object_list_container; 930 return *impl->global_object_list_container;
940} 931}
941 932
942void KernelCore::InterruptAllPhysicalCores() {
943 for (auto& physical_core : impl->cores) {
944 physical_core.Interrupt();
945 }
946}
947
948void KernelCore::InvalidateAllInstructionCaches() { 933void KernelCore::InvalidateAllInstructionCaches() {
949 for (auto& physical_core : impl->cores) { 934 for (auto& physical_core : impl->cores) {
950 physical_core.ArmInterface().ClearInstructionCache(); 935 physical_core->ArmInterface().ClearInstructionCache();
951 } 936 }
952} 937}
953 938
954void KernelCore::InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size) { 939void KernelCore::InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size) {
955 for (auto& physical_core : impl->cores) { 940 for (auto& physical_core : impl->cores) {
956 if (!physical_core.IsInitialized()) { 941 if (!physical_core->IsInitialized()) {
957 continue; 942 continue;
958 } 943 }
959 physical_core.ArmInterface().InvalidateCacheRange(addr, size); 944 physical_core->ArmInterface().InvalidateCacheRange(addr, size);
960 } 945 }
961} 946}
962 947
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 6c7cf6af2..bcf016a97 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -9,14 +9,12 @@
9#include <string> 9#include <string>
10#include <unordered_map> 10#include <unordered_map>
11#include <vector> 11#include <vector>
12#include "core/arm/cpu_interrupt_handler.h"
13#include "core/hardware_properties.h" 12#include "core/hardware_properties.h"
14#include "core/hle/kernel/k_auto_object.h" 13#include "core/hle/kernel/k_auto_object.h"
15#include "core/hle/kernel/k_slab_heap.h" 14#include "core/hle/kernel/k_slab_heap.h"
16#include "core/hle/kernel/svc_common.h" 15#include "core/hle/kernel/svc_common.h"
17 16
18namespace Core { 17namespace Core {
19class CPUInterruptHandler;
20class ExclusiveMonitor; 18class ExclusiveMonitor;
21class System; 19class System;
22} // namespace Core 20} // namespace Core
@@ -183,12 +181,6 @@ public:
183 181
184 const KAutoObjectWithListContainer& ObjectListContainer() const; 182 const KAutoObjectWithListContainer& ObjectListContainer() const;
185 183
186 std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts();
187
188 const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts() const;
189
190 void InterruptAllPhysicalCores();
191
192 void InvalidateAllInstructionCaches(); 184 void InvalidateAllInstructionCaches();
193 185
194 void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size); 186 void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size);
diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp
index 6e7dacf97..d4375962f 100644
--- a/src/core/hle/kernel/physical_core.cpp
+++ b/src/core/hle/kernel/physical_core.cpp
@@ -1,7 +1,6 @@
1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "core/arm/cpu_interrupt_handler.h"
5#include "core/arm/dynarmic/arm_dynarmic_32.h" 4#include "core/arm/dynarmic/arm_dynarmic_32.h"
6#include "core/arm/dynarmic/arm_dynarmic_64.h" 5#include "core/arm/dynarmic/arm_dynarmic_64.h"
7#include "core/core.h" 6#include "core/core.h"
@@ -11,16 +10,14 @@
11 10
12namespace Kernel { 11namespace Kernel {
13 12
14PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_, 13PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_)
15 Core::CPUInterrupts& interrupts_) 14 : core_index{core_index_}, system{system_}, scheduler{scheduler_} {
16 : core_index{core_index_}, system{system_}, scheduler{scheduler_},
17 interrupts{interrupts_}, guard{std::make_unique<std::mutex>()} {
18#ifdef ARCHITECTURE_x86_64 15#ifdef ARCHITECTURE_x86_64
19 // TODO(bunnei): Initialization relies on a core being available. We may later replace this with 16 // TODO(bunnei): Initialization relies on a core being available. We may later replace this with
20 // a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager. 17 // a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager.
21 auto& kernel = system.Kernel(); 18 auto& kernel = system.Kernel();
22 arm_interface = std::make_unique<Core::ARM_Dynarmic_64>( 19 arm_interface = std::make_unique<Core::ARM_Dynarmic_64>(
23 system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); 20 system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
24#else 21#else
25#error Platform not supported yet. 22#error Platform not supported yet.
26#endif 23#endif
@@ -34,7 +31,7 @@ void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) {
34 if (!is_64_bit) { 31 if (!is_64_bit) {
35 // We already initialized a 64-bit core, replace with a 32-bit one. 32 // We already initialized a 64-bit core, replace with a 32-bit one.
36 arm_interface = std::make_unique<Core::ARM_Dynarmic_32>( 33 arm_interface = std::make_unique<Core::ARM_Dynarmic_32>(
37 system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); 34 system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
38 } 35 }
39#else 36#else
40#error Platform not supported yet. 37#error Platform not supported yet.
@@ -47,24 +44,26 @@ void PhysicalCore::Run() {
47} 44}
48 45
49void PhysicalCore::Idle() { 46void PhysicalCore::Idle() {
50 interrupts[core_index].AwaitInterrupt(); 47 std::unique_lock lk{guard};
48 on_interrupt.wait(lk, [this] { return is_interrupted; });
51} 49}
52 50
53bool PhysicalCore::IsInterrupted() const { 51bool PhysicalCore::IsInterrupted() const {
54 return interrupts[core_index].IsInterrupted(); 52 return is_interrupted;
55} 53}
56 54
57void PhysicalCore::Interrupt() { 55void PhysicalCore::Interrupt() {
58 guard->lock(); 56 std::unique_lock lk{guard};
59 interrupts[core_index].SetInterrupt(true); 57 is_interrupted = true;
60 arm_interface->SignalInterrupt(); 58 arm_interface->SignalInterrupt();
61 guard->unlock(); 59 on_interrupt.notify_all();
62} 60}
63 61
64void PhysicalCore::ClearInterrupt() { 62void PhysicalCore::ClearInterrupt() {
65 guard->lock(); 63 std::unique_lock lk{guard};
66 interrupts[core_index].SetInterrupt(false); 64 is_interrupted = false;
67 guard->unlock(); 65 arm_interface->ClearInterrupt();
66 on_interrupt.notify_all();
68} 67}
69 68
70} // namespace Kernel 69} // namespace Kernel
diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h
index 898d1e5db..2fc8d4be2 100644
--- a/src/core/hle/kernel/physical_core.h
+++ b/src/core/hle/kernel/physical_core.h
@@ -14,7 +14,6 @@ class KScheduler;
14} // namespace Kernel 14} // namespace Kernel
15 15
16namespace Core { 16namespace Core {
17class CPUInterruptHandler;
18class ExclusiveMonitor; 17class ExclusiveMonitor;
19class System; 18class System;
20} // namespace Core 19} // namespace Core
@@ -23,15 +22,11 @@ namespace Kernel {
23 22
24class PhysicalCore { 23class PhysicalCore {
25public: 24public:
26 PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_, 25 PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_);
27 Core::CPUInterrupts& interrupts_);
28 ~PhysicalCore(); 26 ~PhysicalCore();
29 27
30 PhysicalCore(const PhysicalCore&) = delete; 28 YUZU_NON_COPYABLE(PhysicalCore);
31 PhysicalCore& operator=(const PhysicalCore&) = delete; 29 YUZU_NON_MOVEABLE(PhysicalCore);
32
33 PhysicalCore(PhysicalCore&&) = default;
34 PhysicalCore& operator=(PhysicalCore&&) = delete;
35 30
36 /// Initialize the core for the specified parameters. 31 /// Initialize the core for the specified parameters.
37 void Initialize(bool is_64_bit); 32 void Initialize(bool is_64_bit);
@@ -86,9 +81,11 @@ private:
86 const std::size_t core_index; 81 const std::size_t core_index;
87 Core::System& system; 82 Core::System& system;
88 Kernel::KScheduler& scheduler; 83 Kernel::KScheduler& scheduler;
89 Core::CPUInterrupts& interrupts; 84
90 std::unique_ptr<std::mutex> guard; 85 std::mutex guard;
86 std::condition_variable on_interrupt;
91 std::unique_ptr<Core::ARM_Interface> arm_interface; 87 std::unique_ptr<Core::ARM_Interface> arm_interface;
88 bool is_interrupted;
92}; 89};
93 90
94} // namespace Kernel 91} // namespace Kernel
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 4de44cd06..47a1b829b 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -117,6 +117,7 @@ union Result {
117 BitField<0, 9, ErrorModule> module; 117 BitField<0, 9, ErrorModule> module;
118 BitField<9, 13, u32> description; 118 BitField<9, 13, u32> description;
119 119
120 Result() = default;
120 constexpr explicit Result(u32 raw_) : raw(raw_) {} 121 constexpr explicit Result(u32 raw_) : raw(raw_) {}
121 122
122 constexpr Result(ErrorModule module_, u32 description_) 123 constexpr Result(ErrorModule module_, u32 description_)
@@ -130,6 +131,7 @@ union Result {
130 return !IsSuccess(); 131 return !IsSuccess();
131 } 132 }
132}; 133};
134static_assert(std::is_trivial_v<Result>);
133 135
134[[nodiscard]] constexpr bool operator==(const Result& a, const Result& b) { 136[[nodiscard]] constexpr bool operator==(const Result& a, const Result& b) {
135 return a.raw == b.raw; 137 return a.raw == b.raw;
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index def105832..bb838e285 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -534,7 +534,7 @@ public:
534 534
535private: 535private:
536 void CheckAvailability(Kernel::HLERequestContext& ctx) { 536 void CheckAvailability(Kernel::HLERequestContext& ctx) {
537 LOG_WARNING(Service_ACC, "(STUBBED) called"); 537 LOG_DEBUG(Service_ACC, "(STUBBED) called");
538 IPC::ResponseBuilder rb{ctx, 3}; 538 IPC::ResponseBuilder rb{ctx, 3};
539 rb.Push(ResultSuccess); 539 rb.Push(ResultSuccess);
540 rb.Push(false); // TODO: Check when this is supposed to return true and when not 540 rb.Push(false); // TODO: Check when this is supposed to return true and when not
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 118f226e4..6fb7e198e 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -754,7 +754,7 @@ void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
754} 754}
755 755
756void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { 756void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
757 LOG_WARNING(Service_AM, "(STUBBED) called"); 757 LOG_DEBUG(Service_AM, "(STUBBED) called");
758 758
759 IPC::ResponseBuilder rb{ctx, 3}; 759 IPC::ResponseBuilder rb{ctx, 3};
760 rb.Push(ResultSuccess); 760 rb.Push(ResultSuccess);
diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/applets/applet_web_browser.cpp
index 4b804b78c..14aa6f69e 100644
--- a/src/core/hle/service/am/applets/applet_web_browser.cpp
+++ b/src/core/hle/service/am/applets/applet_web_browser.cpp
@@ -21,7 +21,7 @@
21#include "core/hle/service/am/am.h" 21#include "core/hle/service/am/am.h"
22#include "core/hle/service/am/applets/applet_web_browser.h" 22#include "core/hle/service/am/applets/applet_web_browser.h"
23#include "core/hle/service/filesystem/filesystem.h" 23#include "core/hle/service/filesystem/filesystem.h"
24#include "core/hle/service/ns/pl_u.h" 24#include "core/hle/service/ns/iplatform_service_manager.h"
25#include "core/loader/loader.h" 25#include "core/loader/loader.h"
26 26
27namespace Service::AM::Applets { 27namespace Service::AM::Applets {
diff --git a/src/core/hle/service/apm/apm_controller.cpp b/src/core/hle/service/apm/apm_controller.cpp
index 4e710491b..d6de84066 100644
--- a/src/core/hle/service/apm/apm_controller.cpp
+++ b/src/core/hle/service/apm/apm_controller.cpp
@@ -80,7 +80,7 @@ PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(Performa
80} 80}
81 81
82void Controller::SetClockSpeed(u32 mhz) { 82void Controller::SetClockSpeed(u32 mhz) {
83 LOG_INFO(Service_APM, "called, mhz={:08X}", mhz); 83 LOG_DEBUG(Service_APM, "called, mhz={:08X}", mhz);
84 // TODO(DarkLordZach): Actually signal core_timing to change clock speed. 84 // TODO(DarkLordZach): Actually signal core_timing to change clock speed.
85 // TODO(Rodrigo): Remove [[maybe_unused]] when core_timing is used. 85 // TODO(Rodrigo): Remove [[maybe_unused]] when core_timing is used.
86} 86}
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index a44dd842a..49c092301 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -246,9 +246,8 @@ void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) {
246 const auto write_count = 246 const auto write_count =
247 static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(AudioDevice::AudioDeviceName)); 247 static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(AudioDevice::AudioDeviceName));
248 std::vector<AudioDevice::AudioDeviceName> device_names{}; 248 std::vector<AudioDevice::AudioDeviceName> device_names{};
249 std::string print_names{};
250 if (write_count > 0) { 249 if (write_count > 0) {
251 device_names.push_back(AudioDevice::AudioDeviceName("DeviceOut")); 250 device_names.emplace_back("DeviceOut");
252 LOG_DEBUG(Service_Audio, "called. \nName=DeviceOut"); 251 LOG_DEBUG(Service_Audio, "called. \nName=DeviceOut");
253 } else { 252 } else {
254 LOG_DEBUG(Service_Audio, "called. Empty buffer passed in."); 253 LOG_DEBUG(Service_Audio, "called. Empty buffer passed in.");
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 381a66ba5..6fb07c37d 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -50,7 +50,7 @@ public:
50 {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"}, 50 {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
51 {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"}, 51 {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"},
52 {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"}, 52 {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"},
53 {10, nullptr, "RequestUpdateAuto"}, 53 {10, &IAudioRenderer::RequestUpdate, "RequestUpdateAuto"},
54 {11, nullptr, "ExecuteAudioRendererRendering"}, 54 {11, nullptr, "ExecuteAudioRendererRendering"},
55 }; 55 };
56 // clang-format on 56 // clang-format on
@@ -113,15 +113,30 @@ private:
113 113
114 // These buffers are written manually to avoid an issue with WriteBuffer throwing errors for 114 // These buffers are written manually to avoid an issue with WriteBuffer throwing errors for
115 // checking size 0. Performance size is 0 for most games. 115 // checking size 0. Performance size is 0 for most games.
116 const auto buffers{ctx.BufferDescriptorB()}; 116
117 std::vector<u8> output(buffers[0].Size(), 0); 117 std::vector<u8> output{};
118 std::vector<u8> performance(buffers[1].Size(), 0); 118 std::vector<u8> performance{};
119 auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0};
120 if (is_buffer_b) {
121 const auto buffersB{ctx.BufferDescriptorB()};
122 output.resize(buffersB[0].Size(), 0);
123 performance.resize(buffersB[1].Size(), 0);
124 } else {
125 const auto buffersC{ctx.BufferDescriptorC()};
126 output.resize(buffersC[0].Size(), 0);
127 performance.resize(buffersC[1].Size(), 0);
128 }
119 129
120 auto result = impl->RequestUpdate(input, performance, output); 130 auto result = impl->RequestUpdate(input, performance, output);
121 131
122 if (result.IsSuccess()) { 132 if (result.IsSuccess()) {
123 ctx.WriteBufferB(output.data(), output.size(), 0); 133 if (is_buffer_b) {
124 ctx.WriteBufferB(performance.data(), performance.size(), 1); 134 ctx.WriteBufferB(output.data(), output.size(), 0);
135 ctx.WriteBufferB(performance.data(), performance.size(), 1);
136 } else {
137 ctx.WriteBufferC(output.data(), output.size(), 0);
138 ctx.WriteBufferC(performance.data(), performance.size(), 1);
139 }
125 } else { 140 } else {
126 LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.description); 141 LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.description);
127 } 142 }
@@ -237,7 +252,7 @@ private:
237 252
238 std::vector<AudioDevice::AudioDeviceName> out_names{}; 253 std::vector<AudioDevice::AudioDeviceName> out_names{};
239 254
240 u32 out_count = impl->ListAudioDeviceName(out_names, in_count); 255 const u32 out_count = impl->ListAudioDeviceName(out_names, in_count);
241 256
242 std::string out{}; 257 std::string out{};
243 for (u32 i = 0; i < out_count; i++) { 258 for (u32 i = 0; i < out_count; i++) {
@@ -350,7 +365,7 @@ private:
350 365
351 std::vector<AudioDevice::AudioDeviceName> out_names{}; 366 std::vector<AudioDevice::AudioDeviceName> out_names{};
352 367
353 u32 out_count = impl->ListAudioOutputDeviceName(out_names, in_count); 368 const u32 out_count = impl->ListAudioOutputDeviceName(out_names, in_count);
354 369
355 std::string out{}; 370 std::string out{};
356 for (u32 i = 0; i < out_count; i++) { 371 for (u32 i = 0; i < out_count; i++) {
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index fae6e5aff..e23eae36a 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -246,7 +246,8 @@ static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vec
246 entries.reserve(entries.size() + new_data.size()); 246 entries.reserve(entries.size() + new_data.size());
247 247
248 for (const auto& new_entry : new_data) { 248 for (const auto& new_entry : new_data) {
249 entries.emplace_back(new_entry->GetName(), type, new_entry->GetSize()); 249 entries.emplace_back(new_entry->GetName(), type,
250 type == FileSys::EntryType::Directory ? 0 : new_entry->GetSize());
250 } 251 }
251} 252}
252 253
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 3c28dee76..cb29004e8 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -163,28 +163,51 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
163 } 163 }
164 LOG_DEBUG(Service_HID, "Npad connected {}", npad_id); 164 LOG_DEBUG(Service_HID, "Npad connected {}", npad_id);
165 const auto controller_type = controller.device->GetNpadStyleIndex(); 165 const auto controller_type = controller.device->GetNpadStyleIndex();
166 const auto& body_colors = controller.device->GetColors();
167 const auto& battery_level = controller.device->GetBattery();
166 auto* shared_memory = controller.shared_memory; 168 auto* shared_memory = controller.shared_memory;
167 if (controller_type == Core::HID::NpadStyleIndex::None) { 169 if (controller_type == Core::HID::NpadStyleIndex::None) {
168 controller.styleset_changed_event->GetWritableEvent().Signal(); 170 controller.styleset_changed_event->GetWritableEvent().Signal();
169 return; 171 return;
170 } 172 }
173
174 // Reset memory values
171 shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None; 175 shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None;
172 shared_memory->device_type.raw = 0; 176 shared_memory->device_type.raw = 0;
173 shared_memory->system_properties.raw = 0; 177 shared_memory->system_properties.raw = 0;
178 shared_memory->joycon_color.attribute = ColorAttribute::NoController;
179 shared_memory->joycon_color.attribute = ColorAttribute::NoController;
180 shared_memory->fullkey_color = {};
181 shared_memory->joycon_color.left = {};
182 shared_memory->joycon_color.right = {};
183 shared_memory->battery_level_dual = {};
184 shared_memory->battery_level_left = {};
185 shared_memory->battery_level_right = {};
186
174 switch (controller_type) { 187 switch (controller_type) {
175 case Core::HID::NpadStyleIndex::None: 188 case Core::HID::NpadStyleIndex::None:
176 ASSERT(false); 189 ASSERT(false);
177 break; 190 break;
178 case Core::HID::NpadStyleIndex::ProController: 191 case Core::HID::NpadStyleIndex::ProController:
192 shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
193 shared_memory->fullkey_color.fullkey = body_colors.fullkey;
194 shared_memory->battery_level_dual = battery_level.dual.battery_level;
179 shared_memory->style_tag.fullkey.Assign(1); 195 shared_memory->style_tag.fullkey.Assign(1);
180 shared_memory->device_type.fullkey.Assign(1); 196 shared_memory->device_type.fullkey.Assign(1);
181 shared_memory->system_properties.is_vertical.Assign(1); 197 shared_memory->system_properties.is_vertical.Assign(1);
182 shared_memory->system_properties.use_plus.Assign(1); 198 shared_memory->system_properties.use_plus.Assign(1);
183 shared_memory->system_properties.use_minus.Assign(1); 199 shared_memory->system_properties.use_minus.Assign(1);
200 shared_memory->system_properties.is_charging_joy_dual.Assign(
201 battery_level.dual.is_charging);
184 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController; 202 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController;
185 shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1); 203 shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1);
186 break; 204 break;
187 case Core::HID::NpadStyleIndex::Handheld: 205 case Core::HID::NpadStyleIndex::Handheld:
206 shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
207 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
208 shared_memory->fullkey_color.fullkey = body_colors.fullkey;
209 shared_memory->joycon_color.left = body_colors.left;
210 shared_memory->joycon_color.right = body_colors.right;
188 shared_memory->style_tag.handheld.Assign(1); 211 shared_memory->style_tag.handheld.Assign(1);
189 shared_memory->device_type.handheld_left.Assign(1); 212 shared_memory->device_type.handheld_left.Assign(1);
190 shared_memory->device_type.handheld_right.Assign(1); 213 shared_memory->device_type.handheld_right.Assign(1);
@@ -192,47 +215,86 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
192 shared_memory->system_properties.use_plus.Assign(1); 215 shared_memory->system_properties.use_plus.Assign(1);
193 shared_memory->system_properties.use_minus.Assign(1); 216 shared_memory->system_properties.use_minus.Assign(1);
194 shared_memory->system_properties.use_directional_buttons.Assign(1); 217 shared_memory->system_properties.use_directional_buttons.Assign(1);
218 shared_memory->system_properties.is_charging_joy_dual.Assign(
219 battery_level.left.is_charging);
220 shared_memory->system_properties.is_charging_joy_left.Assign(
221 battery_level.left.is_charging);
222 shared_memory->system_properties.is_charging_joy_right.Assign(
223 battery_level.right.is_charging);
195 shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual; 224 shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
196 shared_memory->applet_nfc_xcd.applet_footer.type = 225 shared_memory->applet_nfc_xcd.applet_footer.type =
197 AppletFooterUiType::HandheldJoyConLeftJoyConRight; 226 AppletFooterUiType::HandheldJoyConLeftJoyConRight;
198 shared_memory->sixaxis_handheld_properties.is_newly_assigned.Assign(1); 227 shared_memory->sixaxis_handheld_properties.is_newly_assigned.Assign(1);
199 break; 228 break;
200 case Core::HID::NpadStyleIndex::JoyconDual: 229 case Core::HID::NpadStyleIndex::JoyconDual:
230 shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
231 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
201 shared_memory->style_tag.joycon_dual.Assign(1); 232 shared_memory->style_tag.joycon_dual.Assign(1);
202 if (controller.is_dual_left_connected) { 233 if (controller.is_dual_left_connected) {
234 shared_memory->joycon_color.left = body_colors.left;
235 shared_memory->battery_level_left = battery_level.left.battery_level;
203 shared_memory->device_type.joycon_left.Assign(1); 236 shared_memory->device_type.joycon_left.Assign(1);
204 shared_memory->system_properties.use_minus.Assign(1); 237 shared_memory->system_properties.use_minus.Assign(1);
238 shared_memory->system_properties.is_charging_joy_left.Assign(
239 battery_level.left.is_charging);
205 shared_memory->sixaxis_dual_left_properties.is_newly_assigned.Assign(1); 240 shared_memory->sixaxis_dual_left_properties.is_newly_assigned.Assign(1);
206 } 241 }
207 if (controller.is_dual_right_connected) { 242 if (controller.is_dual_right_connected) {
243 shared_memory->joycon_color.right = body_colors.right;
244 shared_memory->battery_level_right = battery_level.right.battery_level;
208 shared_memory->device_type.joycon_right.Assign(1); 245 shared_memory->device_type.joycon_right.Assign(1);
209 shared_memory->system_properties.use_plus.Assign(1); 246 shared_memory->system_properties.use_plus.Assign(1);
247 shared_memory->system_properties.is_charging_joy_right.Assign(
248 battery_level.right.is_charging);
210 shared_memory->sixaxis_dual_right_properties.is_newly_assigned.Assign(1); 249 shared_memory->sixaxis_dual_right_properties.is_newly_assigned.Assign(1);
211 } 250 }
212 shared_memory->system_properties.use_directional_buttons.Assign(1); 251 shared_memory->system_properties.use_directional_buttons.Assign(1);
213 shared_memory->system_properties.is_vertical.Assign(1); 252 shared_memory->system_properties.is_vertical.Assign(1);
214 shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual; 253 shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual;
254
215 if (controller.is_dual_left_connected && controller.is_dual_right_connected) { 255 if (controller.is_dual_left_connected && controller.is_dual_right_connected) {
216 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDual; 256 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDual;
257 shared_memory->fullkey_color.fullkey = body_colors.left;
258 shared_memory->battery_level_dual = battery_level.left.battery_level;
259 shared_memory->system_properties.is_charging_joy_dual.Assign(
260 battery_level.left.is_charging);
217 } else if (controller.is_dual_left_connected) { 261 } else if (controller.is_dual_left_connected) {
218 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly; 262 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly;
263 shared_memory->fullkey_color.fullkey = body_colors.left;
264 shared_memory->battery_level_dual = battery_level.left.battery_level;
265 shared_memory->system_properties.is_charging_joy_dual.Assign(
266 battery_level.left.is_charging);
219 } else { 267 } else {
220 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualRightOnly; 268 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualRightOnly;
269 shared_memory->fullkey_color.fullkey = body_colors.right;
270 shared_memory->battery_level_dual = battery_level.right.battery_level;
271 shared_memory->system_properties.is_charging_joy_dual.Assign(
272 battery_level.right.is_charging);
221 } 273 }
222 break; 274 break;
223 case Core::HID::NpadStyleIndex::JoyconLeft: 275 case Core::HID::NpadStyleIndex::JoyconLeft:
276 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
277 shared_memory->joycon_color.left = body_colors.left;
278 shared_memory->battery_level_dual = battery_level.left.battery_level;
224 shared_memory->style_tag.joycon_left.Assign(1); 279 shared_memory->style_tag.joycon_left.Assign(1);
225 shared_memory->device_type.joycon_left.Assign(1); 280 shared_memory->device_type.joycon_left.Assign(1);
226 shared_memory->system_properties.is_horizontal.Assign(1); 281 shared_memory->system_properties.is_horizontal.Assign(1);
227 shared_memory->system_properties.use_minus.Assign(1); 282 shared_memory->system_properties.use_minus.Assign(1);
283 shared_memory->system_properties.is_charging_joy_left.Assign(
284 battery_level.left.is_charging);
228 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; 285 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal;
229 shared_memory->sixaxis_left_properties.is_newly_assigned.Assign(1); 286 shared_memory->sixaxis_left_properties.is_newly_assigned.Assign(1);
230 break; 287 break;
231 case Core::HID::NpadStyleIndex::JoyconRight: 288 case Core::HID::NpadStyleIndex::JoyconRight:
289 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
290 shared_memory->joycon_color.right = body_colors.right;
291 shared_memory->battery_level_right = battery_level.right.battery_level;
232 shared_memory->style_tag.joycon_right.Assign(1); 292 shared_memory->style_tag.joycon_right.Assign(1);
233 shared_memory->device_type.joycon_right.Assign(1); 293 shared_memory->device_type.joycon_right.Assign(1);
234 shared_memory->system_properties.is_horizontal.Assign(1); 294 shared_memory->system_properties.is_horizontal.Assign(1);
235 shared_memory->system_properties.use_plus.Assign(1); 295 shared_memory->system_properties.use_plus.Assign(1);
296 shared_memory->system_properties.is_charging_joy_right.Assign(
297 battery_level.right.is_charging);
236 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; 298 shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal;
237 shared_memory->sixaxis_right_properties.is_newly_assigned.Assign(1); 299 shared_memory->sixaxis_right_properties.is_newly_assigned.Assign(1);
238 break; 300 break;
@@ -269,21 +331,6 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) {
269 break; 331 break;
270 } 332 }
271 333
272 const auto& body_colors = controller.device->GetColors();
273
274 shared_memory->fullkey_color.attribute = ColorAttribute::Ok;
275 shared_memory->fullkey_color.fullkey = body_colors.fullkey;
276
277 shared_memory->joycon_color.attribute = ColorAttribute::Ok;
278 shared_memory->joycon_color.left = body_colors.left;
279 shared_memory->joycon_color.right = body_colors.right;
280
281 // TODO: Investigate when we should report all batery types
282 const auto& battery_level = controller.device->GetBattery();
283 shared_memory->battery_level_dual = battery_level.dual.battery_level;
284 shared_memory->battery_level_left = battery_level.left.battery_level;
285 shared_memory->battery_level_right = battery_level.right.battery_level;
286
287 controller.is_connected = true; 334 controller.is_connected = true;
288 controller.device->Connect(); 335 controller.device->Connect();
289 SignalStyleSetChangedEvent(npad_id); 336 SignalStyleSetChangedEvent(npad_id);
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 5ecbddf94..3d3457160 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -819,12 +819,12 @@ void Hid::EnableSixAxisSensorUnalteredPassthrough(Kernel::HLERequestContext& ctx
819 const auto result = controller.EnableSixAxisSensorUnalteredPassthrough( 819 const auto result = controller.EnableSixAxisSensorUnalteredPassthrough(
820 parameters.sixaxis_handle, parameters.enabled); 820 parameters.sixaxis_handle, parameters.enabled);
821 821
822 LOG_WARNING(Service_HID, 822 LOG_DEBUG(Service_HID,
823 "(STUBBED) called, enabled={}, npad_type={}, npad_id={}, device_index={}, " 823 "(STUBBED) called, enabled={}, npad_type={}, npad_id={}, device_index={}, "
824 "applet_resource_user_id={}", 824 "applet_resource_user_id={}",
825 parameters.enabled, parameters.sixaxis_handle.npad_type, 825 parameters.enabled, parameters.sixaxis_handle.npad_type,
826 parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index, 826 parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index,
827 parameters.applet_resource_user_id); 827 parameters.applet_resource_user_id);
828 828
829 IPC::ResponseBuilder rb{ctx, 2}; 829 IPC::ResponseBuilder rb{ctx, 2};
830 rb.Push(result); 830 rb.Push(result);
@@ -846,7 +846,7 @@ void Hid::IsSixAxisSensorUnalteredPassthroughEnabled(Kernel::HLERequestContext&
846 const auto result = controller.IsSixAxisSensorUnalteredPassthroughEnabled( 846 const auto result = controller.IsSixAxisSensorUnalteredPassthroughEnabled(
847 parameters.sixaxis_handle, is_unaltered_sisxaxis_enabled); 847 parameters.sixaxis_handle, is_unaltered_sisxaxis_enabled);
848 848
849 LOG_WARNING( 849 LOG_DEBUG(
850 Service_HID, 850 Service_HID,
851 "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", 851 "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
852 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, 852 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
@@ -2146,12 +2146,18 @@ public:
2146 {324, nullptr, "GetUniquePadButtonSet"}, 2146 {324, nullptr, "GetUniquePadButtonSet"},
2147 {325, nullptr, "GetUniquePadColor"}, 2147 {325, nullptr, "GetUniquePadColor"},
2148 {326, nullptr, "GetUniquePadAppletDetailedUiType"}, 2148 {326, nullptr, "GetUniquePadAppletDetailedUiType"},
2149 {327, nullptr, "GetAbstractedPadIdDataFromNpad"},
2150 {328, nullptr, "AttachAbstractedPadToNpad"},
2151 {329, nullptr, "DetachAbstractedPadAll"},
2152 {330, nullptr, "CheckAbstractedPadConnection"},
2149 {500, nullptr, "SetAppletResourceUserId"}, 2153 {500, nullptr, "SetAppletResourceUserId"},
2150 {501, nullptr, "RegisterAppletResourceUserId"}, 2154 {501, nullptr, "RegisterAppletResourceUserId"},
2151 {502, nullptr, "UnregisterAppletResourceUserId"}, 2155 {502, nullptr, "UnregisterAppletResourceUserId"},
2152 {503, nullptr, "EnableAppletToGetInput"}, 2156 {503, nullptr, "EnableAppletToGetInput"},
2153 {504, nullptr, "SetAruidValidForVibration"}, 2157 {504, nullptr, "SetAruidValidForVibration"},
2154 {505, nullptr, "EnableAppletToGetSixAxisSensor"}, 2158 {505, nullptr, "EnableAppletToGetSixAxisSensor"},
2159 {506, nullptr, "EnableAppletToGetPadInput"},
2160 {507, nullptr, "EnableAppletToGetTouchScreen"},
2155 {510, nullptr, "SetVibrationMasterVolume"}, 2161 {510, nullptr, "SetVibrationMasterVolume"},
2156 {511, nullptr, "GetVibrationMasterVolume"}, 2162 {511, nullptr, "GetVibrationMasterVolume"},
2157 {512, nullptr, "BeginPermitVibrationSession"}, 2163 {512, nullptr, "BeginPermitVibrationSession"},
diff --git a/src/core/hle/service/ldn/errors.h b/src/core/hle/service/ldn/errors.h
deleted file mode 100644
index 972a74806..000000000
--- a/src/core/hle/service/ldn/errors.h
+++ /dev/null
@@ -1,12 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7
8namespace Service::LDN {
9
10constexpr Result ERROR_DISABLED{ErrorModule::LDN, 22};
11
12} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp
index 125d4dc4c..c11daff54 100644
--- a/src/core/hle/service/ldn/ldn.cpp
+++ b/src/core/hle/service/ldn/ldn.cpp
@@ -3,11 +3,15 @@
3 3
4#include <memory> 4#include <memory>
5 5
6#include "core/hle/ipc_helpers.h" 6#include "core/core.h"
7#include "core/hle/result.h"
8#include "core/hle/service/ldn/errors.h"
9#include "core/hle/service/ldn/ldn.h" 7#include "core/hle/service/ldn/ldn.h"
10#include "core/hle/service/sm/sm.h" 8#include "core/hle/service/ldn/ldn_results.h"
9#include "core/hle/service/ldn/ldn_types.h"
10#include "core/internal_network/network.h"
11#include "core/internal_network/network_interface.h"
12
13// This is defined by synchapi.h and conflicts with ServiceContext::CreateEvent
14#undef CreateEvent
11 15
12namespace Service::LDN { 16namespace Service::LDN {
13 17
@@ -100,74 +104,418 @@ class IUserLocalCommunicationService final
100 : public ServiceFramework<IUserLocalCommunicationService> { 104 : public ServiceFramework<IUserLocalCommunicationService> {
101public: 105public:
102 explicit IUserLocalCommunicationService(Core::System& system_) 106 explicit IUserLocalCommunicationService(Core::System& system_)
103 : ServiceFramework{system_, "IUserLocalCommunicationService"} { 107 : ServiceFramework{system_, "IUserLocalCommunicationService", ServiceThreadType::CreateNew},
108 service_context{system, "IUserLocalCommunicationService"}, room_network{
109 system_.GetRoomNetwork()} {
104 // clang-format off 110 // clang-format off
105 static const FunctionInfo functions[] = { 111 static const FunctionInfo functions[] = {
106 {0, &IUserLocalCommunicationService::GetState, "GetState"}, 112 {0, &IUserLocalCommunicationService::GetState, "GetState"},
107 {1, nullptr, "GetNetworkInfo"}, 113 {1, &IUserLocalCommunicationService::GetNetworkInfo, "GetNetworkInfo"},
108 {2, nullptr, "GetIpv4Address"}, 114 {2, nullptr, "GetIpv4Address"},
109 {3, nullptr, "GetDisconnectReason"}, 115 {3, &IUserLocalCommunicationService::GetDisconnectReason, "GetDisconnectReason"},
110 {4, nullptr, "GetSecurityParameter"}, 116 {4, &IUserLocalCommunicationService::GetSecurityParameter, "GetSecurityParameter"},
111 {5, nullptr, "GetNetworkConfig"}, 117 {5, &IUserLocalCommunicationService::GetNetworkConfig, "GetNetworkConfig"},
112 {100, nullptr, "AttachStateChangeEvent"}, 118 {100, &IUserLocalCommunicationService::AttachStateChangeEvent, "AttachStateChangeEvent"},
113 {101, nullptr, "GetNetworkInfoLatestUpdate"}, 119 {101, &IUserLocalCommunicationService::GetNetworkInfoLatestUpdate, "GetNetworkInfoLatestUpdate"},
114 {102, nullptr, "Scan"}, 120 {102, &IUserLocalCommunicationService::Scan, "Scan"},
115 {103, nullptr, "ScanPrivate"}, 121 {103, &IUserLocalCommunicationService::ScanPrivate, "ScanPrivate"},
116 {104, nullptr, "SetWirelessControllerRestriction"}, 122 {104, nullptr, "SetWirelessControllerRestriction"},
117 {200, nullptr, "OpenAccessPoint"}, 123 {200, &IUserLocalCommunicationService::OpenAccessPoint, "OpenAccessPoint"},
118 {201, nullptr, "CloseAccessPoint"}, 124 {201, &IUserLocalCommunicationService::CloseAccessPoint, "CloseAccessPoint"},
119 {202, nullptr, "CreateNetwork"}, 125 {202, &IUserLocalCommunicationService::CreateNetwork, "CreateNetwork"},
120 {203, nullptr, "CreateNetworkPrivate"}, 126 {203, &IUserLocalCommunicationService::CreateNetworkPrivate, "CreateNetworkPrivate"},
121 {204, nullptr, "DestroyNetwork"}, 127 {204, &IUserLocalCommunicationService::DestroyNetwork, "DestroyNetwork"},
122 {205, nullptr, "Reject"}, 128 {205, nullptr, "Reject"},
123 {206, nullptr, "SetAdvertiseData"}, 129 {206, &IUserLocalCommunicationService::SetAdvertiseData, "SetAdvertiseData"},
124 {207, nullptr, "SetStationAcceptPolicy"}, 130 {207, &IUserLocalCommunicationService::SetStationAcceptPolicy, "SetStationAcceptPolicy"},
125 {208, nullptr, "AddAcceptFilterEntry"}, 131 {208, &IUserLocalCommunicationService::AddAcceptFilterEntry, "AddAcceptFilterEntry"},
126 {209, nullptr, "ClearAcceptFilter"}, 132 {209, nullptr, "ClearAcceptFilter"},
127 {300, nullptr, "OpenStation"}, 133 {300, &IUserLocalCommunicationService::OpenStation, "OpenStation"},
128 {301, nullptr, "CloseStation"}, 134 {301, &IUserLocalCommunicationService::CloseStation, "CloseStation"},
129 {302, nullptr, "Connect"}, 135 {302, &IUserLocalCommunicationService::Connect, "Connect"},
130 {303, nullptr, "ConnectPrivate"}, 136 {303, nullptr, "ConnectPrivate"},
131 {304, nullptr, "Disconnect"}, 137 {304, &IUserLocalCommunicationService::Disconnect, "Disconnect"},
132 {400, nullptr, "Initialize"}, 138 {400, &IUserLocalCommunicationService::Initialize, "Initialize"},
133 {401, nullptr, "Finalize"}, 139 {401, &IUserLocalCommunicationService::Finalize, "Finalize"},
134 {402, &IUserLocalCommunicationService::Initialize2, "Initialize2"}, // 7.0.0+ 140 {402, &IUserLocalCommunicationService::Initialize2, "Initialize2"},
135 }; 141 };
136 // clang-format on 142 // clang-format on
137 143
138 RegisterHandlers(functions); 144 RegisterHandlers(functions);
145
146 state_change_event =
147 service_context.CreateEvent("IUserLocalCommunicationService:StateChangeEvent");
148 }
149
150 ~IUserLocalCommunicationService() {
151 service_context.CloseEvent(state_change_event);
152 }
153
154 void OnEventFired() {
155 state_change_event->GetWritableEvent().Signal();
139 } 156 }
140 157
141 void GetState(Kernel::HLERequestContext& ctx) { 158 void GetState(Kernel::HLERequestContext& ctx) {
159 State state = State::Error;
160 LOG_WARNING(Service_LDN, "(STUBBED) called, state = {}", state);
161
162 IPC::ResponseBuilder rb{ctx, 3};
163 rb.Push(ResultSuccess);
164 rb.PushEnum(state);
165 }
166
167 void GetNetworkInfo(Kernel::HLERequestContext& ctx) {
168 const auto write_buffer_size = ctx.GetWriteBufferSize();
169
170 if (write_buffer_size != sizeof(NetworkInfo)) {
171 LOG_ERROR(Service_LDN, "Invalid buffer size {}", write_buffer_size);
172 IPC::ResponseBuilder rb{ctx, 2};
173 rb.Push(ResultBadInput);
174 return;
175 }
176
177 NetworkInfo network_info{};
178 const auto rc = ResultSuccess;
179 if (rc.IsError()) {
180 LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
181 IPC::ResponseBuilder rb{ctx, 2};
182 rb.Push(rc);
183 return;
184 }
185
186 LOG_WARNING(Service_LDN, "(STUBBED) called, ssid='{}', nodes={}",
187 network_info.common.ssid.GetStringValue(), network_info.ldn.node_count);
188
189 ctx.WriteBuffer<NetworkInfo>(network_info);
190 IPC::ResponseBuilder rb{ctx, 2};
191 rb.Push(rc);
192 }
193
194 void GetDisconnectReason(Kernel::HLERequestContext& ctx) {
195 const auto disconnect_reason = DisconnectReason::None;
196
197 LOG_WARNING(Service_LDN, "(STUBBED) called, disconnect_reason={}", disconnect_reason);
198
199 IPC::ResponseBuilder rb{ctx, 3};
200 rb.Push(ResultSuccess);
201 rb.PushEnum(disconnect_reason);
202 }
203
204 void GetSecurityParameter(Kernel::HLERequestContext& ctx) {
205 SecurityParameter security_parameter{};
206 NetworkInfo info{};
207 const Result rc = ResultSuccess;
208
209 if (rc.IsError()) {
210 LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
211 IPC::ResponseBuilder rb{ctx, 2};
212 rb.Push(rc);
213 return;
214 }
215
216 security_parameter.session_id = info.network_id.session_id;
217 std::memcpy(security_parameter.data.data(), info.ldn.security_parameter.data(),
218 sizeof(SecurityParameter::data));
219
142 LOG_WARNING(Service_LDN, "(STUBBED) called"); 220 LOG_WARNING(Service_LDN, "(STUBBED) called");
143 221
222 IPC::ResponseBuilder rb{ctx, 10};
223 rb.Push(rc);
224 rb.PushRaw<SecurityParameter>(security_parameter);
225 }
226
227 void GetNetworkConfig(Kernel::HLERequestContext& ctx) {
228 NetworkConfig config{};
229 NetworkInfo info{};
230 const Result rc = ResultSuccess;
231
232 if (rc.IsError()) {
233 LOG_ERROR(Service_LDN, "NetworkConfig is not valid {}", rc.raw);
234 IPC::ResponseBuilder rb{ctx, 2};
235 rb.Push(rc);
236 return;
237 }
238
239 config.intent_id = info.network_id.intent_id;
240 config.channel = info.common.channel;
241 config.node_count_max = info.ldn.node_count_max;
242 config.local_communication_version = info.ldn.nodes[0].local_communication_version;
243
244 LOG_WARNING(Service_LDN,
245 "(STUBBED) called, intent_id={}/{}, channel={}, node_count_max={}, "
246 "local_communication_version={}",
247 config.intent_id.local_communication_id, config.intent_id.scene_id,
248 config.channel, config.node_count_max, config.local_communication_version);
249
250 IPC::ResponseBuilder rb{ctx, 10};
251 rb.Push(rc);
252 rb.PushRaw<NetworkConfig>(config);
253 }
254
255 void AttachStateChangeEvent(Kernel::HLERequestContext& ctx) {
256 LOG_INFO(Service_LDN, "called");
257
258 IPC::ResponseBuilder rb{ctx, 2, 1};
259 rb.Push(ResultSuccess);
260 rb.PushCopyObjects(state_change_event->GetReadableEvent());
261 }
262
263 void GetNetworkInfoLatestUpdate(Kernel::HLERequestContext& ctx) {
264 const std::size_t network_buffer_size = ctx.GetWriteBufferSize(0);
265 const std::size_t node_buffer_count = ctx.GetWriteBufferSize(1) / sizeof(NodeLatestUpdate);
266
267 if (node_buffer_count == 0 || network_buffer_size != sizeof(NetworkInfo)) {
268 LOG_ERROR(Service_LDN, "Invalid buffer size {}, {}", network_buffer_size,
269 node_buffer_count);
270 IPC::ResponseBuilder rb{ctx, 2};
271 rb.Push(ResultBadInput);
272 return;
273 }
274
275 NetworkInfo info;
276 std::vector<NodeLatestUpdate> latest_update(node_buffer_count);
277
278 const auto rc = ResultSuccess;
279 if (rc.IsError()) {
280 LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
281 IPC::ResponseBuilder rb{ctx, 2};
282 rb.Push(rc);
283 return;
284 }
285
286 LOG_WARNING(Service_LDN, "(STUBBED) called, ssid='{}', nodes={}",
287 info.common.ssid.GetStringValue(), info.ldn.node_count);
288
289 ctx.WriteBuffer(info, 0);
290 ctx.WriteBuffer(latest_update, 1);
291
292 IPC::ResponseBuilder rb{ctx, 2};
293 rb.Push(ResultSuccess);
294 }
295
296 void Scan(Kernel::HLERequestContext& ctx) {
297 ScanImpl(ctx);
298 }
299
300 void ScanPrivate(Kernel::HLERequestContext& ctx) {
301 ScanImpl(ctx, true);
302 }
303
304 void ScanImpl(Kernel::HLERequestContext& ctx, bool is_private = false) {
305 IPC::RequestParser rp{ctx};
306 const auto channel{rp.PopEnum<WifiChannel>()};
307 const auto scan_filter{rp.PopRaw<ScanFilter>()};
308
309 const std::size_t network_info_size = ctx.GetWriteBufferSize() / sizeof(NetworkInfo);
310
311 if (network_info_size == 0) {
312 LOG_ERROR(Service_LDN, "Invalid buffer size {}", network_info_size);
313 IPC::ResponseBuilder rb{ctx, 2};
314 rb.Push(ResultBadInput);
315 return;
316 }
317
318 u16 count = 0;
319 std::vector<NetworkInfo> network_infos(network_info_size);
320
321 LOG_WARNING(Service_LDN,
322 "(STUBBED) called, channel={}, filter_scan_flag={}, filter_network_type={}",
323 channel, scan_filter.flag, scan_filter.network_type);
324
325 ctx.WriteBuffer(network_infos);
326
144 IPC::ResponseBuilder rb{ctx, 3}; 327 IPC::ResponseBuilder rb{ctx, 3};
328 rb.Push(ResultSuccess);
329 rb.Push<u32>(count);
330 }
331
332 void OpenAccessPoint(Kernel::HLERequestContext& ctx) {
333 LOG_WARNING(Service_LDN, "(STUBBED) called");
334
335 IPC::ResponseBuilder rb{ctx, 2};
336 rb.Push(ResultSuccess);
337 }
338
339 void CloseAccessPoint(Kernel::HLERequestContext& ctx) {
340 LOG_WARNING(Service_LDN, "(STUBBED) called");
341
342 IPC::ResponseBuilder rb{ctx, 2};
343 rb.Push(ResultSuccess);
344 }
345
346 void CreateNetwork(Kernel::HLERequestContext& ctx) {
347 IPC::RequestParser rp{ctx};
348 struct Parameters {
349 SecurityConfig security_config;
350 UserConfig user_config;
351 INSERT_PADDING_WORDS_NOINIT(1);
352 NetworkConfig network_config;
353 };
354 static_assert(sizeof(Parameters) == 0x98, "Parameters has incorrect size.");
355
356 const auto parameters{rp.PopRaw<Parameters>()};
357
358 LOG_WARNING(Service_LDN,
359 "(STUBBED) called, passphrase_size={}, security_mode={}, "
360 "local_communication_version={}",
361 parameters.security_config.passphrase_size,
362 parameters.security_config.security_mode,
363 parameters.network_config.local_communication_version);
364
365 IPC::ResponseBuilder rb{ctx, 2};
366 rb.Push(ResultSuccess);
367 }
368
369 void CreateNetworkPrivate(Kernel::HLERequestContext& ctx) {
370 IPC::RequestParser rp{ctx};
371 struct Parameters {
372 SecurityConfig security_config;
373 SecurityParameter security_parameter;
374 UserConfig user_config;
375 NetworkConfig network_config;
376 };
377 static_assert(sizeof(Parameters) == 0xB8, "Parameters has incorrect size.");
378
379 const auto parameters{rp.PopRaw<Parameters>()};
380
381 LOG_WARNING(Service_LDN,
382 "(STUBBED) called, passphrase_size={}, security_mode={}, "
383 "local_communication_version={}",
384 parameters.security_config.passphrase_size,
385 parameters.security_config.security_mode,
386 parameters.network_config.local_communication_version);
387
388 IPC::ResponseBuilder rb{ctx, 2};
389 rb.Push(ResultSuccess);
390 }
391
392 void DestroyNetwork(Kernel::HLERequestContext& ctx) {
393 LOG_WARNING(Service_LDN, "(STUBBED) called");
394
395 IPC::ResponseBuilder rb{ctx, 2};
396 rb.Push(ResultSuccess);
397 }
398
399 void SetAdvertiseData(Kernel::HLERequestContext& ctx) {
400 std::vector<u8> read_buffer = ctx.ReadBuffer();
401
402 LOG_WARNING(Service_LDN, "(STUBBED) called, size {}", read_buffer.size());
403
404 IPC::ResponseBuilder rb{ctx, 2};
405 rb.Push(ResultSuccess);
406 }
407
408 void SetStationAcceptPolicy(Kernel::HLERequestContext& ctx) {
409 LOG_WARNING(Service_LDN, "(STUBBED) called");
410
411 IPC::ResponseBuilder rb{ctx, 2};
412 rb.Push(ResultSuccess);
413 }
145 414
146 // Indicate a network error, as we do not actually emulate LDN 415 void AddAcceptFilterEntry(Kernel::HLERequestContext& ctx) {
147 rb.Push(static_cast<u32>(State::Error)); 416 LOG_WARNING(Service_LDN, "(STUBBED) called");
148 417
418 IPC::ResponseBuilder rb{ctx, 2};
419 rb.Push(ResultSuccess);
420 }
421
422 void OpenStation(Kernel::HLERequestContext& ctx) {
423 LOG_WARNING(Service_LDN, "(STUBBED) called");
424
425 IPC::ResponseBuilder rb{ctx, 2};
426 rb.Push(ResultSuccess);
427 }
428
429 void CloseStation(Kernel::HLERequestContext& ctx) {
430 LOG_WARNING(Service_LDN, "(STUBBED) called");
431
432 IPC::ResponseBuilder rb{ctx, 2};
433 rb.Push(ResultSuccess);
434 }
435
436 void Connect(Kernel::HLERequestContext& ctx) {
437 IPC::RequestParser rp{ctx};
438 struct Parameters {
439 SecurityConfig security_config;
440 UserConfig user_config;
441 u32 local_communication_version;
442 u32 option;
443 };
444 static_assert(sizeof(Parameters) == 0x7C, "Parameters has incorrect size.");
445
446 const auto parameters{rp.PopRaw<Parameters>()};
447
448 LOG_WARNING(Service_LDN,
449 "(STUBBED) called, passphrase_size={}, security_mode={}, "
450 "local_communication_version={}",
451 parameters.security_config.passphrase_size,
452 parameters.security_config.security_mode,
453 parameters.local_communication_version);
454
455 const std::vector<u8> read_buffer = ctx.ReadBuffer();
456 NetworkInfo network_info{};
457
458 if (read_buffer.size() != sizeof(NetworkInfo)) {
459 LOG_ERROR(Frontend, "NetworkInfo doesn't match read_buffer size!");
460 IPC::ResponseBuilder rb{ctx, 2};
461 rb.Push(ResultBadInput);
462 return;
463 }
464
465 std::memcpy(&network_info, read_buffer.data(), read_buffer.size());
466
467 IPC::ResponseBuilder rb{ctx, 2};
468 rb.Push(ResultSuccess);
469 }
470
471 void Disconnect(Kernel::HLERequestContext& ctx) {
472 LOG_WARNING(Service_LDN, "(STUBBED) called");
473
474 IPC::ResponseBuilder rb{ctx, 2};
475 rb.Push(ResultSuccess);
476 }
477 void Initialize(Kernel::HLERequestContext& ctx) {
478 LOG_WARNING(Service_LDN, "(STUBBED) called");
479
480 const auto rc = InitializeImpl(ctx);
481
482 IPC::ResponseBuilder rb{ctx, 2};
483 rb.Push(rc);
484 }
485
486 void Finalize(Kernel::HLERequestContext& ctx) {
487 LOG_WARNING(Service_LDN, "(STUBBED) called");
488
489 is_initialized = false;
490
491 IPC::ResponseBuilder rb{ctx, 2};
149 rb.Push(ResultSuccess); 492 rb.Push(ResultSuccess);
150 } 493 }
151 494
152 void Initialize2(Kernel::HLERequestContext& ctx) { 495 void Initialize2(Kernel::HLERequestContext& ctx) {
153 LOG_DEBUG(Service_LDN, "called"); 496 LOG_WARNING(Service_LDN, "(STUBBED) called");
154 497
155 is_initialized = true; 498 const auto rc = InitializeImpl(ctx);
156 499
157 IPC::ResponseBuilder rb{ctx, 2}; 500 IPC::ResponseBuilder rb{ctx, 2};
158 rb.Push(ERROR_DISABLED); 501 rb.Push(rc);
502 }
503
504 Result InitializeImpl(Kernel::HLERequestContext& ctx) {
505 const auto network_interface = Network::GetSelectedNetworkInterface();
506 if (!network_interface) {
507 LOG_ERROR(Service_LDN, "No network interface is set");
508 return ResultAirplaneModeEnabled;
509 }
510
511 is_initialized = true;
512 // TODO (flTobi): Change this to ResultSuccess when LDN is fully implemented
513 return ResultAirplaneModeEnabled;
159 } 514 }
160 515
161private: 516 KernelHelpers::ServiceContext service_context;
162 enum class State { 517 Kernel::KEvent* state_change_event;
163 None, 518 Network::RoomNetwork& room_network;
164 Initialized,
165 AccessPointOpened,
166 AccessPointCreated,
167 StationOpened,
168 StationConnected,
169 Error,
170 };
171 519
172 bool is_initialized{}; 520 bool is_initialized{};
173}; 521};
@@ -273,7 +621,7 @@ public:
273 LOG_WARNING(Service_LDN, "(STUBBED) called"); 621 LOG_WARNING(Service_LDN, "(STUBBED) called");
274 622
275 IPC::ResponseBuilder rb{ctx, 2}; 623 IPC::ResponseBuilder rb{ctx, 2};
276 rb.Push(ERROR_DISABLED); 624 rb.Push(ResultDisabled);
277 } 625 }
278}; 626};
279 627
diff --git a/src/core/hle/service/ldn/ldn.h b/src/core/hle/service/ldn/ldn.h
index a0031ac71..6afe2ea6f 100644
--- a/src/core/hle/service/ldn/ldn.h
+++ b/src/core/hle/service/ldn/ldn.h
@@ -3,6 +3,12 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/k_event.h"
8#include "core/hle/result.h"
9#include "core/hle/service/kernel_helpers.h"
10#include "core/hle/service/sm/sm.h"
11
6namespace Core { 12namespace Core {
7class System; 13class System;
8} 14}
diff --git a/src/core/hle/service/ldn/ldn_results.h b/src/core/hle/service/ldn/ldn_results.h
new file mode 100644
index 000000000..f340bda42
--- /dev/null
+++ b/src/core/hle/service/ldn/ldn_results.h
@@ -0,0 +1,27 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include "core/hle/result.h"
7
8namespace Service::LDN {
9
10constexpr Result ResultAdvertiseDataTooLarge{ErrorModule::LDN, 10};
11constexpr Result ResultAuthenticationFailed{ErrorModule::LDN, 20};
12constexpr Result ResultDisabled{ErrorModule::LDN, 22};
13constexpr Result ResultAirplaneModeEnabled{ErrorModule::LDN, 23};
14constexpr Result ResultInvalidNodeCount{ErrorModule::LDN, 30};
15constexpr Result ResultConnectionFailed{ErrorModule::LDN, 31};
16constexpr Result ResultBadState{ErrorModule::LDN, 32};
17constexpr Result ResultNoIpAddress{ErrorModule::LDN, 33};
18constexpr Result ResultInvalidBufferCount{ErrorModule::LDN, 50};
19constexpr Result ResultAccessPointConnectionFailed{ErrorModule::LDN, 65};
20constexpr Result ResultAuthenticationTimeout{ErrorModule::LDN, 66};
21constexpr Result ResultMaximumNodeCount{ErrorModule::LDN, 67};
22constexpr Result ResultBadInput{ErrorModule::LDN, 96};
23constexpr Result ResultLocalCommunicationIdNotFound{ErrorModule::LDN, 97};
24constexpr Result ResultLocalCommunicationVersionTooLow{ErrorModule::LDN, 113};
25constexpr Result ResultLocalCommunicationVersionTooHigh{ErrorModule::LDN, 114};
26
27} // namespace Service::LDN
diff --git a/src/core/hle/service/ldn/ldn_types.h b/src/core/hle/service/ldn/ldn_types.h
new file mode 100644
index 000000000..6231e936d
--- /dev/null
+++ b/src/core/hle/service/ldn/ldn_types.h
@@ -0,0 +1,292 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#pragma once
5
6#include <fmt/format.h>
7
8#include "common/common_funcs.h"
9#include "common/common_types.h"
10#include "network/network.h"
11
12namespace Service::LDN {
13
14constexpr size_t SsidLengthMax = 32;
15constexpr size_t AdvertiseDataSizeMax = 384;
16constexpr size_t UserNameBytesMax = 32;
17constexpr int NodeCountMax = 8;
18constexpr int StationCountMax = NodeCountMax - 1;
19constexpr size_t PassphraseLengthMax = 64;
20
21enum class SecurityMode : u16 {
22 All,
23 Retail,
24 Debug,
25};
26
27enum class NodeStateChange : u8 {
28 None,
29 Connect,
30 Disconnect,
31 DisconnectAndConnect,
32};
33
34enum class ScanFilterFlag : u32 {
35 None = 0,
36 LocalCommunicationId = 1 << 0,
37 SessionId = 1 << 1,
38 NetworkType = 1 << 2,
39 Ssid = 1 << 4,
40 SceneId = 1 << 5,
41 IntentId = LocalCommunicationId | SceneId,
42 NetworkId = IntentId | SessionId,
43};
44
45enum class NetworkType : u32 {
46 None,
47 General,
48 Ldn,
49 All,
50};
51
52enum class PackedNetworkType : u8 {
53 None,
54 General,
55 Ldn,
56 All,
57};
58
59enum class State : u32 {
60 None,
61 Initialized,
62 AccessPointOpened,
63 AccessPointCreated,
64 StationOpened,
65 StationConnected,
66 Error,
67};
68
69enum class DisconnectReason : s16 {
70 Unknown = -1,
71 None,
72 DisconnectedByUser,
73 DisconnectedBySystem,
74 DestroyedByUser,
75 DestroyedBySystem,
76 Rejected,
77 SignalLost,
78};
79
80enum class NetworkError {
81 Unknown = -1,
82 None = 0,
83 PortUnreachable,
84 TooManyPlayers,
85 VersionTooLow,
86 VersionTooHigh,
87 ConnectFailure,
88 ConnectNotFound,
89 ConnectTimeout,
90 ConnectRejected,
91 RejectFailed,
92};
93
94enum class AcceptPolicy : u8 {
95 AcceptAll,
96 RejectAll,
97 BlackList,
98 WhiteList,
99};
100
101enum class WifiChannel : s16 {
102 Default = 0,
103 wifi24_1 = 1,
104 wifi24_6 = 6,
105 wifi24_11 = 11,
106 wifi50_36 = 36,
107 wifi50_40 = 40,
108 wifi50_44 = 44,
109 wifi50_48 = 48,
110};
111
112enum class LinkLevel : s8 {
113 Bad,
114 Low,
115 Good,
116 Excellent,
117};
118
119struct NodeLatestUpdate {
120 NodeStateChange state_change;
121 INSERT_PADDING_BYTES(0x7); // Unknown
122};
123static_assert(sizeof(NodeLatestUpdate) == 0x8, "NodeLatestUpdate is an invalid size");
124
125struct SessionId {
126 u64 high;
127 u64 low;
128
129 bool operator==(const SessionId&) const = default;
130};
131static_assert(sizeof(SessionId) == 0x10, "SessionId is an invalid size");
132
133struct IntentId {
134 u64 local_communication_id;
135 INSERT_PADDING_BYTES(0x2); // Reserved
136 u16 scene_id;
137 INSERT_PADDING_BYTES(0x4); // Reserved
138};
139static_assert(sizeof(IntentId) == 0x10, "IntentId is an invalid size");
140
141struct NetworkId {
142 IntentId intent_id;
143 SessionId session_id;
144};
145static_assert(sizeof(NetworkId) == 0x20, "NetworkId is an invalid size");
146
147struct Ssid {
148 u8 length{};
149 std::array<char, SsidLengthMax + 1> raw{};
150
151 Ssid() = default;
152
153 explicit Ssid(std::string_view data) {
154 length = static_cast<u8>(std::min(data.size(), SsidLengthMax));
155 data.copy(raw.data(), length);
156 raw[length] = 0;
157 }
158
159 std::string GetStringValue() const {
160 return std::string(raw.data());
161 }
162};
163static_assert(sizeof(Ssid) == 0x22, "Ssid is an invalid size");
164
165struct Ipv4Address {
166 union {
167 u32 raw{};
168 std::array<u8, 4> bytes;
169 };
170
171 std::string GetStringValue() const {
172 return fmt::format("{}.{}.{}.{}", bytes[3], bytes[2], bytes[1], bytes[0]);
173 }
174};
175static_assert(sizeof(Ipv4Address) == 0x4, "Ipv4Address is an invalid size");
176
177struct MacAddress {
178 std::array<u8, 6> raw{};
179
180 friend bool operator==(const MacAddress& lhs, const MacAddress& rhs) = default;
181};
182static_assert(sizeof(MacAddress) == 0x6, "MacAddress is an invalid size");
183
184struct ScanFilter {
185 NetworkId network_id;
186 NetworkType network_type;
187 MacAddress mac_address;
188 Ssid ssid;
189 INSERT_PADDING_BYTES(0x10);
190 ScanFilterFlag flag;
191};
192static_assert(sizeof(ScanFilter) == 0x60, "ScanFilter is an invalid size");
193
194struct CommonNetworkInfo {
195 MacAddress bssid;
196 Ssid ssid;
197 WifiChannel channel;
198 LinkLevel link_level;
199 PackedNetworkType network_type;
200 INSERT_PADDING_BYTES(0x4);
201};
202static_assert(sizeof(CommonNetworkInfo) == 0x30, "CommonNetworkInfo is an invalid size");
203
204struct NodeInfo {
205 Ipv4Address ipv4_address;
206 MacAddress mac_address;
207 s8 node_id;
208 u8 is_connected;
209 std::array<u8, UserNameBytesMax + 1> user_name;
210 INSERT_PADDING_BYTES(0x1); // Reserved
211 s16 local_communication_version;
212 INSERT_PADDING_BYTES(0x10); // Reserved
213};
214static_assert(sizeof(NodeInfo) == 0x40, "NodeInfo is an invalid size");
215
216struct LdnNetworkInfo {
217 std::array<u8, 0x10> security_parameter;
218 SecurityMode security_mode;
219 AcceptPolicy station_accept_policy;
220 u8 has_action_frame;
221 INSERT_PADDING_BYTES(0x2); // Padding
222 u8 node_count_max;
223 u8 node_count;
224 std::array<NodeInfo, NodeCountMax> nodes;
225 INSERT_PADDING_BYTES(0x2); // Reserved
226 u16 advertise_data_size;
227 std::array<u8, AdvertiseDataSizeMax> advertise_data;
228 INSERT_PADDING_BYTES(0x8C); // Reserved
229 u64 random_authentication_id;
230};
231static_assert(sizeof(LdnNetworkInfo) == 0x430, "LdnNetworkInfo is an invalid size");
232
233struct NetworkInfo {
234 NetworkId network_id;
235 CommonNetworkInfo common;
236 LdnNetworkInfo ldn;
237};
238static_assert(sizeof(NetworkInfo) == 0x480, "NetworkInfo is an invalid size");
239
240struct SecurityConfig {
241 SecurityMode security_mode;
242 u16 passphrase_size;
243 std::array<u8, PassphraseLengthMax> passphrase;
244};
245static_assert(sizeof(SecurityConfig) == 0x44, "SecurityConfig is an invalid size");
246
247struct UserConfig {
248 std::array<u8, UserNameBytesMax + 1> user_name;
249 INSERT_PADDING_BYTES(0xF); // Reserved
250};
251static_assert(sizeof(UserConfig) == 0x30, "UserConfig is an invalid size");
252
253#pragma pack(push, 4)
254struct ConnectRequest {
255 SecurityConfig security_config;
256 UserConfig user_config;
257 u32 local_communication_version;
258 u32 option_unknown;
259 NetworkInfo network_info;
260};
261static_assert(sizeof(ConnectRequest) == 0x4FC, "ConnectRequest is an invalid size");
262#pragma pack(pop)
263
264struct SecurityParameter {
265 std::array<u8, 0x10> data; // Data, used with the same key derivation as SecurityConfig
266 SessionId session_id;
267};
268static_assert(sizeof(SecurityParameter) == 0x20, "SecurityParameter is an invalid size");
269
270struct NetworkConfig {
271 IntentId intent_id;
272 WifiChannel channel;
273 u8 node_count_max;
274 INSERT_PADDING_BYTES(0x1); // Reserved
275 u16 local_communication_version;
276 INSERT_PADDING_BYTES(0xA); // Reserved
277};
278static_assert(sizeof(NetworkConfig) == 0x20, "NetworkConfig is an invalid size");
279
280struct AddressEntry {
281 Ipv4Address ipv4_address;
282 MacAddress mac_address;
283 INSERT_PADDING_BYTES(0x2); // Reserved
284};
285static_assert(sizeof(AddressEntry) == 0xC, "AddressEntry is an invalid size");
286
287struct AddressList {
288 std::array<AddressEntry, 0x8> addresses;
289};
290static_assert(sizeof(AddressList) == 0x60, "AddressList is an invalid size");
291
292} // namespace Service::LDN
diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp
index 5ebb124a7..ba8c0e230 100644
--- a/src/core/hle/service/mm/mm_u.cpp
+++ b/src/core/hle/service/mm/mm_u.cpp
@@ -46,7 +46,7 @@ private:
46 IPC::RequestParser rp{ctx}; 46 IPC::RequestParser rp{ctx};
47 min = rp.Pop<u32>(); 47 min = rp.Pop<u32>();
48 max = rp.Pop<u32>(); 48 max = rp.Pop<u32>();
49 LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max); 49 LOG_DEBUG(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max);
50 50
51 current = min; 51 current = min;
52 IPC::ResponseBuilder rb{ctx, 2}; 52 IPC::ResponseBuilder rb{ctx, 2};
@@ -54,7 +54,7 @@ private:
54 } 54 }
55 55
56 void GetOld(Kernel::HLERequestContext& ctx) { 56 void GetOld(Kernel::HLERequestContext& ctx) {
57 LOG_WARNING(Service_MM, "(STUBBED) called"); 57 LOG_DEBUG(Service_MM, "(STUBBED) called");
58 58
59 IPC::ResponseBuilder rb{ctx, 3}; 59 IPC::ResponseBuilder rb{ctx, 3};
60 rb.Push(ResultSuccess); 60 rb.Push(ResultSuccess);
@@ -81,8 +81,8 @@ private:
81 u32 input_id = rp.Pop<u32>(); 81 u32 input_id = rp.Pop<u32>();
82 min = rp.Pop<u32>(); 82 min = rp.Pop<u32>();
83 max = rp.Pop<u32>(); 83 max = rp.Pop<u32>();
84 LOG_WARNING(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}", 84 LOG_DEBUG(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}", input_id,
85 input_id, min, max); 85 min, max);
86 86
87 current = min; 87 current = min;
88 IPC::ResponseBuilder rb{ctx, 2}; 88 IPC::ResponseBuilder rb{ctx, 2};
@@ -90,7 +90,7 @@ private:
90 } 90 }
91 91
92 void Get(Kernel::HLERequestContext& ctx) { 92 void Get(Kernel::HLERequestContext& ctx) {
93 LOG_WARNING(Service_MM, "(STUBBED) called"); 93 LOG_DEBUG(Service_MM, "(STUBBED) called");
94 94
95 IPC::ResponseBuilder rb{ctx, 3}; 95 IPC::ResponseBuilder rb{ctx, 3};
96 rb.Push(ResultSuccess); 96 rb.Push(ResultSuccess);
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 2889973e4..e3ef06481 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -6,7 +6,6 @@
6#include "core/hle/kernel/k_event.h" 6#include "core/hle/kernel/k_event.h"
7#include "core/hle/service/kernel_helpers.h" 7#include "core/hle/service/kernel_helpers.h"
8#include "core/hle/service/nifm/nifm.h" 8#include "core/hle/service/nifm/nifm.h"
9#include "core/hle/service/service.h"
10 9
11namespace { 10namespace {
12 11
@@ -271,213 +270,228 @@ public:
271 } 270 }
272}; 271};
273 272
274class IGeneralService final : public ServiceFramework<IGeneralService> { 273void IGeneralService::GetClientId(Kernel::HLERequestContext& ctx) {
275public: 274 static constexpr u32 client_id = 1;
276 explicit IGeneralService(Core::System& system_); 275 LOG_WARNING(Service_NIFM, "(STUBBED) called");
277 276
278private: 277 IPC::ResponseBuilder rb{ctx, 4};
279 void GetClientId(Kernel::HLERequestContext& ctx) { 278 rb.Push(ResultSuccess);
280 static constexpr u32 client_id = 1; 279 rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid
281 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 280}
282 281
283 IPC::ResponseBuilder rb{ctx, 4}; 282void IGeneralService::CreateScanRequest(Kernel::HLERequestContext& ctx) {
284 rb.Push(ResultSuccess); 283 LOG_DEBUG(Service_NIFM, "called");
285 rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid
286 }
287 284
288 void CreateScanRequest(Kernel::HLERequestContext& ctx) { 285 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
289 LOG_DEBUG(Service_NIFM, "called");
290 286
291 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 287 rb.Push(ResultSuccess);
288 rb.PushIpcInterface<IScanRequest>(system);
289}
292 290
293 rb.Push(ResultSuccess); 291void IGeneralService::CreateRequest(Kernel::HLERequestContext& ctx) {
294 rb.PushIpcInterface<IScanRequest>(system); 292 LOG_DEBUG(Service_NIFM, "called");
295 }
296 293
297 void CreateRequest(Kernel::HLERequestContext& ctx) { 294 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
298 LOG_DEBUG(Service_NIFM, "called");
299 295
300 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 296 rb.Push(ResultSuccess);
297 rb.PushIpcInterface<IRequest>(system);
298}
301 299
302 rb.Push(ResultSuccess); 300void IGeneralService::GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) {
303 rb.PushIpcInterface<IRequest>(system); 301 LOG_WARNING(Service_NIFM, "(STUBBED) called");
304 }
305 302
306 void GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) { 303 const auto net_iface = Network::GetSelectedNetworkInterface();
307 LOG_WARNING(Service_NIFM, "(STUBBED) called");
308 304
309 const auto net_iface = Network::GetSelectedNetworkInterface(); 305 SfNetworkProfileData network_profile_data = [&net_iface] {
310 306 if (!net_iface) {
311 const SfNetworkProfileData network_profile_data = [&net_iface] { 307 return SfNetworkProfileData{};
312 if (!net_iface) { 308 }
313 return SfNetworkProfileData{}; 309
314 } 310 return SfNetworkProfileData{
315 311 .ip_setting_data{
316 return SfNetworkProfileData{ 312 .ip_address_setting{
317 .ip_setting_data{ 313 .is_automatic{true},
318 .ip_address_setting{ 314 .current_address{Network::TranslateIPv4(net_iface->ip_address)},
319 .is_automatic{true}, 315 .subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)},
320 .current_address{Network::TranslateIPv4(net_iface->ip_address)}, 316 .gateway{Network::TranslateIPv4(net_iface->gateway)},
321 .subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)},
322 .gateway{Network::TranslateIPv4(net_iface->gateway)},
323 },
324 .dns_setting{
325 .is_automatic{true},
326 .primary_dns{1, 1, 1, 1},
327 .secondary_dns{1, 0, 0, 1},
328 },
329 .proxy_setting{
330 .enabled{false},
331 .port{},
332 .proxy_server{},
333 .automatic_auth_enabled{},
334 .user{},
335 .password{},
336 },
337 .mtu{1500},
338 }, 317 },
339 .uuid{0xdeadbeef, 0xdeadbeef}, 318 .dns_setting{
340 .network_name{"yuzu Network"}, 319 .is_automatic{true},
341 .wireless_setting_data{ 320 .primary_dns{1, 1, 1, 1},
342 .ssid_length{12}, 321 .secondary_dns{1, 0, 0, 1},
343 .ssid{"yuzu Network"},
344 .passphrase{"yuzupassword"},
345 }, 322 },
346 }; 323 .proxy_setting{
347 }(); 324 .enabled{false},
348 325 .port{},
349 ctx.WriteBuffer(network_profile_data); 326 .proxy_server{},
327 .automatic_auth_enabled{},
328 .user{},
329 .password{},
330 },
331 .mtu{1500},
332 },
333 .uuid{0xdeadbeef, 0xdeadbeef},
334 .network_name{"yuzu Network"},
335 .wireless_setting_data{
336 .ssid_length{12},
337 .ssid{"yuzu Network"},
338 .passphrase{"yuzupassword"},
339 },
340 };
341 }();
350 342
351 IPC::ResponseBuilder rb{ctx, 2}; 343 // When we're connected to a room, spoof the hosts IP address
352 rb.Push(ResultSuccess); 344 if (auto room_member = network.GetRoomMember().lock()) {
345 if (room_member->IsConnected()) {
346 network_profile_data.ip_setting_data.ip_address_setting.current_address =
347 room_member->GetFakeIpAddress();
348 }
353 } 349 }
354 350
355 void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { 351 ctx.WriteBuffer(network_profile_data);
356 LOG_WARNING(Service_NIFM, "(STUBBED) called");
357 352
358 IPC::ResponseBuilder rb{ctx, 2}; 353 IPC::ResponseBuilder rb{ctx, 2};
359 rb.Push(ResultSuccess); 354 rb.Push(ResultSuccess);
360 } 355}
361 356
362 void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) { 357void IGeneralService::RemoveNetworkProfile(Kernel::HLERequestContext& ctx) {
363 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 358 LOG_WARNING(Service_NIFM, "(STUBBED) called");
364 359
365 auto ipv4 = Network::GetHostIPv4Address(); 360 IPC::ResponseBuilder rb{ctx, 2};
366 if (!ipv4) { 361 rb.Push(ResultSuccess);
367 LOG_ERROR(Service_NIFM, "Couldn't get host IPv4 address, defaulting to 0.0.0.0"); 362}
368 ipv4.emplace(Network::IPv4Address{0, 0, 0, 0});
369 }
370 363
371 IPC::ResponseBuilder rb{ctx, 3}; 364void IGeneralService::GetCurrentIpAddress(Kernel::HLERequestContext& ctx) {
372 rb.Push(ResultSuccess); 365 LOG_WARNING(Service_NIFM, "(STUBBED) called");
373 rb.PushRaw(*ipv4); 366
367 auto ipv4 = Network::GetHostIPv4Address();
368 if (!ipv4) {
369 LOG_ERROR(Service_NIFM, "Couldn't get host IPv4 address, defaulting to 0.0.0.0");
370 ipv4.emplace(Network::IPv4Address{0, 0, 0, 0});
374 } 371 }
375 372
376 void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { 373 // When we're connected to a room, spoof the hosts IP address
377 LOG_DEBUG(Service_NIFM, "called"); 374 if (auto room_member = network.GetRoomMember().lock()) {
375 if (room_member->IsConnected()) {
376 ipv4 = room_member->GetFakeIpAddress();
377 }
378 }
378 379
379 ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, 380 IPC::ResponseBuilder rb{ctx, 3};
380 "SfNetworkProfileData is not the correct size"); 381 rb.Push(ResultSuccess);
381 u128 uuid{}; 382 rb.PushRaw(*ipv4);
382 auto buffer = ctx.ReadBuffer(); 383}
383 std::memcpy(&uuid, buffer.data() + 8, sizeof(u128));
384 384
385 IPC::ResponseBuilder rb{ctx, 6, 0, 1}; 385void IGeneralService::CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
386 LOG_DEBUG(Service_NIFM, "called");
386 387
387 rb.Push(ResultSuccess); 388 ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, "SfNetworkProfileData is not the correct size");
388 rb.PushIpcInterface<INetworkProfile>(system); 389 u128 uuid{};
389 rb.PushRaw<u128>(uuid); 390 auto buffer = ctx.ReadBuffer();
390 } 391 std::memcpy(&uuid, buffer.data() + 8, sizeof(u128));
391 392
392 void GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) { 393 IPC::ResponseBuilder rb{ctx, 6, 0, 1};
393 LOG_WARNING(Service_NIFM, "(STUBBED) called");
394 394
395 struct IpConfigInfo { 395 rb.Push(ResultSuccess);
396 IpAddressSetting ip_address_setting{}; 396 rb.PushIpcInterface<INetworkProfile>(system);
397 DnsSetting dns_setting{}; 397 rb.PushRaw<u128>(uuid);
398 }; 398}
399 static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting),
400 "IpConfigInfo has incorrect size.");
401 399
402 const auto net_iface = Network::GetSelectedNetworkInterface(); 400void IGeneralService::GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) {
401 LOG_WARNING(Service_NIFM, "(STUBBED) called");
403 402
404 const IpConfigInfo ip_config_info = [&net_iface] { 403 struct IpConfigInfo {
405 if (!net_iface) { 404 IpAddressSetting ip_address_setting{};
406 return IpConfigInfo{}; 405 DnsSetting dns_setting{};
407 } 406 };
407 static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting),
408 "IpConfigInfo has incorrect size.");
408 409
409 return IpConfigInfo{ 410 const auto net_iface = Network::GetSelectedNetworkInterface();
410 .ip_address_setting{
411 .is_automatic{true},
412 .current_address{Network::TranslateIPv4(net_iface->ip_address)},
413 .subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)},
414 .gateway{Network::TranslateIPv4(net_iface->gateway)},
415 },
416 .dns_setting{
417 .is_automatic{true},
418 .primary_dns{1, 1, 1, 1},
419 .secondary_dns{1, 0, 0, 1},
420 },
421 };
422 }();
423 411
424 IPC::ResponseBuilder rb{ctx, 2 + (sizeof(IpConfigInfo) + 3) / sizeof(u32)}; 412 IpConfigInfo ip_config_info = [&net_iface] {
425 rb.Push(ResultSuccess); 413 if (!net_iface) {
426 rb.PushRaw<IpConfigInfo>(ip_config_info); 414 return IpConfigInfo{};
427 } 415 }
428 416
429 void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) { 417 return IpConfigInfo{
430 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 418 .ip_address_setting{
419 .is_automatic{true},
420 .current_address{Network::TranslateIPv4(net_iface->ip_address)},
421 .subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)},
422 .gateway{Network::TranslateIPv4(net_iface->gateway)},
423 },
424 .dns_setting{
425 .is_automatic{true},
426 .primary_dns{1, 1, 1, 1},
427 .secondary_dns{1, 0, 0, 1},
428 },
429 };
430 }();
431 431
432 IPC::ResponseBuilder rb{ctx, 3}; 432 // When we're connected to a room, spoof the hosts IP address
433 rb.Push(ResultSuccess); 433 if (auto room_member = network.GetRoomMember().lock()) {
434 rb.Push<u8>(0); 434 if (room_member->IsConnected()) {
435 ip_config_info.ip_address_setting.current_address = room_member->GetFakeIpAddress();
436 }
435 } 437 }
436 438
437 void GetInternetConnectionStatus(Kernel::HLERequestContext& ctx) { 439 IPC::ResponseBuilder rb{ctx, 2 + (sizeof(IpConfigInfo) + 3) / sizeof(u32)};
438 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 440 rb.Push(ResultSuccess);
441 rb.PushRaw<IpConfigInfo>(ip_config_info);
442}
439 443
440 struct Output { 444void IGeneralService::IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) {
441 InternetConnectionType type{InternetConnectionType::WiFi}; 445 LOG_WARNING(Service_NIFM, "(STUBBED) called");
442 u8 wifi_strength{3};
443 InternetConnectionStatus state{InternetConnectionStatus::Connected};
444 };
445 static_assert(sizeof(Output) == 0x3, "Output has incorrect size.");
446 446
447 constexpr Output out{}; 447 IPC::ResponseBuilder rb{ctx, 3};
448 rb.Push(ResultSuccess);
449 rb.Push<u8>(1);
450}
448 451
449 IPC::ResponseBuilder rb{ctx, 3}; 452void IGeneralService::GetInternetConnectionStatus(Kernel::HLERequestContext& ctx) {
450 rb.Push(ResultSuccess); 453 LOG_WARNING(Service_NIFM, "(STUBBED) called");
451 rb.PushRaw(out);
452 }
453 454
454 void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) { 455 struct Output {
455 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 456 InternetConnectionType type{InternetConnectionType::WiFi};
457 u8 wifi_strength{3};
458 InternetConnectionStatus state{InternetConnectionStatus::Connected};
459 };
460 static_assert(sizeof(Output) == 0x3, "Output has incorrect size.");
456 461
457 IPC::ResponseBuilder rb{ctx, 3}; 462 constexpr Output out{};
458 rb.Push(ResultSuccess); 463
459 if (Network::GetHostIPv4Address().has_value()) { 464 IPC::ResponseBuilder rb{ctx, 3};
460 rb.Push<u8>(1); 465 rb.Push(ResultSuccess);
461 } else { 466 rb.PushRaw(out);
462 rb.Push<u8>(0); 467}
463 } 468
469void IGeneralService::IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) {
470 LOG_WARNING(Service_NIFM, "(STUBBED) called");
471
472 IPC::ResponseBuilder rb{ctx, 3};
473 rb.Push(ResultSuccess);
474 if (Network::GetHostIPv4Address().has_value()) {
475 rb.Push<u8>(1);
476 } else {
477 rb.Push<u8>(0);
464 } 478 }
479}
465 480
466 void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) { 481void IGeneralService::IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
467 LOG_WARNING(Service_NIFM, "(STUBBED) called"); 482 LOG_ERROR(Service_NIFM, "(STUBBED) called");
468 483
469 IPC::ResponseBuilder rb{ctx, 3}; 484 IPC::ResponseBuilder rb{ctx, 3};
470 rb.Push(ResultSuccess); 485 rb.Push(ResultSuccess);
471 if (Network::GetHostIPv4Address().has_value()) { 486 if (Network::GetHostIPv4Address().has_value()) {
472 rb.Push<u8>(1); 487 rb.Push<u8>(1);
473 } else { 488 } else {
474 rb.Push<u8>(0); 489 rb.Push<u8>(0);
475 }
476 } 490 }
477}; 491}
478 492
479IGeneralService::IGeneralService(Core::System& system_) 493IGeneralService::IGeneralService(Core::System& system_)
480 : ServiceFramework{system_, "IGeneralService"} { 494 : ServiceFramework{system_, "IGeneralService"}, network{system_.GetRoomNetwork()} {
481 // clang-format off 495 // clang-format off
482 static const FunctionInfo functions[] = { 496 static const FunctionInfo functions[] = {
483 {1, &IGeneralService::GetClientId, "GetClientId"}, 497 {1, &IGeneralService::GetClientId, "GetClientId"},
@@ -528,6 +542,8 @@ IGeneralService::IGeneralService(Core::System& system_)
528 RegisterHandlers(functions); 542 RegisterHandlers(functions);
529} 543}
530 544
545IGeneralService::~IGeneralService() = default;
546
531class NetworkInterface final : public ServiceFramework<NetworkInterface> { 547class NetworkInterface final : public ServiceFramework<NetworkInterface> {
532public: 548public:
533 explicit NetworkInterface(const char* name, Core::System& system_) 549 explicit NetworkInterface(const char* name, Core::System& system_)
diff --git a/src/core/hle/service/nifm/nifm.h b/src/core/hle/service/nifm/nifm.h
index 5f62d0014..48161be28 100644
--- a/src/core/hle/service/nifm/nifm.h
+++ b/src/core/hle/service/nifm/nifm.h
@@ -3,6 +3,11 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/service/service.h"
7#include "network/network.h"
8#include "network/room.h"
9#include "network/room_member.h"
10
6namespace Core { 11namespace Core {
7class System; 12class System;
8} 13}
@@ -16,4 +21,26 @@ namespace Service::NIFM {
16/// Registers all NIFM services with the specified service manager. 21/// Registers all NIFM services with the specified service manager.
17void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); 22void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
18 23
24class IGeneralService final : public ServiceFramework<IGeneralService> {
25public:
26 explicit IGeneralService(Core::System& system_);
27 ~IGeneralService() override;
28
29private:
30 void GetClientId(Kernel::HLERequestContext& ctx);
31 void CreateScanRequest(Kernel::HLERequestContext& ctx);
32 void CreateRequest(Kernel::HLERequestContext& ctx);
33 void GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx);
34 void RemoveNetworkProfile(Kernel::HLERequestContext& ctx);
35 void GetCurrentIpAddress(Kernel::HLERequestContext& ctx);
36 void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx);
37 void GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx);
38 void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx);
39 void GetInternetConnectionStatus(Kernel::HLERequestContext& ctx);
40 void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx);
41 void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx);
42
43 Network::RoomNetwork& network;
44};
45
19} // namespace Service::NIFM 46} // namespace Service::NIFM
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/iplatform_service_manager.cpp
index cc11f3e08..fd047ff26 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/iplatform_service_manager.cpp
@@ -20,7 +20,7 @@
20#include "core/hle/kernel/kernel.h" 20#include "core/hle/kernel/kernel.h"
21#include "core/hle/kernel/physical_memory.h" 21#include "core/hle/kernel/physical_memory.h"
22#include "core/hle/service/filesystem/filesystem.h" 22#include "core/hle/service/filesystem/filesystem.h"
23#include "core/hle/service/ns/pl_u.h" 23#include "core/hle/service/ns/iplatform_service_manager.h"
24 24
25namespace Service::NS { 25namespace Service::NS {
26 26
@@ -99,7 +99,7 @@ static u32 GetU32Swapped(const u8* data) {
99 return Common::swap32(value); 99 return Common::swap32(value);
100} 100}
101 101
102struct PL_U::Impl { 102struct IPlatformServiceManager::Impl {
103 const FontRegion& GetSharedFontRegion(std::size_t index) const { 103 const FontRegion& GetSharedFontRegion(std::size_t index) const {
104 if (index >= shared_font_regions.size() || shared_font_regions.empty()) { 104 if (index >= shared_font_regions.size() || shared_font_regions.empty()) {
105 // No font fallback 105 // No font fallback
@@ -134,16 +134,16 @@ struct PL_U::Impl {
134 std::vector<FontRegion> shared_font_regions; 134 std::vector<FontRegion> shared_font_regions;
135}; 135};
136 136
137PL_U::PL_U(Core::System& system_) 137IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const char* service_name_)
138 : ServiceFramework{system_, "pl:u"}, impl{std::make_unique<Impl>()} { 138 : ServiceFramework{system_, service_name_}, impl{std::make_unique<Impl>()} {
139 // clang-format off 139 // clang-format off
140 static const FunctionInfo functions[] = { 140 static const FunctionInfo functions[] = {
141 {0, &PL_U::RequestLoad, "RequestLoad"}, 141 {0, &IPlatformServiceManager::RequestLoad, "RequestLoad"},
142 {1, &PL_U::GetLoadState, "GetLoadState"}, 142 {1, &IPlatformServiceManager::GetLoadState, "GetLoadState"},
143 {2, &PL_U::GetSize, "GetSize"}, 143 {2, &IPlatformServiceManager::GetSize, "GetSize"},
144 {3, &PL_U::GetSharedMemoryAddressOffset, "GetSharedMemoryAddressOffset"}, 144 {3, &IPlatformServiceManager::GetSharedMemoryAddressOffset, "GetSharedMemoryAddressOffset"},
145 {4, &PL_U::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}, 145 {4, &IPlatformServiceManager::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"},
146 {5, &PL_U::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"}, 146 {5, &IPlatformServiceManager::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"},
147 {6, nullptr, "GetSharedFontInOrderOfPriorityForSystem"}, 147 {6, nullptr, "GetSharedFontInOrderOfPriorityForSystem"},
148 {100, nullptr, "RequestApplicationFunctionAuthorization"}, 148 {100, nullptr, "RequestApplicationFunctionAuthorization"},
149 {101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"}, 149 {101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"},
@@ -206,9 +206,9 @@ PL_U::PL_U(Core::System& system_)
206 } 206 }
207} 207}
208 208
209PL_U::~PL_U() = default; 209IPlatformServiceManager::~IPlatformServiceManager() = default;
210 210
211void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) { 211void IPlatformServiceManager::RequestLoad(Kernel::HLERequestContext& ctx) {
212 IPC::RequestParser rp{ctx}; 212 IPC::RequestParser rp{ctx};
213 const u32 shared_font_type{rp.Pop<u32>()}; 213 const u32 shared_font_type{rp.Pop<u32>()};
214 // Games don't call this so all fonts should be loaded 214 // Games don't call this so all fonts should be loaded
@@ -218,7 +218,7 @@ void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) {
218 rb.Push(ResultSuccess); 218 rb.Push(ResultSuccess);
219} 219}
220 220
221void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) { 221void IPlatformServiceManager::GetLoadState(Kernel::HLERequestContext& ctx) {
222 IPC::RequestParser rp{ctx}; 222 IPC::RequestParser rp{ctx};
223 const u32 font_id{rp.Pop<u32>()}; 223 const u32 font_id{rp.Pop<u32>()};
224 LOG_DEBUG(Service_NS, "called, font_id={}", font_id); 224 LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
@@ -228,7 +228,7 @@ void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) {
228 rb.Push<u32>(static_cast<u32>(LoadState::Done)); 228 rb.Push<u32>(static_cast<u32>(LoadState::Done));
229} 229}
230 230
231void PL_U::GetSize(Kernel::HLERequestContext& ctx) { 231void IPlatformServiceManager::GetSize(Kernel::HLERequestContext& ctx) {
232 IPC::RequestParser rp{ctx}; 232 IPC::RequestParser rp{ctx};
233 const u32 font_id{rp.Pop<u32>()}; 233 const u32 font_id{rp.Pop<u32>()};
234 LOG_DEBUG(Service_NS, "called, font_id={}", font_id); 234 LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
@@ -238,7 +238,7 @@ void PL_U::GetSize(Kernel::HLERequestContext& ctx) {
238 rb.Push<u32>(impl->GetSharedFontRegion(font_id).size); 238 rb.Push<u32>(impl->GetSharedFontRegion(font_id).size);
239} 239}
240 240
241void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { 241void IPlatformServiceManager::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
242 IPC::RequestParser rp{ctx}; 242 IPC::RequestParser rp{ctx};
243 const u32 font_id{rp.Pop<u32>()}; 243 const u32 font_id{rp.Pop<u32>()};
244 LOG_DEBUG(Service_NS, "called, font_id={}", font_id); 244 LOG_DEBUG(Service_NS, "called, font_id={}", font_id);
@@ -248,7 +248,7 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) {
248 rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset); 248 rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset);
249} 249}
250 250
251void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { 251void IPlatformServiceManager::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
252 // Map backing memory for the font data 252 // Map backing memory for the font data
253 LOG_DEBUG(Service_NS, "called"); 253 LOG_DEBUG(Service_NS, "called");
254 254
@@ -261,7 +261,7 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
261 rb.PushCopyObjects(&kernel.GetFontSharedMem()); 261 rb.PushCopyObjects(&kernel.GetFontSharedMem());
262} 262}
263 263
264void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) { 264void IPlatformServiceManager::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) {
265 IPC::RequestParser rp{ctx}; 265 IPC::RequestParser rp{ctx};
266 const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for 266 const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for
267 LOG_DEBUG(Service_NS, "called, language_code={:X}", language_code); 267 LOG_DEBUG(Service_NS, "called, language_code={:X}", language_code);
diff --git a/src/core/hle/service/ns/pl_u.h b/src/core/hle/service/ns/iplatform_service_manager.h
index 07d0ac934..ed6eda89f 100644
--- a/src/core/hle/service/ns/pl_u.h
+++ b/src/core/hle/service/ns/iplatform_service_manager.h
@@ -36,10 +36,10 @@ constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{
36void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output); 36void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output);
37void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, std::size_t& offset); 37void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, std::size_t& offset);
38 38
39class PL_U final : public ServiceFramework<PL_U> { 39class IPlatformServiceManager final : public ServiceFramework<IPlatformServiceManager> {
40public: 40public:
41 explicit PL_U(Core::System& system_); 41 explicit IPlatformServiceManager(Core::System& system_, const char* service_name_);
42 ~PL_U() override; 42 ~IPlatformServiceManager() override;
43 43
44private: 44private:
45 void RequestLoad(Kernel::HLERequestContext& ctx); 45 void RequestLoad(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index aafc8fe03..f7318c3cb 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -9,10 +9,10 @@
9#include "core/file_sys/vfs.h" 9#include "core/file_sys/vfs.h"
10#include "core/hle/ipc_helpers.h" 10#include "core/hle/ipc_helpers.h"
11#include "core/hle/service/ns/errors.h" 11#include "core/hle/service/ns/errors.h"
12#include "core/hle/service/ns/iplatform_service_manager.h"
12#include "core/hle/service/ns/language.h" 13#include "core/hle/service/ns/language.h"
13#include "core/hle/service/ns/ns.h" 14#include "core/hle/service/ns/ns.h"
14#include "core/hle/service/ns/pdm_qry.h" 15#include "core/hle/service/ns/pdm_qry.h"
15#include "core/hle/service/ns/pl_u.h"
16#include "core/hle/service/set/set.h" 16#include "core/hle/service/set/set.h"
17 17
18namespace Service::NS { 18namespace Service::NS {
@@ -764,7 +764,8 @@ void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system
764 764
765 std::make_shared<PDM_QRY>(system)->InstallAsService(service_manager); 765 std::make_shared<PDM_QRY>(system)->InstallAsService(service_manager);
766 766
767 std::make_shared<PL_U>(system)->InstallAsService(service_manager); 767 std::make_shared<IPlatformServiceManager>(system, "pl:s")->InstallAsService(service_manager);
768 std::make_shared<IPlatformServiceManager>(system, "pl:u")->InstallAsService(service_manager);
768} 769}
769 770
770} // namespace Service::NS 771} // namespace Service::NS
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index 2a5128c60..a7385fce8 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -1,6 +1,7 @@
1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "audio_core/audio_core.h"
4#include "common/assert.h" 5#include "common/assert.h"
5#include "common/logging/log.h" 6#include "common/logging/log.h"
6#include "core/core.h" 7#include "core/core.h"
@@ -65,7 +66,10 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>&
65 return NvResult::NotImplemented; 66 return NvResult::NotImplemented;
66} 67}
67 68
68void nvhost_nvdec::OnOpen(DeviceFD fd) {} 69void nvhost_nvdec::OnOpen(DeviceFD fd) {
70 LOG_INFO(Service_NVDRV, "NVDEC video stream started");
71 system.AudioCore().SetNVDECActive(true);
72}
69 73
70void nvhost_nvdec::OnClose(DeviceFD fd) { 74void nvhost_nvdec::OnClose(DeviceFD fd) {
71 LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); 75 LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
@@ -73,6 +77,7 @@ void nvhost_nvdec::OnClose(DeviceFD fd) {
73 if (iter != fd_to_id.end()) { 77 if (iter != fd_to_id.end()) {
74 system.GPU().ClearCdmaInstance(iter->second); 78 system.GPU().ClearCdmaInstance(iter->second);
75 } 79 }
80 system.AudioCore().SetNVDECActive(false);
76} 81}
77 82
78} // namespace Service::Nvidia::Devices 83} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index 728bfa00b..d8518149d 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -198,7 +198,7 @@ NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output)
198 IocParamParams params; 198 IocParamParams params;
199 std::memcpy(&params, input.data(), sizeof(params)); 199 std::memcpy(&params, input.data(), sizeof(params));
200 200
201 LOG_WARNING(Service_NVDRV, "(STUBBED) called type={}", params.param); 201 LOG_DEBUG(Service_NVDRV, "(STUBBED) called type={}", params.param);
202 202
203 auto object = GetObject(params.handle); 203 auto object = GetObject(params.handle);
204 if (!object) { 204 if (!object) {
@@ -243,7 +243,7 @@ NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
243 IocFreeParams params; 243 IocFreeParams params;
244 std::memcpy(&params, input.data(), sizeof(params)); 244 std::memcpy(&params, input.data(), sizeof(params));
245 245
246 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 246 LOG_DEBUG(Service_NVDRV, "(STUBBED) called");
247 247
248 auto itr = handles.find(params.handle); 248 auto itr = handles.find(params.handle);
249 if (itr == handles.end()) { 249 if (itr == handles.end()) {
diff --git a/src/core/hle/service/pcv/pcv.cpp b/src/core/hle/service/pcv/pcv.cpp
index 0989474be..f7a497a14 100644
--- a/src/core/hle/service/pcv/pcv.cpp
+++ b/src/core/hle/service/pcv/pcv.cpp
@@ -3,6 +3,7 @@
3 3
4#include <memory> 4#include <memory>
5 5
6#include "core/hle/ipc_helpers.h"
6#include "core/hle/service/pcv/pcv.h" 7#include "core/hle/service/pcv/pcv.h"
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8#include "core/hle/service/sm/sm.h" 9#include "core/hle/service/sm/sm.h"
@@ -77,10 +78,102 @@ public:
77 } 78 }
78}; 79};
79 80
81class IClkrstSession final : public ServiceFramework<IClkrstSession> {
82public:
83 explicit IClkrstSession(Core::System& system_, DeviceCode deivce_code_)
84 : ServiceFramework{system_, "IClkrstSession"}, deivce_code(deivce_code_) {
85 // clang-format off
86 static const FunctionInfo functions[] = {
87 {0, nullptr, "SetClockEnabled"},
88 {1, nullptr, "SetClockDisabled"},
89 {2, nullptr, "SetResetAsserted"},
90 {3, nullptr, "SetResetDeasserted"},
91 {4, nullptr, "SetPowerEnabled"},
92 {5, nullptr, "SetPowerDisabled"},
93 {6, nullptr, "GetState"},
94 {7, &IClkrstSession::SetClockRate, "SetClockRate"},
95 {8, &IClkrstSession::GetClockRate, "GetClockRate"},
96 {9, nullptr, "SetMinVClockRate"},
97 {10, nullptr, "GetPossibleClockRates"},
98 {11, nullptr, "GetDvfsTable"},
99 };
100 // clang-format on
101 RegisterHandlers(functions);
102 }
103
104private:
105 void SetClockRate(Kernel::HLERequestContext& ctx) {
106 IPC::RequestParser rp{ctx};
107 clock_rate = rp.Pop<u32>();
108 LOG_DEBUG(Service_PCV, "(STUBBED) called, clock_rate={}", clock_rate);
109
110 IPC::ResponseBuilder rb{ctx, 2};
111 rb.Push(ResultSuccess);
112 }
113
114 void GetClockRate(Kernel::HLERequestContext& ctx) {
115 LOG_DEBUG(Service_PCV, "(STUBBED) called");
116
117 IPC::ResponseBuilder rb{ctx, 3};
118 rb.Push(ResultSuccess);
119 rb.Push<u32>(clock_rate);
120 }
121
122 DeviceCode deivce_code;
123 u32 clock_rate{};
124};
125
126class CLKRST final : public ServiceFramework<CLKRST> {
127public:
128 explicit CLKRST(Core::System& system_, const char* name) : ServiceFramework{system_, name} {
129 // clang-format off
130 static const FunctionInfo functions[] = {
131 {0, &CLKRST::OpenSession, "OpenSession"},
132 {1, nullptr, "GetTemperatureThresholds"},
133 {2, nullptr, "SetTemperature"},
134 {3, nullptr, "GetModuleStateTable"},
135 {4, nullptr, "GetModuleStateTableEvent"},
136 {5, nullptr, "GetModuleStateTableMaxCount"},
137 };
138 // clang-format on
139
140 RegisterHandlers(functions);
141 }
142
143private:
144 void OpenSession(Kernel::HLERequestContext& ctx) {
145 IPC::RequestParser rp{ctx};
146 const auto device_code = static_cast<DeviceCode>(rp.Pop<u32>());
147 const auto unkonwn_input = rp.Pop<u32>();
148
149 LOG_DEBUG(Service_PCV, "called, device_code={}, input={}", device_code, unkonwn_input);
150
151 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
152 rb.Push(ResultSuccess);
153 rb.PushIpcInterface<IClkrstSession>(system, device_code);
154 }
155};
156
157class CLKRST_A final : public ServiceFramework<CLKRST_A> {
158public:
159 explicit CLKRST_A(Core::System& system_) : ServiceFramework{system_, "clkrst:a"} {
160 // clang-format off
161 static const FunctionInfo functions[] = {
162 {0, nullptr, "ReleaseControl"},
163 };
164 // clang-format on
165
166 RegisterHandlers(functions);
167 }
168};
169
80void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { 170void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
81 std::make_shared<PCV>(system)->InstallAsService(sm); 171 std::make_shared<PCV>(system)->InstallAsService(sm);
82 std::make_shared<PCV_ARB>(system)->InstallAsService(sm); 172 std::make_shared<PCV_ARB>(system)->InstallAsService(sm);
83 std::make_shared<PCV_IMM>(system)->InstallAsService(sm); 173 std::make_shared<PCV_IMM>(system)->InstallAsService(sm);
174 std::make_shared<CLKRST>(system, "clkrst")->InstallAsService(sm);
175 std::make_shared<CLKRST>(system, "clkrst:i")->InstallAsService(sm);
176 std::make_shared<CLKRST_A>(system)->InstallAsService(sm);
84} 177}
85 178
86} // namespace Service::PCV 179} // namespace Service::PCV
diff --git a/src/core/hle/service/pcv/pcv.h b/src/core/hle/service/pcv/pcv.h
index a42e6f8f6..6b26b6fa7 100644
--- a/src/core/hle/service/pcv/pcv.h
+++ b/src/core/hle/service/pcv/pcv.h
@@ -13,6 +13,97 @@ class ServiceManager;
13 13
14namespace Service::PCV { 14namespace Service::PCV {
15 15
16enum class DeviceCode : u32 {
17 Cpu = 0x40000001,
18 Gpu = 0x40000002,
19 I2s1 = 0x40000003,
20 I2s2 = 0x40000004,
21 I2s3 = 0x40000005,
22 Pwm = 0x40000006,
23 I2c1 = 0x02000001,
24 I2c2 = 0x02000002,
25 I2c3 = 0x02000003,
26 I2c4 = 0x02000004,
27 I2c5 = 0x02000005,
28 I2c6 = 0x02000006,
29 Spi1 = 0x07000000,
30 Spi2 = 0x07000001,
31 Spi3 = 0x07000002,
32 Spi4 = 0x07000003,
33 Disp1 = 0x40000011,
34 Disp2 = 0x40000012,
35 Isp = 0x40000013,
36 Vi = 0x40000014,
37 Sdmmc1 = 0x40000015,
38 Sdmmc2 = 0x40000016,
39 Sdmmc3 = 0x40000017,
40 Sdmmc4 = 0x40000018,
41 Owr = 0x40000019,
42 Csite = 0x4000001A,
43 Tsec = 0x4000001B,
44 Mselect = 0x4000001C,
45 Hda2codec2x = 0x4000001D,
46 Actmon = 0x4000001E,
47 I2cSlow = 0x4000001F,
48 Sor1 = 0x40000020,
49 Sata = 0x40000021,
50 Hda = 0x40000022,
51 XusbCoreHostSrc = 0x40000023,
52 XusbFalconSrc = 0x40000024,
53 XusbFsSrc = 0x40000025,
54 XusbCoreDevSrc = 0x40000026,
55 XusbSsSrc = 0x40000027,
56 UartA = 0x03000001,
57 UartB = 0x35000405,
58 UartC = 0x3500040F,
59 UartD = 0x37000001,
60 Host1x = 0x4000002C,
61 Entropy = 0x4000002D,
62 SocTherm = 0x4000002E,
63 Vic = 0x4000002F,
64 Nvenc = 0x40000030,
65 Nvjpg = 0x40000031,
66 Nvdec = 0x40000032,
67 Qspi = 0x40000033,
68 ViI2c = 0x40000034,
69 Tsecb = 0x40000035,
70 Ape = 0x40000036,
71 AudioDsp = 0x40000037,
72 AudioUart = 0x40000038,
73 Emc = 0x40000039,
74 Plle = 0x4000003A,
75 PlleHwSeq = 0x4000003B,
76 Dsi = 0x4000003C,
77 Maud = 0x4000003D,
78 Dpaux1 = 0x4000003E,
79 MipiCal = 0x4000003F,
80 UartFstMipiCal = 0x40000040,
81 Osc = 0x40000041,
82 SysBus = 0x40000042,
83 SorSafe = 0x40000043,
84 XusbSs = 0x40000044,
85 XusbHost = 0x40000045,
86 XusbDevice = 0x40000046,
87 Extperiph1 = 0x40000047,
88 Ahub = 0x40000048,
89 Hda2hdmicodec = 0x40000049,
90 Gpuaux = 0x4000004A,
91 UsbD = 0x4000004B,
92 Usb2 = 0x4000004C,
93 Pcie = 0x4000004D,
94 Afi = 0x4000004E,
95 PciExClk = 0x4000004F,
96 PExUsbPhy = 0x40000050,
97 XUsbPadCtl = 0x40000051,
98 Apbdma = 0x40000052,
99 Usb2TrkClk = 0x40000053,
100 XUsbIoPll = 0x40000054,
101 XUsbIoPllHwSeq = 0x40000055,
102 Cec = 0x40000056,
103 Extperiph2 = 0x40000057,
104 OscClk = 0x40000080
105};
106
16void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); 107void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
17 108
18} // namespace Service::PCV 109} // namespace Service::PCV
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index c7194731e..cc679cc81 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -9,12 +9,16 @@
9#include <fmt/format.h> 9#include <fmt/format.h>
10 10
11#include "common/microprofile.h" 11#include "common/microprofile.h"
12#include "common/socket_types.h"
13#include "core/core.h"
12#include "core/hle/ipc_helpers.h" 14#include "core/hle/ipc_helpers.h"
13#include "core/hle/kernel/k_thread.h" 15#include "core/hle/kernel/k_thread.h"
14#include "core/hle/service/sockets/bsd.h" 16#include "core/hle/service/sockets/bsd.h"
15#include "core/hle/service/sockets/sockets_translate.h" 17#include "core/hle/service/sockets/sockets_translate.h"
16#include "core/internal_network/network.h" 18#include "core/internal_network/network.h"
19#include "core/internal_network/socket_proxy.h"
17#include "core/internal_network/sockets.h" 20#include "core/internal_network/sockets.h"
21#include "network/network.h"
18 22
19namespace Service::Sockets { 23namespace Service::Sockets {
20 24
@@ -472,7 +476,13 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco
472 476
473 LOG_INFO(Service, "New socket fd={}", fd); 477 LOG_INFO(Service, "New socket fd={}", fd);
474 478
475 descriptor.socket = std::make_unique<Network::Socket>(); 479 auto room_member = room_network.GetRoomMember().lock();
480 if (room_member && room_member->IsConnected()) {
481 descriptor.socket = std::make_unique<Network::ProxySocket>(room_network);
482 } else {
483 descriptor.socket = std::make_unique<Network::Socket>();
484 }
485
476 descriptor.socket->Initialize(Translate(domain), Translate(type), Translate(type, protocol)); 486 descriptor.socket->Initialize(Translate(domain), Translate(type), Translate(type, protocol));
477 descriptor.is_connection_based = IsConnectionBased(type); 487 descriptor.is_connection_based = IsConnectionBased(type);
478 488
@@ -648,7 +658,7 @@ std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
648 ASSERT(arg == 0); 658 ASSERT(arg == 0);
649 return {descriptor.flags, Errno::SUCCESS}; 659 return {descriptor.flags, Errno::SUCCESS};
650 case FcntlCmd::SETFL: { 660 case FcntlCmd::SETFL: {
651 const bool enable = (arg & FLAG_O_NONBLOCK) != 0; 661 const bool enable = (arg & Network::FLAG_O_NONBLOCK) != 0;
652 const Errno bsd_errno = Translate(descriptor.socket->SetNonBlock(enable)); 662 const Errno bsd_errno = Translate(descriptor.socket->SetNonBlock(enable));
653 if (bsd_errno != Errno::SUCCESS) { 663 if (bsd_errno != Errno::SUCCESS) {
654 return {-1, bsd_errno}; 664 return {-1, bsd_errno};
@@ -669,7 +679,7 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, con
669 return Errno::BADF; 679 return Errno::BADF;
670 } 680 }
671 681
672 Network::Socket* const socket = file_descriptors[fd]->socket.get(); 682 Network::SocketBase* const socket = file_descriptors[fd]->socket.get();
673 683
674 if (optname == OptName::LINGER) { 684 if (optname == OptName::LINGER) {
675 ASSERT(optlen == sizeof(Linger)); 685 ASSERT(optlen == sizeof(Linger));
@@ -724,6 +734,8 @@ std::pair<s32, Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message)
724 FileDescriptor& descriptor = *file_descriptors[fd]; 734 FileDescriptor& descriptor = *file_descriptors[fd];
725 735
726 // Apply flags 736 // Apply flags
737 using Network::FLAG_MSG_DONTWAIT;
738 using Network::FLAG_O_NONBLOCK;
727 if ((flags & FLAG_MSG_DONTWAIT) != 0) { 739 if ((flags & FLAG_MSG_DONTWAIT) != 0) {
728 flags &= ~FLAG_MSG_DONTWAIT; 740 flags &= ~FLAG_MSG_DONTWAIT;
729 if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) { 741 if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
@@ -759,6 +771,8 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess
759 } 771 }
760 772
761 // Apply flags 773 // Apply flags
774 using Network::FLAG_MSG_DONTWAIT;
775 using Network::FLAG_O_NONBLOCK;
762 if ((flags & FLAG_MSG_DONTWAIT) != 0) { 776 if ((flags & FLAG_MSG_DONTWAIT) != 0) {
763 flags &= ~FLAG_MSG_DONTWAIT; 777 flags &= ~FLAG_MSG_DONTWAIT;
764 if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) { 778 if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) {
@@ -857,8 +871,19 @@ void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) co
857 rb.PushEnum(bsd_errno); 871 rb.PushEnum(bsd_errno);
858} 872}
859 873
874void BSD::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
875 for (auto& optional_descriptor : file_descriptors) {
876 if (!optional_descriptor.has_value()) {
877 continue;
878 }
879 FileDescriptor& descriptor = *optional_descriptor;
880 descriptor.socket.get()->HandleProxyPacket(packet);
881 }
882}
883
860BSD::BSD(Core::System& system_, const char* name) 884BSD::BSD(Core::System& system_, const char* name)
861 : ServiceFramework{system_, name, ServiceThreadType::CreateNew} { 885 : ServiceFramework{system_, name, ServiceThreadType::CreateNew}, room_network{
886 system_.GetRoomNetwork()} {
862 // clang-format off 887 // clang-format off
863 static const FunctionInfo functions[] = { 888 static const FunctionInfo functions[] = {
864 {0, &BSD::RegisterClient, "RegisterClient"}, 889 {0, &BSD::RegisterClient, "RegisterClient"},
@@ -899,9 +924,20 @@ BSD::BSD(Core::System& system_, const char* name)
899 // clang-format on 924 // clang-format on
900 925
901 RegisterHandlers(functions); 926 RegisterHandlers(functions);
927
928 if (auto room_member = room_network.GetRoomMember().lock()) {
929 proxy_packet_received = room_member->BindOnProxyPacketReceived(
930 [this](const Network::ProxyPacket& packet) { OnProxyPacketReceived(packet); });
931 } else {
932 LOG_ERROR(Service, "Network isn't initalized");
933 }
902} 934}
903 935
904BSD::~BSD() = default; 936BSD::~BSD() {
937 if (auto room_member = room_network.GetRoomMember().lock()) {
938 room_member->Unbind(proxy_packet_received);
939 }
940}
905 941
906BSDCFG::BSDCFG(Core::System& system_) : ServiceFramework{system_, "bsdcfg"} { 942BSDCFG::BSDCFG(Core::System& system_) : ServiceFramework{system_, "bsdcfg"} {
907 // clang-format off 943 // clang-format off
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h
index 9ea36428d..81e855e0f 100644
--- a/src/core/hle/service/sockets/bsd.h
+++ b/src/core/hle/service/sockets/bsd.h
@@ -7,14 +7,17 @@
7#include <vector> 7#include <vector>
8 8
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/socket_types.h"
10#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
11#include "core/hle/service/sockets/sockets.h" 12#include "core/hle/service/sockets/sockets.h"
13#include "network/network.h"
12 14
13namespace Core { 15namespace Core {
14class System; 16class System;
15} 17}
16 18
17namespace Network { 19namespace Network {
20class SocketBase;
18class Socket; 21class Socket;
19} // namespace Network 22} // namespace Network
20 23
@@ -30,7 +33,7 @@ private:
30 static constexpr size_t MAX_FD = 128; 33 static constexpr size_t MAX_FD = 128;
31 34
32 struct FileDescriptor { 35 struct FileDescriptor {
33 std::unique_ptr<Network::Socket> socket; 36 std::unique_ptr<Network::SocketBase> socket;
34 s32 flags = 0; 37 s32 flags = 0;
35 bool is_connection_based = false; 38 bool is_connection_based = false;
36 }; 39 };
@@ -165,6 +168,14 @@ private:
165 void BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept; 168 void BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept;
166 169
167 std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors; 170 std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors;
171
172 Network::RoomNetwork& room_network;
173
174 /// Callback to parse and handle a received wifi packet.
175 void OnProxyPacketReceived(const Network::ProxyPacket& packet);
176
177 // Callback identifier for the OnProxyPacketReceived event.
178 Network::RoomMember::CallbackHandle<Network::ProxyPacket> proxy_packet_received;
168}; 179};
169 180
170class BSDCFG final : public ServiceFramework<BSDCFG> { 181class BSDCFG final : public ServiceFramework<BSDCFG> {
diff --git a/src/core/hle/service/sockets/sockets.h b/src/core/hle/service/sockets/sockets.h
index b735b00fc..31b7dad33 100644
--- a/src/core/hle/service/sockets/sockets.h
+++ b/src/core/hle/service/sockets/sockets.h
@@ -22,7 +22,9 @@ enum class Errno : u32 {
22 AGAIN = 11, 22 AGAIN = 11,
23 INVAL = 22, 23 INVAL = 22,
24 MFILE = 24, 24 MFILE = 24,
25 MSGSIZE = 90,
25 NOTCONN = 107, 26 NOTCONN = 107,
27 TIMEDOUT = 110,
26}; 28};
27 29
28enum class Domain : u32 { 30enum class Domain : u32 {
@@ -96,10 +98,6 @@ struct Linger {
96 u32 linger; 98 u32 linger;
97}; 99};
98 100
99constexpr u32 FLAG_MSG_DONTWAIT = 0x80;
100
101constexpr u32 FLAG_O_NONBLOCK = 0x800;
102
103/// Registers all Sockets services with the specified service manager. 101/// Registers all Sockets services with the specified service manager.
104void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); 102void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);
105 103
diff --git a/src/core/hle/service/sockets/sockets_translate.cpp b/src/core/hle/service/sockets/sockets_translate.cpp
index 2db10ec81..023aa0486 100644
--- a/src/core/hle/service/sockets/sockets_translate.cpp
+++ b/src/core/hle/service/sockets/sockets_translate.cpp
@@ -25,6 +25,8 @@ Errno Translate(Network::Errno value) {
25 return Errno::MFILE; 25 return Errno::MFILE;
26 case Network::Errno::NOTCONN: 26 case Network::Errno::NOTCONN:
27 return Errno::NOTCONN; 27 return Errno::NOTCONN;
28 case Network::Errno::TIMEDOUT:
29 return Errno::TIMEDOUT;
28 default: 30 default:
29 UNIMPLEMENTED_MSG("Unimplemented errno={}", value); 31 UNIMPLEMENTED_MSG("Unimplemented errno={}", value);
30 return Errno::SUCCESS; 32 return Errno::SUCCESS;
diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp
index 36c43cc8f..cdf38a2a4 100644
--- a/src/core/internal_network/network.cpp
+++ b/src/core/internal_network/network.cpp
@@ -32,6 +32,7 @@
32#include "core/internal_network/network.h" 32#include "core/internal_network/network.h"
33#include "core/internal_network/network_interface.h" 33#include "core/internal_network/network_interface.h"
34#include "core/internal_network/sockets.h" 34#include "core/internal_network/sockets.h"
35#include "network/network.h"
35 36
36namespace Network { 37namespace Network {
37 38
@@ -114,7 +115,10 @@ Errno TranslateNativeError(int e) {
114 return Errno::NETDOWN; 115 return Errno::NETDOWN;
115 case WSAENETUNREACH: 116 case WSAENETUNREACH:
116 return Errno::NETUNREACH; 117 return Errno::NETUNREACH;
118 case WSAEMSGSIZE:
119 return Errno::MSGSIZE;
117 default: 120 default:
121 UNIMPLEMENTED_MSG("Unimplemented errno={}", e);
118 return Errno::OTHER; 122 return Errno::OTHER;
119 } 123 }
120} 124}
@@ -125,7 +129,6 @@ using SOCKET = int;
125using WSAPOLLFD = pollfd; 129using WSAPOLLFD = pollfd;
126using ULONG = u64; 130using ULONG = u64;
127 131
128constexpr SOCKET INVALID_SOCKET = -1;
129constexpr SOCKET SOCKET_ERROR = -1; 132constexpr SOCKET SOCKET_ERROR = -1;
130 133
131constexpr int SD_RECEIVE = SHUT_RD; 134constexpr int SD_RECEIVE = SHUT_RD;
@@ -206,7 +209,10 @@ Errno TranslateNativeError(int e) {
206 return Errno::NETDOWN; 209 return Errno::NETDOWN;
207 case ENETUNREACH: 210 case ENETUNREACH:
208 return Errno::NETUNREACH; 211 return Errno::NETUNREACH;
212 case EMSGSIZE:
213 return Errno::MSGSIZE;
209 default: 214 default:
215 UNIMPLEMENTED_MSG("Unimplemented errno={}", e);
210 return Errno::OTHER; 216 return Errno::OTHER;
211 } 217 }
212} 218}
@@ -329,16 +335,6 @@ PollEvents TranslatePollRevents(short revents) {
329 return result; 335 return result;
330} 336}
331 337
332template <typename T>
333Errno SetSockOpt(SOCKET fd, int option, T value) {
334 const int result =
335 setsockopt(fd, SOL_SOCKET, option, reinterpret_cast<const char*>(&value), sizeof(value));
336 if (result != SOCKET_ERROR) {
337 return Errno::SUCCESS;
338 }
339 return GetAndLogLastError();
340}
341
342} // Anonymous namespace 338} // Anonymous namespace
343 339
344NetworkInstance::NetworkInstance() { 340NetworkInstance::NetworkInstance() {
@@ -350,26 +346,16 @@ NetworkInstance::~NetworkInstance() {
350} 346}
351 347
352std::optional<IPv4Address> GetHostIPv4Address() { 348std::optional<IPv4Address> GetHostIPv4Address() {
353 const std::string& selected_network_interface = Settings::values.network_interface.GetValue(); 349 const auto network_interface = Network::GetSelectedNetworkInterface();
354 const auto network_interfaces = Network::GetAvailableNetworkInterfaces(); 350 if (!network_interface.has_value()) {
355 if (network_interfaces.size() == 0) { 351 LOG_ERROR(Network, "GetSelectedNetworkInterface returned no interface");
356 LOG_ERROR(Network, "GetAvailableNetworkInterfaces returned no interfaces");
357 return {}; 352 return {};
358 } 353 }
359 354
360 const auto res = 355 std::array<char, 16> ip_addr = {};
361 std::ranges::find_if(network_interfaces, [&selected_network_interface](const auto& iface) { 356 ASSERT(inet_ntop(AF_INET, &network_interface->ip_address, ip_addr.data(), sizeof(ip_addr)) !=
362 return iface.name == selected_network_interface; 357 nullptr);
363 }); 358 return TranslateIPv4(network_interface->ip_address);
364
365 if (res != network_interfaces.end()) {
366 char ip_addr[16] = {};
367 ASSERT(inet_ntop(AF_INET, &res->ip_address, ip_addr, sizeof(ip_addr)) != nullptr);
368 return TranslateIPv4(res->ip_address);
369 } else {
370 LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface);
371 return {};
372 }
373} 359}
374 360
375std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) { 361std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) {
@@ -412,7 +398,19 @@ Socket::~Socket() {
412 fd = INVALID_SOCKET; 398 fd = INVALID_SOCKET;
413} 399}
414 400
415Socket::Socket(Socket&& rhs) noexcept : fd{std::exchange(rhs.fd, INVALID_SOCKET)} {} 401Socket::Socket(Socket&& rhs) noexcept {
402 fd = std::exchange(rhs.fd, INVALID_SOCKET);
403}
404
405template <typename T>
406Errno Socket::SetSockOpt(SOCKET fd_, int option, T value) {
407 const int result =
408 setsockopt(fd_, SOL_SOCKET, option, reinterpret_cast<const char*>(&value), sizeof(value));
409 if (result != SOCKET_ERROR) {
410 return Errno::SUCCESS;
411 }
412 return GetAndLogLastError();
413}
416 414
417Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) { 415Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) {
418 fd = socket(TranslateDomain(domain), TranslateType(type), TranslateProtocol(protocol)); 416 fd = socket(TranslateDomain(domain), TranslateType(type), TranslateProtocol(protocol));
@@ -423,7 +421,7 @@ Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) {
423 return GetAndLogLastError(); 421 return GetAndLogLastError();
424} 422}
425 423
426std::pair<Socket::AcceptResult, Errno> Socket::Accept() { 424std::pair<SocketBase::AcceptResult, Errno> Socket::Accept() {
427 sockaddr addr; 425 sockaddr addr;
428 socklen_t addrlen = sizeof(addr); 426 socklen_t addrlen = sizeof(addr);
429 const SOCKET new_socket = accept(fd, &addr, &addrlen); 427 const SOCKET new_socket = accept(fd, &addr, &addrlen);
@@ -634,4 +632,8 @@ bool Socket::IsOpened() const {
634 return fd != INVALID_SOCKET; 632 return fd != INVALID_SOCKET;
635} 633}
636 634
635void Socket::HandleProxyPacket(const ProxyPacket& packet) {
636 LOG_WARNING(Network, "ProxyPacket received, but not in Proxy mode!");
637}
638
637} // namespace Network 639} // namespace Network
diff --git a/src/core/internal_network/network.h b/src/core/internal_network/network.h
index 10e5ef10d..36994c22e 100644
--- a/src/core/internal_network/network.h
+++ b/src/core/internal_network/network.h
@@ -8,6 +8,7 @@
8 8
9#include "common/common_funcs.h" 9#include "common/common_funcs.h"
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/socket_types.h"
11 12
12#ifdef _WIN32 13#ifdef _WIN32
13#include <winsock2.h> 14#include <winsock2.h>
@@ -17,6 +18,7 @@
17 18
18namespace Network { 19namespace Network {
19 20
21class SocketBase;
20class Socket; 22class Socket;
21 23
22/// Error code for network functions 24/// Error code for network functions
@@ -31,46 +33,11 @@ enum class Errno {
31 HOSTUNREACH, 33 HOSTUNREACH,
32 NETDOWN, 34 NETDOWN,
33 NETUNREACH, 35 NETUNREACH,
36 TIMEDOUT,
37 MSGSIZE,
34 OTHER, 38 OTHER,
35}; 39};
36 40
37/// Address families
38enum class Domain {
39 INET, ///< Address family for IPv4
40};
41
42/// Socket types
43enum class Type {
44 STREAM,
45 DGRAM,
46 RAW,
47 SEQPACKET,
48};
49
50/// Protocol values for sockets
51enum class Protocol {
52 ICMP,
53 TCP,
54 UDP,
55};
56
57/// Shutdown mode
58enum class ShutdownHow {
59 RD,
60 WR,
61 RDWR,
62};
63
64/// Array of IPv4 address
65using IPv4Address = std::array<u8, 4>;
66
67/// Cross-platform sockaddr structure
68struct SockAddrIn {
69 Domain family;
70 IPv4Address ip;
71 u16 portno;
72};
73
74/// Cross-platform poll fd structure 41/// Cross-platform poll fd structure
75 42
76enum class PollEvents : u16 { 43enum class PollEvents : u16 {
@@ -86,7 +53,7 @@ enum class PollEvents : u16 {
86DECLARE_ENUM_FLAG_OPERATORS(PollEvents); 53DECLARE_ENUM_FLAG_OPERATORS(PollEvents);
87 54
88struct PollFD { 55struct PollFD {
89 Socket* socket; 56 SocketBase* socket;
90 PollEvents events; 57 PollEvents events;
91 PollEvents revents; 58 PollEvents revents;
92}; 59};
diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp
new file mode 100644
index 000000000..0c746bd82
--- /dev/null
+++ b/src/core/internal_network/socket_proxy.cpp
@@ -0,0 +1,290 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <chrono>
5#include <thread>
6
7#include "common/assert.h"
8#include "common/logging/log.h"
9#include "core/internal_network/network.h"
10#include "core/internal_network/network_interface.h"
11#include "core/internal_network/socket_proxy.h"
12
13namespace Network {
14
15ProxySocket::ProxySocket(RoomNetwork& room_network_) noexcept : room_network{room_network_} {}
16
17ProxySocket::~ProxySocket() {
18 if (fd == INVALID_SOCKET) {
19 return;
20 }
21 fd = INVALID_SOCKET;
22}
23
24void ProxySocket::HandleProxyPacket(const ProxyPacket& packet) {
25 if (protocol != packet.protocol || local_endpoint.portno != packet.remote_endpoint.portno ||
26 closed) {
27 return;
28 }
29
30 if (!broadcast && packet.broadcast) {
31 LOG_INFO(Network, "Received broadcast packet, but not configured for broadcast mode");
32 return;
33 }
34
35 std::lock_guard guard(packets_mutex);
36 received_packets.push(packet);
37}
38
39template <typename T>
40Errno ProxySocket::SetSockOpt(SOCKET fd_, int option, T value) {
41 LOG_DEBUG(Network, "(STUBBED) called");
42 return Errno::SUCCESS;
43}
44
45Errno ProxySocket::Initialize(Domain domain, Type type, Protocol socket_protocol) {
46 protocol = socket_protocol;
47 SetSockOpt(fd, SO_TYPE, type);
48
49 return Errno::SUCCESS;
50}
51
52std::pair<ProxySocket::AcceptResult, Errno> ProxySocket::Accept() {
53 LOG_WARNING(Network, "(STUBBED) called");
54 return {AcceptResult{}, Errno::SUCCESS};
55}
56
57Errno ProxySocket::Connect(SockAddrIn addr_in) {
58 LOG_WARNING(Network, "(STUBBED) called");
59 return Errno::SUCCESS;
60}
61
62std::pair<SockAddrIn, Errno> ProxySocket::GetPeerName() {
63 LOG_WARNING(Network, "(STUBBED) called");
64 return {SockAddrIn{}, Errno::SUCCESS};
65}
66
67std::pair<SockAddrIn, Errno> ProxySocket::GetSockName() {
68 LOG_WARNING(Network, "(STUBBED) called");
69 return {SockAddrIn{}, Errno::SUCCESS};
70}
71
72Errno ProxySocket::Bind(SockAddrIn addr) {
73 if (is_bound) {
74 LOG_WARNING(Network, "Rebinding Socket is unimplemented!");
75 return Errno::SUCCESS;
76 }
77 local_endpoint = addr;
78 is_bound = true;
79
80 return Errno::SUCCESS;
81}
82
83Errno ProxySocket::Listen(s32 backlog) {
84 LOG_WARNING(Network, "(STUBBED) called");
85 return Errno::SUCCESS;
86}
87
88Errno ProxySocket::Shutdown(ShutdownHow how) {
89 LOG_WARNING(Network, "(STUBBED) called");
90 return Errno::SUCCESS;
91}
92
93std::pair<s32, Errno> ProxySocket::Recv(int flags, std::vector<u8>& message) {
94 LOG_WARNING(Network, "(STUBBED) called");
95 ASSERT(flags == 0);
96 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
97
98 return {static_cast<s32>(0), Errno::SUCCESS};
99}
100
101std::pair<s32, Errno> ProxySocket::RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) {
102 ASSERT(flags == 0);
103 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
104
105 // TODO (flTobi): Verify the timeout behavior and break when connection is lost
106 const auto timestamp = std::chrono::steady_clock::now();
107 // When receive_timeout is set to zero, the socket is supposed to wait indefinitely until a
108 // packet arrives. In order to prevent lost packets from hanging the emulation thread, we set
109 // the timeout to 5s instead
110 const auto timeout = receive_timeout == 0 ? 5000 : receive_timeout;
111 while (true) {
112 {
113 std::lock_guard guard(packets_mutex);
114 if (received_packets.size() > 0) {
115 return ReceivePacket(flags, message, addr, message.size());
116 }
117 }
118
119 if (!blocking) {
120 return {-1, Errno::AGAIN};
121 }
122
123 std::this_thread::yield();
124
125 const auto time_diff = std::chrono::steady_clock::now() - timestamp;
126 const auto time_diff_ms =
127 std::chrono::duration_cast<std::chrono::milliseconds>(time_diff).count();
128
129 if (time_diff_ms > timeout) {
130 return {-1, Errno::TIMEDOUT};
131 }
132 }
133}
134
135std::pair<s32, Errno> ProxySocket::ReceivePacket(int flags, std::vector<u8>& message,
136 SockAddrIn* addr, std::size_t max_length) {
137 ProxyPacket& packet = received_packets.front();
138 if (addr) {
139 addr->family = Domain::INET;
140 addr->ip = packet.local_endpoint.ip; // The senders ip address
141 addr->portno = packet.local_endpoint.portno; // The senders port number
142 }
143
144 bool peek = (flags & FLAG_MSG_PEEK) != 0;
145 std::size_t read_bytes;
146 if (packet.data.size() > max_length) {
147 read_bytes = max_length;
148 message.clear();
149 std::copy(packet.data.begin(), packet.data.begin() + read_bytes,
150 std::back_inserter(message));
151 message.resize(max_length);
152
153 if (protocol == Protocol::UDP) {
154 if (!peek) {
155 received_packets.pop();
156 }
157 return {-1, Errno::MSGSIZE};
158 } else if (protocol == Protocol::TCP) {
159 std::vector<u8> numArray(packet.data.size() - max_length);
160 std::copy(packet.data.begin() + max_length, packet.data.end(),
161 std::back_inserter(numArray));
162 packet.data = numArray;
163 }
164 } else {
165 read_bytes = packet.data.size();
166 message.clear();
167 std::copy(packet.data.begin(), packet.data.end(), std::back_inserter(message));
168 message.resize(max_length);
169 if (!peek) {
170 received_packets.pop();
171 }
172 }
173
174 return {static_cast<u32>(read_bytes), Errno::SUCCESS};
175}
176
177std::pair<s32, Errno> ProxySocket::Send(const std::vector<u8>& message, int flags) {
178 LOG_WARNING(Network, "(STUBBED) called");
179 ASSERT(message.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
180 ASSERT(flags == 0);
181
182 return {static_cast<s32>(0), Errno::SUCCESS};
183}
184
185void ProxySocket::SendPacket(ProxyPacket& packet) {
186 if (auto room_member = room_network.GetRoomMember().lock()) {
187 if (room_member->IsConnected()) {
188 room_member->SendProxyPacket(packet);
189 }
190 }
191}
192
193std::pair<s32, Errno> ProxySocket::SendTo(u32 flags, const std::vector<u8>& message,
194 const SockAddrIn* addr) {
195 ASSERT(flags == 0);
196
197 if (!is_bound) {
198 LOG_ERROR(Network, "ProxySocket is not bound!");
199 return {static_cast<s32>(message.size()), Errno::SUCCESS};
200 }
201
202 if (auto room_member = room_network.GetRoomMember().lock()) {
203 if (!room_member->IsConnected()) {
204 return {static_cast<s32>(message.size()), Errno::SUCCESS};
205 }
206 }
207
208 ProxyPacket packet;
209 packet.local_endpoint = local_endpoint;
210 packet.remote_endpoint = *addr;
211 packet.protocol = protocol;
212 packet.broadcast = broadcast && packet.remote_endpoint.ip[3] == 255;
213
214 auto& ip = local_endpoint.ip;
215 auto ipv4 = Network::GetHostIPv4Address();
216 // If the ip is all zeroes (INADDR_ANY) or if it matches the hosts ip address,
217 // replace it with a "fake" routing address
218 if (std::all_of(ip.begin(), ip.end(), [](u8 i) { return i == 0; }) || (ipv4 && ipv4 == ip)) {
219 if (auto room_member = room_network.GetRoomMember().lock()) {
220 packet.local_endpoint.ip = room_member->GetFakeIpAddress();
221 }
222 }
223
224 packet.data.clear();
225 std::copy(message.begin(), message.end(), std::back_inserter(packet.data));
226
227 SendPacket(packet);
228
229 return {static_cast<s32>(message.size()), Errno::SUCCESS};
230}
231
232Errno ProxySocket::Close() {
233 fd = INVALID_SOCKET;
234 closed = true;
235
236 return Errno::SUCCESS;
237}
238
239Errno ProxySocket::SetLinger(bool enable, u32 linger) {
240 struct Linger {
241 u16 linger_enable;
242 u16 linger_time;
243 } values;
244 values.linger_enable = enable ? 1 : 0;
245 values.linger_time = static_cast<u16>(linger);
246
247 return SetSockOpt(fd, SO_LINGER, values);
248}
249
250Errno ProxySocket::SetReuseAddr(bool enable) {
251 return SetSockOpt<u32>(fd, SO_REUSEADDR, enable ? 1 : 0);
252}
253
254Errno ProxySocket::SetBroadcast(bool enable) {
255 broadcast = enable;
256 return SetSockOpt<u32>(fd, SO_BROADCAST, enable ? 1 : 0);
257}
258
259Errno ProxySocket::SetSndBuf(u32 value) {
260 return SetSockOpt(fd, SO_SNDBUF, value);
261}
262
263Errno ProxySocket::SetKeepAlive(bool enable) {
264 return Errno::SUCCESS;
265}
266
267Errno ProxySocket::SetRcvBuf(u32 value) {
268 return SetSockOpt(fd, SO_RCVBUF, value);
269}
270
271Errno ProxySocket::SetSndTimeo(u32 value) {
272 send_timeout = value;
273 return SetSockOpt(fd, SO_SNDTIMEO, static_cast<int>(value));
274}
275
276Errno ProxySocket::SetRcvTimeo(u32 value) {
277 receive_timeout = value;
278 return SetSockOpt(fd, SO_RCVTIMEO, static_cast<int>(value));
279}
280
281Errno ProxySocket::SetNonBlock(bool enable) {
282 blocking = !enable;
283 return Errno::SUCCESS;
284}
285
286bool ProxySocket::IsOpened() const {
287 return fd != INVALID_SOCKET;
288}
289
290} // namespace Network
diff --git a/src/core/internal_network/socket_proxy.h b/src/core/internal_network/socket_proxy.h
new file mode 100644
index 000000000..f12b5f567
--- /dev/null
+++ b/src/core/internal_network/socket_proxy.h
@@ -0,0 +1,97 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <mutex>
7#include <vector>
8#include <queue>
9
10#include "common/common_funcs.h"
11#include "core/internal_network/sockets.h"
12#include "network/network.h"
13
14namespace Network {
15
16class ProxySocket : public SocketBase {
17public:
18 YUZU_NON_COPYABLE(ProxySocket);
19 YUZU_NON_MOVEABLE(ProxySocket);
20
21 explicit ProxySocket(RoomNetwork& room_network_) noexcept;
22 ~ProxySocket() override;
23
24 void HandleProxyPacket(const ProxyPacket& packet) override;
25
26 Errno Initialize(Domain domain, Type type, Protocol socket_protocol) override;
27
28 Errno Close() override;
29
30 std::pair<AcceptResult, Errno> Accept() override;
31
32 Errno Connect(SockAddrIn addr_in) override;
33
34 std::pair<SockAddrIn, Errno> GetPeerName() override;
35
36 std::pair<SockAddrIn, Errno> GetSockName() override;
37
38 Errno Bind(SockAddrIn addr) override;
39
40 Errno Listen(s32 backlog) override;
41
42 Errno Shutdown(ShutdownHow how) override;
43
44 std::pair<s32, Errno> Recv(int flags, std::vector<u8>& message) override;
45
46 std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) override;
47
48 std::pair<s32, Errno> ReceivePacket(int flags, std::vector<u8>& message, SockAddrIn* addr,
49 std::size_t max_length);
50
51 std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags) override;
52
53 void SendPacket(ProxyPacket& packet);
54
55 std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message,
56 const SockAddrIn* addr) override;
57
58 Errno SetLinger(bool enable, u32 linger) override;
59
60 Errno SetReuseAddr(bool enable) override;
61
62 Errno SetBroadcast(bool enable) override;
63
64 Errno SetKeepAlive(bool enable) override;
65
66 Errno SetSndBuf(u32 value) override;
67
68 Errno SetRcvBuf(u32 value) override;
69
70 Errno SetSndTimeo(u32 value) override;
71
72 Errno SetRcvTimeo(u32 value) override;
73
74 Errno SetNonBlock(bool enable) override;
75
76 template <typename T>
77 Errno SetSockOpt(SOCKET fd, int option, T value);
78
79 bool IsOpened() const override;
80
81private:
82 bool broadcast = false;
83 bool closed = false;
84 u32 send_timeout = 0;
85 u32 receive_timeout = 0;
86 bool is_bound = false;
87 SockAddrIn local_endpoint{};
88 bool blocking = true;
89 std::queue<ProxyPacket> received_packets;
90 Protocol protocol;
91
92 std::mutex packets_mutex;
93
94 RoomNetwork& room_network;
95};
96
97} // namespace Network
diff --git a/src/core/internal_network/sockets.h b/src/core/internal_network/sockets.h
index 77e27e928..a70429b19 100644
--- a/src/core/internal_network/sockets.h
+++ b/src/core/internal_network/sockets.h
@@ -14,20 +14,88 @@
14 14
15#include "common/common_types.h" 15#include "common/common_types.h"
16#include "core/internal_network/network.h" 16#include "core/internal_network/network.h"
17#include "network/network.h"
17 18
18// TODO: C++20 Replace std::vector usages with std::span 19// TODO: C++20 Replace std::vector usages with std::span
19 20
20namespace Network { 21namespace Network {
21 22
22class Socket { 23class SocketBase {
23public: 24public:
25#ifdef YUZU_UNIX
26 using SOCKET = int;
27 static constexpr SOCKET INVALID_SOCKET = -1;
28 static constexpr SOCKET SOCKET_ERROR = -1;
29#endif
30
24 struct AcceptResult { 31 struct AcceptResult {
25 std::unique_ptr<Socket> socket; 32 std::unique_ptr<SocketBase> socket;
26 SockAddrIn sockaddr_in; 33 SockAddrIn sockaddr_in;
27 }; 34 };
35 virtual ~SocketBase() = default;
36
37 virtual SocketBase& operator=(const SocketBase&) = delete;
38
39 // Avoid closing sockets implicitly
40 virtual SocketBase& operator=(SocketBase&&) noexcept = delete;
41
42 virtual Errno Initialize(Domain domain, Type type, Protocol protocol) = 0;
43
44 virtual Errno Close() = 0;
45
46 virtual std::pair<AcceptResult, Errno> Accept() = 0;
47
48 virtual Errno Connect(SockAddrIn addr_in) = 0;
49
50 virtual std::pair<SockAddrIn, Errno> GetPeerName() = 0;
51
52 virtual std::pair<SockAddrIn, Errno> GetSockName() = 0;
53
54 virtual Errno Bind(SockAddrIn addr) = 0;
55
56 virtual Errno Listen(s32 backlog) = 0;
57
58 virtual Errno Shutdown(ShutdownHow how) = 0;
59
60 virtual std::pair<s32, Errno> Recv(int flags, std::vector<u8>& message) = 0;
61
62 virtual std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message,
63 SockAddrIn* addr) = 0;
64
65 virtual std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags) = 0;
66
67 virtual std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message,
68 const SockAddrIn* addr) = 0;
69
70 virtual Errno SetLinger(bool enable, u32 linger) = 0;
28 71
29 explicit Socket() = default; 72 virtual Errno SetReuseAddr(bool enable) = 0;
30 ~Socket(); 73
74 virtual Errno SetKeepAlive(bool enable) = 0;
75
76 virtual Errno SetBroadcast(bool enable) = 0;
77
78 virtual Errno SetSndBuf(u32 value) = 0;
79
80 virtual Errno SetRcvBuf(u32 value) = 0;
81
82 virtual Errno SetSndTimeo(u32 value) = 0;
83
84 virtual Errno SetRcvTimeo(u32 value) = 0;
85
86 virtual Errno SetNonBlock(bool enable) = 0;
87
88 virtual bool IsOpened() const = 0;
89
90 virtual void HandleProxyPacket(const ProxyPacket& packet) = 0;
91
92 SOCKET fd = INVALID_SOCKET;
93};
94
95class Socket : public SocketBase {
96public:
97 Socket() = default;
98 ~Socket() override;
31 99
32 Socket(const Socket&) = delete; 100 Socket(const Socket&) = delete;
33 Socket& operator=(const Socket&) = delete; 101 Socket& operator=(const Socket&) = delete;
@@ -37,57 +105,57 @@ public:
37 // Avoid closing sockets implicitly 105 // Avoid closing sockets implicitly
38 Socket& operator=(Socket&&) noexcept = delete; 106 Socket& operator=(Socket&&) noexcept = delete;
39 107
40 Errno Initialize(Domain domain, Type type, Protocol protocol); 108 Errno Initialize(Domain domain, Type type, Protocol protocol) override;
41 109
42 Errno Close(); 110 Errno Close() override;
43 111
44 std::pair<AcceptResult, Errno> Accept(); 112 std::pair<AcceptResult, Errno> Accept() override;
45 113
46 Errno Connect(SockAddrIn addr_in); 114 Errno Connect(SockAddrIn addr_in) override;
47 115
48 std::pair<SockAddrIn, Errno> GetPeerName(); 116 std::pair<SockAddrIn, Errno> GetPeerName() override;
49 117
50 std::pair<SockAddrIn, Errno> GetSockName(); 118 std::pair<SockAddrIn, Errno> GetSockName() override;
51 119
52 Errno Bind(SockAddrIn addr); 120 Errno Bind(SockAddrIn addr) override;
53 121
54 Errno Listen(s32 backlog); 122 Errno Listen(s32 backlog) override;
55 123
56 Errno Shutdown(ShutdownHow how); 124 Errno Shutdown(ShutdownHow how) override;
57 125
58 std::pair<s32, Errno> Recv(int flags, std::vector<u8>& message); 126 std::pair<s32, Errno> Recv(int flags, std::vector<u8>& message) override;
59 127
60 std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr); 128 std::pair<s32, Errno> RecvFrom(int flags, std::vector<u8>& message, SockAddrIn* addr) override;
61 129
62 std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags); 130 std::pair<s32, Errno> Send(const std::vector<u8>& message, int flags) override;
63 131
64 std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message, const SockAddrIn* addr); 132 std::pair<s32, Errno> SendTo(u32 flags, const std::vector<u8>& message,
133 const SockAddrIn* addr) override;
65 134
66 Errno SetLinger(bool enable, u32 linger); 135 Errno SetLinger(bool enable, u32 linger) override;
67 136
68 Errno SetReuseAddr(bool enable); 137 Errno SetReuseAddr(bool enable) override;
69 138
70 Errno SetKeepAlive(bool enable); 139 Errno SetKeepAlive(bool enable) override;
71 140
72 Errno SetBroadcast(bool enable); 141 Errno SetBroadcast(bool enable) override;
73 142
74 Errno SetSndBuf(u32 value); 143 Errno SetSndBuf(u32 value) override;
75 144
76 Errno SetRcvBuf(u32 value); 145 Errno SetRcvBuf(u32 value) override;
77 146
78 Errno SetSndTimeo(u32 value); 147 Errno SetSndTimeo(u32 value) override;
79 148
80 Errno SetRcvTimeo(u32 value); 149 Errno SetRcvTimeo(u32 value) override;
81 150
82 Errno SetNonBlock(bool enable); 151 Errno SetNonBlock(bool enable) override;
83 152
84 bool IsOpened() const; 153 template <typename T>
154 Errno SetSockOpt(SOCKET fd, int option, T value);
85 155
86#if defined(_WIN32) 156 bool IsOpened() const override;
87 SOCKET fd = INVALID_SOCKET; 157
88#elif YUZU_UNIX 158 void HandleProxyPacket(const ProxyPacket& packet) override;
89 int fd = -1;
90#endif
91}; 159};
92 160
93std::pair<s32, Errno> Poll(std::vector<PollFD>& poll_fds, s32 timeout); 161std::pair<s32, Errno> Poll(std::vector<PollFD>& poll_fds, s32 timeout);
diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp
index 9af46a0f7..d8a1bf82a 100644
--- a/src/core/loader/kip.cpp
+++ b/src/core/loader/kip.cpp
@@ -14,7 +14,7 @@ namespace Loader {
14 14
15namespace { 15namespace {
16constexpr u32 PageAlignSize(u32 size) { 16constexpr u32 PageAlignSize(u32 size) {
17 return static_cast<u32>((size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK); 17 return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
18} 18}
19} // Anonymous namespace 19} // Anonymous namespace
20 20
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 1b0bb0876..73d04d7ee 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -125,7 +125,7 @@ FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& nro_file) {
125} 125}
126 126
127static constexpr u32 PageAlignSize(u32 size) { 127static constexpr u32 PageAlignSize(u32 size) {
128 return static_cast<u32>((size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK); 128 return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
129} 129}
130 130
131static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data) { 131static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data) {
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 8dd956fc6..4c3b3c655 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -45,7 +45,7 @@ std::vector<u8> DecompressSegment(const std::vector<u8>& compressed_data,
45} 45}
46 46
47constexpr u32 PageAlignSize(u32 size) { 47constexpr u32 PageAlignSize(u32 size) {
48 return static_cast<u32>((size + Core::Memory::PAGE_MASK) & ~Core::Memory::PAGE_MASK); 48 return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
49} 49}
50} // Anonymous namespace 50} // Anonymous namespace
51 51
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 1b44280b5..34ad7cadd 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -36,10 +36,11 @@ struct Memory::Impl {
36 } 36 }
37 37
38 void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, PAddr target) { 38 void MapMemoryRegion(Common::PageTable& page_table, VAddr base, u64 size, PAddr target) {
39 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size); 39 ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size);
40 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base); 40 ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", base);
41 ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}", target); 41 ASSERT_MSG(target >= DramMemoryMap::Base, "Out of bounds target: {:016X}", target);
42 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, target, Common::PageType::Memory); 42 MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, target,
43 Common::PageType::Memory);
43 44
44 if (Settings::IsFastmemEnabled()) { 45 if (Settings::IsFastmemEnabled()) {
45 system.DeviceMemory().buffer.Map(base, target - DramMemoryMap::Base, size); 46 system.DeviceMemory().buffer.Map(base, target - DramMemoryMap::Base, size);
@@ -47,9 +48,10 @@ struct Memory::Impl {
47 } 48 }
48 49
49 void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) { 50 void UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) {
50 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: {:016X}", size); 51 ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size);
51 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: {:016X}", base); 52 ASSERT_MSG((base & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", base);
52 MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, 0, Common::PageType::Unmapped); 53 MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, 0,
54 Common::PageType::Unmapped);
53 55
54 if (Settings::IsFastmemEnabled()) { 56 if (Settings::IsFastmemEnabled()) {
55 system.DeviceMemory().buffer.Unmap(base, size); 57 system.DeviceMemory().buffer.Unmap(base, size);
@@ -57,7 +59,7 @@ struct Memory::Impl {
57 } 59 }
58 60
59 [[nodiscard]] u8* GetPointerFromRasterizerCachedMemory(VAddr vaddr) const { 61 [[nodiscard]] u8* GetPointerFromRasterizerCachedMemory(VAddr vaddr) const {
60 const PAddr paddr{current_page_table->backing_addr[vaddr >> PAGE_BITS]}; 62 const PAddr paddr{current_page_table->backing_addr[vaddr >> YUZU_PAGEBITS]};
61 63
62 if (!paddr) { 64 if (!paddr) {
63 return {}; 65 return {};
@@ -67,7 +69,7 @@ struct Memory::Impl {
67 } 69 }
68 70
69 [[nodiscard]] u8* GetPointerFromDebugMemory(VAddr vaddr) const { 71 [[nodiscard]] u8* GetPointerFromDebugMemory(VAddr vaddr) const {
70 const PAddr paddr{current_page_table->backing_addr[vaddr >> PAGE_BITS]}; 72 const PAddr paddr{current_page_table->backing_addr[vaddr >> YUZU_PAGEBITS]};
71 73
72 if (paddr == 0) { 74 if (paddr == 0) {
73 return {}; 75 return {};
@@ -176,13 +178,14 @@ struct Memory::Impl {
176 auto on_unmapped, auto on_memory, auto on_rasterizer, auto increment) { 178 auto on_unmapped, auto on_memory, auto on_rasterizer, auto increment) {
177 const auto& page_table = process.PageTable().PageTableImpl(); 179 const auto& page_table = process.PageTable().PageTableImpl();
178 std::size_t remaining_size = size; 180 std::size_t remaining_size = size;
179 std::size_t page_index = addr >> PAGE_BITS; 181 std::size_t page_index = addr >> YUZU_PAGEBITS;
180 std::size_t page_offset = addr & PAGE_MASK; 182 std::size_t page_offset = addr & YUZU_PAGEMASK;
181 183
182 while (remaining_size) { 184 while (remaining_size) {
183 const std::size_t copy_amount = 185 const std::size_t copy_amount =
184 std::min(static_cast<std::size_t>(PAGE_SIZE) - page_offset, remaining_size); 186 std::min(static_cast<std::size_t>(YUZU_PAGESIZE) - page_offset, remaining_size);
185 const auto current_vaddr = static_cast<VAddr>((page_index << PAGE_BITS) + page_offset); 187 const auto current_vaddr =
188 static_cast<VAddr>((page_index << YUZU_PAGEBITS) + page_offset);
186 189
187 const auto [pointer, type] = page_table.pointers[page_index].PointerType(); 190 const auto [pointer, type] = page_table.pointers[page_index].PointerType();
188 switch (type) { 191 switch (type) {
@@ -192,7 +195,7 @@ struct Memory::Impl {
192 } 195 }
193 case Common::PageType::Memory: { 196 case Common::PageType::Memory: {
194 DEBUG_ASSERT(pointer); 197 DEBUG_ASSERT(pointer);
195 u8* mem_ptr = pointer + page_offset + (page_index << PAGE_BITS); 198 u8* mem_ptr = pointer + page_offset + (page_index << YUZU_PAGEBITS);
196 on_memory(copy_amount, mem_ptr); 199 on_memory(copy_amount, mem_ptr);
197 break; 200 break;
198 } 201 }
@@ -339,10 +342,10 @@ struct Memory::Impl {
339 // Iterate over a contiguous CPU address space, marking/unmarking the region. 342 // Iterate over a contiguous CPU address space, marking/unmarking the region.
340 // The region is at a granularity of CPU pages. 343 // The region is at a granularity of CPU pages.
341 344
342 const u64 num_pages = ((vaddr + size - 1) >> PAGE_BITS) - (vaddr >> PAGE_BITS) + 1; 345 const u64 num_pages = ((vaddr + size - 1) >> YUZU_PAGEBITS) - (vaddr >> YUZU_PAGEBITS) + 1;
343 for (u64 i = 0; i < num_pages; ++i, vaddr += PAGE_SIZE) { 346 for (u64 i = 0; i < num_pages; ++i, vaddr += YUZU_PAGESIZE) {
344 const Common::PageType page_type{ 347 const Common::PageType page_type{
345 current_page_table->pointers[vaddr >> PAGE_BITS].Type()}; 348 current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Type()};
346 if (debug) { 349 if (debug) {
347 // Switch page type to debug if now debug 350 // Switch page type to debug if now debug
348 switch (page_type) { 351 switch (page_type) {
@@ -354,7 +357,7 @@ struct Memory::Impl {
354 // Page is already marked. 357 // Page is already marked.
355 break; 358 break;
356 case Common::PageType::Memory: 359 case Common::PageType::Memory:
357 current_page_table->pointers[vaddr >> PAGE_BITS].Store( 360 current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Store(
358 nullptr, Common::PageType::DebugMemory); 361 nullptr, Common::PageType::DebugMemory);
359 break; 362 break;
360 default: 363 default:
@@ -371,9 +374,9 @@ struct Memory::Impl {
371 // Don't mess with already non-debug or rasterizer memory. 374 // Don't mess with already non-debug or rasterizer memory.
372 break; 375 break;
373 case Common::PageType::DebugMemory: { 376 case Common::PageType::DebugMemory: {
374 u8* const pointer{GetPointerFromDebugMemory(vaddr & ~PAGE_MASK)}; 377 u8* const pointer{GetPointerFromDebugMemory(vaddr & ~YUZU_PAGEMASK)};
375 current_page_table->pointers[vaddr >> PAGE_BITS].Store( 378 current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Store(
376 pointer - (vaddr & ~PAGE_MASK), Common::PageType::Memory); 379 pointer - (vaddr & ~YUZU_PAGEMASK), Common::PageType::Memory);
377 break; 380 break;
378 } 381 }
379 default: 382 default:
@@ -398,10 +401,10 @@ struct Memory::Impl {
398 // granularity of CPU pages, hence why we iterate on a CPU page basis (note: GPU page size 401 // granularity of CPU pages, hence why we iterate on a CPU page basis (note: GPU page size
399 // is different). This assumes the specified GPU address region is contiguous as well. 402 // is different). This assumes the specified GPU address region is contiguous as well.
400 403
401 const u64 num_pages = ((vaddr + size - 1) >> PAGE_BITS) - (vaddr >> PAGE_BITS) + 1; 404 const u64 num_pages = ((vaddr + size - 1) >> YUZU_PAGEBITS) - (vaddr >> YUZU_PAGEBITS) + 1;
402 for (u64 i = 0; i < num_pages; ++i, vaddr += PAGE_SIZE) { 405 for (u64 i = 0; i < num_pages; ++i, vaddr += YUZU_PAGESIZE) {
403 const Common::PageType page_type{ 406 const Common::PageType page_type{
404 current_page_table->pointers[vaddr >> PAGE_BITS].Type()}; 407 current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Type()};
405 if (cached) { 408 if (cached) {
406 // Switch page type to cached if now cached 409 // Switch page type to cached if now cached
407 switch (page_type) { 410 switch (page_type) {
@@ -411,7 +414,7 @@ struct Memory::Impl {
411 break; 414 break;
412 case Common::PageType::DebugMemory: 415 case Common::PageType::DebugMemory:
413 case Common::PageType::Memory: 416 case Common::PageType::Memory:
414 current_page_table->pointers[vaddr >> PAGE_BITS].Store( 417 current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Store(
415 nullptr, Common::PageType::RasterizerCachedMemory); 418 nullptr, Common::PageType::RasterizerCachedMemory);
416 break; 419 break;
417 case Common::PageType::RasterizerCachedMemory: 420 case Common::PageType::RasterizerCachedMemory:
@@ -434,16 +437,16 @@ struct Memory::Impl {
434 // that this area is already unmarked as cached. 437 // that this area is already unmarked as cached.
435 break; 438 break;
436 case Common::PageType::RasterizerCachedMemory: { 439 case Common::PageType::RasterizerCachedMemory: {
437 u8* const pointer{GetPointerFromRasterizerCachedMemory(vaddr & ~PAGE_MASK)}; 440 u8* const pointer{GetPointerFromRasterizerCachedMemory(vaddr & ~YUZU_PAGEMASK)};
438 if (pointer == nullptr) { 441 if (pointer == nullptr) {
439 // It's possible that this function has been called while updating the 442 // It's possible that this function has been called while updating the
440 // pagetable after unmapping a VMA. In that case the underlying VMA will no 443 // pagetable after unmapping a VMA. In that case the underlying VMA will no
441 // longer exist, and we should just leave the pagetable entry blank. 444 // longer exist, and we should just leave the pagetable entry blank.
442 current_page_table->pointers[vaddr >> PAGE_BITS].Store( 445 current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Store(
443 nullptr, Common::PageType::Unmapped); 446 nullptr, Common::PageType::Unmapped);
444 } else { 447 } else {
445 current_page_table->pointers[vaddr >> PAGE_BITS].Store( 448 current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Store(
446 pointer - (vaddr & ~PAGE_MASK), Common::PageType::Memory); 449 pointer - (vaddr & ~YUZU_PAGEMASK), Common::PageType::Memory);
447 } 450 }
448 break; 451 break;
449 } 452 }
@@ -465,8 +468,8 @@ struct Memory::Impl {
465 */ 468 */
466 void MapPages(Common::PageTable& page_table, VAddr base, u64 size, PAddr target, 469 void MapPages(Common::PageTable& page_table, VAddr base, u64 size, PAddr target,
467 Common::PageType type) { 470 Common::PageType type) {
468 LOG_DEBUG(HW_Memory, "Mapping {:016X} onto {:016X}-{:016X}", target, base * PAGE_SIZE, 471 LOG_DEBUG(HW_Memory, "Mapping {:016X} onto {:016X}-{:016X}", target, base * YUZU_PAGESIZE,
469 (base + size) * PAGE_SIZE); 472 (base + size) * YUZU_PAGESIZE);
470 473
471 // During boot, current_page_table might not be set yet, in which case we need not flush 474 // During boot, current_page_table might not be set yet, in which case we need not flush
472 if (system.IsPoweredOn()) { 475 if (system.IsPoweredOn()) {
@@ -474,7 +477,7 @@ struct Memory::Impl {
474 for (u64 i = 0; i < size; i++) { 477 for (u64 i = 0; i < size; i++) {
475 const auto page = base + i; 478 const auto page = base + i;
476 if (page_table.pointers[page].Type() == Common::PageType::RasterizerCachedMemory) { 479 if (page_table.pointers[page].Type() == Common::PageType::RasterizerCachedMemory) {
477 gpu.FlushAndInvalidateRegion(page << PAGE_BITS, PAGE_SIZE); 480 gpu.FlushAndInvalidateRegion(page << YUZU_PAGEBITS, YUZU_PAGESIZE);
478 } 481 }
479 } 482 }
480 } 483 }
@@ -485,7 +488,7 @@ struct Memory::Impl {
485 488
486 if (!target) { 489 if (!target) {
487 ASSERT_MSG(type != Common::PageType::Memory, 490 ASSERT_MSG(type != Common::PageType::Memory,
488 "Mapping memory page without a pointer @ {:016x}", base * PAGE_SIZE); 491 "Mapping memory page without a pointer @ {:016x}", base * YUZU_PAGESIZE);
489 492
490 while (base != end) { 493 while (base != end) {
491 page_table.pointers[base].Store(nullptr, type); 494 page_table.pointers[base].Store(nullptr, type);
@@ -496,14 +499,14 @@ struct Memory::Impl {
496 } else { 499 } else {
497 while (base != end) { 500 while (base != end) {
498 page_table.pointers[base].Store( 501 page_table.pointers[base].Store(
499 system.DeviceMemory().GetPointer(target) - (base << PAGE_BITS), type); 502 system.DeviceMemory().GetPointer(target) - (base << YUZU_PAGEBITS), type);
500 page_table.backing_addr[base] = target - (base << PAGE_BITS); 503 page_table.backing_addr[base] = target - (base << YUZU_PAGEBITS);
501 504
502 ASSERT_MSG(page_table.pointers[base].Pointer(), 505 ASSERT_MSG(page_table.pointers[base].Pointer(),
503 "memory mapping base yield a nullptr within the table"); 506 "memory mapping base yield a nullptr within the table");
504 507
505 base += 1; 508 base += 1;
506 target += PAGE_SIZE; 509 target += YUZU_PAGESIZE;
507 } 510 }
508 } 511 }
509 } 512 }
@@ -518,7 +521,7 @@ struct Memory::Impl {
518 } 521 }
519 522
520 // Avoid adding any extra logic to this fast-path block 523 // Avoid adding any extra logic to this fast-path block
521 const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> PAGE_BITS].Raw(); 524 const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Raw();
522 if (u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) { 525 if (u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) {
523 return &pointer[vaddr]; 526 return &pointer[vaddr];
524 } 527 }
@@ -657,7 +660,7 @@ void Memory::UnmapRegion(Common::PageTable& page_table, VAddr base, u64 size) {
657bool Memory::IsValidVirtualAddress(const VAddr vaddr) const { 660bool Memory::IsValidVirtualAddress(const VAddr vaddr) const {
658 const Kernel::KProcess& process = *system.CurrentProcess(); 661 const Kernel::KProcess& process = *system.CurrentProcess();
659 const auto& page_table = process.PageTable().PageTableImpl(); 662 const auto& page_table = process.PageTable().PageTableImpl();
660 const size_t page = vaddr >> PAGE_BITS; 663 const size_t page = vaddr >> YUZU_PAGEBITS;
661 if (page >= page_table.pointers.size()) { 664 if (page >= page_table.pointers.size()) {
662 return false; 665 return false;
663 } 666 }
@@ -668,9 +671,9 @@ bool Memory::IsValidVirtualAddress(const VAddr vaddr) const {
668 671
669bool Memory::IsValidVirtualAddressRange(VAddr base, u64 size) const { 672bool Memory::IsValidVirtualAddressRange(VAddr base, u64 size) const {
670 VAddr end = base + size; 673 VAddr end = base + size;
671 VAddr page = Common::AlignDown(base, PAGE_SIZE); 674 VAddr page = Common::AlignDown(base, YUZU_PAGESIZE);
672 675
673 for (; page < end; page += PAGE_SIZE) { 676 for (; page < end; page += YUZU_PAGESIZE) {
674 if (!IsValidVirtualAddress(page)) { 677 if (!IsValidVirtualAddress(page)) {
675 return false; 678 return false;
676 } 679 }
diff --git a/src/core/memory.h b/src/core/memory.h
index 2a21fbcfd..a11ff8766 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -27,9 +27,9 @@ namespace Core::Memory {
27 * Page size used by the ARM architecture. This is the smallest granularity with which memory can 27 * Page size used by the ARM architecture. This is the smallest granularity with which memory can
28 * be mapped. 28 * be mapped.
29 */ 29 */
30constexpr std::size_t PAGE_BITS = 12; 30constexpr std::size_t YUZU_PAGEBITS = 12;
31constexpr u64 PAGE_SIZE = 1ULL << PAGE_BITS; 31constexpr u64 YUZU_PAGESIZE = 1ULL << YUZU_PAGEBITS;
32constexpr u64 PAGE_MASK = PAGE_SIZE - 1; 32constexpr u64 YUZU_PAGEMASK = YUZU_PAGESIZE - 1;
33 33
34/// Virtual user-space memory regions 34/// Virtual user-space memory regions
35enum : VAddr { 35enum : VAddr {