diff options
Diffstat (limited to 'src')
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 | ||
| 15 | namespace Core { | 17 | namespace Core { |
| 16 | namespace { | ||
| 17 | |||
| 18 | constexpr u64 ELF_DYNAMIC_TAG_NULL = 0; | ||
| 19 | constexpr u64 ELF_DYNAMIC_TAG_STRTAB = 5; | ||
| 20 | constexpr u64 ELF_DYNAMIC_TAG_SYMTAB = 6; | ||
| 21 | constexpr u64 ELF_DYNAMIC_TAG_SYMENT = 11; | ||
| 22 | |||
| 23 | enum 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 | |||
| 33 | enum class ELFSymbolBinding : u8 { | ||
| 34 | Local = 0, | ||
| 35 | Global = 1, | ||
| 36 | Weak = 2, | ||
| 37 | }; | ||
| 38 | |||
| 39 | enum class ELFSymbolVisibility : u8 { | ||
| 40 | Default = 0, | ||
| 41 | Internal = 1, | ||
| 42 | Hidden = 2, | ||
| 43 | Protected = 3, | ||
| 44 | }; | ||
| 45 | |||
| 46 | struct 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 | }; | ||
| 59 | static_assert(sizeof(ELFSymbol) == 0x18, "ELFSymbol has incorrect size."); | ||
| 60 | |||
| 61 | using Symbols = std::vector<std::pair<ELFSymbol, std::string>>; | ||
| 62 | |||
| 63 | Symbols 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 | |||
| 123 | std::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 | ||
| 140 | constexpr u64 SEGMENT_BASE = 0x7100000000ull; | 19 | constexpr 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 | |||
| 11 | namespace Core { | ||
| 12 | namespace { | ||
| 13 | |||
| 14 | constexpr u64 ELF_DYNAMIC_TAG_NULL = 0; | ||
| 15 | constexpr u64 ELF_DYNAMIC_TAG_STRTAB = 5; | ||
| 16 | constexpr u64 ELF_DYNAMIC_TAG_SYMTAB = 6; | ||
| 17 | constexpr u64 ELF_DYNAMIC_TAG_SYMENT = 11; | ||
| 18 | |||
| 19 | enum 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 | |||
| 29 | enum class ELFSymbolBinding : u8 { | ||
| 30 | Local = 0, | ||
| 31 | Global = 1, | ||
| 32 | Weak = 2, | ||
| 33 | }; | ||
| 34 | |||
| 35 | enum class ELFSymbolVisibility : u8 { | ||
| 36 | Default = 0, | ||
| 37 | Internal = 1, | ||
| 38 | Hidden = 2, | ||
| 39 | Protected = 3, | ||
| 40 | }; | ||
| 41 | |||
| 42 | struct 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 | }; | ||
| 55 | static_assert(sizeof(ELF64Symbol) == 0x18, "ELF64Symbol has incorrect size."); | ||
| 56 | |||
| 57 | struct 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 | }; | ||
| 70 | static_assert(sizeof(ELF32Symbol) == 0x10, "ELF32Symbol has incorrect size."); | ||
| 71 | |||
| 72 | } // Anonymous namespace | ||
| 73 | |||
| 74 | namespace Symbols { | ||
| 75 | |||
| 76 | template <typename Word, typename ELFSymbol, typename ByteReader> | ||
| 77 | static 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 | |||
| 151 | Symbols 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 | |||
| 162 | Symbols 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 | |||
| 174 | std::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 | |||
| 15 | namespace Core::Memory { | ||
| 16 | class Memory; | ||
| 17 | } // namespace Core::Memory | ||
| 18 | |||
| 19 | namespace Core::Symbols { | ||
| 20 | |||
| 21 | using Symbols = std::map<std::string, std::pair<VAddr, std::size_t>, std::less<>>; | ||
| 22 | |||
| 23 | Symbols GetSymbols(VAddr base, Core::Memory::Memory& memory, bool is_64 = true); | ||
| 24 | Symbols GetSymbols(std::span<const u8> data, bool is_64 = true); | ||
| 25 | std::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 | ||
| 134 | void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) { | 134 | void 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 | ||
| 195 | ConsoleMotionValues EmulatedConsole::GetMotionValues() const { | 199 | ConsoleMotionValues EmulatedConsole::GetMotionValues() const { |
| 200 | std::scoped_lock lock{mutex}; | ||
| 196 | return console.motion_values; | 201 | return console.motion_values; |
| 197 | } | 202 | } |
| 198 | 203 | ||
| 199 | TouchValues EmulatedConsole::GetTouchValues() const { | 204 | TouchValues EmulatedConsole::GetTouchValues() const { |
| 205 | std::scoped_lock lock{mutex}; | ||
| 200 | return console.touch_values; | 206 | return console.touch_values; |
| 201 | } | 207 | } |
| 202 | 208 | ||
| 203 | ConsoleMotion EmulatedConsole::GetMotion() const { | 209 | ConsoleMotion EmulatedConsole::GetMotion() const { |
| 210 | std::scoped_lock lock{mutex}; | ||
| 204 | return console.motion_state; | 211 | return console.motion_state; |
| 205 | } | 212 | } |
| 206 | 213 | ||
| 207 | TouchFingerState EmulatedConsole::GetTouch() const { | 214 | TouchFingerState EmulatedConsole::GetTouch() const { |
| 215 | std::scoped_lock lock{mutex}; | ||
| 208 | return console.touch_state; | 216 | return console.touch_state; |
| 209 | } | 217 | } |
| 210 | 218 | ||
| 211 | void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) { | 219 | void 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 | ||
| 220 | int EmulatedConsole::SetCallback(ConsoleUpdateCallback update_callback) { | 229 | int 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 | ||
| 226 | void EmulatedConsole::DeleteCallback(int key) { | 235 | void 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 | ||
| 355 | void EmulatedController::EnableSystemButtons() { | 355 | void EmulatedController::EnableSystemButtons() { |
| 356 | std::scoped_lock lock{mutex}; | ||
| 356 | system_buttons_enabled = true; | 357 | system_buttons_enabled = true; |
| 357 | } | 358 | } |
| 358 | 359 | ||
| 359 | void EmulatedController::DisableSystemButtons() { | 360 | void EmulatedController::DisableSystemButtons() { |
| 361 | std::scoped_lock lock{mutex}; | ||
| 360 | system_buttons_enabled = false; | 362 | system_buttons_enabled = false; |
| 361 | } | 363 | } |
| 362 | 364 | ||
| 363 | void EmulatedController::ResetSystemButtons() { | 365 | void 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 | ||
| 934 | bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const { | 948 | bool 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 | ||
| 949 | bool EmulatedController::IsControllerSupported(bool use_temporary_value) const { | 964 | bool 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 | ||
| 1001 | void EmulatedController::Disconnect() { | 1019 | void 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 | ||
| 1018 | bool EmulatedController::IsConnected(bool get_temporary_value) const { | 1037 | bool 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 | ||
| 1031 | NpadIdType EmulatedController::GetNpadIdType() const { | 1051 | NpadIdType EmulatedController::GetNpadIdType() const { |
| 1052 | std::scoped_lock lock{mutex}; | ||
| 1032 | return npad_id_type; | 1053 | return npad_id_type; |
| 1033 | } | 1054 | } |
| 1034 | 1055 | ||
| 1035 | NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) const { | 1056 | NpadStyleIndex 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 | ||
| 1042 | void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) { | 1064 | void 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 | ||
| 1090 | ButtonValues EmulatedController::GetButtonsValues() const { | 1113 | ButtonValues EmulatedController::GetButtonsValues() const { |
| 1114 | std::scoped_lock lock{mutex}; | ||
| 1091 | return controller.button_values; | 1115 | return controller.button_values; |
| 1092 | } | 1116 | } |
| 1093 | 1117 | ||
| 1094 | SticksValues EmulatedController::GetSticksValues() const { | 1118 | SticksValues EmulatedController::GetSticksValues() const { |
| 1119 | std::scoped_lock lock{mutex}; | ||
| 1095 | return controller.stick_values; | 1120 | return controller.stick_values; |
| 1096 | } | 1121 | } |
| 1097 | 1122 | ||
| 1098 | TriggerValues EmulatedController::GetTriggersValues() const { | 1123 | TriggerValues EmulatedController::GetTriggersValues() const { |
| 1124 | std::scoped_lock lock{mutex}; | ||
| 1099 | return controller.trigger_values; | 1125 | return controller.trigger_values; |
| 1100 | } | 1126 | } |
| 1101 | 1127 | ||
| 1102 | ControllerMotionValues EmulatedController::GetMotionValues() const { | 1128 | ControllerMotionValues EmulatedController::GetMotionValues() const { |
| 1129 | std::scoped_lock lock{mutex}; | ||
| 1103 | return controller.motion_values; | 1130 | return controller.motion_values; |
| 1104 | } | 1131 | } |
| 1105 | 1132 | ||
| 1106 | ColorValues EmulatedController::GetColorsValues() const { | 1133 | ColorValues EmulatedController::GetColorsValues() const { |
| 1134 | std::scoped_lock lock{mutex}; | ||
| 1107 | return controller.color_values; | 1135 | return controller.color_values; |
| 1108 | } | 1136 | } |
| 1109 | 1137 | ||
| 1110 | BatteryValues EmulatedController::GetBatteryValues() const { | 1138 | BatteryValues EmulatedController::GetBatteryValues() const { |
| 1139 | std::scoped_lock lock{mutex}; | ||
| 1111 | return controller.battery_values; | 1140 | return controller.battery_values; |
| 1112 | } | 1141 | } |
| 1113 | 1142 | ||
| 1114 | HomeButtonState EmulatedController::GetHomeButtons() const { | 1143 | HomeButtonState 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 | ||
| 1121 | CaptureButtonState EmulatedController::GetCaptureButtons() const { | 1151 | CaptureButtonState 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 | ||
| 1128 | NpadButtonState EmulatedController::GetNpadButtons() const { | 1159 | NpadButtonState 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 | ||
| 1135 | DebugPadButton EmulatedController::GetDebugPadButtons() const { | 1167 | DebugPadButton 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 | ||
| 1142 | AnalogSticks EmulatedController::GetSticks() const { | 1175 | AnalogSticks 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 | ||
| 1156 | NpadGcTriggerState EmulatedController::GetTriggers() const { | 1195 | NpadGcTriggerState 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 | ||
| 1163 | MotionState EmulatedController::GetMotions() const { | 1203 | MotionState 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 | ||
| 1175 | ControllerColors EmulatedController::GetColors() const { | 1221 | ControllerColors EmulatedController::GetColors() const { |
| 1222 | std::scoped_lock lock{mutex}; | ||
| 1176 | return controller.colors_state; | 1223 | return controller.colors_state; |
| 1177 | } | 1224 | } |
| 1178 | 1225 | ||
| 1179 | BatteryLevelState EmulatedController::GetBattery() const { | 1226 | BatteryLevelState EmulatedController::GetBattery() const { |
| 1227 | std::scoped_lock lock{mutex}; | ||
| 1180 | return controller.battery_state; | 1228 | return controller.battery_state; |
| 1181 | } | 1229 | } |
| 1182 | 1230 | ||
| 1183 | void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) { | 1231 | void 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 | ||
| 1195 | int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) { | 1244 | int 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 | ||
| 1201 | void EmulatedController::DeleteCallback(int key) { | 1250 | void 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 | ||
| 385 | void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callback) { | 393 | void 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 | ||
| 403 | KeyboardValues EmulatedDevices::GetKeyboardValues() const { | 413 | KeyboardValues 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 | ||
| 407 | KeyboardModifierValues EmulatedDevices::GetKeyboardModdifierValues() const { | 418 | KeyboardModifierValues 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 | ||
| 411 | MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const { | 423 | MouseButtonValues 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 | ||
| 415 | KeyboardKey EmulatedDevices::GetKeyboard() const { | 428 | KeyboardKey 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 | ||
| 419 | KeyboardModifier EmulatedDevices::GetKeyboardModifier() const { | 433 | KeyboardModifier 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 | ||
| 423 | MouseButton EmulatedDevices::GetMouseButtons() const { | 438 | MouseButton 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 | ||
| 427 | MousePosition EmulatedDevices::GetMousePosition() const { | 443 | MousePosition 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 | ||
| 431 | AnalogStickState EmulatedDevices::GetMouseWheel() const { | 448 | AnalogStickState 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 | ||
| 435 | void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) { | 453 | void 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 | ||
| 444 | int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) { | 463 | int 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 | ||
| 450 | void EmulatedDevices::DeleteCallback(int key) { | 469 | void 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 | ||
| 150 | u64 KSystemControl::GenerateRandomU64() { | 150 | u64 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 | ||
| 349 | ResultCode KPageTable::UnmapCodeMemory(VAddr dst_address, VAddr src_address, std::size_t size) { | 349 | ResultCode 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 | ||
| 27 | class KPageTable final { | 27 | class KPageTable final { |
| 28 | public: | 28 | public: |
| 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 | ||
| 8 | namespace Service::Sockets { | 28 | namespace 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 | ||
| 32 | SFDNSRES::~SFDNSRES() = default; | 52 | SFDNSRES::~SFDNSRES() = default; |
| 33 | 53 | ||
| 34 | void SFDNSRES::GetAddrInfoRequest(Kernel::HLERequestContext& ctx) { | 54 | enum class NetDbError : s32 { |
| 55 | Internal = -1, | ||
| 56 | Success = 0, | ||
| 57 | HostNotFound = 1, | ||
| 58 | TryAgain = 2, | ||
| 59 | NoRecovery = 3, | ||
| 60 | NoData = 4, | ||
| 61 | }; | ||
| 62 | |||
| 63 | static 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 | |||
| 77 | static 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 | |||
| 189 | static 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 | |||
| 225 | void 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 | |||
| 235 | void 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 | ||
| 20 | private: | 20 | private: |
| 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 | ||
| 47 | enum class OptName : u32 { | 47 | enum 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 | ||
| 603 | Errno Socket::SetKeepAlive(bool enable) { | ||
| 604 | return SetSockOpt<u32>(fd, SO_KEEPALIVE, enable ? 1 : 0); | ||
| 605 | } | ||
| 606 | |||
| 603 | Errno Socket::SetBroadcast(bool enable) { | 607 | Errno 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; |