summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt7
-rw-r--r--src/audio_core/cubeb_sink.cpp2
-rw-r--r--src/common/atomic_ops.cpp37
-rw-r--r--src/common/atomic_ops.h10
-rw-r--r--src/common/concepts.h10
-rw-r--r--src/common/detached_tasks.cpp3
-rw-r--r--src/common/hex_util.cpp34
-rw-r--r--src/common/hex_util.h29
-rw-r--r--src/common/logging/backend.cpp22
-rw-r--r--src/common/logging/backend.h14
-rw-r--r--src/common/lz4_compression.cpp21
-rw-r--r--src/common/lz4_compression.h10
-rw-r--r--src/common/math_util.h2
-rw-r--r--src/common/virtual_buffer.cpp9
-rw-r--r--src/common/zstd_compression.cpp13
-rw-r--r--src/common/zstd_compression.h7
-rw-r--r--src/core/crypto/aes_util.cpp21
-rw-r--r--src/core/crypto/aes_util.h9
-rw-r--r--src/core/crypto/ctr_encryption_layer.cpp9
-rw-r--r--src/core/crypto/ctr_encryption_layer.h9
-rw-r--r--src/core/crypto/key_manager.cpp10
-rw-r--r--src/core/crypto/partition_data_manager.cpp211
-rw-r--r--src/core/file_sys/content_archive.cpp7
-rw-r--r--src/core/file_sys/nca_patch.cpp3
-rw-r--r--src/core/file_sys/registered_cache.h6
-rw-r--r--src/core/file_sys/system_archive/mii_model.cpp18
-rw-r--r--src/core/file_sys/system_archive/ng_word.cpp42
-rw-r--r--src/core/file_sys/system_archive/time_zone_binary.cpp9
-rw-r--r--src/core/file_sys/vfs_vector.h13
-rw-r--r--src/core/frontend/emu_window.h4
-rw-r--r--src/core/hle/ipc_helpers.h4
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp2
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp46
-rw-r--r--src/core/hle/kernel/memory/page_table.cpp23
-rw-r--r--src/core/hle/kernel/scheduler.cpp31
-rw-r--r--src/core/hle/kernel/scheduler.h2
-rw-r--r--src/core/hle/service/am/am.cpp6
-rw-r--r--src/core/hle/service/am/am.h7
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp3
-rw-r--r--src/core/hle/service/audio/audout_u.cpp2
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.cpp6
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp21
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h10
-rw-r--r--src/core/hle/service/sm/sm.h2
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.cpp4
-rw-r--r--src/core/loader/loader.cpp2
-rw-r--r--src/core/memory.cpp10
-rw-r--r--src/core/memory/cheat_engine.cpp26
-rw-r--r--src/core/tools/freezer.cpp31
-rw-r--r--src/core/tools/freezer.h7
-rw-r--r--src/input_common/gcadapter/gc_poller.cpp14
-rw-r--r--src/input_common/sdl/sdl_impl.cpp25
-rw-r--r--src/input_common/udp/client.cpp6
-rw-r--r--src/video_core/engines/maxwell_dma.cpp21
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_disk_cache.cpp3
-rw-r--r--src/video_core/renderer_vulkan/wrapper.h28
-rw-r--r--src/video_core/shader/control_flow.cpp30
-rw-r--r--src/video_core/shader/decode/memory.cpp6
-rw-r--r--src/video_core/texture_cache/surface_params.cpp1
-rw-r--r--src/video_core/textures/decoders.cpp42
-rw-r--r--src/video_core/textures/decoders.h5
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp61
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.cpp11
-rw-r--r--src/yuzu/game_list_worker.cpp2
65 files changed, 572 insertions, 531 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 54dca3302..71efbb40d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -60,9 +60,14 @@ else()
60 -Wmissing-declarations 60 -Wmissing-declarations
61 -Wno-attributes 61 -Wno-attributes
62 -Wno-unused-parameter 62 -Wno-unused-parameter
63 -fconcepts
64 ) 63 )
65 64
65 # TODO: Remove when we update to a GCC compiler that enables this
66 # by default (i.e. GCC 10 or newer).
67 if (CMAKE_CXX_COMPILER_ID STREQUAL GNU)
68 add_compile_options(-fconcepts)
69 endif()
70
66 if (ARCHITECTURE_x86_64) 71 if (ARCHITECTURE_x86_64)
67 add_compile_options("-mcx16") 72 add_compile_options("-mcx16")
68 endif() 73 endif()
diff --git a/src/audio_core/cubeb_sink.cpp b/src/audio_core/cubeb_sink.cpp
index 41bf5cd4d..c27df946c 100644
--- a/src/audio_core/cubeb_sink.cpp
+++ b/src/audio_core/cubeb_sink.cpp
@@ -78,7 +78,7 @@ public:
78 const s16 surround_left{samples[i + 4]}; 78 const s16 surround_left{samples[i + 4]};
79 const s16 surround_right{samples[i + 5]}; 79 const s16 surround_right{samples[i + 5]};
80 // Not used in the ATSC reference implementation 80 // Not used in the ATSC reference implementation
81 [[maybe_unused]] const s16 low_frequency_effects { samples[i + 3] }; 81 [[maybe_unused]] const s16 low_frequency_effects{samples[i + 3]};
82 82
83 constexpr s32 clev{707}; // center mixing level coefficient 83 constexpr s32 clev{707}; // center mixing level coefficient
84 constexpr s32 slev{707}; // surround mixing level coefficient 84 constexpr s32 slev{707}; // surround mixing level coefficient
diff --git a/src/common/atomic_ops.cpp b/src/common/atomic_ops.cpp
index 1098e21ff..1612d0e67 100644
--- a/src/common/atomic_ops.cpp
+++ b/src/common/atomic_ops.cpp
@@ -14,50 +14,55 @@ namespace Common {
14 14
15#if _MSC_VER 15#if _MSC_VER
16 16
17bool AtomicCompareAndSwap(u8 volatile* pointer, u8 value, u8 expected) { 17bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
18 u8 result = _InterlockedCompareExchange8((char*)pointer, value, expected); 18 const u8 result =
19 _InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected);
19 return result == expected; 20 return result == expected;
20} 21}
21 22
22bool AtomicCompareAndSwap(u16 volatile* pointer, u16 value, u16 expected) { 23bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
23 u16 result = _InterlockedCompareExchange16((short*)pointer, value, expected); 24 const u16 result =
25 _InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected);
24 return result == expected; 26 return result == expected;
25} 27}
26 28
27bool AtomicCompareAndSwap(u32 volatile* pointer, u32 value, u32 expected) { 29bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
28 u32 result = _InterlockedCompareExchange((long*)pointer, value, expected); 30 const u32 result =
31 _InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected);
29 return result == expected; 32 return result == expected;
30} 33}
31 34
32bool AtomicCompareAndSwap(u64 volatile* pointer, u64 value, u64 expected) { 35bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
33 u64 result = _InterlockedCompareExchange64((__int64*)pointer, value, expected); 36 const u64 result = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer),
37 value, expected);
34 return result == expected; 38 return result == expected;
35} 39}
36 40
37bool AtomicCompareAndSwap(u64 volatile* pointer, u128 value, u128 expected) { 41bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
38 return _InterlockedCompareExchange128((__int64*)pointer, value[1], value[0], 42 return _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1],
39 (__int64*)expected.data()) != 0; 43 value[0],
44 reinterpret_cast<__int64*>(expected.data())) != 0;
40} 45}
41 46
42#else 47#else
43 48
44bool AtomicCompareAndSwap(u8 volatile* pointer, u8 value, u8 expected) { 49bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
45 return __sync_bool_compare_and_swap(pointer, expected, value); 50 return __sync_bool_compare_and_swap(pointer, expected, value);
46} 51}
47 52
48bool AtomicCompareAndSwap(u16 volatile* pointer, u16 value, u16 expected) { 53bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
49 return __sync_bool_compare_and_swap(pointer, expected, value); 54 return __sync_bool_compare_and_swap(pointer, expected, value);
50} 55}
51 56
52bool AtomicCompareAndSwap(u32 volatile* pointer, u32 value, u32 expected) { 57bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
53 return __sync_bool_compare_and_swap(pointer, expected, value); 58 return __sync_bool_compare_and_swap(pointer, expected, value);
54} 59}
55 60
56bool AtomicCompareAndSwap(u64 volatile* pointer, u64 value, u64 expected) { 61bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
57 return __sync_bool_compare_and_swap(pointer, expected, value); 62 return __sync_bool_compare_and_swap(pointer, expected, value);
58} 63}
59 64
60bool AtomicCompareAndSwap(u64 volatile* pointer, u128 value, u128 expected) { 65bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
61 unsigned __int128 value_a; 66 unsigned __int128 value_a;
62 unsigned __int128 expected_a; 67 unsigned __int128 expected_a;
63 std::memcpy(&value_a, value.data(), sizeof(u128)); 68 std::memcpy(&value_a, value.data(), sizeof(u128));
diff --git a/src/common/atomic_ops.h b/src/common/atomic_ops.h
index e6181d521..8d6b73c00 100644
--- a/src/common/atomic_ops.h
+++ b/src/common/atomic_ops.h
@@ -8,10 +8,10 @@
8 8
9namespace Common { 9namespace Common {
10 10
11bool AtomicCompareAndSwap(u8 volatile* pointer, u8 value, u8 expected); 11bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected);
12bool AtomicCompareAndSwap(u16 volatile* pointer, u16 value, u16 expected); 12bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected);
13bool AtomicCompareAndSwap(u32 volatile* pointer, u32 value, u32 expected); 13bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected);
14bool AtomicCompareAndSwap(u64 volatile* pointer, u64 value, u64 expected); 14bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected);
15bool AtomicCompareAndSwap(u64 volatile* pointer, u128 value, u128 expected); 15bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected);
16 16
17} // namespace Common 17} // namespace Common
diff --git a/src/common/concepts.h b/src/common/concepts.h
index db5fb373d..54252e778 100644
--- a/src/common/concepts.h
+++ b/src/common/concepts.h
@@ -23,10 +23,12 @@ concept IsSTLContainer = requires(T t) {
23 t.size(); 23 t.size();
24}; 24};
25 25
26// Check if type T is derived from T2 26// TODO: Replace with std::derived_from when the <concepts> header
27template <typename T, typename T2> 27// is available on all supported platforms.
28concept IsBaseOf = requires { 28template <typename Derived, typename Base>
29 std::is_base_of_v<T, T2>; 29concept DerivedFrom = requires {
30 std::is_base_of_v<Base, Derived>;
31 std::is_convertible_v<const volatile Derived*, const volatile Base*>;
30}; 32};
31 33
32} // namespace Common 34} // namespace Common
diff --git a/src/common/detached_tasks.cpp b/src/common/detached_tasks.cpp
index f268d6021..f2b4939df 100644
--- a/src/common/detached_tasks.cpp
+++ b/src/common/detached_tasks.cpp
@@ -34,8 +34,7 @@ void DetachedTasks::AddTask(std::function<void()> task) {
34 std::unique_lock lock{instance->mutex}; 34 std::unique_lock lock{instance->mutex};
35 --instance->count; 35 --instance->count;
36 std::notify_all_at_thread_exit(instance->cv, std::move(lock)); 36 std::notify_all_at_thread_exit(instance->cv, std::move(lock));
37 }) 37 }).detach();
38 .detach();
39} 38}
40 39
41} // namespace Common 40} // namespace Common
diff --git a/src/common/hex_util.cpp b/src/common/hex_util.cpp
index c2f6cf0f6..74f52dd11 100644
--- a/src/common/hex_util.cpp
+++ b/src/common/hex_util.cpp
@@ -3,21 +3,9 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/hex_util.h" 5#include "common/hex_util.h"
6#include "common/logging/log.h"
7 6
8namespace Common { 7namespace Common {
9 8
10u8 ToHexNibble(char c1) {
11 if (c1 >= 65 && c1 <= 70)
12 return c1 - 55;
13 if (c1 >= 97 && c1 <= 102)
14 return c1 - 87;
15 if (c1 >= 48 && c1 <= 57)
16 return c1 - 48;
17 LOG_ERROR(Common, "Invalid hex digit: 0x{:02X}", c1);
18 return 0;
19}
20
21std::vector<u8> HexStringToVector(std::string_view str, bool little_endian) { 9std::vector<u8> HexStringToVector(std::string_view str, bool little_endian) {
22 std::vector<u8> out(str.size() / 2); 10 std::vector<u8> out(str.size() / 2);
23 if (little_endian) { 11 if (little_endian) {
@@ -30,26 +18,4 @@ std::vector<u8> HexStringToVector(std::string_view str, bool little_endian) {
30 return out; 18 return out;
31} 19}
32 20
33std::array<u8, 16> operator""_array16(const char* str, std::size_t len) {
34 if (len != 32) {
35 LOG_ERROR(Common,
36 "Attempting to parse string to array that is not of correct size (expected=32, "
37 "actual={}).",
38 len);
39 return {};
40 }
41 return HexStringToArray<16>(str);
42}
43
44std::array<u8, 32> operator""_array32(const char* str, std::size_t len) {
45 if (len != 64) {
46 LOG_ERROR(Common,
47 "Attempting to parse string to array that is not of correct size (expected=64, "
48 "actual={}).",
49 len);
50 return {};
51 }
52 return HexStringToArray<32>(str);
53}
54
55} // namespace Common 21} // namespace Common
diff --git a/src/common/hex_util.h b/src/common/hex_util.h
index bb4736f96..a0a0e78a4 100644
--- a/src/common/hex_util.h
+++ b/src/common/hex_util.h
@@ -14,19 +14,31 @@
14 14
15namespace Common { 15namespace Common {
16 16
17u8 ToHexNibble(char c1); 17constexpr u8 ToHexNibble(char c) {
18 if (c >= 65 && c <= 70) {
19 return c - 55;
20 }
21
22 if (c >= 97 && c <= 102) {
23 return c - 87;
24 }
25
26 return c - 48;
27}
18 28
19std::vector<u8> HexStringToVector(std::string_view str, bool little_endian); 29std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
20 30
21template <std::size_t Size, bool le = false> 31template <std::size_t Size, bool le = false>
22std::array<u8, Size> HexStringToArray(std::string_view str) { 32constexpr std::array<u8, Size> HexStringToArray(std::string_view str) {
23 std::array<u8, Size> out{}; 33 std::array<u8, Size> out{};
24 if constexpr (le) { 34 if constexpr (le) {
25 for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) 35 for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {
26 out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]); 36 out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
37 }
27 } else { 38 } else {
28 for (std::size_t i = 0; i < 2 * Size; i += 2) 39 for (std::size_t i = 0; i < 2 * Size; i += 2) {
29 out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]); 40 out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
41 }
30 } 42 }
31 return out; 43 return out;
32} 44}
@@ -48,7 +60,12 @@ std::string HexToString(const ContiguousContainer& data, bool upper = true) {
48 return out; 60 return out;
49} 61}
50 62
51std::array<u8, 0x10> operator"" _array16(const char* str, std::size_t len); 63constexpr std::array<u8, 16> AsArray(const char (&data)[17]) {
52std::array<u8, 0x20> operator"" _array32(const char* str, std::size_t len); 64 return HexStringToArray<16>(data);
65}
66
67constexpr std::array<u8, 32> AsArray(const char (&data)[65]) {
68 return HexStringToArray<32>(data);
69}
53 70
54} // namespace Common 71} // namespace Common
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 04bc3128f..62cfde397 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -113,19 +113,19 @@ private:
113 Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr, 113 Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
114 const char* function, std::string message) const { 114 const char* function, std::string message) const {
115 using std::chrono::duration_cast; 115 using std::chrono::duration_cast;
116 using std::chrono::microseconds;
116 using std::chrono::steady_clock; 117 using std::chrono::steady_clock;
117 118
118 Entry entry; 119 return {
119 entry.timestamp = 120 .timestamp = duration_cast<microseconds>(steady_clock::now() - time_origin),
120 duration_cast<std::chrono::microseconds>(steady_clock::now() - time_origin); 121 .log_class = log_class,
121 entry.log_class = log_class; 122 .log_level = log_level,
122 entry.log_level = log_level; 123 .filename = filename,
123 entry.filename = filename; 124 .line_num = line_nr,
124 entry.line_num = line_nr; 125 .function = function,
125 entry.function = function; 126 .message = std::move(message),
126 entry.message = std::move(message); 127 .final_entry = false,
127 128 };
128 return entry;
129 } 129 }
130 130
131 std::mutex writing_mutex; 131 std::mutex writing_mutex;
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h
index fc338c70d..e5d702568 100644
--- a/src/common/logging/backend.h
+++ b/src/common/logging/backend.h
@@ -21,19 +21,13 @@ class Filter;
21 */ 21 */
22struct Entry { 22struct Entry {
23 std::chrono::microseconds timestamp; 23 std::chrono::microseconds timestamp;
24 Class log_class; 24 Class log_class{};
25 Level log_level; 25 Level log_level{};
26 const char* filename; 26 const char* filename = nullptr;
27 unsigned int line_num; 27 unsigned int line_num = 0;
28 std::string function; 28 std::string function;
29 std::string message; 29 std::string message;
30 bool final_entry = false; 30 bool final_entry = false;
31
32 Entry() = default;
33 Entry(Entry&& o) = default;
34
35 Entry& operator=(Entry&& o) = default;
36 Entry& operator=(const Entry& o) = default;
37}; 31};
38 32
39/** 33/**
diff --git a/src/common/lz4_compression.cpp b/src/common/lz4_compression.cpp
index ade6759bb..8e2e4094b 100644
--- a/src/common/lz4_compression.cpp
+++ b/src/common/lz4_compression.cpp
@@ -10,14 +10,14 @@
10 10
11namespace Common::Compression { 11namespace Common::Compression {
12 12
13std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size) { 13std::vector<u8> CompressDataLZ4(std::span<const u8> source) {
14 ASSERT_MSG(source_size <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size"); 14 ASSERT_MSG(source.size() <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size");
15 15
16 const auto source_size_int = static_cast<int>(source_size); 16 const auto source_size_int = static_cast<int>(source.size());
17 const int max_compressed_size = LZ4_compressBound(source_size_int); 17 const int max_compressed_size = LZ4_compressBound(source_size_int);
18 std::vector<u8> compressed(max_compressed_size); 18 std::vector<u8> compressed(max_compressed_size);
19 19
20 const int compressed_size = LZ4_compress_default(reinterpret_cast<const char*>(source), 20 const int compressed_size = LZ4_compress_default(reinterpret_cast<const char*>(source.data()),
21 reinterpret_cast<char*>(compressed.data()), 21 reinterpret_cast<char*>(compressed.data()),
22 source_size_int, max_compressed_size); 22 source_size_int, max_compressed_size);
23 23
@@ -31,18 +31,17 @@ std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size) {
31 return compressed; 31 return compressed;
32} 32}
33 33
34std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size, 34std::vector<u8> CompressDataLZ4HC(std::span<const u8> source, s32 compression_level) {
35 s32 compression_level) { 35 ASSERT_MSG(source.size() <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size");
36 ASSERT_MSG(source_size <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size");
37 36
38 compression_level = std::clamp(compression_level, LZ4HC_CLEVEL_MIN, LZ4HC_CLEVEL_MAX); 37 compression_level = std::clamp(compression_level, LZ4HC_CLEVEL_MIN, LZ4HC_CLEVEL_MAX);
39 38
40 const auto source_size_int = static_cast<int>(source_size); 39 const auto source_size_int = static_cast<int>(source.size());
41 const int max_compressed_size = LZ4_compressBound(source_size_int); 40 const int max_compressed_size = LZ4_compressBound(source_size_int);
42 std::vector<u8> compressed(max_compressed_size); 41 std::vector<u8> compressed(max_compressed_size);
43 42
44 const int compressed_size = LZ4_compress_HC( 43 const int compressed_size = LZ4_compress_HC(
45 reinterpret_cast<const char*>(source), reinterpret_cast<char*>(compressed.data()), 44 reinterpret_cast<const char*>(source.data()), reinterpret_cast<char*>(compressed.data()),
46 source_size_int, max_compressed_size, compression_level); 45 source_size_int, max_compressed_size, compression_level);
47 46
48 if (compressed_size <= 0) { 47 if (compressed_size <= 0) {
@@ -55,8 +54,8 @@ std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size,
55 return compressed; 54 return compressed;
56} 55}
57 56
58std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size) { 57std::vector<u8> CompressDataLZ4HCMax(std::span<const u8> source) {
59 return CompressDataLZ4HC(source, source_size, LZ4HC_CLEVEL_MAX); 58 return CompressDataLZ4HC(source, LZ4HC_CLEVEL_MAX);
60} 59}
61 60
62std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed, 61std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed,
diff --git a/src/common/lz4_compression.h b/src/common/lz4_compression.h
index 4c16f6e03..173f9b9ad 100644
--- a/src/common/lz4_compression.h
+++ b/src/common/lz4_compression.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <span>
7#include <vector> 8#include <vector>
8 9
9#include "common/common_types.h" 10#include "common/common_types.h"
@@ -14,11 +15,10 @@ namespace Common::Compression {
14 * Compresses a source memory region with LZ4 and returns the compressed data in a vector. 15 * Compresses a source memory region with LZ4 and returns the compressed data in a vector.
15 * 16 *
16 * @param source the uncompressed source memory region. 17 * @param source the uncompressed source memory region.
17 * @param source_size the size in bytes of the uncompressed source memory region.
18 * 18 *
19 * @return the compressed data. 19 * @return the compressed data.
20 */ 20 */
21std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size); 21std::vector<u8> CompressDataLZ4(std::span<const u8> source);
22 22
23/** 23/**
24 * Utilizes the LZ4 subalgorithm LZ4HC with the specified compression level. Higher compression 24 * Utilizes the LZ4 subalgorithm LZ4HC with the specified compression level. Higher compression
@@ -27,22 +27,20 @@ std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size);
27 * also be decompressed with the default LZ4 decompression. 27 * also be decompressed with the default LZ4 decompression.
28 * 28 *
29 * @param source the uncompressed source memory region. 29 * @param source the uncompressed source memory region.
30 * @param source_size the size in bytes of the uncompressed source memory region.
31 * @param compression_level the used compression level. Should be between 3 and 12. 30 * @param compression_level the used compression level. Should be between 3 and 12.
32 * 31 *
33 * @return the compressed data. 32 * @return the compressed data.
34 */ 33 */
35std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size, s32 compression_level); 34std::vector<u8> CompressDataLZ4HC(std::span<const u8> source, s32 compression_level);
36 35
37/** 36/**
38 * Utilizes the LZ4 subalgorithm LZ4HC with the highest possible compression level. 37 * Utilizes the LZ4 subalgorithm LZ4HC with the highest possible compression level.
39 * 38 *
40 * @param source the uncompressed source memory region. 39 * @param source the uncompressed source memory region.
41 * @param source_size the size in bytes of the uncompressed source memory region.
42 * 40 *
43 * @return the compressed data. 41 * @return the compressed data.
44 */ 42 */
45std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size); 43std::vector<u8> CompressDataLZ4HCMax(std::span<const u8> source);
46 44
47/** 45/**
48 * Decompresses a source memory region with LZ4 and returns the uncompressed data in a vector. 46 * Decompresses a source memory region with LZ4 and returns the uncompressed data in a vector.
diff --git a/src/common/math_util.h b/src/common/math_util.h
index 83ef0201f..abca3177c 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -54,6 +54,6 @@ struct Rectangle {
54}; 54};
55 55
56template <typename T> 56template <typename T>
57Rectangle(T, T, T, T)->Rectangle<T>; 57Rectangle(T, T, T, T) -> Rectangle<T>;
58 58
59} // namespace Common 59} // namespace Common
diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp
index be5b67752..b009cb500 100644
--- a/src/common/virtual_buffer.cpp
+++ b/src/common/virtual_buffer.cpp
@@ -5,16 +5,7 @@
5#ifdef _WIN32 5#ifdef _WIN32
6#include <windows.h> 6#include <windows.h>
7#else 7#else
8#include <stdio.h>
9#include <sys/mman.h> 8#include <sys/mman.h>
10#include <sys/types.h>
11#if defined __APPLE__ || defined __FreeBSD__ || defined __OpenBSD__
12#include <sys/sysctl.h>
13#elif defined __HAIKU__
14#include <OS.h>
15#else
16#include <sys/sysinfo.h>
17#endif
18#endif 9#endif
19 10
20#include "common/assert.h" 11#include "common/assert.h"
diff --git a/src/common/zstd_compression.cpp b/src/common/zstd_compression.cpp
index 978526492..770833ee7 100644
--- a/src/common/zstd_compression.cpp
+++ b/src/common/zstd_compression.cpp
@@ -5,19 +5,18 @@
5#include <algorithm> 5#include <algorithm>
6#include <zstd.h> 6#include <zstd.h>
7 7
8#include "common/assert.h"
9#include "common/zstd_compression.h" 8#include "common/zstd_compression.h"
10 9
11namespace Common::Compression { 10namespace Common::Compression {
12 11
13std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size, s32 compression_level) { 12std::vector<u8> CompressDataZSTD(std::span<const u8> source, s32 compression_level) {
14 compression_level = std::clamp(compression_level, 1, ZSTD_maxCLevel()); 13 compression_level = std::clamp(compression_level, 1, ZSTD_maxCLevel());
15 14
16 const std::size_t max_compressed_size = ZSTD_compressBound(source_size); 15 const std::size_t max_compressed_size = ZSTD_compressBound(source.size());
17 std::vector<u8> compressed(max_compressed_size); 16 std::vector<u8> compressed(max_compressed_size);
18 17
19 const std::size_t compressed_size = 18 const std::size_t compressed_size = ZSTD_compress(
20 ZSTD_compress(compressed.data(), compressed.size(), source, source_size, compression_level); 19 compressed.data(), compressed.size(), source.data(), source.size(), compression_level);
21 20
22 if (ZSTD_isError(compressed_size)) { 21 if (ZSTD_isError(compressed_size)) {
23 // Compression failed 22 // Compression failed
@@ -29,8 +28,8 @@ std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size, s32
29 return compressed; 28 return compressed;
30} 29}
31 30
32std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size) { 31std::vector<u8> CompressDataZSTDDefault(std::span<const u8> source) {
33 return CompressDataZSTD(source, source_size, ZSTD_CLEVEL_DEFAULT); 32 return CompressDataZSTD(source, ZSTD_CLEVEL_DEFAULT);
34} 33}
35 34
36std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed) { 35std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed) {
diff --git a/src/common/zstd_compression.h b/src/common/zstd_compression.h
index e9de941c8..b5edf19e7 100644
--- a/src/common/zstd_compression.h
+++ b/src/common/zstd_compression.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <span>
7#include <vector> 8#include <vector>
8 9
9#include "common/common_types.h" 10#include "common/common_types.h"
@@ -14,23 +15,21 @@ namespace Common::Compression {
14 * Compresses a source memory region with Zstandard and returns the compressed data in a vector. 15 * Compresses a source memory region with Zstandard and returns the compressed data in a vector.
15 * 16 *
16 * @param source the uncompressed source memory region. 17 * @param source the uncompressed source memory region.
17 * @param source_size the size in bytes of the uncompressed source memory region.
18 * @param compression_level the used compression level. Should be between 1 and 22. 18 * @param compression_level the used compression level. Should be between 1 and 22.
19 * 19 *
20 * @return the compressed data. 20 * @return the compressed data.
21 */ 21 */
22std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size, s32 compression_level); 22std::vector<u8> CompressDataZSTD(std::span<const u8> source, s32 compression_level);
23 23
24/** 24/**
25 * Compresses a source memory region with Zstandard with the default compression level and returns 25 * Compresses a source memory region with Zstandard with the default compression level and returns
26 * the compressed data in a vector. 26 * the compressed data in a vector.
27 * 27 *
28 * @param source the uncompressed source memory region. 28 * @param source the uncompressed source memory region.
29 * @param source_size the size in bytes of the uncompressed source memory region.
30 * 29 *
31 * @return the compressed data. 30 * @return the compressed data.
32 */ 31 */
33std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size); 32std::vector<u8> CompressDataZSTDDefault(std::span<const u8> source);
34 33
35/** 34/**
36 * Decompresses a source memory region with Zstandard and returns the uncompressed data in a vector. 35 * Decompresses a source memory region with Zstandard and returns the uncompressed data in a vector.
diff --git a/src/core/crypto/aes_util.cpp b/src/core/crypto/aes_util.cpp
index 4be76bb43..330996b24 100644
--- a/src/core/crypto/aes_util.cpp
+++ b/src/core/crypto/aes_util.cpp
@@ -2,6 +2,7 @@
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 <array>
5#include <mbedtls/cipher.h> 6#include <mbedtls/cipher.h>
6#include "common/assert.h" 7#include "common/assert.h"
7#include "common/logging/log.h" 8#include "common/logging/log.h"
@@ -10,8 +11,10 @@
10 11
11namespace Core::Crypto { 12namespace Core::Crypto {
12namespace { 13namespace {
13std::vector<u8> CalculateNintendoTweak(std::size_t sector_id) { 14using NintendoTweak = std::array<u8, 16>;
14 std::vector<u8> out(0x10); 15
16NintendoTweak CalculateNintendoTweak(std::size_t sector_id) {
17 NintendoTweak out{};
15 for (std::size_t i = 0xF; i <= 0xF; --i) { 18 for (std::size_t i = 0xF; i <= 0xF; --i) {
16 out[i] = sector_id & 0xFF; 19 out[i] = sector_id & 0xFF;
17 sector_id >>= 8; 20 sector_id >>= 8;
@@ -64,13 +67,6 @@ AESCipher<Key, KeySize>::~AESCipher() {
64} 67}
65 68
66template <typename Key, std::size_t KeySize> 69template <typename Key, std::size_t KeySize>
67void AESCipher<Key, KeySize>::SetIV(std::vector<u8> iv) {
68 ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, iv.data(), iv.size()) ||
69 mbedtls_cipher_set_iv(&ctx->decryption_context, iv.data(), iv.size())) == 0,
70 "Failed to set IV on mbedtls ciphers.");
71}
72
73template <typename Key, std::size_t KeySize>
74void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* dest, Op op) const { 70void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* dest, Op op) const {
75 auto* const context = op == Op::Encrypt ? &ctx->encryption_context : &ctx->decryption_context; 71 auto* const context = op == Op::Encrypt ? &ctx->encryption_context : &ctx->decryption_context;
76 72
@@ -124,6 +120,13 @@ void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, std::size_t size, u8*
124 } 120 }
125} 121}
126 122
123template <typename Key, std::size_t KeySize>
124void AESCipher<Key, KeySize>::SetIVImpl(const u8* data, std::size_t size) {
125 ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, data, size) ||
126 mbedtls_cipher_set_iv(&ctx->decryption_context, data, size)) == 0,
127 "Failed to set IV on mbedtls ciphers.");
128}
129
127template class AESCipher<Key128>; 130template class AESCipher<Key128>;
128template class AESCipher<Key256>; 131template class AESCipher<Key256>;
129} // namespace Core::Crypto 132} // namespace Core::Crypto
diff --git a/src/core/crypto/aes_util.h b/src/core/crypto/aes_util.h
index edc4ab910..e2a304186 100644
--- a/src/core/crypto/aes_util.h
+++ b/src/core/crypto/aes_util.h
@@ -6,7 +6,6 @@
6 6
7#include <memory> 7#include <memory>
8#include <type_traits> 8#include <type_traits>
9#include <vector>
10#include "common/common_types.h" 9#include "common/common_types.h"
11#include "core/file_sys/vfs.h" 10#include "core/file_sys/vfs.h"
12 11
@@ -32,10 +31,12 @@ class AESCipher {
32 31
33public: 32public:
34 AESCipher(Key key, Mode mode); 33 AESCipher(Key key, Mode mode);
35
36 ~AESCipher(); 34 ~AESCipher();
37 35
38 void SetIV(std::vector<u8> iv); 36 template <typename ContiguousContainer>
37 void SetIV(const ContiguousContainer& container) {
38 SetIVImpl(std::data(container), std::size(container));
39 }
39 40
40 template <typename Source, typename Dest> 41 template <typename Source, typename Dest>
41 void Transcode(const Source* src, std::size_t size, Dest* dest, Op op) const { 42 void Transcode(const Source* src, std::size_t size, Dest* dest, Op op) const {
@@ -59,6 +60,8 @@ public:
59 std::size_t sector_size, Op op); 60 std::size_t sector_size, Op op);
60 61
61private: 62private:
63 void SetIVImpl(const u8* data, std::size_t size);
64
62 std::unique_ptr<CipherContext> ctx; 65 std::unique_ptr<CipherContext> ctx;
63}; 66};
64} // namespace Core::Crypto 67} // namespace Core::Crypto
diff --git a/src/core/crypto/ctr_encryption_layer.cpp b/src/core/crypto/ctr_encryption_layer.cpp
index 902841c77..5c84bb0a4 100644
--- a/src/core/crypto/ctr_encryption_layer.cpp
+++ b/src/core/crypto/ctr_encryption_layer.cpp
@@ -2,6 +2,7 @@
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 <algorithm>
5#include <cstring> 6#include <cstring>
6#include "common/assert.h" 7#include "common/assert.h"
7#include "core/crypto/ctr_encryption_layer.h" 8#include "core/crypto/ctr_encryption_layer.h"
@@ -10,8 +11,7 @@ namespace Core::Crypto {
10 11
11CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_, 12CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_,
12 std::size_t base_offset) 13 std::size_t base_offset)
13 : EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR), 14 : EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR) {}
14 iv(16, 0) {}
15 15
16std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const { 16std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const {
17 if (length == 0) 17 if (length == 0)
@@ -39,9 +39,8 @@ std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t o
39 return read + Read(data + read, length - read, offset + read); 39 return read + Read(data + read, length - read, offset + read);
40} 40}
41 41
42void CTREncryptionLayer::SetIV(const std::vector<u8>& iv_) { 42void CTREncryptionLayer::SetIV(const IVData& iv_) {
43 const auto length = std::min(iv_.size(), iv.size()); 43 iv = iv_;
44 iv.assign(iv_.cbegin(), iv_.cbegin() + length);
45} 44}
46 45
47void CTREncryptionLayer::UpdateIV(std::size_t offset) const { 46void CTREncryptionLayer::UpdateIV(std::size_t offset) const {
diff --git a/src/core/crypto/ctr_encryption_layer.h b/src/core/crypto/ctr_encryption_layer.h
index a7bf810f4..a2429f001 100644
--- a/src/core/crypto/ctr_encryption_layer.h
+++ b/src/core/crypto/ctr_encryption_layer.h
@@ -4,7 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <vector> 7#include <array>
8
8#include "core/crypto/aes_util.h" 9#include "core/crypto/aes_util.h"
9#include "core/crypto/encryption_layer.h" 10#include "core/crypto/encryption_layer.h"
10#include "core/crypto/key_manager.h" 11#include "core/crypto/key_manager.h"
@@ -14,18 +15,20 @@ namespace Core::Crypto {
14// Sits on top of a VirtualFile and provides CTR-mode AES decription. 15// Sits on top of a VirtualFile and provides CTR-mode AES decription.
15class CTREncryptionLayer : public EncryptionLayer { 16class CTREncryptionLayer : public EncryptionLayer {
16public: 17public:
18 using IVData = std::array<u8, 16>;
19
17 CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, std::size_t base_offset); 20 CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, std::size_t base_offset);
18 21
19 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; 22 std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
20 23
21 void SetIV(const std::vector<u8>& iv); 24 void SetIV(const IVData& iv);
22 25
23private: 26private:
24 std::size_t base_offset; 27 std::size_t base_offset;
25 28
26 // Must be mutable as operations modify cipher contexts. 29 // Must be mutable as operations modify cipher contexts.
27 mutable AESCipher<Key128> cipher; 30 mutable AESCipher<Key128> cipher;
28 mutable std::vector<u8> iv; 31 mutable IVData iv{};
29 32
30 void UpdateIV(std::size_t offset) const; 33 void UpdateIV(std::size_t offset) const;
31}; 34};
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index f87fe0abc..c09f7ad41 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -40,12 +40,14 @@ namespace Core::Crypto {
40constexpr u64 CURRENT_CRYPTO_REVISION = 0x5; 40constexpr u64 CURRENT_CRYPTO_REVISION = 0x5;
41constexpr u64 FULL_TICKET_SIZE = 0x400; 41constexpr u64 FULL_TICKET_SIZE = 0x400;
42 42
43using namespace Common; 43using Common::AsArray;
44 44
45const std::array<SHA256Hash, 2> eticket_source_hashes{ 45// clang-format off
46 "B71DB271DC338DF380AA2C4335EF8873B1AFD408E80B3582D8719FC81C5E511C"_array32, // eticket_rsa_kek_source 46constexpr std::array eticket_source_hashes{
47 "E8965A187D30E57869F562D04383C996DE487BBA5761363D2D4D32391866A85C"_array32, // eticket_rsa_kekek_source 47 AsArray("B71DB271DC338DF380AA2C4335EF8873B1AFD408E80B3582D8719FC81C5E511C"), // eticket_rsa_kek_source
48 AsArray("E8965A187D30E57869F562D04383C996DE487BBA5761363D2D4D32391866A85C"), // eticket_rsa_kekek_source
48}; 49};
50// clang-format on
49 51
50const std::map<std::pair<S128KeyType, u64>, std::string> KEYS_VARIABLE_LENGTH{ 52const std::map<std::pair<S128KeyType, u64>, std::string> KEYS_VARIABLE_LENGTH{
51 {{S128KeyType::Master, 0}, "master_key_"}, 53 {{S128KeyType::Master, 0}, "master_key_"},
diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp
index 7ed71ac3a..3e96f7516 100644
--- a/src/core/crypto/partition_data_manager.cpp
+++ b/src/core/crypto/partition_data_manager.cpp
@@ -27,7 +27,7 @@
27#include "core/file_sys/vfs_offset.h" 27#include "core/file_sys/vfs_offset.h"
28#include "core/file_sys/vfs_vector.h" 28#include "core/file_sys/vfs_vector.h"
29 29
30using namespace Common; 30using Common::AsArray;
31 31
32namespace Core::Crypto { 32namespace Core::Crypto {
33 33
@@ -47,105 +47,123 @@ struct Package2Header {
47}; 47};
48static_assert(sizeof(Package2Header) == 0x200, "Package2Header has incorrect size."); 48static_assert(sizeof(Package2Header) == 0x200, "Package2Header has incorrect size.");
49 49
50const std::array<SHA256Hash, 0x10> source_hashes{ 50// clang-format off
51 "B24BD293259DBC7AC5D63F88E60C59792498E6FC5443402C7FFE87EE8B61A3F0"_array32, // keyblob_mac_key_source 51constexpr std::array source_hashes{
52 "7944862A3A5C31C6720595EFD302245ABD1B54CCDCF33000557681E65C5664A4"_array32, // master_key_source 52 AsArray("B24BD293259DBC7AC5D63F88E60C59792498E6FC5443402C7FFE87EE8B61A3F0"), // keyblob_mac_key_source
53 "21E2DF100FC9E094DB51B47B9B1D6E94ED379DB8B547955BEF8FE08D8DD35603"_array32, // package2_key_source 53 AsArray("7944862A3A5C31C6720595EFD302245ABD1B54CCDCF33000557681E65C5664A4"), // master_key_source
54 "FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"_array32, // aes_kek_generation_source 54 AsArray("21E2DF100FC9E094DB51B47B9B1D6E94ED379DB8B547955BEF8FE08D8DD35603"), // package2_key_source
55 "FBD10056999EDC7ACDB96098E47E2C3606230270D23281E671F0F389FC5BC585"_array32, // aes_key_generation_source 55 AsArray("FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"), // aes_kek_generation_source
56 "C48B619827986C7F4E3081D59DB2B460C84312650E9A8E6B458E53E8CBCA4E87"_array32, // titlekek_source 56 AsArray("FBD10056999EDC7ACDB96098E47E2C3606230270D23281E671F0F389FC5BC585"), // aes_key_generation_source
57 "04AD66143C726B2A139FB6B21128B46F56C553B2B3887110304298D8D0092D9E"_array32, // key_area_key_application_source 57 AsArray("C48B619827986C7F4E3081D59DB2B460C84312650E9A8E6B458E53E8CBCA4E87"), // titlekek_source
58 "FD434000C8FF2B26F8E9A9D2D2C12F6BE5773CBB9DC86300E1BD99F8EA33A417"_array32, // key_area_key_ocean_source 58 AsArray("04AD66143C726B2A139FB6B21128B46F56C553B2B3887110304298D8D0092D9E"), // key_area_key_application_source
59 "1F17B1FD51AD1C2379B58F152CA4912EC2106441E51722F38700D5937A1162F7"_array32, // key_area_key_system_source 59 AsArray("FD434000C8FF2B26F8E9A9D2D2C12F6BE5773CBB9DC86300E1BD99F8EA33A417"), // key_area_key_ocean_source
60 "6B2ED877C2C52334AC51E59ABFA7EC457F4A7D01E46291E9F2EAA45F011D24B7"_array32, // sd_card_kek_source 60 AsArray("1F17B1FD51AD1C2379B58F152CA4912EC2106441E51722F38700D5937A1162F7"), // key_area_key_system_source
61 "D482743563D3EA5DCDC3B74E97C9AC8A342164FA041A1DC80F17F6D31E4BC01C"_array32, // sd_card_save_key_source 61 AsArray("6B2ED877C2C52334AC51E59ABFA7EC457F4A7D01E46291E9F2EAA45F011D24B7"), // sd_card_kek_source
62 "2E751CECF7D93A2B957BD5FFCB082FD038CC2853219DD3092C6DAB9838F5A7CC"_array32, // sd_card_nca_key_source 62 AsArray("D482743563D3EA5DCDC3B74E97C9AC8A342164FA041A1DC80F17F6D31E4BC01C"), // sd_card_save_key_source
63 "1888CAED5551B3EDE01499E87CE0D86827F80820EFB275921055AA4E2ABDFFC2"_array32, // header_kek_source 63 AsArray("2E751CECF7D93A2B957BD5FFCB082FD038CC2853219DD3092C6DAB9838F5A7CC"), // sd_card_nca_key_source
64 "8F783E46852DF6BE0BA4E19273C4ADBAEE16380043E1B8C418C4089A8BD64AA6"_array32, // header_key_source 64 AsArray("1888CAED5551B3EDE01499E87CE0D86827F80820EFB275921055AA4E2ABDFFC2"), // header_kek_source
65 "D1757E52F1AE55FA882EC690BC6F954AC46A83DC22F277F8806BD55577C6EED7"_array32, // rsa_kek_seed3 65 AsArray("8F783E46852DF6BE0BA4E19273C4ADBAEE16380043E1B8C418C4089A8BD64AA6"), // header_key_source
66 "FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"_array32, // rsa_kek_mask0 66 AsArray("D1757E52F1AE55FA882EC690BC6F954AC46A83DC22F277F8806BD55577C6EED7"), // rsa_kek_seed3
67 AsArray("FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"), // rsa_kek_mask0
67}; 68};
68 69// clang-format on
69const std::array<SHA256Hash, 0x20> keyblob_source_hashes{ 70
70 "8A06FE274AC491436791FDB388BCDD3AB9943BD4DEF8094418CDAC150FD73786"_array32, // keyblob_key_source_00 71// clang-format off
71 "2D5CAEB2521FEF70B47E17D6D0F11F8CE2C1E442A979AD8035832C4E9FBCCC4B"_array32, // keyblob_key_source_01 72constexpr std::array keyblob_source_hashes{
72 "61C5005E713BAE780641683AF43E5F5C0E03671117F702F401282847D2FC6064"_array32, // keyblob_key_source_02 73 AsArray("8A06FE274AC491436791FDB388BCDD3AB9943BD4DEF8094418CDAC150FD73786"), // keyblob_key_source_00
73 "8E9795928E1C4428E1B78F0BE724D7294D6934689C11B190943923B9D5B85903"_array32, // keyblob_key_source_03 74 AsArray("2D5CAEB2521FEF70B47E17D6D0F11F8CE2C1E442A979AD8035832C4E9FBCCC4B"), // keyblob_key_source_01
74 "95FA33AF95AFF9D9B61D164655B32710ED8D615D46C7D6CC3CC70481B686B402"_array32, // keyblob_key_source_04 75 AsArray("61C5005E713BAE780641683AF43E5F5C0E03671117F702F401282847D2FC6064"), // keyblob_key_source_02
75 "3F5BE7B3C8B1ABD8C10B4B703D44766BA08730562C172A4FE0D6B866B3E2DB3E"_array32, // keyblob_key_source_05 76 AsArray("8E9795928E1C4428E1B78F0BE724D7294D6934689C11B190943923B9D5B85903"), // keyblob_key_source_03
76 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_06 77 AsArray("95FA33AF95AFF9D9B61D164655B32710ED8D615D46C7D6CC3CC70481B686B402"), // keyblob_key_source_04
77 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_07 78 AsArray("3F5BE7B3C8B1ABD8C10B4B703D44766BA08730562C172A4FE0D6B866B3E2DB3E"), // keyblob_key_source_05
78 79 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_06
79 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_08 80 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_07
80 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_09 81
81 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0A 82 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_08
82 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0B 83 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_09
83 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0C 84 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0A
84 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0D 85 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0B
85 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0E 86 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0C
86 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0F 87 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0D
87 88 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0E
88 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_10 89 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0F
89 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_11 90
90 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_12 91 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_10
91 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_13 92 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_11
92 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_14 93 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_12
93 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_15 94 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_13
94 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_16 95 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_14
95 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_17 96 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_15
96 97 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_16
97 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_18 98 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_17
98 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_19 99
99 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1A 100 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_18
100 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1B 101 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_19
101 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1C 102 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1A
102 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1D 103 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1B
103 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1E 104 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1C
104 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1F 105 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1D
106 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1E
107 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1F
105}; 108};
106 109// clang-format on
107const std::array<SHA256Hash, 0x20> master_key_hashes{ 110
108 "0EE359BE3C864BB0782E1D70A718A0342C551EED28C369754F9C4F691BECF7CA"_array32, // master_key_00 111// clang-format off
109 "4FE707B7E4ABDAF727C894AAF13B1351BFE2AC90D875F73B2E20FA94B9CC661E"_array32, // master_key_01 112constexpr std::array master_key_hashes{
110 "79277C0237A2252EC3DFAC1F7C359C2B3D121E9DB15BB9AB4C2B4408D2F3AE09"_array32, // master_key_02 113 AsArray("0EE359BE3C864BB0782E1D70A718A0342C551EED28C369754F9C4F691BECF7CA"), // master_key_00
111 "4F36C565D13325F65EE134073C6A578FFCB0008E02D69400836844EAB7432754"_array32, // master_key_03 114 AsArray("4FE707B7E4ABDAF727C894AAF13B1351BFE2AC90D875F73B2E20FA94B9CC661E"), // master_key_01
112 "75FF1D95D26113550EE6FCC20ACB58E97EDEB3A2FF52543ED5AEC63BDCC3DA50"_array32, // master_key_04 115 AsArray("79277C0237A2252EC3DFAC1F7C359C2B3D121E9DB15BB9AB4C2B4408D2F3AE09"), // master_key_02
113 "EBE2BCD6704673EC0F88A187BB2AD9F1CC82B718C389425941BDC194DC46B0DD"_array32, // master_key_05 116 AsArray("4F36C565D13325F65EE134073C6A578FFCB0008E02D69400836844EAB7432754"), // master_key_03
114 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_06 117 AsArray("75FF1D95D26113550EE6FCC20ACB58E97EDEB3A2FF52543ED5AEC63BDCC3DA50"), // master_key_04
115 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_07 118 AsArray("EBE2BCD6704673EC0F88A187BB2AD9F1CC82B718C389425941BDC194DC46B0DD"), // master_key_05
116 119 AsArray("9497E6779F5D840F2BBA1DE4E95BA1D6F21EFC94717D5AE5CA37D7EC5BD37A19"), // master_key_06
117 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_08 120 AsArray("4EC96B8CB01B8DCE382149443430B2B6EBCB2983348AFA04A25E53609DABEDF6"), // master_key_07
118 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_09 121
119 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0A 122 AsArray("2998E2E23609BC2675FF062A2D64AF5B1B78DFF463B24119D64A1B64F01B2D51"), // master_key_08
120 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0B 123 AsArray("9D486A98067C44B37CF173D3BF577891EB6081FF6B4A166347D9DBBF7025076B"), // master_key_09
121 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0C 124 AsArray("4EC5A237A75A083A9C5F6CF615601522A7F822D06BD4BA32612C9CEBBB29BD45"), // master_key_0A
122 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0D 125 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0B
123 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0E 126 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0C
124 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0F 127 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0D
125 128 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0E
126 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_10 129 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0F
127 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_11 130
128 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_12 131 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_10
129 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_13 132 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_11
130 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_14 133 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_12
131 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_15 134 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_13
132 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_16 135 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_14
133 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_17 136 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_15
134 137 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_16
135 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_18 138 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_17
136 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_19 139
137 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1A 140 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_18
138 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1B 141 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_19
139 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1C 142 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1A
140 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1D 143 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1B
141 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1E 144 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1C
142 "0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1F 145 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1D
146 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1E
147 AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1F
143}; 148};
149// clang-format on
150
151static constexpr u8 CalculateMaxKeyblobSourceHash() {
152 const auto is_zero = [](const auto& data) {
153 // TODO: Replace with std::all_of whenever mingw decides to update their
154 // libraries to include the constexpr variant of it.
155 for (const auto element : data) {
156 if (element != 0) {
157 return false;
158 }
159 }
160 return true;
161 };
144 162
145static u8 CalculateMaxKeyblobSourceHash() {
146 for (s8 i = 0x1F; i >= 0; --i) { 163 for (s8 i = 0x1F; i >= 0; --i) {
147 if (keyblob_source_hashes[i] != SHA256Hash{}) 164 if (!is_zero(keyblob_source_hashes[i])) {
148 return static_cast<u8>(i + 1); 165 return static_cast<u8>(i + 1);
166 }
149 } 167 }
150 168
151 return 0; 169 return 0;
@@ -346,10 +364,9 @@ FileSys::VirtualFile PartitionDataManager::GetPackage2Raw(Package2Type type) con
346} 364}
347 365
348static bool AttemptDecrypt(const std::array<u8, 16>& key, Package2Header& header) { 366static bool AttemptDecrypt(const std::array<u8, 16>& key, Package2Header& header) {
349 const std::vector<u8> iv(header.header_ctr.begin(), header.header_ctr.end());
350 Package2Header temp = header; 367 Package2Header temp = header;
351 AESCipher<Key128> cipher(key, Mode::CTR); 368 AESCipher<Key128> cipher(key, Mode::CTR);
352 cipher.SetIV(iv); 369 cipher.SetIV(header.header_ctr);
353 cipher.Transcode(&temp.header_ctr, sizeof(Package2Header) - 0x100, &temp.header_ctr, 370 cipher.Transcode(&temp.header_ctr, sizeof(Package2Header) - 0x100, &temp.header_ctr,
354 Op::Decrypt); 371 Op::Decrypt);
355 if (temp.magic == Common::MakeMagic('P', 'K', '2', '1')) { 372 if (temp.magic == Common::MakeMagic('P', 'K', '2', '1')) {
@@ -388,7 +405,7 @@ void PartitionDataManager::DecryptPackage2(const std::array<Key128, 0x20>& packa
388 auto c = a->ReadAllBytes(); 405 auto c = a->ReadAllBytes();
389 406
390 AESCipher<Key128> cipher(package2_keys[revision], Mode::CTR); 407 AESCipher<Key128> cipher(package2_keys[revision], Mode::CTR);
391 cipher.SetIV({header.section_ctr[1].begin(), header.section_ctr[1].end()}); 408 cipher.SetIV(header.section_ctr[1]);
392 cipher.Transcode(c.data(), c.size(), c.data(), Op::Decrypt); 409 cipher.Transcode(c.data(), c.size(), c.data(), Op::Decrypt);
393 410
394 const auto ini_file = std::make_shared<FileSys::VectorVfsFile>(c); 411 const auto ini_file = std::make_shared<FileSys::VectorVfsFile>(c);
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index 473245d5a..5039341c7 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -495,9 +495,10 @@ VirtualFile NCA::Decrypt(const NCASectionHeader& s_header, VirtualFile in, u64 s
495 495
496 auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>(std::move(in), *key, 496 auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>(std::move(in), *key,
497 starting_offset); 497 starting_offset);
498 std::vector<u8> iv(16); 498 Core::Crypto::CTREncryptionLayer::IVData iv{};
499 for (u8 i = 0; i < 8; ++i) 499 for (std::size_t i = 0; i < 8; ++i) {
500 iv[i] = s_header.raw.section_ctr[0x8 - i - 1]; 500 iv[i] = s_header.raw.section_ctr[8 - i - 1];
501 }
501 out->SetIV(iv); 502 out->SetIV(iv);
502 return std::static_pointer_cast<VfsFile>(out); 503 return std::static_pointer_cast<VfsFile>(out);
503 } 504 }
diff --git a/src/core/file_sys/nca_patch.cpp b/src/core/file_sys/nca_patch.cpp
index 0090cc6c4..fe7375e84 100644
--- a/src/core/file_sys/nca_patch.cpp
+++ b/src/core/file_sys/nca_patch.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <array>
6#include <cstddef> 7#include <cstddef>
7#include <cstring> 8#include <cstring>
8 9
@@ -66,7 +67,7 @@ std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const {
66 Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(key, Core::Crypto::Mode::CTR); 67 Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(key, Core::Crypto::Mode::CTR);
67 68
68 // Calculate AES IV 69 // Calculate AES IV
69 std::vector<u8> iv(16); 70 std::array<u8, 16> iv{};
70 auto subsection_ctr = subsection.ctr; 71 auto subsection_ctr = subsection.ctr;
71 auto offset_iv = section_offset + base_offset; 72 auto offset_iv = section_offset + base_offset;
72 for (std::size_t i = 0; i < section_ctr.size(); ++i) 73 for (std::size_t i = 0; i < section_ctr.size(); ++i)
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index ec1d54f27..5b414b0f0 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -133,9 +133,9 @@ public:
133 // Parsing function defines the conversion from raw file to NCA. If there are other steps 133 // Parsing function defines the conversion from raw file to NCA. If there are other steps
134 // besides creating the NCA from the file (e.g. NAX0 on SD Card), that should go in a custom 134 // besides creating the NCA from the file (e.g. NAX0 on SD Card), that should go in a custom
135 // parsing function. 135 // parsing function.
136 explicit RegisteredCache(VirtualDir dir, 136 explicit RegisteredCache(
137 ContentProviderParsingFunction parsing_function = 137 VirtualDir dir, ContentProviderParsingFunction parsing_function =
138 [](const VirtualFile& file, const NcaID& id) { return file; }); 138 [](const VirtualFile& file, const NcaID& id) { return file; });
139 ~RegisteredCache() override; 139 ~RegisteredCache() override;
140 140
141 void Refresh() override; 141 void Refresh() override;
diff --git a/src/core/file_sys/system_archive/mii_model.cpp b/src/core/file_sys/system_archive/mii_model.cpp
index 61bb67945..d65c7d234 100644
--- a/src/core/file_sys/system_archive/mii_model.cpp
+++ b/src/core/file_sys/system_archive/mii_model.cpp
@@ -27,18 +27,12 @@ VirtualDir MiiModel() {
27 auto out = std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{}, 27 auto out = std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{},
28 std::vector<VirtualDir>{}, "data"); 28 std::vector<VirtualDir>{}, "data");
29 29
30 out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_LOW_LINEAR.size()>>( 30 out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_LOW_LINEAR, "NXTextureLowLinear.dat"));
31 MiiModelData::TEXTURE_LOW_LINEAR, "NXTextureLowLinear.dat")); 31 out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_LOW_SRGB, "NXTextureLowSRGB.dat"));
32 out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_LOW_SRGB.size()>>( 32 out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_MID_LINEAR, "NXTextureMidLinear.dat"));
33 MiiModelData::TEXTURE_LOW_SRGB, "NXTextureLowSRGB.dat")); 33 out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_MID_SRGB, "NXTextureMidSRGB.dat"));
34 out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_MID_LINEAR.size()>>( 34 out->AddFile(MakeArrayFile(MiiModelData::SHAPE_HIGH, "ShapeHigh.dat"));
35 MiiModelData::TEXTURE_MID_LINEAR, "NXTextureMidLinear.dat")); 35 out->AddFile(MakeArrayFile(MiiModelData::SHAPE_MID, "ShapeMid.dat"));
36 out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_MID_SRGB.size()>>(
37 MiiModelData::TEXTURE_MID_SRGB, "NXTextureMidSRGB.dat"));
38 out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::SHAPE_HIGH.size()>>(
39 MiiModelData::SHAPE_HIGH, "ShapeHigh.dat"));
40 out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::SHAPE_MID.size()>>(
41 MiiModelData::SHAPE_MID, "ShapeMid.dat"));
42 36
43 return out; 37 return out;
44} 38}
diff --git a/src/core/file_sys/system_archive/ng_word.cpp b/src/core/file_sys/system_archive/ng_word.cpp
index f4443784d..100d3c5db 100644
--- a/src/core/file_sys/system_archive/ng_word.cpp
+++ b/src/core/file_sys/system_archive/ng_word.cpp
@@ -24,19 +24,18 @@ constexpr std::array<u8, 30> WORD_TXT{
24} // namespace NgWord1Data 24} // namespace NgWord1Data
25 25
26VirtualDir NgWord1() { 26VirtualDir NgWord1() {
27 std::vector<VirtualFile> files(NgWord1Data::NUMBER_WORD_TXT_FILES); 27 std::vector<VirtualFile> files;
28 files.reserve(NgWord1Data::NUMBER_WORD_TXT_FILES);
28 29
29 for (std::size_t i = 0; i < files.size(); ++i) { 30 for (std::size_t i = 0; i < files.size(); ++i) {
30 files[i] = std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>( 31 files.push_back(MakeArrayFile(NgWord1Data::WORD_TXT, fmt::format("{}.txt", i)));
31 NgWord1Data::WORD_TXT, fmt::format("{}.txt", i));
32 } 32 }
33 33
34 files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>( 34 files.push_back(MakeArrayFile(NgWord1Data::WORD_TXT, "common.txt"));
35 NgWord1Data::WORD_TXT, "common.txt")); 35 files.push_back(MakeArrayFile(NgWord1Data::VERSION_DAT, "version.dat"));
36 files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::VERSION_DAT.size()>>(
37 NgWord1Data::VERSION_DAT, "version.dat"));
38 36
39 return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data"); 37 return std::make_shared<VectorVfsDirectory>(std::move(files), std::vector<VirtualDir>{},
38 "data");
40} 39}
41 40
42namespace NgWord2Data { 41namespace NgWord2Data {
@@ -55,27 +54,22 @@ constexpr std::array<u8, 0x2C> AC_NX_DATA{
55} // namespace NgWord2Data 54} // namespace NgWord2Data
56 55
57VirtualDir NgWord2() { 56VirtualDir NgWord2() {
58 std::vector<VirtualFile> files(NgWord2Data::NUMBER_AC_NX_FILES * 3); 57 std::vector<VirtualFile> files;
58 files.reserve(NgWord2Data::NUMBER_AC_NX_FILES * 3);
59 59
60 for (std::size_t i = 0; i < NgWord2Data::NUMBER_AC_NX_FILES; ++i) { 60 for (std::size_t i = 0; i < NgWord2Data::NUMBER_AC_NX_FILES; ++i) {
61 files[3 * i] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>( 61 files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b1_nx", i)));
62 NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b1_nx", i)); 62 files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b2_nx", i)));
63 files[3 * i + 1] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>( 63 files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_not_b_nx", i)));
64 NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b2_nx", i));
65 files[3 * i + 2] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
66 NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_not_b_nx", i));
67 } 64 }
68 65
69 files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>( 66 files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, "ac_common_b1_nx"));
70 NgWord2Data::AC_NX_DATA, "ac_common_b1_nx")); 67 files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, "ac_common_b2_nx"));
71 files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>( 68 files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, "ac_common_not_b_nx"));
72 NgWord2Data::AC_NX_DATA, "ac_common_b2_nx")); 69 files.push_back(MakeArrayFile(NgWord2Data::VERSION_DAT, "version.dat"));
73 files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
74 NgWord2Data::AC_NX_DATA, "ac_common_not_b_nx"));
75 files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::VERSION_DAT.size()>>(
76 NgWord2Data::VERSION_DAT, "version.dat"));
77 70
78 return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data"); 71 return std::make_shared<VectorVfsDirectory>(std::move(files), std::vector<VirtualDir>{},
72 "data");
79} 73}
80 74
81} // namespace FileSys::SystemArchive 75} // namespace FileSys::SystemArchive
diff --git a/src/core/file_sys/system_archive/time_zone_binary.cpp b/src/core/file_sys/system_archive/time_zone_binary.cpp
index d1de63f20..8fd005012 100644
--- a/src/core/file_sys/system_archive/time_zone_binary.cpp
+++ b/src/core/file_sys/system_archive/time_zone_binary.cpp
@@ -654,12 +654,13 @@ static VirtualFile GenerateDefaultTimeZoneFile() {
654} 654}
655 655
656VirtualDir TimeZoneBinary() { 656VirtualDir TimeZoneBinary() {
657 const std::vector<VirtualDir> root_dirs{std::make_shared<VectorVfsDirectory>( 657 std::vector<VirtualDir> root_dirs{std::make_shared<VectorVfsDirectory>(
658 std::vector<VirtualFile>{GenerateDefaultTimeZoneFile()}, std::vector<VirtualDir>{}, 658 std::vector<VirtualFile>{GenerateDefaultTimeZoneFile()}, std::vector<VirtualDir>{},
659 "zoneinfo")}; 659 "zoneinfo")};
660 const std::vector<VirtualFile> root_files{ 660 std::vector<VirtualFile> root_files{MakeArrayFile(LOCATION_NAMES, "binaryList.txt")};
661 std::make_shared<ArrayVfsFile<LOCATION_NAMES.size()>>(LOCATION_NAMES, "binaryList.txt")}; 661
662 return std::make_shared<VectorVfsDirectory>(root_files, root_dirs, "data"); 662 return std::make_shared<VectorVfsDirectory>(std::move(root_files), std::move(root_dirs),
663 "data");
663} 664}
664 665
665} // namespace FileSys::SystemArchive 666} // namespace FileSys::SystemArchive
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h
index ac36cb2ee..95d3da2f2 100644
--- a/src/core/file_sys/vfs_vector.h
+++ b/src/core/file_sys/vfs_vector.h
@@ -4,7 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
7#include <cstring> 8#include <cstring>
9#include <memory>
10#include <string>
11#include <vector>
8#include "core/file_sys/vfs.h" 12#include "core/file_sys/vfs.h"
9 13
10namespace FileSys { 14namespace FileSys {
@@ -13,7 +17,8 @@ namespace FileSys {
13template <std::size_t size> 17template <std::size_t size>
14class ArrayVfsFile : public VfsFile { 18class ArrayVfsFile : public VfsFile {
15public: 19public:
16 ArrayVfsFile(std::array<u8, size> data, std::string name = "", VirtualDir parent = nullptr) 20 explicit ArrayVfsFile(const std::array<u8, size>& data, std::string name = "",
21 VirtualDir parent = nullptr)
17 : data(data), name(std::move(name)), parent(std::move(parent)) {} 22 : data(data), name(std::move(name)), parent(std::move(parent)) {}
18 23
19 std::string GetName() const override { 24 std::string GetName() const override {
@@ -61,6 +66,12 @@ private:
61 VirtualDir parent; 66 VirtualDir parent;
62}; 67};
63 68
69template <std::size_t Size, typename... Args>
70std::shared_ptr<ArrayVfsFile<Size>> MakeArrayFile(const std::array<u8, Size>& data,
71 Args&&... args) {
72 return std::make_shared<ArrayVfsFile<Size>>(data, std::forward<Args>(args)...);
73}
74
64// An implementation of VfsFile that is backed by a vector optionally supplied upon construction 75// An implementation of VfsFile that is backed by a vector optionally supplied upon construction
65class VectorVfsFile : public VfsFile { 76class VectorVfsFile : public VfsFile {
66public: 77public:
diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h
index 13aa14934..3e8780243 100644
--- a/src/core/frontend/emu_window.h
+++ b/src/core/frontend/emu_window.h
@@ -39,7 +39,7 @@ public:
39 39
40 class Scoped { 40 class Scoped {
41 public: 41 public:
42 explicit Scoped(GraphicsContext& context_) : context(context_) { 42 [[nodiscard]] explicit Scoped(GraphicsContext& context_) : context(context_) {
43 context.MakeCurrent(); 43 context.MakeCurrent();
44 } 44 }
45 ~Scoped() { 45 ~Scoped() {
@@ -52,7 +52,7 @@ public:
52 52
53 /// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value 53 /// Calls MakeCurrent on the context and calls DoneCurrent when the scope for the returned value
54 /// ends 54 /// ends
55 Scoped Acquire() { 55 [[nodiscard]] Scoped Acquire() {
56 return Scoped{*this}; 56 return Scoped{*this};
57 } 57 }
58}; 58};
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h
index 0dc6a4a43..1b503331f 100644
--- a/src/core/hle/ipc_helpers.h
+++ b/src/core/hle/ipc_helpers.h
@@ -229,6 +229,8 @@ inline void ResponseBuilder::Push(u32 value) {
229 229
230template <typename T> 230template <typename T>
231void ResponseBuilder::PushRaw(const T& value) { 231void ResponseBuilder::PushRaw(const T& value) {
232 static_assert(std::is_trivially_copyable_v<T>,
233 "It's undefined behavior to use memcpy with non-trivially copyable objects");
232 std::memcpy(cmdbuf + index, &value, sizeof(T)); 234 std::memcpy(cmdbuf + index, &value, sizeof(T));
233 index += (sizeof(T) + 3) / 4; // round up to word length 235 index += (sizeof(T) + 3) / 4; // round up to word length
234} 236}
@@ -384,6 +386,8 @@ inline s32 RequestParser::Pop() {
384 386
385template <typename T> 387template <typename T>
386void RequestParser::PopRaw(T& value) { 388void RequestParser::PopRaw(T& value) {
389 static_assert(std::is_trivially_copyable_v<T>,
390 "It's undefined behavior to use memcpy with non-trivially copyable objects");
387 std::memcpy(&value, cmdbuf + index, sizeof(T)); 391 std::memcpy(&value, cmdbuf + index, sizeof(T));
388 index += (sizeof(T) + 3) / 4; // round up to word length 392 index += (sizeof(T) + 3) / 4; // round up to word length
389} 393}
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index df0debe1b..b882eaa0f 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -81,7 +81,7 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32
81 do { 81 do {
82 current_value = monitor.ExclusiveRead32(current_core, address); 82 current_value = monitor.ExclusiveRead32(current_core, address);
83 83
84 if (current_value != value) { 84 if (current_value != static_cast<u32>(value)) {
85 return ERR_INVALID_STATE; 85 return ERR_INVALID_STATE;
86 } 86 }
87 current_value++; 87 current_value++;
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 9277b5d08..81f85643b 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -293,13 +293,15 @@ std::vector<u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const {
293 BufferDescriptorA()[buffer_index].Size()}; 293 BufferDescriptorA()[buffer_index].Size()};
294 294
295 if (is_buffer_a) { 295 if (is_buffer_a) {
296 ASSERT_OR_EXECUTE_MSG(BufferDescriptorA().size() > buffer_index, { return buffer; }, 296 ASSERT_OR_EXECUTE_MSG(
297 "BufferDescriptorA invalid buffer_index {}", buffer_index); 297 BufferDescriptorA().size() > buffer_index, { return buffer; },
298 "BufferDescriptorA invalid buffer_index {}", buffer_index);
298 buffer.resize(BufferDescriptorA()[buffer_index].Size()); 299 buffer.resize(BufferDescriptorA()[buffer_index].Size());
299 memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size()); 300 memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), buffer.data(), buffer.size());
300 } else { 301 } else {
301 ASSERT_OR_EXECUTE_MSG(BufferDescriptorX().size() > buffer_index, { return buffer; }, 302 ASSERT_OR_EXECUTE_MSG(
302 "BufferDescriptorX invalid buffer_index {}", buffer_index); 303 BufferDescriptorX().size() > buffer_index, { return buffer; },
304 "BufferDescriptorX invalid buffer_index {}", buffer_index);
303 buffer.resize(BufferDescriptorX()[buffer_index].Size()); 305 buffer.resize(BufferDescriptorX()[buffer_index].Size());
304 memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size()); 306 memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), buffer.data(), buffer.size());
305 } 307 }
@@ -324,16 +326,16 @@ std::size_t HLERequestContext::WriteBuffer(const void* buffer, std::size_t size,
324 } 326 }
325 327
326 if (is_buffer_b) { 328 if (is_buffer_b) {
327 ASSERT_OR_EXECUTE_MSG(BufferDescriptorB().size() > buffer_index && 329 ASSERT_OR_EXECUTE_MSG(
328 BufferDescriptorB()[buffer_index].Size() >= size, 330 BufferDescriptorB().size() > buffer_index &&
329 { return 0; }, "BufferDescriptorB is invalid, index={}, size={}", 331 BufferDescriptorB()[buffer_index].Size() >= size,
330 buffer_index, size); 332 { return 0; }, "BufferDescriptorB is invalid, index={}, size={}", buffer_index, size);
331 memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size); 333 memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size);
332 } else { 334 } else {
333 ASSERT_OR_EXECUTE_MSG(BufferDescriptorC().size() > buffer_index && 335 ASSERT_OR_EXECUTE_MSG(
334 BufferDescriptorC()[buffer_index].Size() >= size, 336 BufferDescriptorC().size() > buffer_index &&
335 { return 0; }, "BufferDescriptorC is invalid, index={}, size={}", 337 BufferDescriptorC()[buffer_index].Size() >= size,
336 buffer_index, size); 338 { return 0; }, "BufferDescriptorC is invalid, index={}, size={}", buffer_index, size);
337 memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size); 339 memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size);
338 } 340 }
339 341
@@ -344,12 +346,14 @@ std::size_t HLERequestContext::GetReadBufferSize(std::size_t buffer_index) const
344 const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && 346 const bool is_buffer_a{BufferDescriptorA().size() > buffer_index &&
345 BufferDescriptorA()[buffer_index].Size()}; 347 BufferDescriptorA()[buffer_index].Size()};
346 if (is_buffer_a) { 348 if (is_buffer_a) {
347 ASSERT_OR_EXECUTE_MSG(BufferDescriptorA().size() > buffer_index, { return 0; }, 349 ASSERT_OR_EXECUTE_MSG(
348 "BufferDescriptorA invalid buffer_index {}", buffer_index); 350 BufferDescriptorA().size() > buffer_index, { return 0; },
351 "BufferDescriptorA invalid buffer_index {}", buffer_index);
349 return BufferDescriptorA()[buffer_index].Size(); 352 return BufferDescriptorA()[buffer_index].Size();
350 } else { 353 } else {
351 ASSERT_OR_EXECUTE_MSG(BufferDescriptorX().size() > buffer_index, { return 0; }, 354 ASSERT_OR_EXECUTE_MSG(
352 "BufferDescriptorX invalid buffer_index {}", buffer_index); 355 BufferDescriptorX().size() > buffer_index, { return 0; },
356 "BufferDescriptorX invalid buffer_index {}", buffer_index);
353 return BufferDescriptorX()[buffer_index].Size(); 357 return BufferDescriptorX()[buffer_index].Size();
354 } 358 }
355} 359}
@@ -358,12 +362,14 @@ std::size_t HLERequestContext::GetWriteBufferSize(std::size_t buffer_index) cons
358 const bool is_buffer_b{BufferDescriptorB().size() > buffer_index && 362 const bool is_buffer_b{BufferDescriptorB().size() > buffer_index &&
359 BufferDescriptorB()[buffer_index].Size()}; 363 BufferDescriptorB()[buffer_index].Size()};
360 if (is_buffer_b) { 364 if (is_buffer_b) {
361 ASSERT_OR_EXECUTE_MSG(BufferDescriptorB().size() > buffer_index, { return 0; }, 365 ASSERT_OR_EXECUTE_MSG(
362 "BufferDescriptorB invalid buffer_index {}", buffer_index); 366 BufferDescriptorB().size() > buffer_index, { return 0; },
367 "BufferDescriptorB invalid buffer_index {}", buffer_index);
363 return BufferDescriptorB()[buffer_index].Size(); 368 return BufferDescriptorB()[buffer_index].Size();
364 } else { 369 } else {
365 ASSERT_OR_EXECUTE_MSG(BufferDescriptorC().size() > buffer_index, { return 0; }, 370 ASSERT_OR_EXECUTE_MSG(
366 "BufferDescriptorC invalid buffer_index {}", buffer_index); 371 BufferDescriptorC().size() > buffer_index, { return 0; },
372 "BufferDescriptorC invalid buffer_index {}", buffer_index);
367 return BufferDescriptorC()[buffer_index].Size(); 373 return BufferDescriptorC()[buffer_index].Size();
368 } 374 }
369 return 0; 375 return 0;
diff --git a/src/core/hle/kernel/memory/page_table.cpp b/src/core/hle/kernel/memory/page_table.cpp
index 5d6aac00f..a3fadb533 100644
--- a/src/core/hle/kernel/memory/page_table.cpp
+++ b/src/core/hle/kernel/memory/page_table.cpp
@@ -604,7 +604,6 @@ ResultCode PageTable::MapPages(VAddr addr, const PageLinkedList& page_linked_lis
604 if (const auto result{ 604 if (const auto result{
605 Operate(cur_addr, node.GetNumPages(), perm, OperationType::Map, node.GetAddress())}; 605 Operate(cur_addr, node.GetNumPages(), perm, OperationType::Map, node.GetAddress())};
606 result.IsError()) { 606 result.IsError()) {
607 const MemoryInfo info{block_manager->FindBlock(cur_addr).GetMemoryInfo()};
608 const std::size_t num_pages{(addr - cur_addr) / PageSize}; 607 const std::size_t num_pages{(addr - cur_addr) / PageSize};
609 608
610 ASSERT( 609 ASSERT(
@@ -852,11 +851,12 @@ ResultCode PageTable::LockForDeviceAddressSpace(VAddr addr, std::size_t size) {
852 return result; 851 return result;
853 } 852 }
854 853
855 block_manager->UpdateLock(addr, size / PageSize, 854 block_manager->UpdateLock(
856 [](MemoryBlockManager::iterator block, MemoryPermission perm) { 855 addr, size / PageSize,
857 block->ShareToDevice(perm); 856 [](MemoryBlockManager::iterator block, MemoryPermission perm) {
858 }, 857 block->ShareToDevice(perm);
859 perm); 858 },
859 perm);
860 860
861 return RESULT_SUCCESS; 861 return RESULT_SUCCESS;
862} 862}
@@ -874,11 +874,12 @@ ResultCode PageTable::UnlockForDeviceAddressSpace(VAddr addr, std::size_t size)
874 return result; 874 return result;
875 } 875 }
876 876
877 block_manager->UpdateLock(addr, size / PageSize, 877 block_manager->UpdateLock(
878 [](MemoryBlockManager::iterator block, MemoryPermission perm) { 878 addr, size / PageSize,
879 block->UnshareToDevice(perm); 879 [](MemoryBlockManager::iterator block, MemoryPermission perm) {
880 }, 880 block->UnshareToDevice(perm);
881 perm); 881 },
882 perm);
882 883
883 return RESULT_SUCCESS; 884 return RESULT_SUCCESS;
884} 885}
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index f93e5e4b0..a4b234424 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -131,7 +131,8 @@ u32 GlobalScheduler::SelectThreads() {
131 u32 cores_needing_context_switch{}; 131 u32 cores_needing_context_switch{};
132 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { 132 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
133 Scheduler& sched = kernel.Scheduler(core); 133 Scheduler& sched = kernel.Scheduler(core);
134 ASSERT(top_threads[core] == nullptr || top_threads[core]->GetProcessorID() == core); 134 ASSERT(top_threads[core] == nullptr ||
135 static_cast<u32>(top_threads[core]->GetProcessorID()) == core);
135 if (update_thread(top_threads[core], sched)) { 136 if (update_thread(top_threads[core], sched)) {
136 cores_needing_context_switch |= (1ul << core); 137 cores_needing_context_switch |= (1ul << core);
137 } 138 }
@@ -663,32 +664,26 @@ void Scheduler::Reload() {
663} 664}
664 665
665void Scheduler::SwitchContextStep2() { 666void Scheduler::SwitchContextStep2() {
666 Thread* previous_thread = current_thread_prev.get();
667 Thread* new_thread = selected_thread.get();
668
669 // Load context of new thread 667 // Load context of new thread
670 Process* const previous_process = 668 if (selected_thread) {
671 previous_thread != nullptr ? previous_thread->GetOwnerProcess() : nullptr; 669 ASSERT_MSG(selected_thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable,
672
673 if (new_thread) {
674 ASSERT_MSG(new_thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable,
675 "Thread must be runnable."); 670 "Thread must be runnable.");
676 671
677 // Cancel any outstanding wakeup events for this thread 672 // Cancel any outstanding wakeup events for this thread
678 new_thread->SetIsRunning(true); 673 selected_thread->SetIsRunning(true);
679 new_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); 674 selected_thread->last_running_ticks = system.CoreTiming().GetCPUTicks();
680 new_thread->SetWasRunning(false); 675 selected_thread->SetWasRunning(false);
681 676
682 auto* const thread_owner_process = current_thread->GetOwnerProcess(); 677 auto* const thread_owner_process = current_thread->GetOwnerProcess();
683 if (thread_owner_process != nullptr) { 678 if (thread_owner_process != nullptr) {
684 system.Kernel().MakeCurrentProcess(thread_owner_process); 679 system.Kernel().MakeCurrentProcess(thread_owner_process);
685 } 680 }
686 if (!new_thread->IsHLEThread()) { 681 if (!selected_thread->IsHLEThread()) {
687 Core::ARM_Interface& cpu_core = new_thread->ArmInterface(); 682 Core::ARM_Interface& cpu_core = selected_thread->ArmInterface();
688 cpu_core.LoadContext(new_thread->GetContext32()); 683 cpu_core.LoadContext(selected_thread->GetContext32());
689 cpu_core.LoadContext(new_thread->GetContext64()); 684 cpu_core.LoadContext(selected_thread->GetContext64());
690 cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); 685 cpu_core.SetTlsAddress(selected_thread->GetTLSAddress());
691 cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); 686 cpu_core.SetTPIDR_EL0(selected_thread->GetTPIDR_EL0());
692 cpu_core.ChangeProcessorID(this->core_id); 687 cpu_core.ChangeProcessorID(this->core_id);
693 cpu_core.ClearExclusiveState(); 688 cpu_core.ClearExclusiveState();
694 } 689 }
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
index b3b4b5169..36e3c26fb 100644
--- a/src/core/hle/kernel/scheduler.h
+++ b/src/core/hle/kernel/scheduler.h
@@ -289,7 +289,7 @@ private:
289 289
290class SchedulerLock { 290class SchedulerLock {
291public: 291public:
292 explicit SchedulerLock(KernelCore& kernel); 292 [[nodiscard]] explicit SchedulerLock(KernelCore& kernel);
293 ~SchedulerLock(); 293 ~SchedulerLock();
294 294
295protected: 295protected:
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 55a1edf1a..7d92b25a3 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -378,7 +378,11 @@ void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext&
378} 378}
379 379
380void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { 380void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) {
381 LOG_WARNING(Service_AM, "(STUBBED) called"); 381 IPC::RequestParser rp{ctx};
382 const auto permission = rp.PopEnum<ScreenshotPermission>();
383 LOG_DEBUG(Service_AM, "called, permission={}", permission);
384
385 screenshot_permission = permission;
382 386
383 IPC::ResponseBuilder rb{ctx, 2}; 387 IPC::ResponseBuilder rb{ctx, 2};
384 rb.Push(RESULT_SUCCESS); 388 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 6cfb11b48..6e69796ec 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -149,6 +149,12 @@ private:
149 void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx); 149 void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx);
150 void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx); 150 void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx);
151 151
152 enum class ScreenshotPermission : u32 {
153 Inherit = 0,
154 Enable = 1,
155 Disable = 2,
156 };
157
152 Core::System& system; 158 Core::System& system;
153 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 159 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
154 Kernel::EventPair launchable_event; 160 Kernel::EventPair launchable_event;
@@ -157,6 +163,7 @@ private:
157 u32 idle_time_detection_extension = 0; 163 u32 idle_time_detection_extension = 0;
158 u64 num_fatal_sections_entered = 0; 164 u64 num_fatal_sections_entered = 0;
159 bool is_auto_sleep_disabled = false; 165 bool is_auto_sleep_disabled = false;
166 ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit;
160}; 167};
161 168
162class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> { 169class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp
index 9f30e167d..4157fbf39 100644
--- a/src/core/hle/service/am/applets/web_browser.cpp
+++ b/src/core/hle/service/am/applets/web_browser.cpp
@@ -551,7 +551,8 @@ void WebBrowser::ExecuteShop() {
551} 551}
552 552
553void WebBrowser::ExecuteOffline() { 553void WebBrowser::ExecuteOffline() {
554 frontend.OpenPageLocal(filename, [this] { UnpackRomFS(); }, [this] { Finalize(); }); 554 frontend.OpenPageLocal(
555 filename, [this] { UnpackRomFS(); }, [this] { Finalize(); });
555} 556}
556 557
557} // namespace Service::AM::Applets 558} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index dd80dd1dc..9b4910e53 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -206,7 +206,7 @@ private:
206 AudioCore::StreamPtr stream; 206 AudioCore::StreamPtr stream;
207 std::string device_name; 207 std::string device_name;
208 208
209 [[maybe_unused]] AudoutParams audio_params {}; 209 [[maybe_unused]] AudoutParams audio_params{};
210 210
211 /// This is the event handle used to check if the audio buffer was released 211 /// This is the event handle used to check if the audio buffer was released
212 Kernel::EventPair buffer_event; 212 Kernel::EventPair buffer_event;
diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp
index d29e78d7e..51c2ba964 100644
--- a/src/core/hle/service/bcat/backend/boxcat.cpp
+++ b/src/core/hle/service/bcat/backend/boxcat.cpp
@@ -365,8 +365,7 @@ bool Boxcat::Synchronize(TitleIDVersion title, ProgressServiceBackend& progress)
365 365
366 std::thread([this, title, &progress] { 366 std::thread([this, title, &progress] {
367 SynchronizeInternal(applet_manager, dir_getter, title, progress); 367 SynchronizeInternal(applet_manager, dir_getter, title, progress);
368 }) 368 }).detach();
369 .detach();
370 369
371 return true; 370 return true;
372} 371}
@@ -377,8 +376,7 @@ bool Boxcat::SynchronizeDirectory(TitleIDVersion title, std::string name,
377 376
378 std::thread([this, title, name, &progress] { 377 std::thread([this, title, name, &progress] {
379 SynchronizeInternal(applet_manager, dir_getter, title, progress, name); 378 SynchronizeInternal(applet_manager, dir_getter, title, progress, name);
380 }) 379 }).detach();
381 .detach();
382 380
383 return true; 381 return true;
384} 382}
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index caca80dde..637b310d7 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -24,13 +24,13 @@ BufferQueue::~BufferQueue() = default;
24void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) { 24void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) {
25 LOG_WARNING(Service, "Adding graphics buffer {}", slot); 25 LOG_WARNING(Service, "Adding graphics buffer {}", slot);
26 26
27 Buffer buffer{};
28 buffer.slot = slot;
29 buffer.igbp_buffer = igbp_buffer;
30 buffer.status = Buffer::Status::Free;
31 free_buffers.push_back(slot); 27 free_buffers.push_back(slot);
28 queue.push_back({
29 .slot = slot,
30 .status = Buffer::Status::Free,
31 .igbp_buffer = igbp_buffer,
32 });
32 33
33 queue.emplace_back(buffer);
34 buffer_wait_event.writable->Signal(); 34 buffer_wait_event.writable->Signal();
35} 35}
36 36
@@ -38,7 +38,7 @@ std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::Dequeue
38 u32 height) { 38 u32 height) {
39 39
40 if (free_buffers.empty()) { 40 if (free_buffers.empty()) {
41 return {}; 41 return std::nullopt;
42 } 42 }
43 43
44 auto f_itr = free_buffers.begin(); 44 auto f_itr = free_buffers.begin();
@@ -69,7 +69,7 @@ std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::Dequeue
69 } 69 }
70 70
71 if (itr == queue.end()) { 71 if (itr == queue.end()) {
72 return {}; 72 return std::nullopt;
73 } 73 }
74 74
75 itr->status = Buffer::Status::Dequeued; 75 itr->status = Buffer::Status::Dequeued;
@@ -103,14 +103,15 @@ std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::Ac
103 auto itr = queue.end(); 103 auto itr = queue.end();
104 // Iterate to find a queued buffer matching the requested slot. 104 // Iterate to find a queued buffer matching the requested slot.
105 while (itr == queue.end() && !queue_sequence.empty()) { 105 while (itr == queue.end() && !queue_sequence.empty()) {
106 u32 slot = queue_sequence.front(); 106 const u32 slot = queue_sequence.front();
107 itr = std::find_if(queue.begin(), queue.end(), [&slot](const Buffer& buffer) { 107 itr = std::find_if(queue.begin(), queue.end(), [&slot](const Buffer& buffer) {
108 return buffer.status == Buffer::Status::Queued && buffer.slot == slot; 108 return buffer.status == Buffer::Status::Queued && buffer.slot == slot;
109 }); 109 });
110 queue_sequence.pop_front(); 110 queue_sequence.pop_front();
111 } 111 }
112 if (itr == queue.end()) 112 if (itr == queue.end()) {
113 return {}; 113 return std::nullopt;
114 }
114 itr->status = Buffer::Status::Acquired; 115 itr->status = Buffer::Status::Acquired;
115 return *itr; 116 return *itr;
116} 117}
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index ff85cbba6..1ebe949c0 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -86,11 +86,13 @@ public:
86 86
87 [[nodiscard]] s64 GetNextTicks() const; 87 [[nodiscard]] s64 GetNextTicks() const;
88 88
89 [[nodiscard]] std::unique_lock<std::mutex> Lock() const { return std::unique_lock{*guard}; } 89 [[nodiscard]] std::unique_lock<std::mutex> Lock() const {
90 return std::unique_lock{*guard};
91 }
90 92
91 private : 93private:
92 /// Finds the display identified by the specified ID. 94 /// Finds the display identified by the specified ID.
93 [[nodiscard]] VI::Display* FindDisplay(u64 display_id); 95 [[nodiscard]] VI::Display* FindDisplay(u64 display_id);
94 96
95 /// Finds the display identified by the specified ID. 97 /// Finds the display identified by the specified ID.
96 [[nodiscard]] const VI::Display* FindDisplay(u64 display_id) const; 98 [[nodiscard]] const VI::Display* FindDisplay(u64 display_id) const;
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index b526a94fe..aabf166b7 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -57,7 +57,7 @@ public:
57 ResultVal<std::shared_ptr<Kernel::ClientPort>> GetServicePort(const std::string& name); 57 ResultVal<std::shared_ptr<Kernel::ClientPort>> GetServicePort(const std::string& name);
58 ResultVal<std::shared_ptr<Kernel::ClientSession>> ConnectToService(const std::string& name); 58 ResultVal<std::shared_ptr<Kernel::ClientSession>> ConnectToService(const std::string& name);
59 59
60 template <Common::IsBaseOf<Kernel::SessionRequestHandler> T> 60 template <Common::DerivedFrom<Kernel::SessionRequestHandler> T>
61 std::shared_ptr<T> GetService(const std::string& service_name) const { 61 std::shared_ptr<T> GetService(const std::string& service_name) const {
62 auto service = registered_services.find(service_name); 62 auto service = registered_services.find(service_name);
63 if (service == registered_services.end()) { 63 if (service == registered_services.end()) {
diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp
index c070d6e97..320672add 100644
--- a/src/core/hle/service/time/time_zone_content_manager.cpp
+++ b/src/core/hle/service/time/time_zone_content_manager.cpp
@@ -73,10 +73,8 @@ TimeZoneContentManager::TimeZoneContentManager(TimeManager& time_manager, Core::
73 73
74 std::string location_name; 74 std::string location_name;
75 const auto timezone_setting = Settings::GetTimeZoneString(); 75 const auto timezone_setting = Settings::GetTimeZoneString();
76 if (timezone_setting == "auto") { 76 if (timezone_setting == "auto" || timezone_setting == "default") {
77 location_name = Common::TimeZone::GetDefaultTimeZone(); 77 location_name = Common::TimeZone::GetDefaultTimeZone();
78 } else if (timezone_setting == "default") {
79 location_name = location_name;
80 } else { 78 } else {
81 location_name = timezone_setting; 79 location_name = timezone_setting;
82 } 80 }
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index b8f8f1448..7c48e55e1 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -25,7 +25,7 @@ namespace Loader {
25 25
26namespace { 26namespace {
27 27
28template <Common::IsBaseOf<AppLoader> T> 28template <Common::DerivedFrom<AppLoader> T>
29std::optional<FileType> IdentifyFileLoader(FileSys::VirtualFile file) { 29std::optional<FileType> IdentifyFileLoader(FileSys::VirtualFile file) {
30 const auto file_type = T::IdentifyType(file); 30 const auto file_type = T::IdentifyType(file);
31 if (file_type != FileType::Error) { 31 if (file_type != FileType::Error) {
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 2c5588933..86d17c6cb 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -704,7 +704,7 @@ struct Memory::Impl {
704 u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; 704 u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
705 if (page_pointer != nullptr) { 705 if (page_pointer != nullptr) {
706 // NOTE: Avoid adding any extra logic to this fast-path block 706 // NOTE: Avoid adding any extra logic to this fast-path block
707 T volatile* pointer = reinterpret_cast<T volatile*>(&page_pointer[vaddr]); 707 auto* pointer = reinterpret_cast<volatile T*>(&page_pointer[vaddr]);
708 return Common::AtomicCompareAndSwap(pointer, data, expected); 708 return Common::AtomicCompareAndSwap(pointer, data, expected);
709 } 709 }
710 710
@@ -720,9 +720,8 @@ struct Memory::Impl {
720 case Common::PageType::RasterizerCachedMemory: { 720 case Common::PageType::RasterizerCachedMemory: {
721 u8* host_ptr{GetPointerFromRasterizerCachedMemory(vaddr)}; 721 u8* host_ptr{GetPointerFromRasterizerCachedMemory(vaddr)};
722 system.GPU().InvalidateRegion(vaddr, sizeof(T)); 722 system.GPU().InvalidateRegion(vaddr, sizeof(T));
723 T volatile* pointer = reinterpret_cast<T volatile*>(&host_ptr); 723 auto* pointer = reinterpret_cast<volatile T*>(&host_ptr);
724 return Common::AtomicCompareAndSwap(pointer, data, expected); 724 return Common::AtomicCompareAndSwap(pointer, data, expected);
725 break;
726 } 725 }
727 default: 726 default:
728 UNREACHABLE(); 727 UNREACHABLE();
@@ -734,7 +733,7 @@ struct Memory::Impl {
734 u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; 733 u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
735 if (page_pointer != nullptr) { 734 if (page_pointer != nullptr) {
736 // NOTE: Avoid adding any extra logic to this fast-path block 735 // NOTE: Avoid adding any extra logic to this fast-path block
737 u64 volatile* pointer = reinterpret_cast<u64 volatile*>(&page_pointer[vaddr]); 736 auto* pointer = reinterpret_cast<volatile u64*>(&page_pointer[vaddr]);
738 return Common::AtomicCompareAndSwap(pointer, data, expected); 737 return Common::AtomicCompareAndSwap(pointer, data, expected);
739 } 738 }
740 739
@@ -750,9 +749,8 @@ struct Memory::Impl {
750 case Common::PageType::RasterizerCachedMemory: { 749 case Common::PageType::RasterizerCachedMemory: {
751 u8* host_ptr{GetPointerFromRasterizerCachedMemory(vaddr)}; 750 u8* host_ptr{GetPointerFromRasterizerCachedMemory(vaddr)};
752 system.GPU().InvalidateRegion(vaddr, sizeof(u128)); 751 system.GPU().InvalidateRegion(vaddr, sizeof(u128));
753 u64 volatile* pointer = reinterpret_cast<u64 volatile*>(&host_ptr); 752 auto* pointer = reinterpret_cast<volatile u64*>(&host_ptr);
754 return Common::AtomicCompareAndSwap(pointer, data, expected); 753 return Common::AtomicCompareAndSwap(pointer, data, expected);
755 break;
756 } 754 }
757 default: 755 default:
758 UNREACHABLE(); 756 UNREACHABLE();
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index eeebdf02e..e503118dd 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -42,7 +42,7 @@ u64 StandardVmCallbacks::HidKeysDown() {
42 if (applet_resource == nullptr) { 42 if (applet_resource == nullptr) {
43 LOG_WARNING(CheatEngine, 43 LOG_WARNING(CheatEngine,
44 "Attempted to read input state, but applet resource is not initialized!"); 44 "Attempted to read input state, but applet resource is not initialized!");
45 return false; 45 return 0;
46 } 46 }
47 47
48 const auto press_state = 48 const auto press_state =
@@ -199,17 +199,29 @@ void CheatEngine::Initialize() {
199 metadata.title_id = system.CurrentProcess()->GetTitleID(); 199 metadata.title_id = system.CurrentProcess()->GetTitleID();
200 200
201 const auto& page_table = system.CurrentProcess()->PageTable(); 201 const auto& page_table = system.CurrentProcess()->PageTable();
202 metadata.heap_extents = {page_table.GetHeapRegionStart(), page_table.GetHeapRegionSize()}; 202 metadata.heap_extents = {
203 metadata.address_space_extents = {page_table.GetAddressSpaceStart(), 203 .base = page_table.GetHeapRegionStart(),
204 page_table.GetAddressSpaceSize()}; 204 .size = page_table.GetHeapRegionSize(),
205 metadata.alias_extents = {page_table.GetAliasCodeRegionStart(), 205 };
206 page_table.GetAliasCodeRegionSize()}; 206
207 metadata.address_space_extents = {
208 .base = page_table.GetAddressSpaceStart(),
209 .size = page_table.GetAddressSpaceSize(),
210 };
211
212 metadata.alias_extents = {
213 .base = page_table.GetAliasCodeRegionStart(),
214 .size = page_table.GetAliasCodeRegionSize(),
215 };
207 216
208 is_pending_reload.exchange(true); 217 is_pending_reload.exchange(true);
209} 218}
210 219
211void CheatEngine::SetMainMemoryParameters(VAddr main_region_begin, u64 main_region_size) { 220void CheatEngine::SetMainMemoryParameters(VAddr main_region_begin, u64 main_region_size) {
212 metadata.main_nso_extents = {main_region_begin, main_region_size}; 221 metadata.main_nso_extents = {
222 .base = main_region_begin,
223 .size = main_region_size,
224 };
213} 225}
214 226
215void CheatEngine::Reload(std::vector<CheatEntry> cheats) { 227void CheatEngine::Reload(std::vector<CheatEntry> cheats) {
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp
index 2003e096f..5c674a099 100644
--- a/src/core/tools/freezer.cpp
+++ b/src/core/tools/freezer.cpp
@@ -107,28 +107,21 @@ void Freezer::Unfreeze(VAddr address) {
107 107
108 LOG_DEBUG(Common_Memory, "Unfreezing memory for address={:016X}", address); 108 LOG_DEBUG(Common_Memory, "Unfreezing memory for address={:016X}", address);
109 109
110 entries.erase( 110 std::erase_if(entries, [address](const Entry& entry) { return entry.address == address; });
111 std::remove_if(entries.begin(), entries.end(),
112 [&address](const Entry& entry) { return entry.address == address; }),
113 entries.end());
114} 111}
115 112
116bool Freezer::IsFrozen(VAddr address) const { 113bool Freezer::IsFrozen(VAddr address) const {
117 std::lock_guard lock{entries_mutex}; 114 std::lock_guard lock{entries_mutex};
118 115
119 return std::find_if(entries.begin(), entries.end(), [&address](const Entry& entry) { 116 return FindEntry(address) != entries.cend();
120 return entry.address == address;
121 }) != entries.end();
122} 117}
123 118
124void Freezer::SetFrozenValue(VAddr address, u64 value) { 119void Freezer::SetFrozenValue(VAddr address, u64 value) {
125 std::lock_guard lock{entries_mutex}; 120 std::lock_guard lock{entries_mutex};
126 121
127 const auto iter = std::find_if(entries.begin(), entries.end(), [&address](const Entry& entry) { 122 const auto iter = FindEntry(address);
128 return entry.address == address;
129 });
130 123
131 if (iter == entries.end()) { 124 if (iter == entries.cend()) {
132 LOG_ERROR(Common_Memory, 125 LOG_ERROR(Common_Memory,
133 "Tried to set freeze value for address={:016X} that is not frozen!", address); 126 "Tried to set freeze value for address={:016X} that is not frozen!", address);
134 return; 127 return;
@@ -143,11 +136,9 @@ void Freezer::SetFrozenValue(VAddr address, u64 value) {
143std::optional<Freezer::Entry> Freezer::GetEntry(VAddr address) const { 136std::optional<Freezer::Entry> Freezer::GetEntry(VAddr address) const {
144 std::lock_guard lock{entries_mutex}; 137 std::lock_guard lock{entries_mutex};
145 138
146 const auto iter = std::find_if(entries.begin(), entries.end(), [&address](const Entry& entry) { 139 const auto iter = FindEntry(address);
147 return entry.address == address;
148 });
149 140
150 if (iter == entries.end()) { 141 if (iter == entries.cend()) {
151 return std::nullopt; 142 return std::nullopt;
152 } 143 }
153 144
@@ -160,6 +151,16 @@ std::vector<Freezer::Entry> Freezer::GetEntries() const {
160 return entries; 151 return entries;
161} 152}
162 153
154Freezer::Entries::iterator Freezer::FindEntry(VAddr address) {
155 return std::find_if(entries.begin(), entries.end(),
156 [address](const Entry& entry) { return entry.address == address; });
157}
158
159Freezer::Entries::const_iterator Freezer::FindEntry(VAddr address) const {
160 return std::find_if(entries.begin(), entries.end(),
161 [address](const Entry& entry) { return entry.address == address; });
162}
163
163void Freezer::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late) { 164void Freezer::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late) {
164 if (!IsActive()) { 165 if (!IsActive()) {
165 LOG_DEBUG(Common_Memory, "Memory freezer has been deactivated, ending callback events."); 166 LOG_DEBUG(Common_Memory, "Memory freezer has been deactivated, ending callback events.");
diff --git a/src/core/tools/freezer.h b/src/core/tools/freezer.h
index 2b2326bc4..0fdb701a7 100644
--- a/src/core/tools/freezer.h
+++ b/src/core/tools/freezer.h
@@ -73,13 +73,18 @@ public:
73 std::vector<Entry> GetEntries() const; 73 std::vector<Entry> GetEntries() const;
74 74
75private: 75private:
76 using Entries = std::vector<Entry>;
77
78 Entries::iterator FindEntry(VAddr address);
79 Entries::const_iterator FindEntry(VAddr address) const;
80
76 void FrameCallback(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); 81 void FrameCallback(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
77 void FillEntryReads(); 82 void FillEntryReads();
78 83
79 std::atomic_bool active{false}; 84 std::atomic_bool active{false};
80 85
81 mutable std::mutex entries_mutex; 86 mutable std::mutex entries_mutex;
82 std::vector<Entry> entries; 87 Entries entries;
83 88
84 std::shared_ptr<Core::Timing::EventType> event; 89 std::shared_ptr<Core::Timing::EventType> event;
85 Core::Timing::CoreTiming& core_timing; 90 Core::Timing::CoreTiming& core_timing;
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp
index f45983f3f..b346fdf8e 100644
--- a/src/input_common/gcadapter/gc_poller.cpp
+++ b/src/input_common/gcadapter/gc_poller.cpp
@@ -148,19 +148,17 @@ void GCButtonFactory::EndConfiguration() {
148 148
149class GCAnalog final : public Input::AnalogDevice { 149class GCAnalog final : public Input::AnalogDevice {
150public: 150public:
151 GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter) 151 GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter,
152 float range_)
152 : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter), 153 : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter),
153 origin_value_x(adapter->GetOriginValue(port_, axis_x_)), 154 origin_value_x(adapter->GetOriginValue(port_, axis_x_)),
154 origin_value_y(adapter->GetOriginValue(port_, axis_y_)) {} 155 origin_value_y(adapter->GetOriginValue(port_, axis_y_)), range(range_) {}
155 156
156 float GetAxis(int axis) const { 157 float GetAxis(int axis) const {
157 if (gcadapter->DeviceConnected(port)) { 158 if (gcadapter->DeviceConnected(port)) {
158 std::lock_guard lock{mutex}; 159 std::lock_guard lock{mutex};
159 const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y; 160 const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y;
160 // division is not by a perfect 128 to account for some variance in center location 161 return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / (100.0f * range);
161 // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range
162 // [20-230]
163 return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / 95.0f;
164 } 162 }
165 return 0.0f; 163 return 0.0f;
166 } 164 }
@@ -215,6 +213,7 @@ private:
215 GCAdapter::Adapter* gcadapter; 213 GCAdapter::Adapter* gcadapter;
216 const float origin_value_x; 214 const float origin_value_x;
217 const float origin_value_y; 215 const float origin_value_y;
216 const float range;
218 mutable std::mutex mutex; 217 mutable std::mutex mutex;
219}; 218};
220 219
@@ -234,8 +233,9 @@ std::unique_ptr<Input::AnalogDevice> GCAnalogFactory::Create(const Common::Param
234 const int axis_x = params.Get("axis_x", 0); 233 const int axis_x = params.Get("axis_x", 0);
235 const int axis_y = params.Get("axis_y", 1); 234 const int axis_y = params.Get("axis_y", 1);
236 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f); 235 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f);
236 const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
237 237
238 return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get()); 238 return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get(), range);
239} 239}
240 240
241void GCAnalogFactory::BeginConfiguration() { 241void GCAnalogFactory::BeginConfiguration() {
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 675b477fa..d76c279d3 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -66,14 +66,14 @@ public:
66 state.axes.insert_or_assign(axis, value); 66 state.axes.insert_or_assign(axis, value);
67 } 67 }
68 68
69 float GetAxis(int axis) const { 69 float GetAxis(int axis, float range) const {
70 std::lock_guard lock{mutex}; 70 std::lock_guard lock{mutex};
71 return state.axes.at(axis) / 32767.0f; 71 return state.axes.at(axis) / (32767.0f * range);
72 } 72 }
73 73
74 std::tuple<float, float> GetAnalog(int axis_x, int axis_y) const { 74 std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range) const {
75 float x = GetAxis(axis_x); 75 float x = GetAxis(axis_x, range);
76 float y = GetAxis(axis_y); 76 float y = GetAxis(axis_y, range);
77 y = -y; // 3DS uses an y-axis inverse from SDL 77 y = -y; // 3DS uses an y-axis inverse from SDL
78 78
79 // Make sure the coordinates are in the unit circle, 79 // Make sure the coordinates are in the unit circle,
@@ -313,7 +313,7 @@ public:
313 trigger_if_greater(trigger_if_greater_) {} 313 trigger_if_greater(trigger_if_greater_) {}
314 314
315 bool GetStatus() const override { 315 bool GetStatus() const override {
316 const float axis_value = joystick->GetAxis(axis); 316 const float axis_value = joystick->GetAxis(axis, 1.0f);
317 if (trigger_if_greater) { 317 if (trigger_if_greater) {
318 return axis_value > threshold; 318 return axis_value > threshold;
319 } 319 }
@@ -329,11 +329,13 @@ private:
329 329
330class SDLAnalog final : public Input::AnalogDevice { 330class SDLAnalog final : public Input::AnalogDevice {
331public: 331public:
332 SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_) 332 SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_,
333 : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_) {} 333 float range_)
334 : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_),
335 range(range_) {}
334 336
335 std::tuple<float, float> GetStatus() const override { 337 std::tuple<float, float> GetStatus() const override {
336 const auto [x, y] = joystick->GetAnalog(axis_x, axis_y); 338 const auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range);
337 const float r = std::sqrt((x * x) + (y * y)); 339 const float r = std::sqrt((x * x) + (y * y));
338 if (r > deadzone) { 340 if (r > deadzone) {
339 return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone), 341 return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone),
@@ -363,6 +365,7 @@ private:
363 const int axis_x; 365 const int axis_x;
364 const int axis_y; 366 const int axis_y;
365 const float deadzone; 367 const float deadzone;
368 const float range;
366}; 369};
367 370
368/// A button device factory that creates button devices from SDL joystick 371/// A button device factory that creates button devices from SDL joystick
@@ -458,13 +461,13 @@ public:
458 const int axis_x = params.Get("axis_x", 0); 461 const int axis_x = params.Get("axis_x", 0);
459 const int axis_y = params.Get("axis_y", 1); 462 const int axis_y = params.Get("axis_y", 1);
460 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f); 463 const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f);
461 464 const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
462 auto joystick = state.GetSDLJoystickByGUID(guid, port); 465 auto joystick = state.GetSDLJoystickByGUID(guid, port);
463 466
464 // This is necessary so accessing GetAxis with axis_x and axis_y won't crash 467 // This is necessary so accessing GetAxis with axis_x and axis_y won't crash
465 joystick->SetAxis(axis_x, 0); 468 joystick->SetAxis(axis_x, 0);
466 joystick->SetAxis(axis_y, 0); 469 joystick->SetAxis(axis_y, 0);
467 return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, deadzone); 470 return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, deadzone, range);
468 } 471 }
469 472
470private: 473private:
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index 6c95a8b42..3f4eaf448 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -224,8 +224,7 @@ void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 clie
224 } else { 224 } else {
225 failure_callback(); 225 failure_callback();
226 } 226 }
227 }) 227 }).detach();
228 .detach();
229} 228}
230 229
231CalibrationConfigurationJob::CalibrationConfigurationJob( 230CalibrationConfigurationJob::CalibrationConfigurationJob(
@@ -279,8 +278,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob(
279 complete_event.Wait(); 278 complete_event.Wait();
280 socket.Stop(); 279 socket.Stop();
281 worker_thread.join(); 280 worker_thread.join();
282 }) 281 }).detach();
283 .detach();
284} 282}
285 283
286CalibrationConfigurationJob::~CalibrationConfigurationJob() { 284CalibrationConfigurationJob::~CalibrationConfigurationJob() {
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index a2d3d7823..e88290754 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -94,7 +94,8 @@ void MaxwellDMA::CopyPitchToPitch() {
94} 94}
95 95
96void MaxwellDMA::CopyBlockLinearToPitch() { 96void MaxwellDMA::CopyBlockLinearToPitch() {
97 ASSERT(regs.src_params.block_size.depth == 0); 97 UNIMPLEMENTED_IF(regs.src_params.block_size.depth != 0);
98 UNIMPLEMENTED_IF(regs.src_params.layer != 0);
98 99
99 // Optimized path for micro copies. 100 // Optimized path for micro copies.
100 const size_t dst_size = static_cast<size_t>(regs.pitch_out) * regs.line_count; 101 const size_t dst_size = static_cast<size_t>(regs.pitch_out) * regs.line_count;
@@ -123,17 +124,12 @@ void MaxwellDMA::CopyBlockLinearToPitch() {
123 write_buffer.resize(dst_size); 124 write_buffer.resize(dst_size);
124 } 125 }
125 126
126 if (Settings::IsGPULevelExtreme()) { 127 memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size);
127 memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size); 128 memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size);
128 memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size);
129 } else {
130 memory_manager.ReadBlockUnsafe(regs.offset_in, read_buffer.data(), src_size);
131 memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size);
132 }
133 129
134 UnswizzleSubrect(regs.line_length_in, regs.line_count, regs.pitch_out, width, bytes_per_pixel, 130 UnswizzleSubrect(regs.line_length_in, regs.line_count, regs.pitch_out, width, bytes_per_pixel,
135 read_buffer.data() + src_layer_size * src_params.layer, write_buffer.data(), 131 block_height, src_params.origin.x, src_params.origin.y, write_buffer.data(),
136 block_height, src_params.origin.x, src_params.origin.y); 132 read_buffer.data());
137 133
138 memory_manager.WriteBlock(regs.offset_out, write_buffer.data(), dst_size); 134 memory_manager.WriteBlock(regs.offset_out, write_buffer.data(), dst_size);
139} 135}
@@ -198,7 +194,6 @@ void MaxwellDMA::FastCopyBlockLinearToPitch() {
198 if (read_buffer.size() < src_size) { 194 if (read_buffer.size() < src_size) {
199 read_buffer.resize(src_size); 195 read_buffer.resize(src_size);
200 } 196 }
201
202 if (write_buffer.size() < dst_size) { 197 if (write_buffer.size() < dst_size) {
203 write_buffer.resize(dst_size); 198 write_buffer.resize(dst_size);
204 } 199 }
@@ -212,8 +207,8 @@ void MaxwellDMA::FastCopyBlockLinearToPitch() {
212 } 207 }
213 208
214 UnswizzleSubrect(regs.line_length_in, regs.line_count, regs.pitch_out, regs.src_params.width, 209 UnswizzleSubrect(regs.line_length_in, regs.line_count, regs.pitch_out, regs.src_params.width,
215 bytes_per_pixel, read_buffer.data(), write_buffer.data(), 210 bytes_per_pixel, regs.src_params.block_size.height, pos_x, pos_y,
216 regs.src_params.block_size.height, pos_x, pos_y); 211 write_buffer.data(), read_buffer.data());
217 212
218 memory_manager.WriteBlock(regs.offset_out, write_buffer.data(), dst_size); 213 memory_manager.WriteBlock(regs.offset_out, write_buffer.data(), dst_size);
219} 214}
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index be71e1733..eb49a36bf 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -403,7 +403,7 @@ void ShaderCacheOpenGL::LoadDiskCache(const std::atomic_bool& stop_loading,
403 } 403 }
404 }; 404 };
405 405
406 const auto num_workers{static_cast<std::size_t>(std::thread::hardware_concurrency() + 1ULL)}; 406 const std::size_t num_workers{std::max(1U, std::thread::hardware_concurrency())};
407 const std::size_t bucket_size{transferable->size() / num_workers}; 407 const std::size_t bucket_size{transferable->size() / num_workers};
408 std::vector<std::unique_ptr<Core::Frontend::GraphicsContext>> contexts(num_workers); 408 std::vector<std::unique_ptr<Core::Frontend::GraphicsContext>> contexts(num_workers);
409 std::vector<std::thread> threads(num_workers); 409 std::vector<std::thread> threads(num_workers);
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
index 2dcc2b0eb..c0e73789b 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
@@ -422,8 +422,7 @@ void ShaderDiskCacheOpenGL::SavePrecompiledHeaderToVirtualPrecompiledCache() {
422void ShaderDiskCacheOpenGL::SaveVirtualPrecompiledFile() { 422void ShaderDiskCacheOpenGL::SaveVirtualPrecompiledFile() {
423 precompiled_cache_virtual_file_offset = 0; 423 precompiled_cache_virtual_file_offset = 0;
424 const std::vector<u8> uncompressed = precompiled_cache_virtual_file.ReadAllBytes(); 424 const std::vector<u8> uncompressed = precompiled_cache_virtual_file.ReadAllBytes();
425 const std::vector<u8> compressed = 425 const std::vector<u8> compressed = Common::Compression::CompressDataZSTDDefault(uncompressed);
426 Common::Compression::CompressDataZSTDDefault(uncompressed.data(), uncompressed.size());
427 426
428 const auto precompiled_path{GetPrecompiledPath()}; 427 const auto precompiled_path{GetPrecompiledPath()};
429 FileUtil::IOFile file(precompiled_path, "wb"); 428 FileUtil::IOFile file(precompiled_path, "wb");
diff --git a/src/video_core/renderer_vulkan/wrapper.h b/src/video_core/renderer_vulkan/wrapper.h
index 71daac9d7..31885ef42 100644
--- a/src/video_core/renderer_vulkan/wrapper.h
+++ b/src/video_core/renderer_vulkan/wrapper.h
@@ -756,8 +756,8 @@ public:
756 } 756 }
757 757
758 VkResult GetQueryResults(VkQueryPool query_pool, u32 first, u32 count, std::size_t data_size, 758 VkResult GetQueryResults(VkQueryPool query_pool, u32 first, u32 count, std::size_t data_size,
759 void* data, VkDeviceSize stride, VkQueryResultFlags flags) const 759 void* data, VkDeviceSize stride,
760 noexcept { 760 VkQueryResultFlags flags) const noexcept {
761 return dld->vkGetQueryPoolResults(handle, query_pool, first, count, data_size, data, stride, 761 return dld->vkGetQueryPoolResults(handle, query_pool, first, count, data_size, data, stride,
762 flags); 762 flags);
763 } 763 }
@@ -849,8 +849,8 @@ public:
849 dld->vkCmdBindPipeline(handle, bind_point, pipeline); 849 dld->vkCmdBindPipeline(handle, bind_point, pipeline);
850 } 850 }
851 851
852 void BindIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType index_type) const 852 void BindIndexBuffer(VkBuffer buffer, VkDeviceSize offset,
853 noexcept { 853 VkIndexType index_type) const noexcept {
854 dld->vkCmdBindIndexBuffer(handle, buffer, offset, index_type); 854 dld->vkCmdBindIndexBuffer(handle, buffer, offset, index_type);
855 } 855 }
856 856
@@ -863,8 +863,8 @@ public:
863 BindVertexBuffers(binding, 1, &buffer, &offset); 863 BindVertexBuffers(binding, 1, &buffer, &offset);
864 } 864 }
865 865
866 void Draw(u32 vertex_count, u32 instance_count, u32 first_vertex, u32 first_instance) const 866 void Draw(u32 vertex_count, u32 instance_count, u32 first_vertex,
867 noexcept { 867 u32 first_instance) const noexcept {
868 dld->vkCmdDraw(handle, vertex_count, instance_count, first_vertex, first_instance); 868 dld->vkCmdDraw(handle, vertex_count, instance_count, first_vertex, first_instance);
869 } 869 }
870 870
@@ -874,15 +874,15 @@ public:
874 first_instance); 874 first_instance);
875 } 875 }
876 876
877 void ClearAttachments(Span<VkClearAttachment> attachments, Span<VkClearRect> rects) const 877 void ClearAttachments(Span<VkClearAttachment> attachments,
878 noexcept { 878 Span<VkClearRect> rects) const noexcept {
879 dld->vkCmdClearAttachments(handle, attachments.size(), attachments.data(), rects.size(), 879 dld->vkCmdClearAttachments(handle, attachments.size(), attachments.data(), rects.size(),
880 rects.data()); 880 rects.data());
881 } 881 }
882 882
883 void BlitImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image, 883 void BlitImage(VkImage src_image, VkImageLayout src_layout, VkImage dst_image,
884 VkImageLayout dst_layout, Span<VkImageBlit> regions, VkFilter filter) const 884 VkImageLayout dst_layout, Span<VkImageBlit> regions,
885 noexcept { 885 VkFilter filter) const noexcept {
886 dld->vkCmdBlitImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(), 886 dld->vkCmdBlitImage(handle, src_image, src_layout, dst_image, dst_layout, regions.size(),
887 regions.data(), filter); 887 regions.data(), filter);
888 } 888 }
@@ -907,8 +907,8 @@ public:
907 regions.data()); 907 regions.data());
908 } 908 }
909 909
910 void CopyBuffer(VkBuffer src_buffer, VkBuffer dst_buffer, Span<VkBufferCopy> regions) const 910 void CopyBuffer(VkBuffer src_buffer, VkBuffer dst_buffer,
911 noexcept { 911 Span<VkBufferCopy> regions) const noexcept {
912 dld->vkCmdCopyBuffer(handle, src_buffer, dst_buffer, regions.size(), regions.data()); 912 dld->vkCmdCopyBuffer(handle, src_buffer, dst_buffer, regions.size(), regions.data());
913 } 913 }
914 914
@@ -924,8 +924,8 @@ public:
924 regions.data()); 924 regions.data());
925 } 925 }
926 926
927 void FillBuffer(VkBuffer dst_buffer, VkDeviceSize dst_offset, VkDeviceSize size, u32 data) const 927 void FillBuffer(VkBuffer dst_buffer, VkDeviceSize dst_offset, VkDeviceSize size,
928 noexcept { 928 u32 data) const noexcept {
929 dld->vkCmdFillBuffer(handle, dst_buffer, dst_offset, size, data); 929 dld->vkCmdFillBuffer(handle, dst_buffer, dst_offset, size, data);
930 } 930 }
931 931
diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp
index 8d86020f6..336397cdb 100644
--- a/src/video_core/shader/control_flow.cpp
+++ b/src/video_core/shader/control_flow.cpp
@@ -187,24 +187,26 @@ std::optional<std::pair<BufferInfo, u64>> TrackLDC(const CFGRebuildState& state,
187 187
188std::optional<u64> TrackSHLRegister(const CFGRebuildState& state, u32& pos, 188std::optional<u64> TrackSHLRegister(const CFGRebuildState& state, u32& pos,
189 u64 ldc_tracked_register) { 189 u64 ldc_tracked_register) {
190 return TrackInstruction<u64>(state, pos, 190 return TrackInstruction<u64>(
191 [ldc_tracked_register](auto instr, const auto& opcode) { 191 state, pos,
192 return opcode.GetId() == OpCode::Id::SHL_IMM && 192 [ldc_tracked_register](auto instr, const auto& opcode) {
193 instr.gpr0.Value() == ldc_tracked_register; 193 return opcode.GetId() == OpCode::Id::SHL_IMM &&
194 }, 194 instr.gpr0.Value() == ldc_tracked_register;
195 [](auto instr, const auto&) { return instr.gpr8.Value(); }); 195 },
196 [](auto instr, const auto&) { return instr.gpr8.Value(); });
196} 197}
197 198
198std::optional<u32> TrackIMNMXValue(const CFGRebuildState& state, u32& pos, 199std::optional<u32> TrackIMNMXValue(const CFGRebuildState& state, u32& pos,
199 u64 shl_tracked_register) { 200 u64 shl_tracked_register) {
200 return TrackInstruction<u32>(state, pos, 201 return TrackInstruction<u32>(
201 [shl_tracked_register](auto instr, const auto& opcode) { 202 state, pos,
202 return opcode.GetId() == OpCode::Id::IMNMX_IMM && 203 [shl_tracked_register](auto instr, const auto& opcode) {
203 instr.gpr0.Value() == shl_tracked_register; 204 return opcode.GetId() == OpCode::Id::IMNMX_IMM &&
204 }, 205 instr.gpr0.Value() == shl_tracked_register;
205 [](auto instr, const auto&) { 206 },
206 return static_cast<u32>(instr.alu.GetSignedImm20_20() + 1); 207 [](auto instr, const auto&) {
207 }); 208 return static_cast<u32>(instr.alu.GetSignedImm20_20() + 1);
209 });
208} 210}
209 211
210std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState& state, u32 pos) { 212std::optional<BranchIndirectInfo> TrackBranchIndirectInfo(const CFGRebuildState& state, u32 pos) {
diff --git a/src/video_core/shader/decode/memory.cpp b/src/video_core/shader/decode/memory.cpp
index 63adbc4a3..e4739394d 100644
--- a/src/video_core/shader/decode/memory.cpp
+++ b/src/video_core/shader/decode/memory.cpp
@@ -471,9 +471,9 @@ std::tuple<Node, Node, GlobalMemoryBase> ShaderIR::TrackGlobalMemory(NodeBlock&
471 471
472 const auto [base_address, index, offset] = 472 const auto [base_address, index, offset] =
473 TrackCbuf(addr_register, global_code, static_cast<s64>(global_code.size())); 473 TrackCbuf(addr_register, global_code, static_cast<s64>(global_code.size()));
474 ASSERT_OR_EXECUTE_MSG(base_address != nullptr, 474 ASSERT_OR_EXECUTE_MSG(
475 { return std::make_tuple(nullptr, nullptr, GlobalMemoryBase{}); }, 475 base_address != nullptr, { return std::make_tuple(nullptr, nullptr, GlobalMemoryBase{}); },
476 "Global memory tracking failed"); 476 "Global memory tracking failed");
477 477
478 bb.push_back(Comment(fmt::format("Base address is c[0x{:x}][0x{:x}]", index, offset))); 478 bb.push_back(Comment(fmt::format("Base address is c[0x{:x}][0x{:x}]", index, offset)));
479 479
diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp
index 9a98f0e98..e614a92df 100644
--- a/src/video_core/texture_cache/surface_params.cpp
+++ b/src/video_core/texture_cache/surface_params.cpp
@@ -96,7 +96,6 @@ SurfaceParams SurfaceParams::CreateForTexture(const FormatLookupTable& lookup_ta
96 } 96 }
97 params.type = GetFormatType(params.pixel_format); 97 params.type = GetFormatType(params.pixel_format);
98 } 98 }
99 params.type = GetFormatType(params.pixel_format);
100 // TODO: on 1DBuffer we should use the tic info. 99 // TODO: on 1DBuffer we should use the tic info.
101 if (tic.IsBuffer()) { 100 if (tic.IsBuffer()) {
102 params.target = SurfaceTarget::TextureBuffer; 101 params.target = SurfaceTarget::TextureBuffer;
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index 474ae620a..16d46a018 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -228,24 +228,30 @@ void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32
228 } 228 }
229} 229}
230 230
231void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32 swizzled_width, 231void UnswizzleSubrect(u32 line_length_in, u32 line_count, u32 pitch, u32 width, u32 bytes_per_pixel,
232 u32 bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, 232 u32 block_height, u32 origin_x, u32 origin_y, u8* output, const u8* input) {
233 u32 block_height_bit, u32 offset_x, u32 offset_y) { 233 const u32 stride = width * bytes_per_pixel;
234 const u32 block_height = 1U << block_height_bit; 234 const u32 gobs_in_x = (stride + GOB_SIZE_X - 1) / GOB_SIZE_X;
235 for (u32 line = 0; line < subrect_height; ++line) { 235 const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block_height);
236 const u32 y2 = line + offset_y; 236
237 const u32 gob_address_y = (y2 / (GOB_SIZE_Y * block_height)) * GOB_SIZE * block_height + 237 const u32 block_height_mask = (1U << block_height) - 1;
238 ((y2 % (GOB_SIZE_Y * block_height)) / GOB_SIZE_Y) * GOB_SIZE; 238 const u32 x_shift = static_cast<u32>(GOB_SIZE_SHIFT) + block_height;
239 const auto& table = LEGACY_SWIZZLE_TABLE[y2 % GOB_SIZE_Y]; 239
240 for (u32 x = 0; x < subrect_width; ++x) { 240 for (u32 line = 0; line < line_count; ++line) {
241 const u32 x2 = (x + offset_x) * bytes_per_pixel; 241 const u32 src_y = line + origin_y;
242 const u32 gob_address = gob_address_y + (x2 / GOB_SIZE_X) * GOB_SIZE * block_height; 242 const auto& table = LEGACY_SWIZZLE_TABLE[src_y % GOB_SIZE_Y];
243 const u32 swizzled_offset = gob_address + table[x2 % GOB_SIZE_X]; 243
244 const u32 unswizzled_offset = line * dest_pitch + x * bytes_per_pixel; 244 const u32 block_y = src_y >> GOB_SIZE_Y_SHIFT;
245 u8* dest_line = unswizzled_data + unswizzled_offset; 245 const u32 src_offset_y = (block_y >> block_height) * block_size +
246 u8* source_addr = swizzled_data + swizzled_offset; 246 ((block_y & block_height_mask) << GOB_SIZE_SHIFT);
247 for (u32 column = 0; column < line_length_in; ++column) {
248 const u32 src_x = (column + origin_x) * bytes_per_pixel;
249 const u32 src_offset_x = (src_x >> GOB_SIZE_X_SHIFT) << x_shift;
250
251 const u32 swizzled_offset = src_offset_y + src_offset_x + table[src_x % GOB_SIZE_X];
252 const u32 unswizzled_offset = line * pitch + column * bytes_per_pixel;
247 253
248 std::memcpy(dest_line, source_addr, bytes_per_pixel); 254 std::memcpy(output + unswizzled_offset, input + swizzled_offset, bytes_per_pixel);
249 } 255 }
250 } 256 }
251} 257}
@@ -261,7 +267,7 @@ void SwizzleSliceToVoxel(u32 line_length_in, u32 line_count, u32 pitch, u32 widt
261 const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block_height + block_depth); 267 const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block_height + block_depth);
262 268
263 const u32 block_height_mask = (1U << block_height) - 1; 269 const u32 block_height_mask = (1U << block_height) - 1;
264 const u32 x_shift = Common::CountTrailingZeroes32(GOB_SIZE << (block_height + block_depth)); 270 const u32 x_shift = static_cast<u32>(GOB_SIZE_SHIFT) + block_height + block_depth;
265 271
266 for (u32 line = 0; line < line_count; ++line) { 272 for (u32 line = 0; line < line_count; ++line) {
267 const auto& table = LEGACY_SWIZZLE_TABLE[line % GOB_SIZE_Y]; 273 const auto& table = LEGACY_SWIZZLE_TABLE[line % GOB_SIZE_Y];
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h
index d6fe35d37..01e156bc8 100644
--- a/src/video_core/textures/decoders.h
+++ b/src/video_core/textures/decoders.h
@@ -48,9 +48,8 @@ void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32
48 u32 block_height_bit, u32 offset_x, u32 offset_y); 48 u32 block_height_bit, u32 offset_x, u32 offset_y);
49 49
50/// Copies a tiled subrectangle into a linear surface. 50/// Copies a tiled subrectangle into a linear surface.
51void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32 swizzled_width, 51void UnswizzleSubrect(u32 line_length_in, u32 line_count, u32 pitch, u32 width, u32 bytes_per_pixel,
52 u32 bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, u32 block_height, 52 u32 block_height, u32 origin_x, u32 origin_y, u8* output, const u8* input);
53 u32 offset_x, u32 offset_y);
54 53
55/// @brief Swizzles a 2D array of pixels into a 3D texture 54/// @brief Swizzles a 2D array of pixels into a 3D texture
56/// @param line_length_in Number of pixels per line 55/// @param line_length_in Number of pixels per line
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index b1850bc95..597defe8c 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -281,24 +281,25 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
281 281
282 button->setContextMenuPolicy(Qt::CustomContextMenu); 282 button->setContextMenuPolicy(Qt::CustomContextMenu);
283 connect(button, &QPushButton::clicked, [=, this] { 283 connect(button, &QPushButton::clicked, [=, this] {
284 HandleClick(button_map[button_id], 284 HandleClick(
285 [=, this](Common::ParamPackage params) { 285 button_map[button_id],
286 // Workaround for ZL & ZR for analog triggers like on XBOX controllors. 286 [=, this](Common::ParamPackage params) {
287 // Analog triggers (from controllers like the XBOX controller) would not 287 // Workaround for ZL & ZR for analog triggers like on XBOX controllors.
288 // work due to a different range of their signals (from 0 to 255 on 288 // Analog triggers (from controllers like the XBOX controller) would not
289 // analog triggers instead of -32768 to 32768 on analog joysticks). The 289 // work due to a different range of their signals (from 0 to 255 on
290 // SDL driver misinterprets analog triggers as analog joysticks. 290 // analog triggers instead of -32768 to 32768 on analog joysticks). The
291 // TODO: reinterpret the signal range for analog triggers to map the 291 // SDL driver misinterprets analog triggers as analog joysticks.
292 // values correctly. This is required for the correct emulation of the 292 // TODO: reinterpret the signal range for analog triggers to map the
293 // analog triggers of the GameCube controller. 293 // values correctly. This is required for the correct emulation of the
294 if (button_id == Settings::NativeButton::ZL || 294 // analog triggers of the GameCube controller.
295 button_id == Settings::NativeButton::ZR) { 295 if (button_id == Settings::NativeButton::ZL ||
296 params.Set("direction", "+"); 296 button_id == Settings::NativeButton::ZR) {
297 params.Set("threshold", "0.5"); 297 params.Set("direction", "+");
298 } 298 params.Set("threshold", "0.5");
299 buttons_param[button_id] = std::move(params); 299 }
300 }, 300 buttons_param[button_id] = std::move(params);
301 InputCommon::Polling::DeviceType::Button); 301 },
302 InputCommon::Polling::DeviceType::Button);
302 }); 303 });
303 connect(button, &QPushButton::customContextMenuRequested, 304 connect(button, &QPushButton::customContextMenuRequested,
304 [=, this](const QPoint& menu_location) { 305 [=, this](const QPoint& menu_location) {
@@ -325,12 +326,13 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
325 326
326 analog_button->setContextMenuPolicy(Qt::CustomContextMenu); 327 analog_button->setContextMenuPolicy(Qt::CustomContextMenu);
327 connect(analog_button, &QPushButton::clicked, [=, this] { 328 connect(analog_button, &QPushButton::clicked, [=, this] {
328 HandleClick(analog_map_buttons[analog_id][sub_button_id], 329 HandleClick(
329 [=, this](const Common::ParamPackage& params) { 330 analog_map_buttons[analog_id][sub_button_id],
330 SetAnalogButton(params, analogs_param[analog_id], 331 [=, this](const Common::ParamPackage& params) {
331 analog_sub_buttons[sub_button_id]); 332 SetAnalogButton(params, analogs_param[analog_id],
332 }, 333 analog_sub_buttons[sub_button_id]);
333 InputCommon::Polling::DeviceType::Button); 334 },
335 InputCommon::Polling::DeviceType::Button);
334 }); 336 });
335 connect(analog_button, &QPushButton::customContextMenuRequested, 337 connect(analog_button, &QPushButton::customContextMenuRequested,
336 [=, this](const QPoint& menu_location) { 338 [=, this](const QPoint& menu_location) {
@@ -357,11 +359,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
357 tr("After pressing OK, first move your joystick horizontally, " 359 tr("After pressing OK, first move your joystick horizontally, "
358 "and then vertically."), 360 "and then vertically."),
359 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { 361 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) {
360 HandleClick(analog_map_stick[analog_id], 362 HandleClick(
361 [=, this](const Common::ParamPackage& params) { 363 analog_map_stick[analog_id],
362 analogs_param[analog_id] = params; 364 [=, this](const Common::ParamPackage& params) {
363 }, 365 analogs_param[analog_id] = params;
364 InputCommon::Polling::DeviceType::Analog); 366 },
367 InputCommon::Polling::DeviceType::Analog);
365 } 368 }
366 }); 369 });
367 370
diff --git a/src/yuzu/configuration/configure_mouse_advanced.cpp b/src/yuzu/configuration/configure_mouse_advanced.cpp
index ea2549363..5bcf5ffa8 100644
--- a/src/yuzu/configuration/configure_mouse_advanced.cpp
+++ b/src/yuzu/configuration/configure_mouse_advanced.cpp
@@ -84,11 +84,12 @@ ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent)
84 84
85 button->setContextMenuPolicy(Qt::CustomContextMenu); 85 button->setContextMenuPolicy(Qt::CustomContextMenu);
86 connect(button, &QPushButton::clicked, [=, this] { 86 connect(button, &QPushButton::clicked, [=, this] {
87 HandleClick(button_map[button_id], 87 HandleClick(
88 [=, this](const Common::ParamPackage& params) { 88 button_map[button_id],
89 buttons_param[button_id] = params; 89 [=, this](const Common::ParamPackage& params) {
90 }, 90 buttons_param[button_id] = params;
91 InputCommon::Polling::DeviceType::Button); 91 },
92 InputCommon::Polling::DeviceType::Button);
92 }); 93 });
93 connect(button, &QPushButton::customContextMenuRequested, 94 connect(button, &QPushButton::customContextMenuRequested,
94 [=, this](const QPoint& menu_location) { 95 [=, this](const QPoint& menu_location) {
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp
index 239016b94..643ca6491 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -350,6 +350,7 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa
350 350
351void GameListWorker::run() { 351void GameListWorker::run() {
352 stop_processing = false; 352 stop_processing = false;
353 provider->ClearAllEntries();
353 354
354 for (UISettings::GameDir& game_dir : game_dirs) { 355 for (UISettings::GameDir& game_dir : game_dirs) {
355 if (game_dir.path == QStringLiteral("SDMC")) { 356 if (game_dir.path == QStringLiteral("SDMC")) {
@@ -368,7 +369,6 @@ void GameListWorker::run() {
368 watch_list.append(game_dir.path); 369 watch_list.append(game_dir.path);
369 auto* const game_list_dir = new GameListDir(game_dir); 370 auto* const game_list_dir = new GameListDir(game_dir);
370 emit DirEntryReady(game_list_dir); 371 emit DirEntryReady(game_list_dir);
371 provider->ClearAllEntries();
372 ScanFileSystem(ScanTarget::FillManualContentProvider, game_dir.path.toStdString(), 372 ScanFileSystem(ScanTarget::FillManualContentProvider, game_dir.path.toStdString(),
373 game_dir.deep_scan ? 256 : 0, game_list_dir); 373 game_dir.deep_scan ? 256 : 0, game_list_dir);
374 ScanFileSystem(ScanTarget::PopulateGameList, game_dir.path.toStdString(), 374 ScanFileSystem(ScanTarget::PopulateGameList, game_dir.path.toStdString(),