summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/arm/arm_interface.cpp141
-rw-r--r--src/core/arm/symbols.cpp190
-rw-r--r--src/core/arm/symbols.h27
-rw-r--r--src/core/file_sys/patch_manager.cpp63
-rw-r--r--src/core/hid/emulated_console.cpp17
-rw-r--r--src/core/hid/emulated_console.h1
-rw-r--r--src/core/hid/emulated_controller.cpp377
-rw-r--r--src/core/hid/emulated_controller.h3
-rw-r--r--src/core/hid/emulated_devices.cpp33
-rw-r--r--src/core/hid/emulated_devices.h1
-rw-r--r--src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp6
-rw-r--r--src/core/hle/kernel/k_auto_object.h2
-rw-r--r--src/core/hle/kernel/k_page_table.cpp11
-rw-r--r--src/core/hle/kernel/k_page_table.h5
-rw-r--r--src/core/hle/kernel/k_process.h2
-rw-r--r--src/core/hle/kernel/k_scheduler_lock.h3
-rw-r--r--src/core/hle/kernel/k_thread.cpp4
-rw-r--r--src/core/hle/kernel/k_thread.h3
-rw-r--r--src/core/hle/kernel/kernel.cpp8
-rw-r--r--src/core/hle/kernel/svc.cpp3
-rw-r--r--src/core/hle/service/ldr/ldr.cpp30
-rw-r--r--src/core/hle/service/sockets/bsd.cpp3
-rw-r--r--src/core/hle/service/sockets/sfdnsres.cpp205
-rw-r--r--src/core/hle/service/sockets/sfdnsres.h1
-rw-r--r--src/core/hle/service/sockets/sockets.h1
-rw-r--r--src/core/network/network.cpp4
-rw-r--r--src/core/network/sockets.h2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp9
29 files changed, 793 insertions, 364 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 81eaf0942..ffbda7925 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -13,6 +13,8 @@ add_library(core STATIC
13 arm/dynarmic/arm_exclusive_monitor.h 13 arm/dynarmic/arm_exclusive_monitor.h
14 arm/exclusive_monitor.cpp 14 arm/exclusive_monitor.cpp
15 arm/exclusive_monitor.h 15 arm/exclusive_monitor.h
16 arm/symbols.cpp
17 arm/symbols.h
16 constants.cpp 18 constants.cpp
17 constants.h 19 constants.h
18 core.cpp 20 core.cpp
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp
index 0951e1976..08bf1201d 100644
--- a/src/core/arm/arm_interface.cpp
+++ b/src/core/arm/arm_interface.cpp
@@ -8,134 +8,13 @@
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "core/arm/arm_interface.h" 10#include "core/arm/arm_interface.h"
11#include "core/arm/symbols.h"
11#include "core/core.h" 12#include "core/core.h"
13#include "core/hle/kernel/k_process.h"
12#include "core/loader/loader.h" 14#include "core/loader/loader.h"
13#include "core/memory.h" 15#include "core/memory.h"
14 16
15namespace Core { 17namespace Core {
16namespace {
17
18constexpr u64 ELF_DYNAMIC_TAG_NULL = 0;
19constexpr u64 ELF_DYNAMIC_TAG_STRTAB = 5;
20constexpr u64 ELF_DYNAMIC_TAG_SYMTAB = 6;
21constexpr u64 ELF_DYNAMIC_TAG_SYMENT = 11;
22
23enum class ELFSymbolType : u8 {
24 None = 0,
25 Object = 1,
26 Function = 2,
27 Section = 3,
28 File = 4,
29 Common = 5,
30 TLS = 6,
31};
32
33enum class ELFSymbolBinding : u8 {
34 Local = 0,
35 Global = 1,
36 Weak = 2,
37};
38
39enum class ELFSymbolVisibility : u8 {
40 Default = 0,
41 Internal = 1,
42 Hidden = 2,
43 Protected = 3,
44};
45
46struct ELFSymbol {
47 u32 name_index;
48 union {
49 u8 info;
50
51 BitField<0, 4, ELFSymbolType> type;
52 BitField<4, 4, ELFSymbolBinding> binding;
53 };
54 ELFSymbolVisibility visibility;
55 u16 sh_index;
56 u64 value;
57 u64 size;
58};
59static_assert(sizeof(ELFSymbol) == 0x18, "ELFSymbol has incorrect size.");
60
61using Symbols = std::vector<std::pair<ELFSymbol, std::string>>;
62
63Symbols GetSymbols(VAddr text_offset, Core::Memory::Memory& memory) {
64 const auto mod_offset = text_offset + memory.Read32(text_offset + 4);
65
66 if (mod_offset < text_offset || (mod_offset & 0b11) != 0 ||
67 memory.Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) {
68 return {};
69 }
70
71 const auto dynamic_offset = memory.Read32(mod_offset + 0x4) + mod_offset;
72
73 VAddr string_table_offset{};
74 VAddr symbol_table_offset{};
75 u64 symbol_entry_size{};
76
77 VAddr dynamic_index = dynamic_offset;
78 while (true) {
79 const u64 tag = memory.Read64(dynamic_index);
80 const u64 value = memory.Read64(dynamic_index + 0x8);
81 dynamic_index += 0x10;
82
83 if (tag == ELF_DYNAMIC_TAG_NULL) {
84 break;
85 }
86
87 if (tag == ELF_DYNAMIC_TAG_STRTAB) {
88 string_table_offset = value;
89 } else if (tag == ELF_DYNAMIC_TAG_SYMTAB) {
90 symbol_table_offset = value;
91 } else if (tag == ELF_DYNAMIC_TAG_SYMENT) {
92 symbol_entry_size = value;
93 }
94 }
95
96 if (string_table_offset == 0 || symbol_table_offset == 0 || symbol_entry_size == 0) {
97 return {};
98 }
99
100 const auto string_table_address = text_offset + string_table_offset;
101 const auto symbol_table_address = text_offset + symbol_table_offset;
102
103 Symbols out;
104
105 VAddr symbol_index = symbol_table_address;
106 while (symbol_index < string_table_address) {
107 ELFSymbol symbol{};
108 memory.ReadBlock(symbol_index, &symbol, sizeof(ELFSymbol));
109
110 VAddr string_offset = string_table_address + symbol.name_index;
111 std::string name;
112 for (u8 c = memory.Read8(string_offset); c != 0; c = memory.Read8(++string_offset)) {
113 name += static_cast<char>(c);
114 }
115
116 symbol_index += symbol_entry_size;
117 out.push_back({symbol, name});
118 }
119
120 return out;
121}
122
123std::optional<std::string> GetSymbolName(const Symbols& symbols, VAddr func_address) {
124 const auto iter =
125 std::find_if(symbols.begin(), symbols.end(), [func_address](const auto& pair) {
126 const auto& symbol = pair.first;
127 const auto end_address = symbol.value + symbol.size;
128 return func_address >= symbol.value && func_address < end_address;
129 });
130
131 if (iter == symbols.end()) {
132 return std::nullopt;
133 }
134
135 return iter->second;
136}
137
138} // Anonymous namespace
139 18
140constexpr u64 SEGMENT_BASE = 0x7100000000ull; 19constexpr u64 SEGMENT_BASE = 0x7100000000ull;
141 20
@@ -169,9 +48,11 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContex
169 return {}; 48 return {};
170 } 49 }
171 50
172 std::map<std::string, Symbols> symbols; 51 std::map<std::string, Symbols::Symbols> symbols;
173 for (const auto& module : modules) { 52 for (const auto& module : modules) {
174 symbols.insert_or_assign(module.second, GetSymbols(module.first, memory)); 53 symbols.insert_or_assign(module.second,
54 Symbols::GetSymbols(module.first, system.Memory(),
55 system.CurrentProcess()->Is64BitProcess()));
175 } 56 }
176 57
177 for (auto& entry : out) { 58 for (auto& entry : out) {
@@ -193,7 +74,7 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContex
193 74
194 const auto symbol_set = symbols.find(entry.module); 75 const auto symbol_set = symbols.find(entry.module);
195 if (symbol_set != symbols.end()) { 76 if (symbol_set != symbols.end()) {
196 const auto symbol = GetSymbolName(symbol_set->second, entry.offset); 77 const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset);
197 if (symbol.has_value()) { 78 if (symbol.has_value()) {
198 // TODO(DarkLordZach): Add demangling of symbol names. 79 // TODO(DarkLordZach): Add demangling of symbol names.
199 entry.name = *symbol; 80 entry.name = *symbol;
@@ -225,9 +106,11 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const {
225 return {}; 106 return {};
226 } 107 }
227 108
228 std::map<std::string, Symbols> symbols; 109 std::map<std::string, Symbols::Symbols> symbols;
229 for (const auto& module : modules) { 110 for (const auto& module : modules) {
230 symbols.insert_or_assign(module.second, GetSymbols(module.first, memory)); 111 symbols.insert_or_assign(module.second,
112 Symbols::GetSymbols(module.first, system.Memory(),
113 system.CurrentProcess()->Is64BitProcess()));
231 } 114 }
232 115
233 for (auto& entry : out) { 116 for (auto& entry : out) {
@@ -249,7 +132,7 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const {
249 132
250 const auto symbol_set = symbols.find(entry.module); 133 const auto symbol_set = symbols.find(entry.module);
251 if (symbol_set != symbols.end()) { 134 if (symbol_set != symbols.end()) {
252 const auto symbol = GetSymbolName(symbol_set->second, entry.offset); 135 const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset);
253 if (symbol.has_value()) { 136 if (symbol.has_value()) {
254 // TODO(DarkLordZach): Add demangling of symbol names. 137 // TODO(DarkLordZach): Add demangling of symbol names.
255 entry.name = *symbol; 138 entry.name = *symbol;
diff --git a/src/core/arm/symbols.cpp b/src/core/arm/symbols.cpp
new file mode 100644
index 000000000..26c44f0c7
--- /dev/null
+++ b/src/core/arm/symbols.cpp
@@ -0,0 +1,190 @@
1// Copyright 2022 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/bit_field.h"
6#include "common/common_funcs.h"
7#include "core/arm/symbols.h"
8#include "core/core.h"
9#include "core/memory.h"
10
11namespace Core {
12namespace {
13
14constexpr u64 ELF_DYNAMIC_TAG_NULL = 0;
15constexpr u64 ELF_DYNAMIC_TAG_STRTAB = 5;
16constexpr u64 ELF_DYNAMIC_TAG_SYMTAB = 6;
17constexpr u64 ELF_DYNAMIC_TAG_SYMENT = 11;
18
19enum class ELFSymbolType : u8 {
20 None = 0,
21 Object = 1,
22 Function = 2,
23 Section = 3,
24 File = 4,
25 Common = 5,
26 TLS = 6,
27};
28
29enum class ELFSymbolBinding : u8 {
30 Local = 0,
31 Global = 1,
32 Weak = 2,
33};
34
35enum class ELFSymbolVisibility : u8 {
36 Default = 0,
37 Internal = 1,
38 Hidden = 2,
39 Protected = 3,
40};
41
42struct ELF64Symbol {
43 u32 name_index;
44 union {
45 u8 info;
46
47 BitField<0, 4, ELFSymbolType> type;
48 BitField<4, 4, ELFSymbolBinding> binding;
49 };
50 ELFSymbolVisibility visibility;
51 u16 sh_index;
52 u64 value;
53 u64 size;
54};
55static_assert(sizeof(ELF64Symbol) == 0x18, "ELF64Symbol has incorrect size.");
56
57struct ELF32Symbol {
58 u32 name_index;
59 u32 value;
60 u32 size;
61 union {
62 u8 info;
63
64 BitField<0, 4, ELFSymbolType> type;
65 BitField<4, 4, ELFSymbolBinding> binding;
66 };
67 ELFSymbolVisibility visibility;
68 u16 sh_index;
69};
70static_assert(sizeof(ELF32Symbol) == 0x10, "ELF32Symbol has incorrect size.");
71
72} // Anonymous namespace
73
74namespace Symbols {
75
76template <typename Word, typename ELFSymbol, typename ByteReader>
77static Symbols GetSymbols(ByteReader ReadBytes) {
78 const auto Read8{[&](u64 index) {
79 u8 ret;
80 ReadBytes(&ret, index, sizeof(u8));
81 return ret;
82 }};
83
84 const auto Read32{[&](u64 index) {
85 u32 ret;
86 ReadBytes(&ret, index, sizeof(u32));
87 return ret;
88 }};
89
90 const auto ReadWord{[&](u64 index) {
91 Word ret;
92 ReadBytes(&ret, index, sizeof(Word));
93 return ret;
94 }};
95
96 const u32 mod_offset = Read32(4);
97
98 if (Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) {
99 return {};
100 }
101
102 VAddr string_table_offset{};
103 VAddr symbol_table_offset{};
104 u64 symbol_entry_size{};
105
106 const auto dynamic_offset = Read32(mod_offset + 0x4) + mod_offset;
107
108 VAddr dynamic_index = dynamic_offset;
109 while (true) {
110 const Word tag = ReadWord(dynamic_index);
111 const Word value = ReadWord(dynamic_index + sizeof(Word));
112 dynamic_index += 2 * sizeof(Word);
113
114 if (tag == ELF_DYNAMIC_TAG_NULL) {
115 break;
116 }
117
118 if (tag == ELF_DYNAMIC_TAG_STRTAB) {
119 string_table_offset = value;
120 } else if (tag == ELF_DYNAMIC_TAG_SYMTAB) {
121 symbol_table_offset = value;
122 } else if (tag == ELF_DYNAMIC_TAG_SYMENT) {
123 symbol_entry_size = value;
124 }
125 }
126
127 if (string_table_offset == 0 || symbol_table_offset == 0 || symbol_entry_size == 0) {
128 return {};
129 }
130
131 Symbols out;
132
133 VAddr symbol_index = symbol_table_offset;
134 while (symbol_index < string_table_offset) {
135 ELFSymbol symbol{};
136 ReadBytes(&symbol, symbol_index, sizeof(ELFSymbol));
137
138 VAddr string_offset = string_table_offset + symbol.name_index;
139 std::string name;
140 for (u8 c = Read8(string_offset); c != 0; c = Read8(++string_offset)) {
141 name += static_cast<char>(c);
142 }
143
144 symbol_index += symbol_entry_size;
145 out[name] = std::make_pair(symbol.value, symbol.size);
146 }
147
148 return out;
149}
150
151Symbols GetSymbols(VAddr base, Core::Memory::Memory& memory, bool is_64) {
152 const auto ReadBytes{
153 [&](void* ptr, size_t offset, size_t size) { memory.ReadBlock(base + offset, ptr, size); }};
154
155 if (is_64) {
156 return GetSymbols<u64, ELF64Symbol>(ReadBytes);
157 } else {
158 return GetSymbols<u32, ELF32Symbol>(ReadBytes);
159 }
160}
161
162Symbols GetSymbols(std::span<const u8> data, bool is_64) {
163 const auto ReadBytes{[&](void* ptr, size_t offset, size_t size) {
164 std::memcpy(ptr, data.data() + offset, size);
165 }};
166
167 if (is_64) {
168 return GetSymbols<u64, ELF64Symbol>(ReadBytes);
169 } else {
170 return GetSymbols<u32, ELF32Symbol>(ReadBytes);
171 }
172}
173
174std::optional<std::string> GetSymbolName(const Symbols& symbols, VAddr addr) {
175 const auto iter = std::find_if(symbols.cbegin(), symbols.cend(), [addr](const auto& pair) {
176 const auto& [name, sym_info] = pair;
177 const auto& [start_address, size] = sym_info;
178 const auto end_address = start_address + size;
179 return addr >= start_address && addr < end_address;
180 });
181
182 if (iter == symbols.cend()) {
183 return std::nullopt;
184 }
185
186 return iter->first;
187}
188
189} // namespace Symbols
190} // namespace Core
diff --git a/src/core/arm/symbols.h b/src/core/arm/symbols.h
new file mode 100644
index 000000000..99e6a9f8e
--- /dev/null
+++ b/src/core/arm/symbols.h
@@ -0,0 +1,27 @@
1// Copyright 2022 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <map>
8#include <optional>
9#include <span>
10#include <string>
11#include <utility>
12
13#include "common/common_types.h"
14
15namespace Core::Memory {
16class Memory;
17} // namespace Core::Memory
18
19namespace Core::Symbols {
20
21using Symbols = std::map<std::string, std::pair<VAddr, std::size_t>, std::less<>>;
22
23Symbols GetSymbols(VAddr base, Core::Memory::Memory& memory, bool is_64 = true);
24Symbols GetSymbols(std::span<const u8> data, bool is_64 = true);
25std::optional<std::string> GetSymbolName(const Symbols& symbols, VAddr addr);
26
27} // namespace Core::Symbols
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index c4e185757..73e724f3d 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -148,29 +148,33 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
148 148
149 // LayeredExeFS 149 // LayeredExeFS
150 const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); 150 const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
151 const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
152
153 std::vector<VirtualDir> patch_dirs = {sdmc_load_dir};
151 if (load_dir != nullptr && load_dir->GetSize() > 0) { 154 if (load_dir != nullptr && load_dir->GetSize() > 0) {
152 auto patch_dirs = load_dir->GetSubdirectories(); 155 const auto load_patch_dirs = load_dir->GetSubdirectories();
153 std::sort( 156 patch_dirs.insert(patch_dirs.end(), load_patch_dirs.begin(), load_patch_dirs.end());
154 patch_dirs.begin(), patch_dirs.end(), 157 }
155 [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
156
157 std::vector<VirtualDir> layers;
158 layers.reserve(patch_dirs.size() + 1);
159 for (const auto& subdir : patch_dirs) {
160 if (std::find(disabled.begin(), disabled.end(), subdir->GetName()) != disabled.end())
161 continue;
162 158
163 auto exefs_dir = FindSubdirectoryCaseless(subdir, "exefs"); 159 std::sort(patch_dirs.begin(), patch_dirs.end(),
164 if (exefs_dir != nullptr) 160 [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
165 layers.push_back(std::move(exefs_dir));
166 }
167 layers.push_back(exefs);
168 161
169 auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers)); 162 std::vector<VirtualDir> layers;
170 if (layered != nullptr) { 163 layers.reserve(patch_dirs.size() + 1);
171 LOG_INFO(Loader, " ExeFS: LayeredExeFS patches applied successfully"); 164 for (const auto& subdir : patch_dirs) {
172 exefs = std::move(layered); 165 if (std::find(disabled.begin(), disabled.end(), subdir->GetName()) != disabled.end())
173 } 166 continue;
167
168 auto exefs_dir = FindSubdirectoryCaseless(subdir, "exefs");
169 if (exefs_dir != nullptr)
170 layers.push_back(std::move(exefs_dir));
171 }
172 layers.push_back(exefs);
173
174 auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers));
175 if (layered != nullptr) {
176 LOG_INFO(Loader, " ExeFS: LayeredExeFS patches applied successfully");
177 exefs = std::move(layered);
174 } 178 }
175 179
176 if (Settings::values.dump_exefs) { 180 if (Settings::values.dump_exefs) {
@@ -536,11 +540,20 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u
536 540
537 // SDMC mod directory (RomFS LayeredFS) 541 // SDMC mod directory (RomFS LayeredFS)
538 const auto sdmc_mod_dir = fs_controller.GetSDMCModificationLoadRoot(title_id); 542 const auto sdmc_mod_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
539 if (sdmc_mod_dir != nullptr && sdmc_mod_dir->GetSize() > 0 && 543 if (sdmc_mod_dir != nullptr && sdmc_mod_dir->GetSize() > 0) {
540 IsDirValidAndNonEmpty(FindSubdirectoryCaseless(sdmc_mod_dir, "romfs"))) { 544 std::string types;
541 const auto mod_disabled = 545 if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(sdmc_mod_dir, "exefs"))) {
542 std::find(disabled.begin(), disabled.end(), "SDMC") != disabled.end(); 546 AppendCommaIfNotEmpty(types, "LayeredExeFS");
543 out.insert_or_assign(mod_disabled ? "[D] SDMC" : "SDMC", "LayeredFS"); 547 }
548 if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(sdmc_mod_dir, "romfs"))) {
549 AppendCommaIfNotEmpty(types, "LayeredFS");
550 }
551
552 if (!types.empty()) {
553 const auto mod_disabled =
554 std::find(disabled.begin(), disabled.end(), "SDMC") != disabled.end();
555 out.insert_or_assign(mod_disabled ? "[D] SDMC" : "SDMC", types);
556 }
544 } 557 }
545 558
546 // DLC 559 // DLC
diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp
index eef0ff493..de565048b 100644
--- a/src/core/hid/emulated_console.cpp
+++ b/src/core/hid/emulated_console.cpp
@@ -132,7 +132,7 @@ void EmulatedConsole::SetMotionParam(Common::ParamPackage param) {
132} 132}
133 133
134void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) { 134void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
135 std::lock_guard lock{mutex}; 135 std::unique_lock lock{mutex};
136 auto& raw_status = console.motion_values.raw_status; 136 auto& raw_status = console.motion_values.raw_status;
137 auto& emulated = console.motion_values.emulated; 137 auto& emulated = console.motion_values.emulated;
138 138
@@ -151,6 +151,7 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
151 emulated.UpdateOrientation(raw_status.delta_timestamp); 151 emulated.UpdateOrientation(raw_status.delta_timestamp);
152 152
153 if (is_configuring) { 153 if (is_configuring) {
154 lock.unlock();
154 TriggerOnChange(ConsoleTriggerType::Motion); 155 TriggerOnChange(ConsoleTriggerType::Motion);
155 return; 156 return;
156 } 157 }
@@ -166,6 +167,7 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
166 // Find what is this value 167 // Find what is this value
167 motion.verticalization_error = 0.0f; 168 motion.verticalization_error = 0.0f;
168 169
170 lock.unlock();
169 TriggerOnChange(ConsoleTriggerType::Motion); 171 TriggerOnChange(ConsoleTriggerType::Motion);
170} 172}
171 173
@@ -173,11 +175,12 @@ void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, st
173 if (index >= console.touch_values.size()) { 175 if (index >= console.touch_values.size()) {
174 return; 176 return;
175 } 177 }
176 std::lock_guard lock{mutex}; 178 std::unique_lock lock{mutex};
177 179
178 console.touch_values[index] = TransformToTouch(callback); 180 console.touch_values[index] = TransformToTouch(callback);
179 181
180 if (is_configuring) { 182 if (is_configuring) {
183 lock.unlock();
181 TriggerOnChange(ConsoleTriggerType::Touch); 184 TriggerOnChange(ConsoleTriggerType::Touch);
182 return; 185 return;
183 } 186 }
@@ -189,26 +192,32 @@ void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, st
189 .pressed = console.touch_values[index].pressed.value, 192 .pressed = console.touch_values[index].pressed.value,
190 }; 193 };
191 194
195 lock.unlock();
192 TriggerOnChange(ConsoleTriggerType::Touch); 196 TriggerOnChange(ConsoleTriggerType::Touch);
193} 197}
194 198
195ConsoleMotionValues EmulatedConsole::GetMotionValues() const { 199ConsoleMotionValues EmulatedConsole::GetMotionValues() const {
200 std::scoped_lock lock{mutex};
196 return console.motion_values; 201 return console.motion_values;
197} 202}
198 203
199TouchValues EmulatedConsole::GetTouchValues() const { 204TouchValues EmulatedConsole::GetTouchValues() const {
205 std::scoped_lock lock{mutex};
200 return console.touch_values; 206 return console.touch_values;
201} 207}
202 208
203ConsoleMotion EmulatedConsole::GetMotion() const { 209ConsoleMotion EmulatedConsole::GetMotion() const {
210 std::scoped_lock lock{mutex};
204 return console.motion_state; 211 return console.motion_state;
205} 212}
206 213
207TouchFingerState EmulatedConsole::GetTouch() const { 214TouchFingerState EmulatedConsole::GetTouch() const {
215 std::scoped_lock lock{mutex};
208 return console.touch_state; 216 return console.touch_state;
209} 217}
210 218
211void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) { 219void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {
220 std::scoped_lock lock{callback_mutex};
212 for (const auto& poller_pair : callback_list) { 221 for (const auto& poller_pair : callback_list) {
213 const ConsoleUpdateCallback& poller = poller_pair.second; 222 const ConsoleUpdateCallback& poller = poller_pair.second;
214 if (poller.on_change) { 223 if (poller.on_change) {
@@ -218,13 +227,13 @@ void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {
218} 227}
219 228
220int EmulatedConsole::SetCallback(ConsoleUpdateCallback update_callback) { 229int EmulatedConsole::SetCallback(ConsoleUpdateCallback update_callback) {
221 std::lock_guard lock{mutex}; 230 std::scoped_lock lock{callback_mutex};
222 callback_list.insert_or_assign(last_callback_key, update_callback); 231 callback_list.insert_or_assign(last_callback_key, update_callback);
223 return last_callback_key++; 232 return last_callback_key++;
224} 233}
225 234
226void EmulatedConsole::DeleteCallback(int key) { 235void EmulatedConsole::DeleteCallback(int key) {
227 std::lock_guard lock{mutex}; 236 std::scoped_lock lock{callback_mutex};
228 const auto& iterator = callback_list.find(key); 237 const auto& iterator = callback_list.find(key);
229 if (iterator == callback_list.end()) { 238 if (iterator == callback_list.end()) {
230 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); 239 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h
index 5eb170823..53677bdc5 100644
--- a/src/core/hid/emulated_console.h
+++ b/src/core/hid/emulated_console.h
@@ -183,6 +183,7 @@ private:
183 TouchDevices touch_devices; 183 TouchDevices touch_devices;
184 184
185 mutable std::mutex mutex; 185 mutable std::mutex mutex;
186 mutable std::mutex callback_mutex;
186 std::unordered_map<int, ConsoleUpdateCallback> callback_list; 187 std::unordered_map<int, ConsoleUpdateCallback> callback_list;
187 int last_callback_key = 0; 188 int last_callback_key = 0;
188 189
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp
index 7e05666d6..c3f21066c 100644
--- a/src/core/hid/emulated_controller.cpp
+++ b/src/core/hid/emulated_controller.cpp
@@ -353,14 +353,17 @@ void EmulatedController::DisableConfiguration() {
353} 353}
354 354
355void EmulatedController::EnableSystemButtons() { 355void EmulatedController::EnableSystemButtons() {
356 std::scoped_lock lock{mutex};
356 system_buttons_enabled = true; 357 system_buttons_enabled = true;
357} 358}
358 359
359void EmulatedController::DisableSystemButtons() { 360void EmulatedController::DisableSystemButtons() {
361 std::scoped_lock lock{mutex};
360 system_buttons_enabled = false; 362 system_buttons_enabled = false;
361} 363}
362 364
363void EmulatedController::ResetSystemButtons() { 365void EmulatedController::ResetSystemButtons() {
366 std::scoped_lock lock{mutex};
364 controller.home_button_state.home.Assign(false); 367 controller.home_button_state.home.Assign(false);
365 controller.capture_button_state.capture.Assign(false); 368 controller.capture_button_state.capture.Assign(false);
366} 369}
@@ -494,139 +497,141 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback
494 if (index >= controller.button_values.size()) { 497 if (index >= controller.button_values.size()) {
495 return; 498 return;
496 } 499 }
497 { 500 std::unique_lock lock{mutex};
498 std::lock_guard lock{mutex}; 501 bool value_changed = false;
499 bool value_changed = false; 502 const auto new_status = TransformToButton(callback);
500 const auto new_status = TransformToButton(callback); 503 auto& current_status = controller.button_values[index];
501 auto& current_status = controller.button_values[index];
502 504
503 // Only read button values that have the same uuid or are pressed once 505 // Only read button values that have the same uuid or are pressed once
504 if (current_status.uuid != uuid) { 506 if (current_status.uuid != uuid) {
505 if (!new_status.value) { 507 if (!new_status.value) {
506 return; 508 return;
507 }
508 } 509 }
510 }
509 511
510 current_status.toggle = new_status.toggle; 512 current_status.toggle = new_status.toggle;
511 current_status.uuid = uuid; 513 current_status.uuid = uuid;
512
513 // Update button status with current
514 if (!current_status.toggle) {
515 current_status.locked = false;
516 if (current_status.value != new_status.value) {
517 current_status.value = new_status.value;
518 value_changed = true;
519 }
520 } else {
521 // Toggle button and lock status
522 if (new_status.value && !current_status.locked) {
523 current_status.locked = true;
524 current_status.value = !current_status.value;
525 value_changed = true;
526 }
527 514
528 // Unlock button ready for next press 515 // Update button status with current
529 if (!new_status.value && current_status.locked) { 516 if (!current_status.toggle) {
530 current_status.locked = false; 517 current_status.locked = false;
531 } 518 if (current_status.value != new_status.value) {
519 current_status.value = new_status.value;
520 value_changed = true;
532 } 521 }
533 522 } else {
534 if (!value_changed) { 523 // Toggle button and lock status
535 return; 524 if (new_status.value && !current_status.locked) {
525 current_status.locked = true;
526 current_status.value = !current_status.value;
527 value_changed = true;
536 } 528 }
537 529
538 if (is_configuring) { 530 // Unlock button ready for next press
539 controller.npad_button_state.raw = NpadButton::None; 531 if (!new_status.value && current_status.locked) {
540 controller.debug_pad_button_state.raw = 0; 532 current_status.locked = false;
541 TriggerOnChange(ControllerTriggerType::Button, false);
542 return;
543 } 533 }
534 }
544 535
545 switch (index) { 536 if (!value_changed) {
546 case Settings::NativeButton::A: 537 return;
547 controller.npad_button_state.a.Assign(current_status.value); 538 }
548 controller.debug_pad_button_state.a.Assign(current_status.value); 539
549 break; 540 if (is_configuring) {
550 case Settings::NativeButton::B: 541 controller.npad_button_state.raw = NpadButton::None;
551 controller.npad_button_state.b.Assign(current_status.value); 542 controller.debug_pad_button_state.raw = 0;
552 controller.debug_pad_button_state.b.Assign(current_status.value); 543 lock.unlock();
553 break; 544 TriggerOnChange(ControllerTriggerType::Button, false);
554 case Settings::NativeButton::X: 545 return;
555 controller.npad_button_state.x.Assign(current_status.value); 546 }
556 controller.debug_pad_button_state.x.Assign(current_status.value); 547
557 break; 548 switch (index) {
558 case Settings::NativeButton::Y: 549 case Settings::NativeButton::A:
559 controller.npad_button_state.y.Assign(current_status.value); 550 controller.npad_button_state.a.Assign(current_status.value);
560 controller.debug_pad_button_state.y.Assign(current_status.value); 551 controller.debug_pad_button_state.a.Assign(current_status.value);
561 break; 552 break;
562 case Settings::NativeButton::LStick: 553 case Settings::NativeButton::B:
563 controller.npad_button_state.stick_l.Assign(current_status.value); 554 controller.npad_button_state.b.Assign(current_status.value);
564 break; 555 controller.debug_pad_button_state.b.Assign(current_status.value);
565 case Settings::NativeButton::RStick: 556 break;
566 controller.npad_button_state.stick_r.Assign(current_status.value); 557 case Settings::NativeButton::X:
567 break; 558 controller.npad_button_state.x.Assign(current_status.value);
568 case Settings::NativeButton::L: 559 controller.debug_pad_button_state.x.Assign(current_status.value);
569 controller.npad_button_state.l.Assign(current_status.value); 560 break;
570 controller.debug_pad_button_state.l.Assign(current_status.value); 561 case Settings::NativeButton::Y:
571 break; 562 controller.npad_button_state.y.Assign(current_status.value);
572 case Settings::NativeButton::R: 563 controller.debug_pad_button_state.y.Assign(current_status.value);
573 controller.npad_button_state.r.Assign(current_status.value); 564 break;
574 controller.debug_pad_button_state.r.Assign(current_status.value); 565 case Settings::NativeButton::LStick:
575 break; 566 controller.npad_button_state.stick_l.Assign(current_status.value);
576 case Settings::NativeButton::ZL: 567 break;
577 controller.npad_button_state.zl.Assign(current_status.value); 568 case Settings::NativeButton::RStick:
578 controller.debug_pad_button_state.zl.Assign(current_status.value); 569 controller.npad_button_state.stick_r.Assign(current_status.value);
579 break; 570 break;
580 case Settings::NativeButton::ZR: 571 case Settings::NativeButton::L:
581 controller.npad_button_state.zr.Assign(current_status.value); 572 controller.npad_button_state.l.Assign(current_status.value);
582 controller.debug_pad_button_state.zr.Assign(current_status.value); 573 controller.debug_pad_button_state.l.Assign(current_status.value);
583 break; 574 break;
584 case Settings::NativeButton::Plus: 575 case Settings::NativeButton::R:
585 controller.npad_button_state.plus.Assign(current_status.value); 576 controller.npad_button_state.r.Assign(current_status.value);
586 controller.debug_pad_button_state.plus.Assign(current_status.value); 577 controller.debug_pad_button_state.r.Assign(current_status.value);
587 break; 578 break;
588 case Settings::NativeButton::Minus: 579 case Settings::NativeButton::ZL:
589 controller.npad_button_state.minus.Assign(current_status.value); 580 controller.npad_button_state.zl.Assign(current_status.value);
590 controller.debug_pad_button_state.minus.Assign(current_status.value); 581 controller.debug_pad_button_state.zl.Assign(current_status.value);
591 break; 582 break;
592 case Settings::NativeButton::DLeft: 583 case Settings::NativeButton::ZR:
593 controller.npad_button_state.left.Assign(current_status.value); 584 controller.npad_button_state.zr.Assign(current_status.value);
594 controller.debug_pad_button_state.d_left.Assign(current_status.value); 585 controller.debug_pad_button_state.zr.Assign(current_status.value);
595 break; 586 break;
596 case Settings::NativeButton::DUp: 587 case Settings::NativeButton::Plus:
597 controller.npad_button_state.up.Assign(current_status.value); 588 controller.npad_button_state.plus.Assign(current_status.value);
598 controller.debug_pad_button_state.d_up.Assign(current_status.value); 589 controller.debug_pad_button_state.plus.Assign(current_status.value);
599 break; 590 break;
600 case Settings::NativeButton::DRight: 591 case Settings::NativeButton::Minus:
601 controller.npad_button_state.right.Assign(current_status.value); 592 controller.npad_button_state.minus.Assign(current_status.value);
602 controller.debug_pad_button_state.d_right.Assign(current_status.value); 593 controller.debug_pad_button_state.minus.Assign(current_status.value);
603 break; 594 break;
604 case Settings::NativeButton::DDown: 595 case Settings::NativeButton::DLeft:
605 controller.npad_button_state.down.Assign(current_status.value); 596 controller.npad_button_state.left.Assign(current_status.value);
606 controller.debug_pad_button_state.d_down.Assign(current_status.value); 597 controller.debug_pad_button_state.d_left.Assign(current_status.value);
607 break; 598 break;
608 case Settings::NativeButton::SL: 599 case Settings::NativeButton::DUp:
609 controller.npad_button_state.left_sl.Assign(current_status.value); 600 controller.npad_button_state.up.Assign(current_status.value);
610 controller.npad_button_state.right_sl.Assign(current_status.value); 601 controller.debug_pad_button_state.d_up.Assign(current_status.value);
611 break; 602 break;
612 case Settings::NativeButton::SR: 603 case Settings::NativeButton::DRight:
613 controller.npad_button_state.left_sr.Assign(current_status.value); 604 controller.npad_button_state.right.Assign(current_status.value);
614 controller.npad_button_state.right_sr.Assign(current_status.value); 605 controller.debug_pad_button_state.d_right.Assign(current_status.value);
615 break; 606 break;
616 case Settings::NativeButton::Home: 607 case Settings::NativeButton::DDown:
617 if (!system_buttons_enabled) { 608 controller.npad_button_state.down.Assign(current_status.value);
618 break; 609 controller.debug_pad_button_state.d_down.Assign(current_status.value);
619 } 610 break;
620 controller.home_button_state.home.Assign(current_status.value); 611 case Settings::NativeButton::SL:
612 controller.npad_button_state.left_sl.Assign(current_status.value);
613 controller.npad_button_state.right_sl.Assign(current_status.value);
614 break;
615 case Settings::NativeButton::SR:
616 controller.npad_button_state.left_sr.Assign(current_status.value);
617 controller.npad_button_state.right_sr.Assign(current_status.value);
618 break;
619 case Settings::NativeButton::Home:
620 if (!system_buttons_enabled) {
621 break; 621 break;
622 case Settings::NativeButton::Screenshot: 622 }
623 if (!system_buttons_enabled) { 623 controller.home_button_state.home.Assign(current_status.value);
624 break; 624 break;
625 } 625 case Settings::NativeButton::Screenshot:
626 controller.capture_button_state.capture.Assign(current_status.value); 626 if (!system_buttons_enabled) {
627 break; 627 break;
628 } 628 }
629 controller.capture_button_state.capture.Assign(current_status.value);
630 break;
629 } 631 }
632
633 lock.unlock();
634
630 if (!is_connected) { 635 if (!is_connected) {
631 if (npad_id_type == NpadIdType::Player1 && npad_type != NpadStyleIndex::Handheld) { 636 if (npad_id_type == NpadIdType::Player1 && npad_type != NpadStyleIndex::Handheld) {
632 Connect(); 637 Connect();
@@ -643,7 +648,7 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
643 if (index >= controller.stick_values.size()) { 648 if (index >= controller.stick_values.size()) {
644 return; 649 return;
645 } 650 }
646 std::lock_guard lock{mutex}; 651 std::unique_lock lock{mutex};
647 const auto stick_value = TransformToStick(callback); 652 const auto stick_value = TransformToStick(callback);
648 653
649 // Only read stick values that have the same uuid or are over the threshold to avoid flapping 654 // Only read stick values that have the same uuid or are over the threshold to avoid flapping
@@ -659,6 +664,7 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
659 if (is_configuring) { 664 if (is_configuring) {
660 controller.analog_stick_state.left = {}; 665 controller.analog_stick_state.left = {};
661 controller.analog_stick_state.right = {}; 666 controller.analog_stick_state.right = {};
667 lock.unlock();
662 TriggerOnChange(ControllerTriggerType::Stick, false); 668 TriggerOnChange(ControllerTriggerType::Stick, false);
663 return; 669 return;
664 } 670 }
@@ -685,6 +691,7 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback,
685 break; 691 break;
686 } 692 }
687 693
694 lock.unlock();
688 TriggerOnChange(ControllerTriggerType::Stick, true); 695 TriggerOnChange(ControllerTriggerType::Stick, true);
689} 696}
690 697
@@ -693,7 +700,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
693 if (index >= controller.trigger_values.size()) { 700 if (index >= controller.trigger_values.size()) {
694 return; 701 return;
695 } 702 }
696 std::lock_guard lock{mutex}; 703 std::unique_lock lock{mutex};
697 const auto trigger_value = TransformToTrigger(callback); 704 const auto trigger_value = TransformToTrigger(callback);
698 705
699 // Only read trigger values that have the same uuid or are pressed once 706 // Only read trigger values that have the same uuid or are pressed once
@@ -709,6 +716,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
709 if (is_configuring) { 716 if (is_configuring) {
710 controller.gc_trigger_state.left = 0; 717 controller.gc_trigger_state.left = 0;
711 controller.gc_trigger_state.right = 0; 718 controller.gc_trigger_state.right = 0;
719 lock.unlock();
712 TriggerOnChange(ControllerTriggerType::Trigger, false); 720 TriggerOnChange(ControllerTriggerType::Trigger, false);
713 return; 721 return;
714 } 722 }
@@ -727,6 +735,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac
727 break; 735 break;
728 } 736 }
729 737
738 lock.unlock();
730 TriggerOnChange(ControllerTriggerType::Trigger, true); 739 TriggerOnChange(ControllerTriggerType::Trigger, true);
731} 740}
732 741
@@ -735,7 +744,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
735 if (index >= controller.motion_values.size()) { 744 if (index >= controller.motion_values.size()) {
736 return; 745 return;
737 } 746 }
738 std::lock_guard lock{mutex}; 747 std::unique_lock lock{mutex};
739 auto& raw_status = controller.motion_values[index].raw_status; 748 auto& raw_status = controller.motion_values[index].raw_status;
740 auto& emulated = controller.motion_values[index].emulated; 749 auto& emulated = controller.motion_values[index].emulated;
741 750
@@ -756,6 +765,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
756 force_update_motion = raw_status.force_update; 765 force_update_motion = raw_status.force_update;
757 766
758 if (is_configuring) { 767 if (is_configuring) {
768 lock.unlock();
759 TriggerOnChange(ControllerTriggerType::Motion, false); 769 TriggerOnChange(ControllerTriggerType::Motion, false);
760 return; 770 return;
761 } 771 }
@@ -767,6 +777,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback
767 motion.orientation = emulated.GetOrientation(); 777 motion.orientation = emulated.GetOrientation();
768 motion.is_at_rest = !emulated.IsMoving(motion_sensitivity); 778 motion.is_at_rest = !emulated.IsMoving(motion_sensitivity);
769 779
780 lock.unlock();
770 TriggerOnChange(ControllerTriggerType::Motion, true); 781 TriggerOnChange(ControllerTriggerType::Motion, true);
771} 782}
772 783
@@ -775,10 +786,11 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
775 if (index >= controller.battery_values.size()) { 786 if (index >= controller.battery_values.size()) {
776 return; 787 return;
777 } 788 }
778 std::lock_guard lock{mutex}; 789 std::unique_lock lock{mutex};
779 controller.battery_values[index] = TransformToBattery(callback); 790 controller.battery_values[index] = TransformToBattery(callback);
780 791
781 if (is_configuring) { 792 if (is_configuring) {
793 lock.unlock();
782 TriggerOnChange(ControllerTriggerType::Battery, false); 794 TriggerOnChange(ControllerTriggerType::Battery, false);
783 return; 795 return;
784 } 796 }
@@ -835,6 +847,8 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac
835 }; 847 };
836 break; 848 break;
837 } 849 }
850
851 lock.unlock();
838 TriggerOnChange(ControllerTriggerType::Battery, true); 852 TriggerOnChange(ControllerTriggerType::Battery, true);
839} 853}
840 854
@@ -932,6 +946,7 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles)
932} 946}
933 947
934bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const { 948bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const {
949 std::scoped_lock lock{mutex};
935 const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; 950 const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
936 switch (type) { 951 switch (type) {
937 case NpadStyleIndex::ProController: 952 case NpadStyleIndex::ProController:
@@ -947,6 +962,7 @@ bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const {
947} 962}
948 963
949bool EmulatedController::IsControllerSupported(bool use_temporary_value) const { 964bool EmulatedController::IsControllerSupported(bool use_temporary_value) const {
965 std::scoped_lock lock{mutex};
950 const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; 966 const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type;
951 switch (type) { 967 switch (type) {
952 case NpadStyleIndex::ProController: 968 case NpadStyleIndex::ProController:
@@ -982,40 +998,44 @@ void EmulatedController::Connect(bool use_temporary_value) {
982 LOG_ERROR(Service_HID, "Controller type {} is not supported", type); 998 LOG_ERROR(Service_HID, "Controller type {} is not supported", type);
983 return; 999 return;
984 } 1000 }
985 {
986 std::lock_guard lock{mutex};
987 if (is_configuring) {
988 tmp_is_connected = true;
989 TriggerOnChange(ControllerTriggerType::Connected, false);
990 return;
991 }
992 1001
993 if (is_connected) { 1002 std::unique_lock lock{mutex};
994 return; 1003 if (is_configuring) {
995 } 1004 tmp_is_connected = true;
996 is_connected = true; 1005 lock.unlock();
1006 TriggerOnChange(ControllerTriggerType::Connected, false);
1007 return;
1008 }
1009
1010 if (is_connected) {
1011 return;
997 } 1012 }
1013 is_connected = true;
1014
1015 lock.unlock();
998 TriggerOnChange(ControllerTriggerType::Connected, true); 1016 TriggerOnChange(ControllerTriggerType::Connected, true);
999} 1017}
1000 1018
1001void EmulatedController::Disconnect() { 1019void EmulatedController::Disconnect() {
1002 { 1020 std::unique_lock lock{mutex};
1003 std::lock_guard lock{mutex}; 1021 if (is_configuring) {
1004 if (is_configuring) { 1022 tmp_is_connected = false;
1005 tmp_is_connected = false; 1023 lock.unlock();
1006 TriggerOnChange(ControllerTriggerType::Disconnected, false); 1024 TriggerOnChange(ControllerTriggerType::Disconnected, false);
1007 return; 1025 return;
1008 } 1026 }
1009 1027
1010 if (!is_connected) { 1028 if (!is_connected) {
1011 return; 1029 return;
1012 }
1013 is_connected = false;
1014 } 1030 }
1031 is_connected = false;
1032
1033 lock.unlock();
1015 TriggerOnChange(ControllerTriggerType::Disconnected, true); 1034 TriggerOnChange(ControllerTriggerType::Disconnected, true);
1016} 1035}
1017 1036
1018bool EmulatedController::IsConnected(bool get_temporary_value) const { 1037bool EmulatedController::IsConnected(bool get_temporary_value) const {
1038 std::scoped_lock lock{mutex};
1019 if (get_temporary_value && is_configuring) { 1039 if (get_temporary_value && is_configuring) {
1020 return tmp_is_connected; 1040 return tmp_is_connected;
1021 } 1041 }
@@ -1029,10 +1049,12 @@ bool EmulatedController::IsVibrationEnabled() const {
1029} 1049}
1030 1050
1031NpadIdType EmulatedController::GetNpadIdType() const { 1051NpadIdType EmulatedController::GetNpadIdType() const {
1052 std::scoped_lock lock{mutex};
1032 return npad_id_type; 1053 return npad_id_type;
1033} 1054}
1034 1055
1035NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) const { 1056NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) const {
1057 std::scoped_lock lock{mutex};
1036 if (get_temporary_value && is_configuring) { 1058 if (get_temporary_value && is_configuring) {
1037 return tmp_npad_type; 1059 return tmp_npad_type;
1038 } 1060 }
@@ -1040,27 +1062,28 @@ NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) c
1040} 1062}
1041 1063
1042void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) { 1064void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) {
1043 { 1065 std::unique_lock lock{mutex};
1044 std::lock_guard lock{mutex};
1045 1066
1046 if (is_configuring) { 1067 if (is_configuring) {
1047 if (tmp_npad_type == npad_type_) { 1068 if (tmp_npad_type == npad_type_) {
1048 return;
1049 }
1050 tmp_npad_type = npad_type_;
1051 TriggerOnChange(ControllerTriggerType::Type, false);
1052 return; 1069 return;
1053 } 1070 }
1071 tmp_npad_type = npad_type_;
1072 lock.unlock();
1073 TriggerOnChange(ControllerTriggerType::Type, false);
1074 return;
1075 }
1054 1076
1055 if (npad_type == npad_type_) { 1077 if (npad_type == npad_type_) {
1056 return; 1078 return;
1057 } 1079 }
1058 if (is_connected) { 1080 if (is_connected) {
1059 LOG_WARNING(Service_HID, "Controller {} type changed while it's connected", 1081 LOG_WARNING(Service_HID, "Controller {} type changed while it's connected",
1060 NpadIdTypeToIndex(npad_id_type)); 1082 NpadIdTypeToIndex(npad_id_type));
1061 }
1062 npad_type = npad_type_;
1063 } 1083 }
1084 npad_type = npad_type_;
1085
1086 lock.unlock();
1064 TriggerOnChange(ControllerTriggerType::Type, true); 1087 TriggerOnChange(ControllerTriggerType::Type, true);
1065} 1088}
1066 1089
@@ -1088,30 +1111,37 @@ LedPattern EmulatedController::GetLedPattern() const {
1088} 1111}
1089 1112
1090ButtonValues EmulatedController::GetButtonsValues() const { 1113ButtonValues EmulatedController::GetButtonsValues() const {
1114 std::scoped_lock lock{mutex};
1091 return controller.button_values; 1115 return controller.button_values;
1092} 1116}
1093 1117
1094SticksValues EmulatedController::GetSticksValues() const { 1118SticksValues EmulatedController::GetSticksValues() const {
1119 std::scoped_lock lock{mutex};
1095 return controller.stick_values; 1120 return controller.stick_values;
1096} 1121}
1097 1122
1098TriggerValues EmulatedController::GetTriggersValues() const { 1123TriggerValues EmulatedController::GetTriggersValues() const {
1124 std::scoped_lock lock{mutex};
1099 return controller.trigger_values; 1125 return controller.trigger_values;
1100} 1126}
1101 1127
1102ControllerMotionValues EmulatedController::GetMotionValues() const { 1128ControllerMotionValues EmulatedController::GetMotionValues() const {
1129 std::scoped_lock lock{mutex};
1103 return controller.motion_values; 1130 return controller.motion_values;
1104} 1131}
1105 1132
1106ColorValues EmulatedController::GetColorsValues() const { 1133ColorValues EmulatedController::GetColorsValues() const {
1134 std::scoped_lock lock{mutex};
1107 return controller.color_values; 1135 return controller.color_values;
1108} 1136}
1109 1137
1110BatteryValues EmulatedController::GetBatteryValues() const { 1138BatteryValues EmulatedController::GetBatteryValues() const {
1139 std::scoped_lock lock{mutex};
1111 return controller.battery_values; 1140 return controller.battery_values;
1112} 1141}
1113 1142
1114HomeButtonState EmulatedController::GetHomeButtons() const { 1143HomeButtonState EmulatedController::GetHomeButtons() const {
1144 std::scoped_lock lock{mutex};
1115 if (is_configuring) { 1145 if (is_configuring) {
1116 return {}; 1146 return {};
1117 } 1147 }
@@ -1119,6 +1149,7 @@ HomeButtonState EmulatedController::GetHomeButtons() const {
1119} 1149}
1120 1150
1121CaptureButtonState EmulatedController::GetCaptureButtons() const { 1151CaptureButtonState EmulatedController::GetCaptureButtons() const {
1152 std::scoped_lock lock{mutex};
1122 if (is_configuring) { 1153 if (is_configuring) {
1123 return {}; 1154 return {};
1124 } 1155 }
@@ -1126,6 +1157,7 @@ CaptureButtonState EmulatedController::GetCaptureButtons() const {
1126} 1157}
1127 1158
1128NpadButtonState EmulatedController::GetNpadButtons() const { 1159NpadButtonState EmulatedController::GetNpadButtons() const {
1160 std::scoped_lock lock{mutex};
1129 if (is_configuring) { 1161 if (is_configuring) {
1130 return {}; 1162 return {};
1131 } 1163 }
@@ -1133,6 +1165,7 @@ NpadButtonState EmulatedController::GetNpadButtons() const {
1133} 1165}
1134 1166
1135DebugPadButton EmulatedController::GetDebugPadButtons() const { 1167DebugPadButton EmulatedController::GetDebugPadButtons() const {
1168 std::scoped_lock lock{mutex};
1136 if (is_configuring) { 1169 if (is_configuring) {
1137 return {}; 1170 return {};
1138 } 1171 }
@@ -1140,20 +1173,27 @@ DebugPadButton EmulatedController::GetDebugPadButtons() const {
1140} 1173}
1141 1174
1142AnalogSticks EmulatedController::GetSticks() const { 1175AnalogSticks EmulatedController::GetSticks() const {
1176 std::unique_lock lock{mutex};
1177
1143 if (is_configuring) { 1178 if (is_configuring) {
1144 return {}; 1179 return {};
1145 } 1180 }
1181
1146 // Some drivers like stick from buttons need constant refreshing 1182 // Some drivers like stick from buttons need constant refreshing
1147 for (auto& device : stick_devices) { 1183 for (auto& device : stick_devices) {
1148 if (!device) { 1184 if (!device) {
1149 continue; 1185 continue;
1150 } 1186 }
1187 lock.unlock();
1151 device->SoftUpdate(); 1188 device->SoftUpdate();
1189 lock.lock();
1152 } 1190 }
1191
1153 return controller.analog_stick_state; 1192 return controller.analog_stick_state;
1154} 1193}
1155 1194
1156NpadGcTriggerState EmulatedController::GetTriggers() const { 1195NpadGcTriggerState EmulatedController::GetTriggers() const {
1196 std::scoped_lock lock{mutex};
1157 if (is_configuring) { 1197 if (is_configuring) {
1158 return {}; 1198 return {};
1159 } 1199 }
@@ -1161,26 +1201,35 @@ NpadGcTriggerState EmulatedController::GetTriggers() const {
1161} 1201}
1162 1202
1163MotionState EmulatedController::GetMotions() const { 1203MotionState EmulatedController::GetMotions() const {
1204 std::unique_lock lock{mutex};
1205
1206 // Some drivers like mouse motion need constant refreshing
1164 if (force_update_motion) { 1207 if (force_update_motion) {
1165 for (auto& device : motion_devices) { 1208 for (auto& device : motion_devices) {
1166 if (!device) { 1209 if (!device) {
1167 continue; 1210 continue;
1168 } 1211 }
1212 lock.unlock();
1169 device->ForceUpdate(); 1213 device->ForceUpdate();
1214 lock.lock();
1170 } 1215 }
1171 } 1216 }
1217
1172 return controller.motion_state; 1218 return controller.motion_state;
1173} 1219}
1174 1220
1175ControllerColors EmulatedController::GetColors() const { 1221ControllerColors EmulatedController::GetColors() const {
1222 std::scoped_lock lock{mutex};
1176 return controller.colors_state; 1223 return controller.colors_state;
1177} 1224}
1178 1225
1179BatteryLevelState EmulatedController::GetBattery() const { 1226BatteryLevelState EmulatedController::GetBattery() const {
1227 std::scoped_lock lock{mutex};
1180 return controller.battery_state; 1228 return controller.battery_state;
1181} 1229}
1182 1230
1183void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) { 1231void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) {
1232 std::scoped_lock lock{callback_mutex};
1184 for (const auto& poller_pair : callback_list) { 1233 for (const auto& poller_pair : callback_list) {
1185 const ControllerUpdateCallback& poller = poller_pair.second; 1234 const ControllerUpdateCallback& poller = poller_pair.second;
1186 if (!is_npad_service_update && poller.is_npad_service) { 1235 if (!is_npad_service_update && poller.is_npad_service) {
@@ -1193,13 +1242,13 @@ void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npa
1193} 1242}
1194 1243
1195int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) { 1244int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) {
1196 std::lock_guard lock{mutex}; 1245 std::scoped_lock lock{callback_mutex};
1197 callback_list.insert_or_assign(last_callback_key, std::move(update_callback)); 1246 callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
1198 return last_callback_key++; 1247 return last_callback_key++;
1199} 1248}
1200 1249
1201void EmulatedController::DeleteCallback(int key) { 1250void EmulatedController::DeleteCallback(int key) {
1202 std::lock_guard lock{mutex}; 1251 std::scoped_lock lock{callback_mutex};
1203 const auto& iterator = callback_list.find(key); 1252 const auto& iterator = callback_list.find(key);
1204 if (iterator == callback_list.end()) { 1253 if (iterator == callback_list.end()) {
1205 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); 1254 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h
index aa52f9572..1e224685d 100644
--- a/src/core/hid/emulated_controller.h
+++ b/src/core/hid/emulated_controller.h
@@ -400,7 +400,7 @@ private:
400 */ 400 */
401 void TriggerOnChange(ControllerTriggerType type, bool is_service_update); 401 void TriggerOnChange(ControllerTriggerType type, bool is_service_update);
402 402
403 NpadIdType npad_id_type; 403 const NpadIdType npad_id_type;
404 NpadStyleIndex npad_type{NpadStyleIndex::None}; 404 NpadStyleIndex npad_type{NpadStyleIndex::None};
405 NpadStyleTag supported_style_tag{NpadStyleSet::All}; 405 NpadStyleTag supported_style_tag{NpadStyleSet::All};
406 bool is_connected{false}; 406 bool is_connected{false};
@@ -434,6 +434,7 @@ private:
434 StickDevices tas_stick_devices; 434 StickDevices tas_stick_devices;
435 435
436 mutable std::mutex mutex; 436 mutable std::mutex mutex;
437 mutable std::mutex callback_mutex;
437 std::unordered_map<int, ControllerUpdateCallback> callback_list; 438 std::unordered_map<int, ControllerUpdateCallback> callback_list;
438 int last_callback_key = 0; 439 int last_callback_key = 0;
439 440
diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp
index 708480f2d..cc0dcd931 100644
--- a/src/core/hid/emulated_devices.cpp
+++ b/src/core/hid/emulated_devices.cpp
@@ -169,7 +169,7 @@ void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& cal
169 if (index >= device_status.keyboard_values.size()) { 169 if (index >= device_status.keyboard_values.size()) {
170 return; 170 return;
171 } 171 }
172 std::lock_guard lock{mutex}; 172 std::unique_lock lock{mutex};
173 bool value_changed = false; 173 bool value_changed = false;
174 const auto new_status = TransformToButton(callback); 174 const auto new_status = TransformToButton(callback);
175 auto& current_status = device_status.keyboard_values[index]; 175 auto& current_status = device_status.keyboard_values[index];
@@ -201,6 +201,7 @@ void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& cal
201 } 201 }
202 202
203 if (is_configuring) { 203 if (is_configuring) {
204 lock.unlock();
204 TriggerOnChange(DeviceTriggerType::Keyboard); 205 TriggerOnChange(DeviceTriggerType::Keyboard);
205 return; 206 return;
206 } 207 }
@@ -208,6 +209,7 @@ void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& cal
208 // Index should be converted from NativeKeyboard to KeyboardKeyIndex 209 // Index should be converted from NativeKeyboard to KeyboardKeyIndex
209 UpdateKey(index, current_status.value); 210 UpdateKey(index, current_status.value);
210 211
212 lock.unlock();
211 TriggerOnChange(DeviceTriggerType::Keyboard); 213 TriggerOnChange(DeviceTriggerType::Keyboard);
212} 214}
213 215
@@ -227,7 +229,7 @@ void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& c
227 if (index >= device_status.keyboard_moddifier_values.size()) { 229 if (index >= device_status.keyboard_moddifier_values.size()) {
228 return; 230 return;
229 } 231 }
230 std::lock_guard lock{mutex}; 232 std::unique_lock lock{mutex};
231 bool value_changed = false; 233 bool value_changed = false;
232 const auto new_status = TransformToButton(callback); 234 const auto new_status = TransformToButton(callback);
233 auto& current_status = device_status.keyboard_moddifier_values[index]; 235 auto& current_status = device_status.keyboard_moddifier_values[index];
@@ -259,6 +261,7 @@ void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& c
259 } 261 }
260 262
261 if (is_configuring) { 263 if (is_configuring) {
264 lock.unlock();
262 TriggerOnChange(DeviceTriggerType::KeyboardModdifier); 265 TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
263 return; 266 return;
264 } 267 }
@@ -289,6 +292,7 @@ void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& c
289 break; 292 break;
290 } 293 }
291 294
295 lock.unlock();
292 TriggerOnChange(DeviceTriggerType::KeyboardModdifier); 296 TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
293} 297}
294 298
@@ -297,7 +301,7 @@ void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callba
297 if (index >= device_status.mouse_button_values.size()) { 301 if (index >= device_status.mouse_button_values.size()) {
298 return; 302 return;
299 } 303 }
300 std::lock_guard lock{mutex}; 304 std::unique_lock lock{mutex};
301 bool value_changed = false; 305 bool value_changed = false;
302 const auto new_status = TransformToButton(callback); 306 const auto new_status = TransformToButton(callback);
303 auto& current_status = device_status.mouse_button_values[index]; 307 auto& current_status = device_status.mouse_button_values[index];
@@ -329,6 +333,7 @@ void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callba
329 } 333 }
330 334
331 if (is_configuring) { 335 if (is_configuring) {
336 lock.unlock();
332 TriggerOnChange(DeviceTriggerType::Mouse); 337 TriggerOnChange(DeviceTriggerType::Mouse);
333 return; 338 return;
334 } 339 }
@@ -351,6 +356,7 @@ void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callba
351 break; 356 break;
352 } 357 }
353 358
359 lock.unlock();
354 TriggerOnChange(DeviceTriggerType::Mouse); 360 TriggerOnChange(DeviceTriggerType::Mouse);
355} 361}
356 362
@@ -359,13 +365,14 @@ void EmulatedDevices::SetMouseAnalog(const Common::Input::CallbackStatus& callba
359 if (index >= device_status.mouse_analog_values.size()) { 365 if (index >= device_status.mouse_analog_values.size()) {
360 return; 366 return;
361 } 367 }
362 std::lock_guard lock{mutex}; 368 std::unique_lock lock{mutex};
363 const auto analog_value = TransformToAnalog(callback); 369 const auto analog_value = TransformToAnalog(callback);
364 370
365 device_status.mouse_analog_values[index] = analog_value; 371 device_status.mouse_analog_values[index] = analog_value;
366 372
367 if (is_configuring) { 373 if (is_configuring) {
368 device_status.mouse_position_state = {}; 374 device_status.mouse_position_state = {};
375 lock.unlock();
369 TriggerOnChange(DeviceTriggerType::Mouse); 376 TriggerOnChange(DeviceTriggerType::Mouse);
370 return; 377 return;
371 } 378 }
@@ -379,17 +386,19 @@ void EmulatedDevices::SetMouseAnalog(const Common::Input::CallbackStatus& callba
379 break; 386 break;
380 } 387 }
381 388
389 lock.unlock();
382 TriggerOnChange(DeviceTriggerType::Mouse); 390 TriggerOnChange(DeviceTriggerType::Mouse);
383} 391}
384 392
385void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callback) { 393void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callback) {
386 std::lock_guard lock{mutex}; 394 std::unique_lock lock{mutex};
387 const auto touch_value = TransformToTouch(callback); 395 const auto touch_value = TransformToTouch(callback);
388 396
389 device_status.mouse_stick_value = touch_value; 397 device_status.mouse_stick_value = touch_value;
390 398
391 if (is_configuring) { 399 if (is_configuring) {
392 device_status.mouse_position_state = {}; 400 device_status.mouse_position_state = {};
401 lock.unlock();
393 TriggerOnChange(DeviceTriggerType::Mouse); 402 TriggerOnChange(DeviceTriggerType::Mouse);
394 return; 403 return;
395 } 404 }
@@ -397,42 +406,52 @@ void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callbac
397 device_status.mouse_position_state.x = touch_value.x.value; 406 device_status.mouse_position_state.x = touch_value.x.value;
398 device_status.mouse_position_state.y = touch_value.y.value; 407 device_status.mouse_position_state.y = touch_value.y.value;
399 408
409 lock.unlock();
400 TriggerOnChange(DeviceTriggerType::Mouse); 410 TriggerOnChange(DeviceTriggerType::Mouse);
401} 411}
402 412
403KeyboardValues EmulatedDevices::GetKeyboardValues() const { 413KeyboardValues EmulatedDevices::GetKeyboardValues() const {
414 std::scoped_lock lock{mutex};
404 return device_status.keyboard_values; 415 return device_status.keyboard_values;
405} 416}
406 417
407KeyboardModifierValues EmulatedDevices::GetKeyboardModdifierValues() const { 418KeyboardModifierValues EmulatedDevices::GetKeyboardModdifierValues() const {
419 std::scoped_lock lock{mutex};
408 return device_status.keyboard_moddifier_values; 420 return device_status.keyboard_moddifier_values;
409} 421}
410 422
411MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const { 423MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const {
424 std::scoped_lock lock{mutex};
412 return device_status.mouse_button_values; 425 return device_status.mouse_button_values;
413} 426}
414 427
415KeyboardKey EmulatedDevices::GetKeyboard() const { 428KeyboardKey EmulatedDevices::GetKeyboard() const {
429 std::scoped_lock lock{mutex};
416 return device_status.keyboard_state; 430 return device_status.keyboard_state;
417} 431}
418 432
419KeyboardModifier EmulatedDevices::GetKeyboardModifier() const { 433KeyboardModifier EmulatedDevices::GetKeyboardModifier() const {
434 std::scoped_lock lock{mutex};
420 return device_status.keyboard_moddifier_state; 435 return device_status.keyboard_moddifier_state;
421} 436}
422 437
423MouseButton EmulatedDevices::GetMouseButtons() const { 438MouseButton EmulatedDevices::GetMouseButtons() const {
439 std::scoped_lock lock{mutex};
424 return device_status.mouse_button_state; 440 return device_status.mouse_button_state;
425} 441}
426 442
427MousePosition EmulatedDevices::GetMousePosition() const { 443MousePosition EmulatedDevices::GetMousePosition() const {
444 std::scoped_lock lock{mutex};
428 return device_status.mouse_position_state; 445 return device_status.mouse_position_state;
429} 446}
430 447
431AnalogStickState EmulatedDevices::GetMouseWheel() const { 448AnalogStickState EmulatedDevices::GetMouseWheel() const {
449 std::scoped_lock lock{mutex};
432 return device_status.mouse_wheel_state; 450 return device_status.mouse_wheel_state;
433} 451}
434 452
435void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) { 453void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
454 std::scoped_lock lock{callback_mutex};
436 for (const auto& poller_pair : callback_list) { 455 for (const auto& poller_pair : callback_list) {
437 const InterfaceUpdateCallback& poller = poller_pair.second; 456 const InterfaceUpdateCallback& poller = poller_pair.second;
438 if (poller.on_change) { 457 if (poller.on_change) {
@@ -442,13 +461,13 @@ void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
442} 461}
443 462
444int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) { 463int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) {
445 std::lock_guard lock{mutex}; 464 std::scoped_lock lock{callback_mutex};
446 callback_list.insert_or_assign(last_callback_key, std::move(update_callback)); 465 callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
447 return last_callback_key++; 466 return last_callback_key++;
448} 467}
449 468
450void EmulatedDevices::DeleteCallback(int key) { 469void EmulatedDevices::DeleteCallback(int key) {
451 std::lock_guard lock{mutex}; 470 std::scoped_lock lock{callback_mutex};
452 const auto& iterator = callback_list.find(key); 471 const auto& iterator = callback_list.find(key);
453 if (iterator == callback_list.end()) { 472 if (iterator == callback_list.end()) {
454 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); 473 LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h
index 790d3b411..73e9f0293 100644
--- a/src/core/hid/emulated_devices.h
+++ b/src/core/hid/emulated_devices.h
@@ -200,6 +200,7 @@ private:
200 MouseStickDevice mouse_stick_device; 200 MouseStickDevice mouse_stick_device;
201 201
202 mutable std::mutex mutex; 202 mutable std::mutex mutex;
203 mutable std::mutex callback_mutex;
203 std::unordered_map<int, InterfaceUpdateCallback> callback_list; 204 std::unordered_map<int, InterfaceUpdateCallback> callback_list;
204 int last_callback_key = 0; 205 int last_callback_key = 0;
205 206
diff --git a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
index 8027bec00..7765e7848 100644
--- a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
+++ b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp
@@ -148,9 +148,9 @@ u64 GenerateUniformRange(u64 min, u64 max, F f) {
148} // Anonymous namespace 148} // Anonymous namespace
149 149
150u64 KSystemControl::GenerateRandomU64() { 150u64 KSystemControl::GenerateRandomU64() {
151 static std::random_device device; 151 std::random_device device;
152 static std::mt19937 gen(device()); 152 std::mt19937 gen(device());
153 static std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max()); 153 std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
154 return distribution(gen); 154 return distribution(gen);
155} 155}
156 156
diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h
index c097373a8..423e8d8f5 100644
--- a/src/core/hle/kernel/k_auto_object.h
+++ b/src/core/hle/kernel/k_auto_object.h
@@ -161,7 +161,7 @@ public:
161 do { 161 do {
162 ASSERT(cur_ref_count > 0); 162 ASSERT(cur_ref_count > 0);
163 } while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count - 1, 163 } while (!m_ref_count.compare_exchange_weak(cur_ref_count, cur_ref_count - 1,
164 std::memory_order_relaxed)); 164 std::memory_order_acq_rel));
165 165
166 // If ref count hits zero, destroy the object. 166 // If ref count hits zero, destroy the object.
167 if (cur_ref_count - 1 == 0) { 167 if (cur_ref_count - 1 == 0) {
diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp
index 599013cf6..47ea3c89c 100644
--- a/src/core/hle/kernel/k_page_table.cpp
+++ b/src/core/hle/kernel/k_page_table.cpp
@@ -346,7 +346,8 @@ ResultCode KPageTable::MapCodeMemory(VAddr dst_address, VAddr src_address, std::
346 return ResultSuccess; 346 return ResultSuccess;
347} 347}
348 348
349ResultCode KPageTable::UnmapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size) { 349ResultCode KPageTable::UnmapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size,
350 ICacheInvalidationStrategy icache_invalidation_strategy) {
350 // Validate the mapping request. 351 // Validate the mapping request.
351 R_UNLESS(this->CanContain(dst_address, size, KMemoryState::AliasCode), 352 R_UNLESS(this->CanContain(dst_address, size, KMemoryState::AliasCode),
352 ResultInvalidMemoryRegion); 353 ResultInvalidMemoryRegion);
@@ -396,7 +397,11 @@ ResultCode KPageTable::UnmapCodeMemory(VAddr dst_address, VAddr src_address, std
396 bool reprotected_pages = false; 397 bool reprotected_pages = false;
397 SCOPE_EXIT({ 398 SCOPE_EXIT({
398 if (reprotected_pages && any_code_pages) { 399 if (reprotected_pages && any_code_pages) {
399 system.InvalidateCpuInstructionCacheRange(dst_address, size); 400 if (icache_invalidation_strategy == ICacheInvalidationStrategy::InvalidateRange) {
401 system.InvalidateCpuInstructionCacheRange(dst_address, size);
402 } else {
403 system.InvalidateCpuInstructionCaches();
404 }
400 } 405 }
401 }); 406 });
402 407
@@ -563,6 +568,8 @@ ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size,
563 block_manager->Update(dst_addr, num_pages, KMemoryState::Free, KMemoryPermission::None, 568 block_manager->Update(dst_addr, num_pages, KMemoryState::Free, KMemoryPermission::None,
564 KMemoryAttribute::None); 569 KMemoryAttribute::None);
565 570
571 system.InvalidateCpuInstructionCaches();
572
566 return ResultSuccess; 573 return ResultSuccess;
567} 574}
568 575
diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h
index bfabdf38c..dd6022975 100644
--- a/src/core/hle/kernel/k_page_table.h
+++ b/src/core/hle/kernel/k_page_table.h
@@ -26,6 +26,8 @@ class KMemoryBlockManager;
26 26
27class KPageTable final { 27class KPageTable final {
28public: 28public:
29 enum class ICacheInvalidationStrategy : u32 { InvalidateRange, InvalidateAll };
30
29 YUZU_NON_COPYABLE(KPageTable); 31 YUZU_NON_COPYABLE(KPageTable);
30 YUZU_NON_MOVEABLE(KPageTable); 32 YUZU_NON_MOVEABLE(KPageTable);
31 33
@@ -38,7 +40,8 @@ public:
38 ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, KMemoryState state, 40 ResultCode MapProcessCode(VAddr addr, std::size_t pages_count, KMemoryState state,
39 KMemoryPermission perm); 41 KMemoryPermission perm);
40 ResultCode MapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size); 42 ResultCode MapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size);
41 ResultCode UnmapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size); 43 ResultCode UnmapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size,
44 ICacheInvalidationStrategy icache_invalidation_strategy);
42 ResultCode UnmapProcessMemory(VAddr dst_addr, std::size_t size, KPageTable& src_page_table, 45 ResultCode UnmapProcessMemory(VAddr dst_addr, std::size_t size, KPageTable& src_page_table,
43 VAddr src_addr); 46 VAddr src_addr);
44 ResultCode MapPhysicalMemory(VAddr addr, std::size_t size); 47 ResultCode MapPhysicalMemory(VAddr addr, std::size_t size);
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h
index 48b17fc74..9f171e3da 100644
--- a/src/core/hle/kernel/k_process.h
+++ b/src/core/hle/kernel/k_process.h
@@ -422,7 +422,7 @@ private:
422 bool is_64bit_process = true; 422 bool is_64bit_process = true;
423 423
424 /// Total running time for the process in ticks. 424 /// Total running time for the process in ticks.
425 u64 total_process_running_time_ticks = 0; 425 std::atomic<u64> total_process_running_time_ticks = 0;
426 426
427 /// Per-process handle table for storing created object handles in. 427 /// Per-process handle table for storing created object handles in.
428 KHandleTable handle_table; 428 KHandleTable handle_table;
diff --git a/src/core/hle/kernel/k_scheduler_lock.h b/src/core/hle/kernel/k_scheduler_lock.h
index 93c47f1b1..016e0a818 100644
--- a/src/core/hle/kernel/k_scheduler_lock.h
+++ b/src/core/hle/kernel/k_scheduler_lock.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <atomic>
7#include "common/assert.h" 8#include "common/assert.h"
8#include "core/hle/kernel/k_spin_lock.h" 9#include "core/hle/kernel/k_spin_lock.h"
9#include "core/hle/kernel/k_thread.h" 10#include "core/hle/kernel/k_thread.h"
@@ -75,7 +76,7 @@ private:
75 KernelCore& kernel; 76 KernelCore& kernel;
76 KAlignedSpinLock spin_lock{}; 77 KAlignedSpinLock spin_lock{};
77 s32 lock_count{}; 78 s32 lock_count{};
78 KThread* owner_thread{}; 79 std::atomic<KThread*> owner_thread{};
79}; 80};
80 81
81} // namespace Kernel 82} // namespace Kernel
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp
index 94c8faf68..d3bb1c871 100644
--- a/src/core/hle/kernel/k_thread.cpp
+++ b/src/core/hle/kernel/k_thread.cpp
@@ -723,7 +723,7 @@ void KThread::UpdateState() {
723 ASSERT(kernel.GlobalSchedulerContext().IsLocked()); 723 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
724 724
725 // Set our suspend flags in state. 725 // Set our suspend flags in state.
726 const auto old_state = thread_state; 726 const ThreadState old_state = thread_state;
727 const auto new_state = 727 const auto new_state =
728 static_cast<ThreadState>(this->GetSuspendFlags()) | (old_state & ThreadState::Mask); 728 static_cast<ThreadState>(this->GetSuspendFlags()) | (old_state & ThreadState::Mask);
729 thread_state = new_state; 729 thread_state = new_state;
@@ -738,7 +738,7 @@ void KThread::Continue() {
738 ASSERT(kernel.GlobalSchedulerContext().IsLocked()); 738 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
739 739
740 // Clear our suspend flags in state. 740 // Clear our suspend flags in state.
741 const auto old_state = thread_state; 741 const ThreadState old_state = thread_state;
742 thread_state = old_state & ThreadState::Mask; 742 thread_state = old_state & ThreadState::Mask;
743 743
744 // Note the state change in scheduler. 744 // Note the state change in scheduler.
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h
index f46db7298..d0fd85130 100644
--- a/src/core/hle/kernel/k_thread.h
+++ b/src/core/hle/kernel/k_thread.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <atomic>
8#include <span> 9#include <span>
9#include <string> 10#include <string>
10#include <utility> 11#include <utility>
@@ -751,7 +752,7 @@ private:
751 KAffinityMask original_physical_affinity_mask{}; 752 KAffinityMask original_physical_affinity_mask{};
752 s32 original_physical_ideal_core_id{}; 753 s32 original_physical_ideal_core_id{};
753 s32 num_core_migration_disables{}; 754 s32 num_core_migration_disables{};
754 ThreadState thread_state{}; 755 std::atomic<ThreadState> thread_state{};
755 std::atomic<bool> termination_requested{}; 756 std::atomic<bool> termination_requested{};
756 bool wait_cancelled{}; 757 bool wait_cancelled{};
757 bool cancellable{}; 758 bool cancellable{};
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index cc6ee0eae..d840d44e6 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -85,7 +85,7 @@ struct KernelCore::Impl {
85 85
86 void InitializeCores() { 86 void InitializeCores() {
87 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { 87 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
88 cores[core_id].Initialize(current_process->Is64BitProcess()); 88 cores[core_id].Initialize((*current_process).Is64BitProcess());
89 system.Memory().SetCurrentPageTable(*current_process, core_id); 89 system.Memory().SetCurrentPageTable(*current_process, core_id);
90 } 90 }
91 } 91 }
@@ -168,11 +168,11 @@ struct KernelCore::Impl {
168 168
169 // Shutdown all processes. 169 // Shutdown all processes.
170 if (current_process) { 170 if (current_process) {
171 current_process->Finalize(); 171 (*current_process).Finalize();
172 // current_process->Close(); 172 // current_process->Close();
173 // TODO: The current process should be destroyed based on accurate ref counting after 173 // TODO: The current process should be destroyed based on accurate ref counting after
174 // calling Close(). Adding a manual Destroy() call instead to avoid a memory leak. 174 // calling Close(). Adding a manual Destroy() call instead to avoid a memory leak.
175 current_process->Destroy(); 175 (*current_process).Destroy();
176 current_process = nullptr; 176 current_process = nullptr;
177 } 177 }
178 178
@@ -711,7 +711,7 @@ struct KernelCore::Impl {
711 711
712 // Lists all processes that exist in the current session. 712 // Lists all processes that exist in the current session.
713 std::vector<KProcess*> process_list; 713 std::vector<KProcess*> process_list;
714 KProcess* current_process{}; 714 std::atomic<KProcess*> current_process{};
715 std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context; 715 std::unique_ptr<Kernel::GlobalSchedulerContext> global_scheduler_context;
716 Kernel::TimeManager time_manager; 716 Kernel::TimeManager time_manager;
717 717
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 976d63234..0c86435b5 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1713,7 +1713,8 @@ static ResultCode UnmapProcessCodeMemory(Core::System& system, Handle process_ha
1713 return ResultInvalidMemoryRegion; 1713 return ResultInvalidMemoryRegion;
1714 } 1714 }
1715 1715
1716 return page_table.UnmapCodeMemory(dst_address, src_address, size); 1716 return page_table.UnmapCodeMemory(dst_address, src_address, size,
1717 KPageTable::ICacheInvalidationStrategy::InvalidateAll);
1717} 1718}
1718 1719
1719/// Exits the current process 1720/// Exits the current process
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index 2477c5612..cf727c167 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -389,8 +389,12 @@ public:
389 389
390 if (bss_size) { 390 if (bss_size) {
391 auto block_guard = detail::ScopeExit([&] { 391 auto block_guard = detail::ScopeExit([&] {
392 page_table.UnmapCodeMemory(addr + nro_size, bss_addr, bss_size); 392 page_table.UnmapCodeMemory(
393 page_table.UnmapCodeMemory(addr, nro_addr, nro_size); 393 addr + nro_size, bss_addr, bss_size,
394 Kernel::KPageTable::ICacheInvalidationStrategy::InvalidateRange);
395 page_table.UnmapCodeMemory(
396 addr, nro_addr, nro_size,
397 Kernel::KPageTable::ICacheInvalidationStrategy::InvalidateRange);
394 }); 398 });
395 399
396 const ResultCode result{ 400 const ResultCode result{
@@ -570,17 +574,21 @@ public:
570 auto& page_table{system.CurrentProcess()->PageTable()}; 574 auto& page_table{system.CurrentProcess()->PageTable()};
571 575
572 if (info.bss_size != 0) { 576 if (info.bss_size != 0) {
573 CASCADE_CODE(page_table.UnmapCodeMemory(info.nro_address + info.text_size + 577 CASCADE_CODE(page_table.UnmapCodeMemory(
574 info.ro_size + info.data_size, 578 info.nro_address + info.text_size + info.ro_size + info.data_size, info.bss_address,
575 info.bss_address, info.bss_size)); 579 info.bss_size, Kernel::KPageTable::ICacheInvalidationStrategy::InvalidateRange));
576 } 580 }
577 581
578 CASCADE_CODE(page_table.UnmapCodeMemory(info.nro_address + info.text_size + info.ro_size, 582 CASCADE_CODE(page_table.UnmapCodeMemory(
579 info.src_addr + info.text_size + info.ro_size, 583 info.nro_address + info.text_size + info.ro_size,
580 info.data_size)); 584 info.src_addr + info.text_size + info.ro_size, info.data_size,
581 CASCADE_CODE(page_table.UnmapCodeMemory(info.nro_address + info.text_size, 585 Kernel::KPageTable::ICacheInvalidationStrategy::InvalidateRange));
582 info.src_addr + info.text_size, info.ro_size)); 586 CASCADE_CODE(page_table.UnmapCodeMemory(
583 CASCADE_CODE(page_table.UnmapCodeMemory(info.nro_address, info.src_addr, info.text_size)); 587 info.nro_address + info.text_size, info.src_addr + info.text_size, info.ro_size,
588 Kernel::KPageTable::ICacheInvalidationStrategy::InvalidateRange));
589 CASCADE_CODE(page_table.UnmapCodeMemory(
590 info.nro_address, info.src_addr, info.text_size,
591 Kernel::KPageTable::ICacheInvalidationStrategy::InvalidateRange));
584 return ResultSuccess; 592 return ResultSuccess;
585 } 593 }
586 594
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index d6702e4e1..d25b050e2 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -689,6 +689,9 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, con
689 case OptName::REUSEADDR: 689 case OptName::REUSEADDR:
690 ASSERT(value == 0 || value == 1); 690 ASSERT(value == 0 || value == 1);
691 return Translate(socket->SetReuseAddr(value != 0)); 691 return Translate(socket->SetReuseAddr(value != 0));
692 case OptName::KEEPALIVE:
693 ASSERT(value == 0 || value == 1);
694 return Translate(socket->SetKeepAlive(value != 0));
692 case OptName::BROADCAST: 695 case OptName::BROADCAST:
693 ASSERT(value == 0 || value == 1); 696 ASSERT(value == 0 || value == 1);
694 return Translate(socket->SetBroadcast(value != 0)); 697 return Translate(socket->SetBroadcast(value != 0));
diff --git a/src/core/hle/service/sockets/sfdnsres.cpp b/src/core/hle/service/sockets/sfdnsres.cpp
index fb6142c49..a193fb578 100644
--- a/src/core/hle/service/sockets/sfdnsres.cpp
+++ b/src/core/hle/service/sockets/sfdnsres.cpp
@@ -2,8 +2,28 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <string_view>
6#include <utility>
7#include <vector>
8
9#include "common/string_util.h"
10#include "common/swap.h"
11#include "core/core.h"
5#include "core/hle/ipc_helpers.h" 12#include "core/hle/ipc_helpers.h"
6#include "core/hle/service/sockets/sfdnsres.h" 13#include "core/hle/service/sockets/sfdnsres.h"
14#include "core/memory.h"
15
16#ifdef _WIN32
17#include <ws2tcpip.h>
18#elif YUZU_UNIX
19#include <arpa/inet.h>
20#include <netdb.h>
21#include <netinet/in.h>
22#include <sys/socket.h>
23#ifndef EAI_NODATA
24#define EAI_NODATA EAI_NONAME
25#endif
26#endif
7 27
8namespace Service::Sockets { 28namespace Service::Sockets {
9 29
@@ -21,7 +41,7 @@ SFDNSRES::SFDNSRES(Core::System& system_) : ServiceFramework{system_, "sfdnsres"
21 {9, nullptr, "CancelRequest"}, 41 {9, nullptr, "CancelRequest"},
22 {10, nullptr, "GetHostByNameRequestWithOptions"}, 42 {10, nullptr, "GetHostByNameRequestWithOptions"},
23 {11, nullptr, "GetHostByAddrRequestWithOptions"}, 43 {11, nullptr, "GetHostByAddrRequestWithOptions"},
24 {12, nullptr, "GetAddrInfoRequestWithOptions"}, 44 {12, &SFDNSRES::GetAddrInfoRequestWithOptions, "GetAddrInfoRequestWithOptions"},
25 {13, nullptr, "GetNameInfoRequestWithOptions"}, 45 {13, nullptr, "GetNameInfoRequestWithOptions"},
26 {14, nullptr, "ResolverSetOptionRequest"}, 46 {14, nullptr, "ResolverSetOptionRequest"},
27 {15, nullptr, "ResolverGetOptionRequest"}, 47 {15, nullptr, "ResolverGetOptionRequest"},
@@ -31,7 +51,142 @@ SFDNSRES::SFDNSRES(Core::System& system_) : ServiceFramework{system_, "sfdnsres"
31 51
32SFDNSRES::~SFDNSRES() = default; 52SFDNSRES::~SFDNSRES() = default;
33 53
34void SFDNSRES::GetAddrInfoRequest(Kernel::HLERequestContext& ctx) { 54enum class NetDbError : s32 {
55 Internal = -1,
56 Success = 0,
57 HostNotFound = 1,
58 TryAgain = 2,
59 NoRecovery = 3,
60 NoData = 4,
61};
62
63static NetDbError AddrInfoErrorToNetDbError(s32 result) {
64 // Best effort guess to map errors
65 switch (result) {
66 case 0:
67 return NetDbError::Success;
68 case EAI_AGAIN:
69 return NetDbError::TryAgain;
70 case EAI_NODATA:
71 return NetDbError::NoData;
72 default:
73 return NetDbError::HostNotFound;
74 }
75}
76
77static std::vector<u8> SerializeAddrInfo(const addrinfo* addrinfo, s32 result_code,
78 std::string_view host) {
79 // Adapted from
80 // https://github.com/switchbrew/libnx/blob/c5a9a909a91657a9818a3b7e18c9b91ff0cbb6e3/nx/source/runtime/resolver.c#L190
81 std::vector<u8> data;
82
83 auto* current = addrinfo;
84 while (current != nullptr) {
85 struct SerializedResponseHeader {
86 u32 magic;
87 s32 flags;
88 s32 family;
89 s32 socket_type;
90 s32 protocol;
91 u32 address_length;
92 };
93 static_assert(sizeof(SerializedResponseHeader) == 0x18,
94 "Response header size must be 0x18 bytes");
95
96 constexpr auto header_size = sizeof(SerializedResponseHeader);
97 const auto addr_size =
98 current->ai_addr && current->ai_addrlen > 0 ? current->ai_addrlen : 4;
99 const auto canonname_size = current->ai_canonname ? strlen(current->ai_canonname) + 1 : 1;
100
101 const auto last_size = data.size();
102 data.resize(last_size + header_size + addr_size + canonname_size);
103
104 // Header in network byte order
105 SerializedResponseHeader header{};
106
107 constexpr auto HEADER_MAGIC = 0xBEEFCAFE;
108 header.magic = htonl(HEADER_MAGIC);
109 header.family = htonl(current->ai_family);
110 header.flags = htonl(current->ai_flags);
111 header.socket_type = htonl(current->ai_socktype);
112 header.protocol = htonl(current->ai_protocol);
113 header.address_length = current->ai_addr ? htonl((u32)current->ai_addrlen) : 0;
114
115 auto* header_ptr = data.data() + last_size;
116 std::memcpy(header_ptr, &header, header_size);
117
118 if (header.address_length == 0) {
119 std::memset(header_ptr + header_size, 0, 4);
120 } else {
121 switch (current->ai_family) {
122 case AF_INET: {
123 struct SockAddrIn {
124 s16 sin_family;
125 u16 sin_port;
126 u32 sin_addr;
127 u8 sin_zero[8];
128 };
129
130 SockAddrIn serialized_addr{};
131 const auto addr = *reinterpret_cast<sockaddr_in*>(current->ai_addr);
132 serialized_addr.sin_port = htons(addr.sin_port);
133 serialized_addr.sin_family = htons(addr.sin_family);
134 serialized_addr.sin_addr = htonl(addr.sin_addr.s_addr);
135 std::memcpy(header_ptr + header_size, &serialized_addr, sizeof(SockAddrIn));
136
137 char addr_string_buf[64]{};
138 inet_ntop(AF_INET, &addr.sin_addr, addr_string_buf, std::size(addr_string_buf));
139 LOG_INFO(Service, "Resolved host '{}' to IPv4 address {}", host, addr_string_buf);
140 break;
141 }
142 case AF_INET6: {
143 struct SockAddrIn6 {
144 s16 sin6_family;
145 u16 sin6_port;
146 u32 sin6_flowinfo;
147 u8 sin6_addr[16];
148 u32 sin6_scope_id;
149 };
150
151 SockAddrIn6 serialized_addr{};
152 const auto addr = *reinterpret_cast<sockaddr_in6*>(current->ai_addr);
153 serialized_addr.sin6_family = htons(addr.sin6_family);
154 serialized_addr.sin6_port = htons(addr.sin6_port);
155 serialized_addr.sin6_flowinfo = htonl(addr.sin6_flowinfo);
156 serialized_addr.sin6_scope_id = htonl(addr.sin6_scope_id);
157 std::memcpy(serialized_addr.sin6_addr, &addr.sin6_addr,
158 sizeof(SockAddrIn6::sin6_addr));
159 std::memcpy(header_ptr + header_size, &serialized_addr, sizeof(SockAddrIn6));
160
161 char addr_string_buf[64]{};
162 inet_ntop(AF_INET6, &addr.sin6_addr, addr_string_buf, std::size(addr_string_buf));
163 LOG_INFO(Service, "Resolved host '{}' to IPv6 address {}", host, addr_string_buf);
164 break;
165 }
166 default:
167 std::memcpy(header_ptr + header_size, current->ai_addr, addr_size);
168 break;
169 }
170 }
171 if (current->ai_canonname) {
172 std::memcpy(header_ptr + addr_size, current->ai_canonname, canonname_size);
173 } else {
174 *(header_ptr + header_size + addr_size) = 0;
175 }
176
177 current = current->ai_next;
178 }
179
180 // 4-byte sentinel value
181 data.push_back(0);
182 data.push_back(0);
183 data.push_back(0);
184 data.push_back(0);
185
186 return data;
187}
188
189static std::pair<u32, s32> GetAddrInfoRequestImpl(Kernel::HLERequestContext& ctx) {
35 struct Parameters { 190 struct Parameters {
36 u8 use_nsd_resolve; 191 u8 use_nsd_resolve;
37 u32 unknown; 192 u32 unknown;
@@ -42,11 +197,51 @@ void SFDNSRES::GetAddrInfoRequest(Kernel::HLERequestContext& ctx) {
42 const auto parameters = rp.PopRaw<Parameters>(); 197 const auto parameters = rp.PopRaw<Parameters>();
43 198
44 LOG_WARNING(Service, 199 LOG_WARNING(Service,
45 "(STUBBED) called. use_nsd_resolve={}, unknown=0x{:08X}, process_id=0x{:016X}", 200 "called with ignored parameters: use_nsd_resolve={}, unknown={}, process_id={}",
46 parameters.use_nsd_resolve, parameters.unknown, parameters.process_id); 201 parameters.use_nsd_resolve, parameters.unknown, parameters.process_id);
47 202
48 IPC::ResponseBuilder rb{ctx, 2}; 203 const auto host_buffer = ctx.ReadBuffer(0);
204 const std::string host = Common::StringFromBuffer(host_buffer);
205
206 const auto service_buffer = ctx.ReadBuffer(1);
207 const std::string service = Common::StringFromBuffer(service_buffer);
208
209 addrinfo* addrinfo;
210 // Pass null for hints. Serialized hints are also passed in a buffer, but are ignored for now
211 s32 result_code = getaddrinfo(host.c_str(), service.c_str(), nullptr, &addrinfo);
212
213 u32 data_size = 0;
214 if (result_code == 0 && addrinfo != nullptr) {
215 const std::vector<u8>& data = SerializeAddrInfo(addrinfo, result_code, host);
216 data_size = static_cast<u32>(data.size());
217 freeaddrinfo(addrinfo);
218
219 ctx.WriteBuffer(data, 0);
220 }
221
222 return std::make_pair(data_size, result_code);
223}
224
225void SFDNSRES::GetAddrInfoRequest(Kernel::HLERequestContext& ctx) {
226 auto [data_size, result_code] = GetAddrInfoRequestImpl(ctx);
227
228 IPC::ResponseBuilder rb{ctx, 4};
229 rb.Push(ResultSuccess);
230 rb.Push(static_cast<s32>(AddrInfoErrorToNetDbError(result_code))); // NetDBErrorCode
231 rb.Push(result_code); // errno
232 rb.Push(data_size); // serialized size
233}
234
235void SFDNSRES::GetAddrInfoRequestWithOptions(Kernel::HLERequestContext& ctx) {
236 // Additional options are ignored
237 auto [data_size, result_code] = GetAddrInfoRequestImpl(ctx);
238
239 IPC::ResponseBuilder rb{ctx, 5};
49 rb.Push(ResultSuccess); 240 rb.Push(ResultSuccess);
241 rb.Push(data_size); // serialized size
242 rb.Push(result_code); // errno
243 rb.Push(static_cast<s32>(AddrInfoErrorToNetDbError(result_code))); // NetDBErrorCode
244 rb.Push(0);
50} 245}
51 246
52} // namespace Service::Sockets 247} // namespace Service::Sockets \ No newline at end of file
diff --git a/src/core/hle/service/sockets/sfdnsres.h b/src/core/hle/service/sockets/sfdnsres.h
index 5d3b4dc2d..f0c57377d 100644
--- a/src/core/hle/service/sockets/sfdnsres.h
+++ b/src/core/hle/service/sockets/sfdnsres.h
@@ -19,6 +19,7 @@ public:
19 19
20private: 20private:
21 void GetAddrInfoRequest(Kernel::HLERequestContext& ctx); 21 void GetAddrInfoRequest(Kernel::HLERequestContext& ctx);
22 void GetAddrInfoRequestWithOptions(Kernel::HLERequestContext& ctx);
22}; 23};
23 24
24} // namespace Service::Sockets 25} // namespace Service::Sockets
diff --git a/src/core/hle/service/sockets/sockets.h b/src/core/hle/service/sockets/sockets.h
index 02dbbae40..d69c86431 100644
--- a/src/core/hle/service/sockets/sockets.h
+++ b/src/core/hle/service/sockets/sockets.h
@@ -46,6 +46,7 @@ enum class Protocol : u32 {
46 46
47enum class OptName : u32 { 47enum class OptName : u32 {
48 REUSEADDR = 0x4, 48 REUSEADDR = 0x4,
49 KEEPALIVE = 0x8,
49 BROADCAST = 0x20, 50 BROADCAST = 0x20,
50 LINGER = 0x80, 51 LINGER = 0x80,
51 SNDBUF = 0x1001, 52 SNDBUF = 0x1001,
diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp
index a3e0664b9..0784a165d 100644
--- a/src/core/network/network.cpp
+++ b/src/core/network/network.cpp
@@ -600,6 +600,10 @@ Errno Socket::SetReuseAddr(bool enable) {
600 return SetSockOpt<u32>(fd, SO_REUSEADDR, enable ? 1 : 0); 600 return SetSockOpt<u32>(fd, SO_REUSEADDR, enable ? 1 : 0);
601} 601}
602 602
603Errno Socket::SetKeepAlive(bool enable) {
604 return SetSockOpt<u32>(fd, SO_KEEPALIVE, enable ? 1 : 0);
605}
606
603Errno Socket::SetBroadcast(bool enable) { 607Errno Socket::SetBroadcast(bool enable) {
604 return SetSockOpt<u32>(fd, SO_BROADCAST, enable ? 1 : 0); 608 return SetSockOpt<u32>(fd, SO_BROADCAST, enable ? 1 : 0);
605} 609}
diff --git a/src/core/network/sockets.h b/src/core/network/sockets.h
index 5e39e7c54..caaefce7c 100644
--- a/src/core/network/sockets.h
+++ b/src/core/network/sockets.h
@@ -67,6 +67,8 @@ public:
67 67
68 Errno SetReuseAddr(bool enable); 68 Errno SetReuseAddr(bool enable);
69 69
70 Errno SetKeepAlive(bool enable);
71
70 Errno SetBroadcast(bool enable); 72 Errno SetBroadcast(bool enable);
71 73
72 Errno SetSndBuf(u32 value); 74 Errno SetSndBuf(u32 value);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 7ab7f0c0a..8ef79753f 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -559,12 +559,19 @@ void RasterizerOpenGL::SyncViewport() {
559 const bool dirty_viewport = flags[Dirty::Viewports] || rescale_viewports; 559 const bool dirty_viewport = flags[Dirty::Viewports] || rescale_viewports;
560 const bool dirty_clip_control = flags[Dirty::ClipControl]; 560 const bool dirty_clip_control = flags[Dirty::ClipControl];
561 561
562 if (dirty_clip_control || flags[Dirty::FrontFace]) { 562 if (dirty_viewport || dirty_clip_control || flags[Dirty::FrontFace]) {
563 flags[Dirty::FrontFace] = false; 563 flags[Dirty::FrontFace] = false;
564 564
565 GLenum mode = MaxwellToGL::FrontFace(regs.front_face); 565 GLenum mode = MaxwellToGL::FrontFace(regs.front_face);
566 bool flip_faces = false;
566 if (regs.screen_y_control.triangle_rast_flip != 0 && 567 if (regs.screen_y_control.triangle_rast_flip != 0 &&
567 regs.viewport_transform[0].scale_y < 0.0f) { 568 regs.viewport_transform[0].scale_y < 0.0f) {
569 flip_faces = !flip_faces;
570 }
571 if (regs.viewport_transform[0].scale_z < 0.0f) {
572 flip_faces = !flip_faces;
573 }
574 if (flip_faces) {
568 switch (mode) { 575 switch (mode) {
569 case GL_CW: 576 case GL_CW:
570 mode = GL_CCW; 577 mode = GL_CCW;