summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/bit_field.h12
-rw-r--r--src/common/swap.h174
-rw-r--r--src/common/uint128.cpp4
-rw-r--r--src/common/uint128.h5
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/core.cpp11
-rw-r--r--src/core/core.h4
-rw-r--r--src/core/file_sys/cheat_engine.cpp493
-rw-r--r--src/core/file_sys/cheat_engine.h227
-rw-r--r--src/core/file_sys/content_archive.h15
-rw-r--r--src/core/file_sys/patch_manager.cpp54
-rw-r--r--src/core/file_sys/patch_manager.h4
-rw-r--r--src/core/file_sys/registered_cache.cpp2
-rw-r--r--src/core/hle/ipc.h44
-rw-r--r--src/core/hle/kernel/code_set.cpp12
-rw-r--r--src/core/hle/kernel/code_set.h90
-rw-r--r--src/core/hle/kernel/mutex.cpp35
-rw-r--r--src/core/hle/kernel/mutex.h20
-rw-r--r--src/core/hle/kernel/process.cpp15
-rw-r--r--src/core/hle/kernel/process.h59
-rw-r--r--src/core/hle/kernel/svc.cpp17
-rw-r--r--src/core/hle/kernel/vm_manager.cpp20
-rw-r--r--src/core/hle/kernel/vm_manager.h11
-rw-r--r--src/core/hle/service/am/am.cpp16
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.h30
-rw-r--r--src/core/hle/service/hid/controllers/npad.h102
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h4
-rw-r--r--src/core/hle/service/hid/hid.h3
-rw-r--r--src/core/hle/service/ldr/ldr.cpp8
-rw-r--r--src/core/hle/service/lm/lm.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdevice.h10
-rw-r--r--src/core/loader/elf.cpp1
-rw-r--r--src/core/loader/nro.cpp1
-rw-r--r--src/core/loader/nso.cpp13
-rw-r--r--src/core/memory.h3
-rw-r--r--src/input_common/sdl/sdl.h12
-rw-r--r--src/input_common/sdl/sdl_impl.cpp9
-rw-r--r--src/input_common/sdl/sdl_impl.h5
-rw-r--r--src/tests/CMakeLists.txt1
-rw-r--r--src/tests/common/bit_field.cpp90
-rw-r--r--src/video_core/rasterizer_cache.h4
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h8
43 files changed, 1406 insertions, 256 deletions
diff --git a/src/common/bit_field.h b/src/common/bit_field.h
index 7433c39ba..902e668e3 100644
--- a/src/common/bit_field.h
+++ b/src/common/bit_field.h
@@ -34,6 +34,7 @@
34#include <limits> 34#include <limits>
35#include <type_traits> 35#include <type_traits>
36#include "common/common_funcs.h" 36#include "common/common_funcs.h"
37#include "common/swap.h"
37 38
38/* 39/*
39 * Abstract bitfield class 40 * Abstract bitfield class
@@ -108,7 +109,7 @@
108 * symptoms. 109 * symptoms.
109 */ 110 */
110#pragma pack(1) 111#pragma pack(1)
111template <std::size_t Position, std::size_t Bits, typename T> 112template <std::size_t Position, std::size_t Bits, typename T, typename EndianTag = LETag>
112struct BitField { 113struct BitField {
113private: 114private:
114 // UnderlyingType is T for non-enum types and the underlying type of T if 115 // UnderlyingType is T for non-enum types and the underlying type of T if
@@ -121,6 +122,8 @@ private:
121 // We store the value as the unsigned type to avoid undefined behaviour on value shifting 122 // We store the value as the unsigned type to avoid undefined behaviour on value shifting
122 using StorageType = std::make_unsigned_t<UnderlyingType>; 123 using StorageType = std::make_unsigned_t<UnderlyingType>;
123 124
125 using StorageTypeWithEndian = typename AddEndian<StorageType, EndianTag>::type;
126
124public: 127public:
125 /// Constants to allow limited introspection of fields if needed 128 /// Constants to allow limited introspection of fields if needed
126 static constexpr std::size_t position = Position; 129 static constexpr std::size_t position = Position;
@@ -170,7 +173,7 @@ public:
170 } 173 }
171 174
172 constexpr FORCE_INLINE void Assign(const T& value) { 175 constexpr FORCE_INLINE void Assign(const T& value) {
173 storage = (storage & ~mask) | FormatValue(value); 176 storage = (static_cast<StorageType>(storage) & ~mask) | FormatValue(value);
174 } 177 }
175 178
176 constexpr T Value() const { 179 constexpr T Value() const {
@@ -182,7 +185,7 @@ public:
182 } 185 }
183 186
184private: 187private:
185 StorageType storage; 188 StorageTypeWithEndian storage;
186 189
187 static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); 190 static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range");
188 191
@@ -193,3 +196,6 @@ private:
193 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable in a BitField"); 196 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable in a BitField");
194}; 197};
195#pragma pack() 198#pragma pack()
199
200template <std::size_t Position, std::size_t Bits, typename T>
201using BitFieldBE = BitField<Position, Bits, T, BETag>;
diff --git a/src/common/swap.h b/src/common/swap.h
index 0e219747f..b3eab1324 100644
--- a/src/common/swap.h
+++ b/src/common/swap.h
@@ -17,6 +17,8 @@
17 17
18#pragma once 18#pragma once
19 19
20#include <type_traits>
21
20#if defined(_MSC_VER) 22#if defined(_MSC_VER)
21#include <cstdlib> 23#include <cstdlib>
22#elif defined(__linux__) 24#elif defined(__linux__)
@@ -170,7 +172,7 @@ struct swap_struct_t {
170 using swapped_t = swap_struct_t; 172 using swapped_t = swap_struct_t;
171 173
172protected: 174protected:
173 T value = T(); 175 T value;
174 176
175 static T swap(T v) { 177 static T swap(T v) {
176 return F::swap(v); 178 return F::swap(v);
@@ -605,52 +607,154 @@ struct swap_double_t {
605 } 607 }
606}; 608};
607 609
608#if COMMON_LITTLE_ENDIAN 610template <typename T>
609using u16_le = u16; 611struct swap_enum_t {
610using u32_le = u32; 612 static_assert(std::is_enum_v<T>);
611using u64_le = u64; 613 using base = std::underlying_type_t<T>;
614
615public:
616 swap_enum_t() = default;
617 swap_enum_t(const T& v) : value(swap(v)) {}
618
619 swap_enum_t& operator=(const T& v) {
620 value = swap(v);
621 return *this;
622 }
623
624 operator T() const {
625 return swap(value);
626 }
627
628 explicit operator base() const {
629 return static_cast<base>(swap(value));
630 }
612 631
613using s16_le = s16; 632protected:
614using s32_le = s32; 633 T value{};
615using s64_le = s64; 634 // clang-format off
635 using swap_t = std::conditional_t<
636 std::is_same_v<base, u16>, swap_16_t<u16>, std::conditional_t<
637 std::is_same_v<base, s16>, swap_16_t<s16>, std::conditional_t<
638 std::is_same_v<base, u32>, swap_32_t<u32>, std::conditional_t<
639 std::is_same_v<base, s32>, swap_32_t<s32>, std::conditional_t<
640 std::is_same_v<base, u64>, swap_64_t<u64>, std::conditional_t<
641 std::is_same_v<base, s64>, swap_64_t<s64>, void>>>>>>;
642 // clang-format on
643 static T swap(T x) {
644 return static_cast<T>(swap_t::swap(static_cast<base>(x)));
645 }
646};
616 647
617using float_le = float; 648struct SwapTag {}; // Use the different endianness from the system
618using double_le = double; 649struct KeepTag {}; // Use the same endianness as the system
619 650
620using u64_be = swap_struct_t<u64, swap_64_t<u64>>; 651template <typename T, typename Tag>
621using s64_be = swap_struct_t<s64, swap_64_t<s64>>; 652struct AddEndian;
622 653
623using u32_be = swap_struct_t<u32, swap_32_t<u32>>; 654// KeepTag specializations
624using s32_be = swap_struct_t<s32, swap_32_t<s32>>;
625 655
626using u16_be = swap_struct_t<u16, swap_16_t<u16>>; 656template <typename T>
627using s16_be = swap_struct_t<s16, swap_16_t<s16>>; 657struct AddEndian<T, KeepTag> {
658 using type = T;
659};
628 660
629using float_be = swap_struct_t<float, swap_float_t<float>>; 661// SwapTag specializations
630using double_be = swap_struct_t<double, swap_double_t<double>>; 662
631#else 663template <>
664struct AddEndian<u8, SwapTag> {
665 using type = u8;
666};
667
668template <>
669struct AddEndian<u16, SwapTag> {
670 using type = swap_struct_t<u16, swap_16_t<u16>>;
671};
672
673template <>
674struct AddEndian<u32, SwapTag> {
675 using type = swap_struct_t<u32, swap_32_t<u32>>;
676};
632 677
633using u64_le = swap_struct_t<u64, swap_64_t<u64>>; 678template <>
634using s64_le = swap_struct_t<s64, swap_64_t<s64>>; 679struct AddEndian<u64, SwapTag> {
680 using type = swap_struct_t<u64, swap_64_t<u64>>;
681};
682
683template <>
684struct AddEndian<s8, SwapTag> {
685 using type = s8;
686};
635 687
636using u32_le = swap_struct_t<u32, swap_32_t<u32>>; 688template <>
637using s32_le = swap_struct_t<s32, swap_32_t<s32>>; 689struct AddEndian<s16, SwapTag> {
690 using type = swap_struct_t<s16, swap_16_t<s16>>;
691};
638 692
639using u16_le = swap_struct_t<u16, swap_16_t<u16>>; 693template <>
640using s16_le = swap_struct_t<s16, swap_16_t<s16>>; 694struct AddEndian<s32, SwapTag> {
695 using type = swap_struct_t<s32, swap_32_t<s32>>;
696};
697
698template <>
699struct AddEndian<s64, SwapTag> {
700 using type = swap_struct_t<s64, swap_64_t<s64>>;
701};
702
703template <>
704struct AddEndian<float, SwapTag> {
705 using type = swap_struct_t<float, swap_float_t<float>>;
706};
707
708template <>
709struct AddEndian<double, SwapTag> {
710 using type = swap_struct_t<double, swap_double_t<double>>;
711};
712
713template <typename T>
714struct AddEndian<T, SwapTag> {
715 static_assert(std::is_enum_v<T>);
716 using type = swap_enum_t<T>;
717};
641 718
642using float_le = swap_struct_t<float, swap_float_t<float>>; 719// Alias LETag/BETag as KeepTag/SwapTag depending on the system
643using double_le = swap_struct_t<double, swap_double_t<double>>; 720#if COMMON_LITTLE_ENDIAN
644 721
645using u16_be = u16; 722using LETag = KeepTag;
646using u32_be = u32; 723using BETag = SwapTag;
647using u64_be = u64;
648 724
649using s16_be = s16; 725#else
650using s32_be = s32;
651using s64_be = s64;
652 726
653using float_be = float; 727using BETag = KeepTag;
654using double_be = double; 728using LETag = SwapTag;
655 729
656#endif 730#endif
731
732// Aliases for LE types
733using u16_le = AddEndian<u16, LETag>::type;
734using u32_le = AddEndian<u32, LETag>::type;
735using u64_le = AddEndian<u64, LETag>::type;
736
737using s16_le = AddEndian<s16, LETag>::type;
738using s32_le = AddEndian<s32, LETag>::type;
739using s64_le = AddEndian<s64, LETag>::type;
740
741template <typename T>
742using enum_le = std::enable_if_t<std::is_enum_v<T>, typename AddEndian<T, LETag>::type>;
743
744using float_le = AddEndian<float, LETag>::type;
745using double_le = AddEndian<double, LETag>::type;
746
747// Aliases for BE types
748using u16_be = AddEndian<u16, BETag>::type;
749using u32_be = AddEndian<u32, BETag>::type;
750using u64_be = AddEndian<u64, BETag>::type;
751
752using s16_be = AddEndian<s16, BETag>::type;
753using s32_be = AddEndian<s32, BETag>::type;
754using s64_be = AddEndian<s64, BETag>::type;
755
756template <typename T>
757using enum_be = std::enable_if_t<std::is_enum_v<T>, typename AddEndian<T, BETag>::type>;
758
759using float_be = AddEndian<float, BETag>::type;
760using double_be = AddEndian<double, BETag>::type;
diff --git a/src/common/uint128.cpp b/src/common/uint128.cpp
index 2238a52c5..32bf56730 100644
--- a/src/common/uint128.cpp
+++ b/src/common/uint128.cpp
@@ -1,3 +1,7 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
1#ifdef _MSC_VER 5#ifdef _MSC_VER
2#include <intrin.h> 6#include <intrin.h>
3 7
diff --git a/src/common/uint128.h b/src/common/uint128.h
index 52e6b46eb..a3be2a2cb 100644
--- a/src/common/uint128.h
+++ b/src/common/uint128.h
@@ -1,3 +1,8 @@
1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
1 6
2#include <utility> 7#include <utility>
3#include "common/common_types.h" 8#include "common/common_types.h"
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 6319414ba..bbbe60896 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -31,6 +31,8 @@ add_library(core STATIC
31 file_sys/bis_factory.h 31 file_sys/bis_factory.h
32 file_sys/card_image.cpp 32 file_sys/card_image.cpp
33 file_sys/card_image.h 33 file_sys/card_image.h
34 file_sys/cheat_engine.cpp
35 file_sys/cheat_engine.h
34 file_sys/content_archive.cpp 36 file_sys/content_archive.cpp
35 file_sys/content_archive.h 37 file_sys/content_archive.h
36 file_sys/control_metadata.cpp 38 file_sys/control_metadata.cpp
@@ -107,6 +109,8 @@ add_library(core STATIC
107 hle/kernel/client_port.h 109 hle/kernel/client_port.h
108 hle/kernel/client_session.cpp 110 hle/kernel/client_session.cpp
109 hle/kernel/client_session.h 111 hle/kernel/client_session.h
112 hle/kernel/code_set.cpp
113 hle/kernel/code_set.h
110 hle/kernel/errors.h 114 hle/kernel/errors.h
111 hle/kernel/handle_table.cpp 115 hle/kernel/handle_table.cpp
112 hle/kernel/handle_table.h 116 hle/kernel/handle_table.h
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 89b3fb418..a88e332be 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -32,6 +32,7 @@
32#include "core/perf_stats.h" 32#include "core/perf_stats.h"
33#include "core/settings.h" 33#include "core/settings.h"
34#include "core/telemetry_session.h" 34#include "core/telemetry_session.h"
35#include "file_sys/cheat_engine.h"
35#include "frontend/applets/profile_select.h" 36#include "frontend/applets/profile_select.h"
36#include "frontend/applets/software_keyboard.h" 37#include "frontend/applets/software_keyboard.h"
37#include "frontend/applets/web_browser.h" 38#include "frontend/applets/web_browser.h"
@@ -205,6 +206,7 @@ struct System::Impl {
205 GDBStub::Shutdown(); 206 GDBStub::Shutdown();
206 Service::Shutdown(); 207 Service::Shutdown();
207 service_manager.reset(); 208 service_manager.reset();
209 cheat_engine.reset();
208 telemetry_session.reset(); 210 telemetry_session.reset();
209 gpu_core.reset(); 211 gpu_core.reset();
210 212
@@ -255,6 +257,8 @@ struct System::Impl {
255 CpuCoreManager cpu_core_manager; 257 CpuCoreManager cpu_core_manager;
256 bool is_powered_on = false; 258 bool is_powered_on = false;
257 259
260 std::unique_ptr<FileSys::CheatEngine> cheat_engine;
261
258 /// Frontend applets 262 /// Frontend applets
259 std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_selector; 263 std::unique_ptr<Core::Frontend::ProfileSelectApplet> profile_selector;
260 std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard; 264 std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard;
@@ -453,6 +457,13 @@ Tegra::DebugContext* System::GetGPUDebugContext() const {
453 return impl->debug_context.get(); 457 return impl->debug_context.get();
454} 458}
455 459
460void System::RegisterCheatList(const std::vector<FileSys::CheatList>& list,
461 const std::string& build_id, VAddr code_region_start,
462 VAddr code_region_end) {
463 impl->cheat_engine =
464 std::make_unique<FileSys::CheatEngine>(list, build_id, code_region_start, code_region_end);
465}
466
456void System::SetFilesystem(std::shared_ptr<FileSys::VfsFilesystem> vfs) { 467void System::SetFilesystem(std::shared_ptr<FileSys::VfsFilesystem> vfs) {
457 impl->virtual_filesystem = std::move(vfs); 468 impl->virtual_filesystem = std::move(vfs);
458} 469}
diff --git a/src/core/core.h b/src/core/core.h
index ba76a41d8..4d83b93cc 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -20,6 +20,7 @@ class WebBrowserApplet;
20} // namespace Core::Frontend 20} // namespace Core::Frontend
21 21
22namespace FileSys { 22namespace FileSys {
23class CheatList;
23class VfsFilesystem; 24class VfsFilesystem;
24} // namespace FileSys 25} // namespace FileSys
25 26
@@ -253,6 +254,9 @@ public:
253 254
254 std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const; 255 std::shared_ptr<FileSys::VfsFilesystem> GetFilesystem() const;
255 256
257 void RegisterCheatList(const std::vector<FileSys::CheatList>& list, const std::string& build_id,
258 VAddr code_region_start, VAddr code_region_end);
259
256 void SetProfileSelector(std::unique_ptr<Frontend::ProfileSelectApplet> applet); 260 void SetProfileSelector(std::unique_ptr<Frontend::ProfileSelectApplet> applet);
257 261
258 const Frontend::ProfileSelectApplet& GetProfileSelector() const; 262 const Frontend::ProfileSelectApplet& GetProfileSelector() const;
diff --git a/src/core/file_sys/cheat_engine.cpp b/src/core/file_sys/cheat_engine.cpp
new file mode 100644
index 000000000..09ca9d705
--- /dev/null
+++ b/src/core/file_sys/cheat_engine.cpp
@@ -0,0 +1,493 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <locale>
6#include "common/hex_util.h"
7#include "common/microprofile.h"
8#include "common/swap.h"
9#include "core/core.h"
10#include "core/core_timing.h"
11#include "core/core_timing_util.h"
12#include "core/file_sys/cheat_engine.h"
13#include "core/hle/kernel/process.h"
14#include "core/hle/service/hid/controllers/controller_base.h"
15#include "core/hle/service/hid/controllers/npad.h"
16#include "core/hle/service/hid/hid.h"
17#include "core/hle/service/sm/sm.h"
18
19namespace FileSys {
20
21constexpr u64 CHEAT_ENGINE_TICKS = Core::Timing::BASE_CLOCK_RATE / 60;
22constexpr u32 KEYPAD_BITMASK = 0x3FFFFFF;
23
24u64 Cheat::Address() const {
25 u64 out;
26 std::memcpy(&out, raw.data(), sizeof(u64));
27 return Common::swap64(out) & 0xFFFFFFFFFF;
28}
29
30u64 Cheat::ValueWidth(u64 offset) const {
31 return Value(offset, width);
32}
33
34u64 Cheat::Value(u64 offset, u64 width) const {
35 u64 out;
36 std::memcpy(&out, raw.data() + offset, sizeof(u64));
37 out = Common::swap64(out);
38 if (width == 8)
39 return out;
40 return out & ((1ull << (width * CHAR_BIT)) - 1);
41}
42
43u32 Cheat::KeypadValue() const {
44 u32 out;
45 std::memcpy(&out, raw.data(), sizeof(u32));
46 return Common::swap32(out) & 0x0FFFFFFF;
47}
48
49void CheatList::SetMemoryParameters(VAddr main_begin, VAddr heap_begin, VAddr main_end,
50 VAddr heap_end, MemoryWriter writer, MemoryReader reader) {
51 this->main_region_begin = main_begin;
52 this->main_region_end = main_end;
53 this->heap_region_begin = heap_begin;
54 this->heap_region_end = heap_end;
55 this->writer = writer;
56 this->reader = reader;
57}
58
59MICROPROFILE_DEFINE(Cheat_Engine, "Add-Ons", "Cheat Engine", MP_RGB(70, 200, 70));
60
61void CheatList::Execute() {
62 MICROPROFILE_SCOPE(Cheat_Engine);
63
64 std::fill(scratch.begin(), scratch.end(), 0);
65 in_standard = false;
66 for (std::size_t i = 0; i < master_list.size(); ++i) {
67 LOG_DEBUG(Common_Filesystem, "Executing block #{:08X} ({})", i, master_list[i].first);
68 current_block = i;
69 ExecuteBlock(master_list[i].second);
70 }
71
72 in_standard = true;
73 for (std::size_t i = 0; i < standard_list.size(); ++i) {
74 LOG_DEBUG(Common_Filesystem, "Executing block #{:08X} ({})", i, standard_list[i].first);
75 current_block = i;
76 ExecuteBlock(standard_list[i].second);
77 }
78}
79
80CheatList::CheatList(ProgramSegment master, ProgramSegment standard)
81 : master_list(master), standard_list(standard) {}
82
83bool CheatList::EvaluateConditional(const Cheat& cheat) const {
84 using ComparisonFunction = bool (*)(u64, u64);
85 constexpr std::array<ComparisonFunction, 6> comparison_functions{
86 [](u64 a, u64 b) { return a > b; }, [](u64 a, u64 b) { return a >= b; },
87 [](u64 a, u64 b) { return a < b; }, [](u64 a, u64 b) { return a <= b; },
88 [](u64 a, u64 b) { return a == b; }, [](u64 a, u64 b) { return a != b; },
89 };
90
91 if (cheat.type == CodeType::ConditionalInput) {
92 const auto applet_resource = Core::System::GetInstance()
93 .ServiceManager()
94 .GetService<Service::HID::Hid>("hid")
95 ->GetAppletResource();
96 if (applet_resource == nullptr) {
97 LOG_WARNING(
98 Common_Filesystem,
99 "Attempted to evaluate input conditional, but applet resource is not initialized!");
100 return false;
101 }
102
103 const auto press_state =
104 applet_resource
105 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)
106 .GetAndResetPressState();
107 return ((press_state & cheat.KeypadValue()) & KEYPAD_BITMASK) != 0;
108 }
109
110 ASSERT(cheat.type == CodeType::Conditional);
111
112 const auto offset =
113 cheat.memory_type == MemoryType::MainNSO ? main_region_begin : heap_region_begin;
114 ASSERT(static_cast<u8>(cheat.comparison_op.Value()) < 6);
115 auto* function = comparison_functions[static_cast<u8>(cheat.comparison_op.Value())];
116 const auto addr = cheat.Address() + offset;
117
118 return function(reader(cheat.width, SanitizeAddress(addr)), cheat.ValueWidth(8));
119}
120
121void CheatList::ProcessBlockPairs(const Block& block) {
122 block_pairs.clear();
123
124 u64 scope = 0;
125 std::map<u64, u64> pairs;
126
127 for (std::size_t i = 0; i < block.size(); ++i) {
128 const auto& cheat = block[i];
129
130 switch (cheat.type) {
131 case CodeType::Conditional:
132 case CodeType::ConditionalInput:
133 pairs.insert_or_assign(scope, i);
134 ++scope;
135 break;
136 case CodeType::EndConditional: {
137 --scope;
138 const auto idx = pairs.at(scope);
139 block_pairs.insert_or_assign(idx, i);
140 break;
141 }
142 case CodeType::Loop: {
143 if (cheat.end_of_loop) {
144 --scope;
145 const auto idx = pairs.at(scope);
146 block_pairs.insert_or_assign(idx, i);
147 } else {
148 pairs.insert_or_assign(scope, i);
149 ++scope;
150 }
151 break;
152 }
153 }
154 }
155}
156
157void CheatList::WriteImmediate(const Cheat& cheat) {
158 const auto offset =
159 cheat.memory_type == MemoryType::MainNSO ? main_region_begin : heap_region_begin;
160 const auto& register_3 = scratch.at(cheat.register_3);
161
162 const auto addr = cheat.Address() + offset + register_3;
163 LOG_DEBUG(Common_Filesystem, "writing value={:016X} to addr={:016X}", addr,
164 cheat.Value(8, cheat.width));
165 writer(cheat.width, SanitizeAddress(addr), cheat.ValueWidth(8));
166}
167
168void CheatList::BeginConditional(const Cheat& cheat) {
169 if (EvaluateConditional(cheat)) {
170 return;
171 }
172
173 const auto iter = block_pairs.find(current_index);
174 ASSERT(iter != block_pairs.end());
175 current_index = iter->second - 1;
176}
177
178void CheatList::EndConditional(const Cheat& cheat) {
179 LOG_DEBUG(Common_Filesystem, "Ending conditional block.");
180}
181
182void CheatList::Loop(const Cheat& cheat) {
183 if (cheat.end_of_loop.Value())
184 ASSERT(!cheat.end_of_loop.Value());
185
186 auto& register_3 = scratch.at(cheat.register_3);
187 const auto iter = block_pairs.find(current_index);
188 ASSERT(iter != block_pairs.end());
189 ASSERT(iter->first < iter->second);
190
191 for (int i = cheat.Value(4, 4); i >= 0; --i) {
192 register_3 = i;
193 for (std::size_t c = iter->first + 1; c < iter->second; ++c) {
194 current_index = c;
195 ExecuteSingleCheat(
196 (in_standard ? standard_list : master_list)[current_block].second[c]);
197 }
198 }
199
200 current_index = iter->second;
201}
202
203void CheatList::LoadImmediate(const Cheat& cheat) {
204 auto& register_3 = scratch.at(cheat.register_3);
205
206 LOG_DEBUG(Common_Filesystem, "setting register={:01X} equal to value={:016X}", cheat.register_3,
207 cheat.Value(4, 8));
208 register_3 = cheat.Value(4, 8);
209}
210
211void CheatList::LoadIndexed(const Cheat& cheat) {
212 const auto offset =
213 cheat.memory_type == MemoryType::MainNSO ? main_region_begin : heap_region_begin;
214 auto& register_3 = scratch.at(cheat.register_3);
215
216 const auto addr = (cheat.load_from_register.Value() ? register_3 : offset) + cheat.Address();
217 LOG_DEBUG(Common_Filesystem, "writing indexed value to register={:01X}, addr={:016X}",
218 cheat.register_3, addr);
219 register_3 = reader(cheat.width, SanitizeAddress(addr));
220}
221
222void CheatList::StoreIndexed(const Cheat& cheat) {
223 const auto& register_3 = scratch.at(cheat.register_3);
224
225 const auto addr =
226 register_3 + (cheat.add_additional_register.Value() ? scratch.at(cheat.register_6) : 0);
227 LOG_DEBUG(Common_Filesystem, "writing value={:016X} to addr={:016X}",
228 cheat.Value(4, cheat.width), addr);
229 writer(cheat.width, SanitizeAddress(addr), cheat.ValueWidth(4));
230}
231
232void CheatList::RegisterArithmetic(const Cheat& cheat) {
233 using ArithmeticFunction = u64 (*)(u64, u64);
234 constexpr std::array<ArithmeticFunction, 5> arithmetic_functions{
235 [](u64 a, u64 b) { return a + b; }, [](u64 a, u64 b) { return a - b; },
236 [](u64 a, u64 b) { return a * b; }, [](u64 a, u64 b) { return a << b; },
237 [](u64 a, u64 b) { return a >> b; },
238 };
239
240 using ArithmeticOverflowCheck = bool (*)(u64, u64);
241 constexpr std::array<ArithmeticOverflowCheck, 5> arithmetic_overflow_checks{
242 [](u64 a, u64 b) { return a > (std::numeric_limits<u64>::max() - b); }, // a + b
243 [](u64 a, u64 b) { return a > (std::numeric_limits<u64>::max() + b); }, // a - b
244 [](u64 a, u64 b) { return a > (std::numeric_limits<u64>::max() / b); }, // a * b
245 [](u64 a, u64 b) { return b >= 64 || (a & ~((1ull << (64 - b)) - 1)) != 0; }, // a << b
246 [](u64 a, u64 b) { return b >= 64 || (a & ((1ull << b) - 1)) != 0; }, // a >> b
247 };
248
249 static_assert(sizeof(arithmetic_functions) == sizeof(arithmetic_overflow_checks),
250 "Missing or have extra arithmetic overflow checks compared to functions!");
251
252 auto& register_3 = scratch.at(cheat.register_3);
253
254 ASSERT(static_cast<u8>(cheat.arithmetic_op.Value()) < 5);
255 auto* function = arithmetic_functions[static_cast<u8>(cheat.arithmetic_op.Value())];
256 auto* overflow_function =
257 arithmetic_overflow_checks[static_cast<u8>(cheat.arithmetic_op.Value())];
258 LOG_DEBUG(Common_Filesystem, "performing arithmetic with register={:01X}, value={:016X}",
259 cheat.register_3, cheat.ValueWidth(4));
260
261 if (overflow_function(register_3, cheat.ValueWidth(4))) {
262 LOG_WARNING(Common_Filesystem,
263 "overflow will occur when performing arithmetic operation={:02X} with operands "
264 "a={:016X}, b={:016X}!",
265 static_cast<u8>(cheat.arithmetic_op.Value()), register_3, cheat.ValueWidth(4));
266 }
267
268 register_3 = function(register_3, cheat.ValueWidth(4));
269}
270
271void CheatList::BeginConditionalInput(const Cheat& cheat) {
272 if (EvaluateConditional(cheat))
273 return;
274
275 const auto iter = block_pairs.find(current_index);
276 ASSERT(iter != block_pairs.end());
277 current_index = iter->second - 1;
278}
279
280VAddr CheatList::SanitizeAddress(VAddr in) const {
281 if ((in < main_region_begin || in >= main_region_end) &&
282 (in < heap_region_begin || in >= heap_region_end)) {
283 LOG_ERROR(Common_Filesystem,
284 "Cheat attempting to access memory at invalid address={:016X}, if this persists, "
285 "the cheat may be incorrect. However, this may be normal early in execution if "
286 "the game has not properly set up yet.",
287 in);
288 return 0; ///< Invalid addresses will hard crash
289 }
290
291 return in;
292}
293
294void CheatList::ExecuteSingleCheat(const Cheat& cheat) {
295 using CheatOperationFunction = void (CheatList::*)(const Cheat&);
296 constexpr std::array<CheatOperationFunction, 9> cheat_operation_functions{
297 &CheatList::WriteImmediate, &CheatList::BeginConditional,
298 &CheatList::EndConditional, &CheatList::Loop,
299 &CheatList::LoadImmediate, &CheatList::LoadIndexed,
300 &CheatList::StoreIndexed, &CheatList::RegisterArithmetic,
301 &CheatList::BeginConditionalInput,
302 };
303
304 const auto index = static_cast<u8>(cheat.type.Value());
305 ASSERT(index < sizeof(cheat_operation_functions));
306 const auto op = cheat_operation_functions[index];
307 (this->*op)(cheat);
308}
309
310void CheatList::ExecuteBlock(const Block& block) {
311 encountered_loops.clear();
312
313 ProcessBlockPairs(block);
314 for (std::size_t i = 0; i < block.size(); ++i) {
315 current_index = i;
316 ExecuteSingleCheat(block[i]);
317 i = current_index;
318 }
319}
320
321CheatParser::~CheatParser() = default;
322
323CheatList CheatParser::MakeCheatList(CheatList::ProgramSegment master,
324 CheatList::ProgramSegment standard) const {
325 return {master, standard};
326}
327
328TextCheatParser::~TextCheatParser() = default;
329
330CheatList TextCheatParser::Parse(const std::vector<u8>& data) const {
331 std::stringstream ss;
332 ss.write(reinterpret_cast<const char*>(data.data()), data.size());
333
334 std::vector<std::string> lines;
335 std::string stream_line;
336 while (std::getline(ss, stream_line)) {
337 // Remove a trailing \r
338 if (!stream_line.empty() && stream_line.back() == '\r')
339 stream_line.pop_back();
340 lines.push_back(std::move(stream_line));
341 }
342
343 CheatList::ProgramSegment master_list;
344 CheatList::ProgramSegment standard_list;
345
346 for (std::size_t i = 0; i < lines.size(); ++i) {
347 auto line = lines[i];
348
349 if (!line.empty() && (line[0] == '[' || line[0] == '{')) {
350 const auto master = line[0] == '{';
351 const auto begin = master ? line.find('{') : line.find('[');
352 const auto end = master ? line.rfind('}') : line.rfind(']');
353
354 ASSERT(begin != std::string::npos && end != std::string::npos);
355
356 const std::string patch_name{line.begin() + begin + 1, line.begin() + end};
357 CheatList::Block block{};
358
359 while (i < lines.size() - 1) {
360 line = lines[++i];
361 if (!line.empty() && (line[0] == '[' || line[0] == '{')) {
362 --i;
363 break;
364 }
365
366 if (line.size() < 8)
367 continue;
368
369 Cheat out{};
370 out.raw = ParseSingleLineCheat(line);
371 block.push_back(out);
372 }
373
374 (master ? master_list : standard_list).emplace_back(patch_name, block);
375 }
376 }
377
378 return MakeCheatList(master_list, standard_list);
379}
380
381std::array<u8, 16> TextCheatParser::ParseSingleLineCheat(const std::string& line) const {
382 std::array<u8, 16> out{};
383
384 if (line.size() < 8)
385 return out;
386
387 const auto word1 = Common::HexStringToArray<sizeof(u32)>(std::string_view{line.data(), 8});
388 std::memcpy(out.data(), word1.data(), sizeof(u32));
389
390 if (line.size() < 17 || line[8] != ' ')
391 return out;
392
393 const auto word2 = Common::HexStringToArray<sizeof(u32)>(std::string_view{line.data() + 9, 8});
394 std::memcpy(out.data() + sizeof(u32), word2.data(), sizeof(u32));
395
396 if (line.size() < 26 || line[17] != ' ') {
397 // Perform shifting in case value is truncated early.
398 const auto type = static_cast<CodeType>((out[0] & 0xF0) >> 4);
399 if (type == CodeType::Loop || type == CodeType::LoadImmediate ||
400 type == CodeType::StoreIndexed || type == CodeType::RegisterArithmetic) {
401 std::memcpy(out.data() + 8, out.data() + 4, sizeof(u32));
402 std::memset(out.data() + 4, 0, sizeof(u32));
403 }
404
405 return out;
406 }
407
408 const auto word3 = Common::HexStringToArray<sizeof(u32)>(std::string_view{line.data() + 18, 8});
409 std::memcpy(out.data() + 2 * sizeof(u32), word3.data(), sizeof(u32));
410
411 if (line.size() < 35 || line[26] != ' ') {
412 // Perform shifting in case value is truncated early.
413 const auto type = static_cast<CodeType>((out[0] & 0xF0) >> 4);
414 if (type == CodeType::WriteImmediate || type == CodeType::Conditional) {
415 std::memcpy(out.data() + 12, out.data() + 8, sizeof(u32));
416 std::memset(out.data() + 8, 0, sizeof(u32));
417 }
418
419 return out;
420 }
421
422 const auto word4 = Common::HexStringToArray<sizeof(u32)>(std::string_view{line.data() + 27, 8});
423 std::memcpy(out.data() + 3 * sizeof(u32), word4.data(), sizeof(u32));
424
425 return out;
426}
427
428u64 MemoryReadImpl(u32 width, VAddr addr) {
429 switch (width) {
430 case 1:
431 return Memory::Read8(addr);
432 case 2:
433 return Memory::Read16(addr);
434 case 4:
435 return Memory::Read32(addr);
436 case 8:
437 return Memory::Read64(addr);
438 default:
439 UNREACHABLE();
440 return 0;
441 }
442}
443
444void MemoryWriteImpl(u32 width, VAddr addr, u64 value) {
445 switch (width) {
446 case 1:
447 Memory::Write8(addr, static_cast<u8>(value));
448 break;
449 case 2:
450 Memory::Write16(addr, static_cast<u16>(value));
451 break;
452 case 4:
453 Memory::Write32(addr, static_cast<u32>(value));
454 break;
455 case 8:
456 Memory::Write64(addr, value);
457 break;
458 default:
459 UNREACHABLE();
460 }
461}
462
463CheatEngine::CheatEngine(std::vector<CheatList> cheats, const std::string& build_id,
464 VAddr code_region_start, VAddr code_region_end)
465 : cheats(std::move(cheats)) {
466 auto& core_timing{Core::System::GetInstance().CoreTiming()};
467 event = core_timing.RegisterEvent(
468 "CheatEngine::FrameCallback::" + build_id,
469 [this](u64 userdata, s64 cycles_late) { FrameCallback(userdata, cycles_late); });
470 core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS, event);
471
472 const auto& vm_manager = Core::System::GetInstance().CurrentProcess()->VMManager();
473 for (auto& list : this->cheats) {
474 list.SetMemoryParameters(code_region_start, vm_manager.GetHeapRegionBaseAddress(),
475 code_region_end, vm_manager.GetHeapRegionEndAddress(),
476 &MemoryWriteImpl, &MemoryReadImpl);
477 }
478}
479
480CheatEngine::~CheatEngine() {
481 auto& core_timing{Core::System::GetInstance().CoreTiming()};
482 core_timing.UnscheduleEvent(event, 0);
483}
484
485void CheatEngine::FrameCallback(u64 userdata, int cycles_late) {
486 for (auto& list : cheats)
487 list.Execute();
488
489 auto& core_timing{Core::System::GetInstance().CoreTiming()};
490 core_timing.ScheduleEvent(CHEAT_ENGINE_TICKS - cycles_late, event);
491}
492
493} // namespace FileSys
diff --git a/src/core/file_sys/cheat_engine.h b/src/core/file_sys/cheat_engine.h
new file mode 100644
index 000000000..7ed69a2c8
--- /dev/null
+++ b/src/core/file_sys/cheat_engine.h
@@ -0,0 +1,227 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <map>
8#include <set>
9#include <vector>
10#include <queue>
11#include "common/bit_field.h"
12#include "common/common_types.h"
13
14namespace Core::Timing {
15struct EventType;
16}
17
18namespace FileSys {
19
20enum class CodeType : u32 {
21 // 0TMR00AA AAAAAAAA YYYYYYYY YYYYYYYY
22 // Writes a T sized value Y to the address A added to the value of register R in memory domain M
23 WriteImmediate = 0,
24
25 // 1TMC00AA AAAAAAAA YYYYYYYY YYYYYYYY
26 // Compares the T sized value Y to the value at address A in memory domain M using the
27 // conditional function C. If success, continues execution. If failure, jumps to the matching
28 // EndConditional statement.
29 Conditional = 1,
30
31 // 20000000
32 // Terminates a Conditional or ConditionalInput block.
33 EndConditional = 2,
34
35 // 300R0000 VVVVVVVV
36 // Starts looping V times, storing the current count in register R.
37 // Loop block is terminated with a matching 310R0000.
38 Loop = 3,
39
40 // 400R0000 VVVVVVVV VVVVVVVV
41 // Sets the value of register R to the value V.
42 LoadImmediate = 4,
43
44 // 5TMRI0AA AAAAAAAA
45 // Sets the value of register R to the value of width T at address A in memory domain M, with
46 // the current value of R added to the address if I == 1.
47 LoadIndexed = 5,
48
49 // 6T0RIFG0 VVVVVVVV VVVVVVVV
50 // Writes the value V of width T to the memory address stored in register R. Adds the value of
51 // register G to the final calculation if F is nonzero. Increments the value of register R by T
52 // after operation if I is nonzero.
53 StoreIndexed = 6,
54
55 // 7T0RA000 VVVVVVVV
56 // Performs the arithmetic operation A on the value in register R and the value V of width T,
57 // storing the result in register R.
58 RegisterArithmetic = 7,
59
60 // 8KKKKKKK
61 // Checks to see if any of the buttons defined by the bitmask K are pressed. If any are,
62 // execution continues. If none are, execution skips to the next EndConditional command.
63 ConditionalInput = 8,
64};
65
66enum class MemoryType : u32 {
67 // Addressed relative to start of main NSO
68 MainNSO = 0,
69
70 // Addressed relative to start of heap
71 Heap = 1,
72};
73
74enum class ArithmeticOp : u32 {
75 Add = 0,
76 Sub = 1,
77 Mult = 2,
78 LShift = 3,
79 RShift = 4,
80};
81
82enum class ComparisonOp : u32 {
83 GreaterThan = 1,
84 GreaterThanEqual = 2,
85 LessThan = 3,
86 LessThanEqual = 4,
87 Equal = 5,
88 Inequal = 6,
89};
90
91union Cheat {
92 std::array<u8, 16> raw;
93
94 BitField<4, 4, CodeType> type;
95 BitField<0, 4, u32> width; // Can be 1, 2, 4, or 8. Measured in bytes.
96 BitField<0, 4, u32> end_of_loop;
97 BitField<12, 4, MemoryType> memory_type;
98 BitField<8, 4, u32> register_3;
99 BitField<8, 4, ComparisonOp> comparison_op;
100 BitField<20, 4, u32> load_from_register;
101 BitField<20, 4, u32> increment_register;
102 BitField<20, 4, ArithmeticOp> arithmetic_op;
103 BitField<16, 4, u32> add_additional_register;
104 BitField<28, 4, u32> register_6;
105
106 u64 Address() const;
107 u64 ValueWidth(u64 offset) const;
108 u64 Value(u64 offset, u64 width) const;
109 u32 KeypadValue() const;
110};
111
112class CheatParser;
113
114// Represents a full collection of cheats for a game. The Execute function should be called every
115// interval that all cheats should be executed. Clients should not directly instantiate this class
116// (hence private constructor), they should instead receive an instance from CheatParser, which
117// guarantees the list is always in an acceptable state.
118class CheatList {
119public:
120 friend class CheatParser;
121
122 using Block = std::vector<Cheat>;
123 using ProgramSegment = std::vector<std::pair<std::string, Block>>;
124
125 // (width in bytes, address, value)
126 using MemoryWriter = void (*)(u32, VAddr, u64);
127 // (width in bytes, address) -> value
128 using MemoryReader = u64 (*)(u32, VAddr);
129
130 void SetMemoryParameters(VAddr main_begin, VAddr heap_begin, VAddr main_end, VAddr heap_end,
131 MemoryWriter writer, MemoryReader reader);
132
133 void Execute();
134
135private:
136 CheatList(ProgramSegment master, ProgramSegment standard);
137
138 void ProcessBlockPairs(const Block& block);
139 void ExecuteSingleCheat(const Cheat& cheat);
140
141 void ExecuteBlock(const Block& block);
142
143 bool EvaluateConditional(const Cheat& cheat) const;
144
145 // Individual cheat operations
146 void WriteImmediate(const Cheat& cheat);
147 void BeginConditional(const Cheat& cheat);
148 void EndConditional(const Cheat& cheat);
149 void Loop(const Cheat& cheat);
150 void LoadImmediate(const Cheat& cheat);
151 void LoadIndexed(const Cheat& cheat);
152 void StoreIndexed(const Cheat& cheat);
153 void RegisterArithmetic(const Cheat& cheat);
154 void BeginConditionalInput(const Cheat& cheat);
155
156 VAddr SanitizeAddress(VAddr in) const;
157
158 // Master Codes are defined as codes that cannot be disabled and are run prior to all
159 // others.
160 ProgramSegment master_list;
161 // All other codes
162 ProgramSegment standard_list;
163
164 bool in_standard = false;
165
166 // 16 (0x0-0xF) scratch registers that can be used by cheats
167 std::array<u64, 16> scratch{};
168
169 MemoryWriter writer = nullptr;
170 MemoryReader reader = nullptr;
171
172 u64 main_region_begin{};
173 u64 heap_region_begin{};
174 u64 main_region_end{};
175 u64 heap_region_end{};
176
177 u64 current_block{};
178 // The current index of the cheat within the current Block
179 u64 current_index{};
180
181 // The 'stack' of the program. When a conditional or loop statement is encountered, its index is
182 // pushed onto this queue. When a end block is encountered, the condition is checked.
183 std::map<u64, u64> block_pairs;
184
185 std::set<u64> encountered_loops;
186};
187
188// Intermediary class that parses a text file or other disk format for storing cheats into a
189// CheatList object, that can be used for execution.
190class CheatParser {
191public:
192 virtual ~CheatParser();
193
194 virtual CheatList Parse(const std::vector<u8>& data) const = 0;
195
196protected:
197 CheatList MakeCheatList(CheatList::ProgramSegment master,
198 CheatList::ProgramSegment standard) const;
199};
200
201// CheatParser implementation that parses text files
202class TextCheatParser final : public CheatParser {
203public:
204 ~TextCheatParser() override;
205
206 CheatList Parse(const std::vector<u8>& data) const override;
207
208private:
209 std::array<u8, 16> ParseSingleLineCheat(const std::string& line) const;
210};
211
212// Class that encapsulates a CheatList and manages its interaction with memory and CoreTiming
213class CheatEngine final {
214public:
215 CheatEngine(std::vector<CheatList> cheats, const std::string& build_id, VAddr code_region_start,
216 VAddr code_region_end);
217 ~CheatEngine();
218
219private:
220 void FrameCallback(u64 userdata, int cycles_late);
221
222 Core::Timing::EventType* event;
223
224 std::vector<CheatList> cheats;
225};
226
227} // namespace FileSys
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index 5d4d05c82..15b9e6624 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -24,13 +24,26 @@ namespace FileSys {
24 24
25union NCASectionHeader; 25union NCASectionHeader;
26 26
27/// Describes the type of content within an NCA archive.
27enum class NCAContentType : u8 { 28enum class NCAContentType : u8 {
29 /// Executable-related data
28 Program = 0, 30 Program = 0,
31
32 /// Metadata.
29 Meta = 1, 33 Meta = 1,
34
35 /// Access control data.
30 Control = 2, 36 Control = 2,
37
38 /// Information related to the game manual
39 /// e.g. Legal information, etc.
31 Manual = 3, 40 Manual = 3,
41
42 /// System data.
32 Data = 4, 43 Data = 4,
33 Data_Unknown5 = 5, ///< Seems to be used on some system archives 44
45 /// Data that can be accessed by applications.
46 PublicData = 5,
34}; 47};
35 48
36enum class NCASectionCryptoType : u8 { 49enum class NCASectionCryptoType : u8 {
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 61706966e..2b09e5d35 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -7,6 +7,7 @@
7#include <cstddef> 7#include <cstddef>
8#include <cstring> 8#include <cstring>
9 9
10#include "common/file_util.h"
10#include "common/hex_util.h" 11#include "common/hex_util.h"
11#include "common/logging/log.h" 12#include "common/logging/log.h"
12#include "core/file_sys/content_archive.h" 13#include "core/file_sys/content_archive.h"
@@ -232,6 +233,57 @@ bool PatchManager::HasNSOPatch(const std::array<u8, 32>& build_id_) const {
232 return !CollectPatches(patch_dirs, build_id).empty(); 233 return !CollectPatches(patch_dirs, build_id).empty();
233} 234}
234 235
236static std::optional<CheatList> ReadCheatFileFromFolder(u64 title_id,
237 const std::array<u8, 0x20>& build_id_,
238 const VirtualDir& base_path, bool upper) {
239 const auto build_id_raw = Common::HexArrayToString(build_id_, upper);
240 const auto build_id = build_id_raw.substr(0, sizeof(u64) * 2);
241 const auto file = base_path->GetFile(fmt::format("{}.txt", build_id));
242
243 if (file == nullptr) {
244 LOG_INFO(Common_Filesystem, "No cheats file found for title_id={:016X}, build_id={}",
245 title_id, build_id);
246 return std::nullopt;
247 }
248
249 std::vector<u8> data(file->GetSize());
250 if (file->Read(data.data(), data.size()) != data.size()) {
251 LOG_INFO(Common_Filesystem, "Failed to read cheats file for title_id={:016X}, build_id={}",
252 title_id, build_id);
253 return std::nullopt;
254 }
255
256 TextCheatParser parser;
257 return parser.Parse(data);
258}
259
260std::vector<CheatList> PatchManager::CreateCheatList(const std::array<u8, 32>& build_id_) const {
261 std::vector<CheatList> out;
262
263 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
264 auto patch_dirs = load_dir->GetSubdirectories();
265 std::sort(patch_dirs.begin(), patch_dirs.end(),
266 [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
267
268 out.reserve(patch_dirs.size());
269 for (const auto& subdir : patch_dirs) {
270 auto cheats_dir = subdir->GetSubdirectory("cheats");
271 if (cheats_dir != nullptr) {
272 auto res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, true);
273 if (res.has_value()) {
274 out.push_back(std::move(*res));
275 continue;
276 }
277
278 res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, false);
279 if (res.has_value())
280 out.push_back(std::move(*res));
281 }
282 }
283
284 return out;
285}
286
235static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) { 287static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) {
236 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); 288 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
237 if ((type != ContentRecordType::Program && type != ContentRecordType::Data) || 289 if ((type != ContentRecordType::Program && type != ContentRecordType::Data) ||
@@ -403,6 +455,8 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
403 } 455 }
404 if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs"))) 456 if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs")))
405 AppendCommaIfNotEmpty(types, "LayeredFS"); 457 AppendCommaIfNotEmpty(types, "LayeredFS");
458 if (IsDirValidAndNonEmpty(mod->GetSubdirectory("cheats")))
459 AppendCommaIfNotEmpty(types, "Cheats");
406 460
407 if (types.empty()) 461 if (types.empty())
408 continue; 462 continue;
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index b8a1652fd..3e3ac6aca 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -8,6 +8,7 @@
8#include <memory> 8#include <memory>
9#include <string> 9#include <string>
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/file_sys/cheat_engine.h"
11#include "core/file_sys/nca_metadata.h" 12#include "core/file_sys/nca_metadata.h"
12#include "core/file_sys/vfs.h" 13#include "core/file_sys/vfs.h"
13 14
@@ -45,6 +46,9 @@ public:
45 // Used to prevent expensive copies in NSO loader. 46 // Used to prevent expensive copies in NSO loader.
46 bool HasNSOPatch(const std::array<u8, 0x20>& build_id) const; 47 bool HasNSOPatch(const std::array<u8, 0x20>& build_id) const;
47 48
49 // Creates a CheatList object with all
50 std::vector<CheatList> CreateCheatList(const std::array<u8, 0x20>& build_id) const;
51
48 // Currently tracked RomFS patches: 52 // Currently tracked RomFS patches:
49 // - Game Updates 53 // - Game Updates
50 // - LayeredFS 54 // - LayeredFS
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 128199063..1c6bacace 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -94,7 +94,7 @@ static ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
94 case NCAContentType::Control: 94 case NCAContentType::Control:
95 return ContentRecordType::Control; 95 return ContentRecordType::Control;
96 case NCAContentType::Data: 96 case NCAContentType::Data:
97 case NCAContentType::Data_Unknown5: 97 case NCAContentType::PublicData:
98 return ContentRecordType::Data; 98 return ContentRecordType::Data;
99 case NCAContentType::Manual: 99 case NCAContentType::Manual:
100 // TODO(DarkLordZach): Peek at NCA contents to differentiate Manual and Legal. 100 // TODO(DarkLordZach): Peek at NCA contents to differentiate Manual and Legal.
diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h
index 455d1f346..fae54bcc7 100644
--- a/src/core/hle/ipc.h
+++ b/src/core/hle/ipc.h
@@ -39,10 +39,10 @@ struct CommandHeader {
39 union { 39 union {
40 u32_le raw_low; 40 u32_le raw_low;
41 BitField<0, 16, CommandType> type; 41 BitField<0, 16, CommandType> type;
42 BitField<16, 4, u32_le> num_buf_x_descriptors; 42 BitField<16, 4, u32> num_buf_x_descriptors;
43 BitField<20, 4, u32_le> num_buf_a_descriptors; 43 BitField<20, 4, u32> num_buf_a_descriptors;
44 BitField<24, 4, u32_le> num_buf_b_descriptors; 44 BitField<24, 4, u32> num_buf_b_descriptors;
45 BitField<28, 4, u32_le> num_buf_w_descriptors; 45 BitField<28, 4, u32> num_buf_w_descriptors;
46 }; 46 };
47 47
48 enum class BufferDescriptorCFlag : u32 { 48 enum class BufferDescriptorCFlag : u32 {
@@ -53,28 +53,28 @@ struct CommandHeader {
53 53
54 union { 54 union {
55 u32_le raw_high; 55 u32_le raw_high;
56 BitField<0, 10, u32_le> data_size; 56 BitField<0, 10, u32> data_size;
57 BitField<10, 4, BufferDescriptorCFlag> buf_c_descriptor_flags; 57 BitField<10, 4, BufferDescriptorCFlag> buf_c_descriptor_flags;
58 BitField<31, 1, u32_le> enable_handle_descriptor; 58 BitField<31, 1, u32> enable_handle_descriptor;
59 }; 59 };
60}; 60};
61static_assert(sizeof(CommandHeader) == 8, "CommandHeader size is incorrect"); 61static_assert(sizeof(CommandHeader) == 8, "CommandHeader size is incorrect");
62 62
63union HandleDescriptorHeader { 63union HandleDescriptorHeader {
64 u32_le raw_high; 64 u32_le raw_high;
65 BitField<0, 1, u32_le> send_current_pid; 65 BitField<0, 1, u32> send_current_pid;
66 BitField<1, 4, u32_le> num_handles_to_copy; 66 BitField<1, 4, u32> num_handles_to_copy;
67 BitField<5, 4, u32_le> num_handles_to_move; 67 BitField<5, 4, u32> num_handles_to_move;
68}; 68};
69static_assert(sizeof(HandleDescriptorHeader) == 4, "HandleDescriptorHeader size is incorrect"); 69static_assert(sizeof(HandleDescriptorHeader) == 4, "HandleDescriptorHeader size is incorrect");
70 70
71struct BufferDescriptorX { 71struct BufferDescriptorX {
72 union { 72 union {
73 BitField<0, 6, u32_le> counter_bits_0_5; 73 BitField<0, 6, u32> counter_bits_0_5;
74 BitField<6, 3, u32_le> address_bits_36_38; 74 BitField<6, 3, u32> address_bits_36_38;
75 BitField<9, 3, u32_le> counter_bits_9_11; 75 BitField<9, 3, u32> counter_bits_9_11;
76 BitField<12, 4, u32_le> address_bits_32_35; 76 BitField<12, 4, u32> address_bits_32_35;
77 BitField<16, 16, u32_le> size; 77 BitField<16, 16, u32> size;
78 }; 78 };
79 79
80 u32_le address_bits_0_31; 80 u32_le address_bits_0_31;
@@ -103,10 +103,10 @@ struct BufferDescriptorABW {
103 u32_le address_bits_0_31; 103 u32_le address_bits_0_31;
104 104
105 union { 105 union {
106 BitField<0, 2, u32_le> flags; 106 BitField<0, 2, u32> flags;
107 BitField<2, 3, u32_le> address_bits_36_38; 107 BitField<2, 3, u32> address_bits_36_38;
108 BitField<24, 4, u32_le> size_bits_32_35; 108 BitField<24, 4, u32> size_bits_32_35;
109 BitField<28, 4, u32_le> address_bits_32_35; 109 BitField<28, 4, u32> address_bits_32_35;
110 }; 110 };
111 111
112 VAddr Address() const { 112 VAddr Address() const {
@@ -128,8 +128,8 @@ struct BufferDescriptorC {
128 u32_le address_bits_0_31; 128 u32_le address_bits_0_31;
129 129
130 union { 130 union {
131 BitField<0, 16, u32_le> address_bits_32_47; 131 BitField<0, 16, u32> address_bits_32_47;
132 BitField<16, 16, u32_le> size; 132 BitField<16, 16, u32> size;
133 }; 133 };
134 134
135 VAddr Address() const { 135 VAddr Address() const {
@@ -167,8 +167,8 @@ struct DomainMessageHeader {
167 struct { 167 struct {
168 union { 168 union {
169 BitField<0, 8, CommandType> command; 169 BitField<0, 8, CommandType> command;
170 BitField<8, 8, u32_le> input_object_count; 170 BitField<8, 8, u32> input_object_count;
171 BitField<16, 16, u32_le> size; 171 BitField<16, 16, u32> size;
172 }; 172 };
173 u32_le object_id; 173 u32_le object_id;
174 INSERT_PADDING_WORDS(2); 174 INSERT_PADDING_WORDS(2);
diff --git a/src/core/hle/kernel/code_set.cpp b/src/core/hle/kernel/code_set.cpp
new file mode 100644
index 000000000..1f434e9af
--- /dev/null
+++ b/src/core/hle/kernel/code_set.cpp
@@ -0,0 +1,12 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/kernel/code_set.h"
6
7namespace Kernel {
8
9CodeSet::CodeSet() = default;
10CodeSet::~CodeSet() = default;
11
12} // namespace Kernel
diff --git a/src/core/hle/kernel/code_set.h b/src/core/hle/kernel/code_set.h
new file mode 100644
index 000000000..834fd23d2
--- /dev/null
+++ b/src/core/hle/kernel/code_set.h
@@ -0,0 +1,90 @@
1// Copyright 2019 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cstddef>
8#include <memory>
9#include <vector>
10
11#include "common/common_types.h"
12
13namespace Kernel {
14
15/**
16 * Represents executable data that may be loaded into a kernel process.
17 *
18 * A code set consists of three basic segments:
19 * - A code (AKA text) segment,
20 * - A read-only data segment (rodata)
21 * - A data segment
22 *
23 * The code segment is the portion of the object file that contains
24 * executable instructions.
25 *
26 * The read-only data segment in the portion of the object file that
27 * contains (as one would expect) read-only data, such as fixed constant
28 * values and data structures.
29 *
30 * The data segment is similar to the read-only data segment -- it contains
31 * variables and data structures that have predefined values, however,
32 * entities within this segment can be modified.
33 */
34struct CodeSet final {
35 /// A single segment within a code set.
36 struct Segment final {
37 /// The byte offset that this segment is located at.
38 std::size_t offset = 0;
39
40 /// The address to map this segment to.
41 VAddr addr = 0;
42
43 /// The size of this segment in bytes.
44 u32 size = 0;
45 };
46
47 explicit CodeSet();
48 ~CodeSet();
49
50 CodeSet(const CodeSet&) = delete;
51 CodeSet& operator=(const CodeSet&) = delete;
52
53 CodeSet(CodeSet&&) = default;
54 CodeSet& operator=(CodeSet&&) = default;
55
56 Segment& CodeSegment() {
57 return segments[0];
58 }
59
60 const Segment& CodeSegment() const {
61 return segments[0];
62 }
63
64 Segment& RODataSegment() {
65 return segments[1];
66 }
67
68 const Segment& RODataSegment() const {
69 return segments[1];
70 }
71
72 Segment& DataSegment() {
73 return segments[2];
74 }
75
76 const Segment& DataSegment() const {
77 return segments[2];
78 }
79
80 /// The overall data that backs this code set.
81 std::shared_ptr<std::vector<u8>> memory;
82
83 /// The segments that comprise this code set.
84 std::array<Segment, 3> segments;
85
86 /// The entry point address for this code set.
87 VAddr entrypoint = 0;
88};
89
90} // namespace Kernel
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 0743670ad..98e87313b 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -2,7 +2,6 @@
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 <map>
6#include <utility> 5#include <utility>
7#include <vector> 6#include <vector>
8 7
@@ -10,8 +9,11 @@
10#include "core/core.h" 9#include "core/core.h"
11#include "core/hle/kernel/errors.h" 10#include "core/hle/kernel/errors.h"
12#include "core/hle/kernel/handle_table.h" 11#include "core/hle/kernel/handle_table.h"
12#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/mutex.h" 13#include "core/hle/kernel/mutex.h"
14#include "core/hle/kernel/object.h" 14#include "core/hle/kernel/object.h"
15#include "core/hle/kernel/process.h"
16#include "core/hle/kernel/scheduler.h"
15#include "core/hle/kernel/thread.h" 17#include "core/hle/kernel/thread.h"
16#include "core/hle/result.h" 18#include "core/hle/result.h"
17#include "core/memory.h" 19#include "core/memory.h"
@@ -57,41 +59,47 @@ static void TransferMutexOwnership(VAddr mutex_addr, SharedPtr<Thread> current_t
57 } 59 }
58} 60}
59 61
60ResultCode Mutex::TryAcquire(HandleTable& handle_table, VAddr address, Handle holding_thread_handle, 62Mutex::Mutex(Core::System& system) : system{system} {}
63Mutex::~Mutex() = default;
64
65ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle,
61 Handle requesting_thread_handle) { 66 Handle requesting_thread_handle) {
62 // The mutex address must be 4-byte aligned 67 // The mutex address must be 4-byte aligned
63 if ((address % sizeof(u32)) != 0) { 68 if ((address % sizeof(u32)) != 0) {
64 return ERR_INVALID_ADDRESS; 69 return ERR_INVALID_ADDRESS;
65 } 70 }
66 71
72 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
73 Thread* const current_thread = system.CurrentScheduler().GetCurrentThread();
67 SharedPtr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle); 74 SharedPtr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle);
68 SharedPtr<Thread> requesting_thread = handle_table.Get<Thread>(requesting_thread_handle); 75 SharedPtr<Thread> requesting_thread = handle_table.Get<Thread>(requesting_thread_handle);
69 76
70 // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another 77 // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another
71 // thread. 78 // thread.
72 ASSERT(requesting_thread == GetCurrentThread()); 79 ASSERT(requesting_thread == current_thread);
73 80
74 u32 addr_value = Memory::Read32(address); 81 const u32 addr_value = Memory::Read32(address);
75 82
76 // If the mutex isn't being held, just return success. 83 // If the mutex isn't being held, just return success.
77 if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) { 84 if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) {
78 return RESULT_SUCCESS; 85 return RESULT_SUCCESS;
79 } 86 }
80 87
81 if (holding_thread == nullptr) 88 if (holding_thread == nullptr) {
82 return ERR_INVALID_HANDLE; 89 return ERR_INVALID_HANDLE;
90 }
83 91
84 // Wait until the mutex is released 92 // Wait until the mutex is released
85 GetCurrentThread()->SetMutexWaitAddress(address); 93 current_thread->SetMutexWaitAddress(address);
86 GetCurrentThread()->SetWaitHandle(requesting_thread_handle); 94 current_thread->SetWaitHandle(requesting_thread_handle);
87 95
88 GetCurrentThread()->SetStatus(ThreadStatus::WaitMutex); 96 current_thread->SetStatus(ThreadStatus::WaitMutex);
89 GetCurrentThread()->InvalidateWakeupCallback(); 97 current_thread->InvalidateWakeupCallback();
90 98
91 // Update the lock holder thread's priority to prevent priority inversion. 99 // Update the lock holder thread's priority to prevent priority inversion.
92 holding_thread->AddMutexWaiter(GetCurrentThread()); 100 holding_thread->AddMutexWaiter(current_thread);
93 101
94 Core::System::GetInstance().PrepareReschedule(); 102 system.PrepareReschedule();
95 103
96 return RESULT_SUCCESS; 104 return RESULT_SUCCESS;
97} 105}
@@ -102,7 +110,8 @@ ResultCode Mutex::Release(VAddr address) {
102 return ERR_INVALID_ADDRESS; 110 return ERR_INVALID_ADDRESS;
103 } 111 }
104 112
105 auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(GetCurrentThread(), address); 113 auto* const current_thread = system.CurrentScheduler().GetCurrentThread();
114 auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(current_thread, address);
106 115
107 // There are no more threads waiting for the mutex, release it completely. 116 // There are no more threads waiting for the mutex, release it completely.
108 if (thread == nullptr) { 117 if (thread == nullptr) {
@@ -111,7 +120,7 @@ ResultCode Mutex::Release(VAddr address) {
111 } 120 }
112 121
113 // Transfer the ownership of the mutex from the previous owner to the new one. 122 // Transfer the ownership of the mutex from the previous owner to the new one.
114 TransferMutexOwnership(address, GetCurrentThread(), thread); 123 TransferMutexOwnership(address, current_thread, thread);
115 124
116 u32 mutex_value = thread->GetWaitHandle(); 125 u32 mutex_value = thread->GetWaitHandle();
117 126
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 81e62d497..b904de2e8 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -5,32 +5,34 @@
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/hle/kernel/object.h"
9 8
10union ResultCode; 9union ResultCode;
11 10
12namespace Kernel { 11namespace Core {
12class System;
13}
13 14
14class HandleTable; 15namespace Kernel {
15class Thread;
16 16
17class Mutex final { 17class Mutex final {
18public: 18public:
19 explicit Mutex(Core::System& system);
20 ~Mutex();
21
19 /// Flag that indicates that a mutex still has threads waiting for it. 22 /// Flag that indicates that a mutex still has threads waiting for it.
20 static constexpr u32 MutexHasWaitersFlag = 0x40000000; 23 static constexpr u32 MutexHasWaitersFlag = 0x40000000;
21 /// Mask of the bits in a mutex address value that contain the mutex owner. 24 /// Mask of the bits in a mutex address value that contain the mutex owner.
22 static constexpr u32 MutexOwnerMask = 0xBFFFFFFF; 25 static constexpr u32 MutexOwnerMask = 0xBFFFFFFF;
23 26
24 /// Attempts to acquire a mutex at the specified address. 27 /// Attempts to acquire a mutex at the specified address.
25 static ResultCode TryAcquire(HandleTable& handle_table, VAddr address, 28 ResultCode TryAcquire(VAddr address, Handle holding_thread_handle,
26 Handle holding_thread_handle, Handle requesting_thread_handle); 29 Handle requesting_thread_handle);
27 30
28 /// Releases the mutex at the specified address. 31 /// Releases the mutex at the specified address.
29 static ResultCode Release(VAddr address); 32 ResultCode Release(VAddr address);
30 33
31private: 34private:
32 Mutex() = default; 35 Core::System& system;
33 ~Mutex() = default;
34}; 36};
35 37
36} // namespace Kernel 38} // namespace Kernel
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 65c51003d..0d782e4ba 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -9,6 +9,7 @@
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "core/core.h" 10#include "core/core.h"
11#include "core/file_sys/program_metadata.h" 11#include "core/file_sys/program_metadata.h"
12#include "core/hle/kernel/code_set.h"
12#include "core/hle/kernel/errors.h" 13#include "core/hle/kernel/errors.h"
13#include "core/hle/kernel/kernel.h" 14#include "core/hle/kernel/kernel.h"
14#include "core/hle/kernel/process.h" 15#include "core/hle/kernel/process.h"
@@ -50,9 +51,6 @@ void SetupMainThread(Process& owner_process, KernelCore& kernel, VAddr entry_poi
50} 51}
51} // Anonymous namespace 52} // Anonymous namespace
52 53
53CodeSet::CodeSet() = default;
54CodeSet::~CodeSet() = default;
55
56SharedPtr<Process> Process::Create(Core::System& system, std::string&& name) { 54SharedPtr<Process> Process::Create(Core::System& system, std::string&& name) {
57 auto& kernel = system.Kernel(); 55 auto& kernel = system.Kernel();
58 56
@@ -212,7 +210,7 @@ void Process::FreeTLSSlot(VAddr tls_address) {
212} 210}
213 211
214void Process::LoadModule(CodeSet module_, VAddr base_addr) { 212void Process::LoadModule(CodeSet module_, VAddr base_addr) {
215 const auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, 213 const auto MapSegment = [&](const CodeSet::Segment& segment, VMAPermission permissions,
216 MemoryState memory_state) { 214 MemoryState memory_state) {
217 const auto vma = vm_manager 215 const auto vma = vm_manager
218 .MapMemoryBlock(segment.addr + base_addr, module_.memory, 216 .MapMemoryBlock(segment.addr + base_addr, module_.memory,
@@ -222,16 +220,17 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) {
222 }; 220 };
223 221
224 // Map CodeSet segments 222 // Map CodeSet segments
225 MapSegment(module_.CodeSegment(), VMAPermission::ReadExecute, MemoryState::CodeStatic); 223 MapSegment(module_.CodeSegment(), VMAPermission::ReadExecute, MemoryState::Code);
226 MapSegment(module_.RODataSegment(), VMAPermission::Read, MemoryState::CodeMutable); 224 MapSegment(module_.RODataSegment(), VMAPermission::Read, MemoryState::CodeData);
227 MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeMutable); 225 MapSegment(module_.DataSegment(), VMAPermission::ReadWrite, MemoryState::CodeData);
228 226
229 // Clear instruction cache in CPU JIT 227 // Clear instruction cache in CPU JIT
230 system.InvalidateCpuInstructionCaches(); 228 system.InvalidateCpuInstructionCaches();
231} 229}
232 230
233Process::Process(Core::System& system) 231Process::Process(Core::System& system)
234 : WaitObject{system.Kernel()}, address_arbiter{system}, system{system} {} 232 : WaitObject{system.Kernel()}, address_arbiter{system}, mutex{system}, system{system} {}
233
235Process::~Process() = default; 234Process::~Process() = default;
236 235
237void Process::Acquire(Thread* thread) { 236void Process::Acquire(Thread* thread) {
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 47ffd4ad3..1bd7bf5c1 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -7,13 +7,13 @@
7#include <array> 7#include <array>
8#include <bitset> 8#include <bitset>
9#include <cstddef> 9#include <cstddef>
10#include <memory>
11#include <string> 10#include <string>
12#include <vector> 11#include <vector>
13#include <boost/container/static_vector.hpp> 12#include <boost/container/static_vector.hpp>
14#include "common/common_types.h" 13#include "common/common_types.h"
15#include "core/hle/kernel/address_arbiter.h" 14#include "core/hle/kernel/address_arbiter.h"
16#include "core/hle/kernel/handle_table.h" 15#include "core/hle/kernel/handle_table.h"
16#include "core/hle/kernel/mutex.h"
17#include "core/hle/kernel/process_capability.h" 17#include "core/hle/kernel/process_capability.h"
18#include "core/hle/kernel/vm_manager.h" 18#include "core/hle/kernel/vm_manager.h"
19#include "core/hle/kernel/wait_object.h" 19#include "core/hle/kernel/wait_object.h"
@@ -33,6 +33,8 @@ class KernelCore;
33class ResourceLimit; 33class ResourceLimit;
34class Thread; 34class Thread;
35 35
36struct CodeSet;
37
36struct AddressMapping { 38struct AddressMapping {
37 // Address and size must be page-aligned 39 // Address and size must be page-aligned
38 VAddr address; 40 VAddr address;
@@ -65,46 +67,6 @@ enum class ProcessStatus {
65 DebugBreak, 67 DebugBreak,
66}; 68};
67 69
68struct CodeSet final {
69 struct Segment {
70 std::size_t offset = 0;
71 VAddr addr = 0;
72 u32 size = 0;
73 };
74
75 explicit CodeSet();
76 ~CodeSet();
77
78 Segment& CodeSegment() {
79 return segments[0];
80 }
81
82 const Segment& CodeSegment() const {
83 return segments[0];
84 }
85
86 Segment& RODataSegment() {
87 return segments[1];
88 }
89
90 const Segment& RODataSegment() const {
91 return segments[1];
92 }
93
94 Segment& DataSegment() {
95 return segments[2];
96 }
97
98 const Segment& DataSegment() const {
99 return segments[2];
100 }
101
102 std::shared_ptr<std::vector<u8>> memory;
103
104 std::array<Segment, 3> segments;
105 VAddr entrypoint = 0;
106};
107
108class Process final : public WaitObject { 70class Process final : public WaitObject {
109public: 71public:
110 enum : u64 { 72 enum : u64 {
@@ -165,6 +127,16 @@ public:
165 return address_arbiter; 127 return address_arbiter;
166 } 128 }
167 129
130 /// Gets a reference to the process' mutex lock.
131 Mutex& GetMutex() {
132 return mutex;
133 }
134
135 /// Gets a const reference to the process' mutex lock
136 const Mutex& GetMutex() const {
137 return mutex;
138 }
139
168 /// Gets the current status of the process 140 /// Gets the current status of the process
169 ProcessStatus GetStatus() const { 141 ProcessStatus GetStatus() const {
170 return status; 142 return status;
@@ -327,6 +299,11 @@ private:
327 /// Per-process address arbiter. 299 /// Per-process address arbiter.
328 AddressArbiter address_arbiter; 300 AddressArbiter address_arbiter;
329 301
302 /// The per-process mutex lock instance used for handling various
303 /// forms of services, such as lock arbitration, and condition
304 /// variable related facilities.
305 Mutex mutex;
306
330 /// Random values for svcGetInfo RandomEntropy 307 /// Random values for svcGetInfo RandomEntropy
331 std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy; 308 std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy;
332 309
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 047fa0c19..a6a17efe7 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -551,9 +551,9 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
551 return ERR_INVALID_ADDRESS; 551 return ERR_INVALID_ADDRESS;
552 } 552 }
553 553
554 auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 554 auto* const current_process = Core::System::GetInstance().Kernel().CurrentProcess();
555 return Mutex::TryAcquire(handle_table, mutex_addr, holding_thread_handle, 555 return current_process->GetMutex().TryAcquire(mutex_addr, holding_thread_handle,
556 requesting_thread_handle); 556 requesting_thread_handle);
557} 557}
558 558
559/// Unlock a mutex 559/// Unlock a mutex
@@ -571,7 +571,8 @@ static ResultCode ArbitrateUnlock(VAddr mutex_addr) {
571 return ERR_INVALID_ADDRESS; 571 return ERR_INVALID_ADDRESS;
572 } 572 }
573 573
574 return Mutex::Release(mutex_addr); 574 auto* const current_process = Core::System::GetInstance().Kernel().CurrentProcess();
575 return current_process->GetMutex().Release(mutex_addr);
575} 576}
576 577
577enum class BreakType : u32 { 578enum class BreakType : u32 {
@@ -1340,11 +1341,15 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
1340 "called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}", 1341 "called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}",
1341 mutex_addr, condition_variable_addr, thread_handle, nano_seconds); 1342 mutex_addr, condition_variable_addr, thread_handle, nano_seconds);
1342 1343
1343 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 1344 auto* const current_process = Core::System::GetInstance().Kernel().CurrentProcess();
1345 const auto& handle_table = current_process->GetHandleTable();
1344 SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); 1346 SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
1345 ASSERT(thread); 1347 ASSERT(thread);
1346 1348
1347 CASCADE_CODE(Mutex::Release(mutex_addr)); 1349 const auto release_result = current_process->GetMutex().Release(mutex_addr);
1350 if (release_result.IsError()) {
1351 return release_result;
1352 }
1348 1353
1349 SharedPtr<Thread> current_thread = GetCurrentThread(); 1354 SharedPtr<Thread> current_thread = GetCurrentThread();
1350 current_thread->SetCondVarWaitAddress(condition_variable_addr); 1355 current_thread->SetCondVarWaitAddress(condition_variable_addr);
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 3def3e52c..22bf55ce7 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -20,16 +20,16 @@ namespace Kernel {
20namespace { 20namespace {
21const char* GetMemoryStateName(MemoryState state) { 21const char* GetMemoryStateName(MemoryState state) {
22 static constexpr const char* names[] = { 22 static constexpr const char* names[] = {
23 "Unmapped", "Io", 23 "Unmapped", "Io",
24 "Normal", "CodeStatic", 24 "Normal", "Code",
25 "CodeMutable", "Heap", 25 "CodeData", "Heap",
26 "Shared", "Unknown1", 26 "Shared", "Unknown1",
27 "ModuleCodeStatic", "ModuleCodeMutable", 27 "ModuleCode", "ModuleCodeData",
28 "IpcBuffer0", "Stack", 28 "IpcBuffer0", "Stack",
29 "ThreadLocal", "TransferMemoryIsolated", 29 "ThreadLocal", "TransferMemoryIsolated",
30 "TransferMemory", "ProcessMemory", 30 "TransferMemory", "ProcessMemory",
31 "Inaccessible", "IpcBuffer1", 31 "Inaccessible", "IpcBuffer1",
32 "IpcBuffer3", "KernelStack", 32 "IpcBuffer3", "KernelStack",
33 }; 33 };
34 34
35 return names[ToSvcMemoryState(state)]; 35 return names[ToSvcMemoryState(state)];
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index b96980f8f..7cdff6094 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -165,12 +165,12 @@ enum class MemoryState : u32 {
165 Unmapped = 0x00, 165 Unmapped = 0x00,
166 Io = 0x01 | FlagMapped, 166 Io = 0x01 | FlagMapped,
167 Normal = 0x02 | FlagMapped | FlagQueryPhysicalAddressAllowed, 167 Normal = 0x02 | FlagMapped | FlagQueryPhysicalAddressAllowed,
168 CodeStatic = 0x03 | CodeFlags | FlagMapProcess, 168 Code = 0x03 | CodeFlags | FlagMapProcess,
169 CodeMutable = 0x04 | CodeFlags | FlagMapProcess | FlagCodeMemory, 169 CodeData = 0x04 | DataFlags | FlagMapProcess | FlagCodeMemory,
170 Heap = 0x05 | DataFlags | FlagCodeMemory, 170 Heap = 0x05 | DataFlags | FlagCodeMemory,
171 Shared = 0x06 | FlagMapped | FlagMemoryPoolAllocated, 171 Shared = 0x06 | FlagMapped | FlagMemoryPoolAllocated,
172 ModuleCodeStatic = 0x08 | CodeFlags | FlagModule | FlagMapProcess, 172 ModuleCode = 0x08 | CodeFlags | FlagModule | FlagMapProcess,
173 ModuleCodeMutable = 0x09 | DataFlags | FlagModule | FlagMapProcess | FlagCodeMemory, 173 ModuleCodeData = 0x09 | DataFlags | FlagModule | FlagMapProcess | FlagCodeMemory,
174 174
175 IpcBuffer0 = 0x0A | FlagMapped | FlagQueryPhysicalAddressAllowed | FlagMemoryPoolAllocated | 175 IpcBuffer0 = 0x0A | FlagMapped | FlagQueryPhysicalAddressAllowed | FlagMemoryPoolAllocated |
176 IPCFlags | FlagSharedDevice | FlagSharedDeviceAligned, 176 IPCFlags | FlagSharedDevice | FlagSharedDeviceAligned,
@@ -617,6 +617,9 @@ private:
617 VAddr new_map_region_base = 0; 617 VAddr new_map_region_base = 0;
618 VAddr new_map_region_end = 0; 618 VAddr new_map_region_end = 0;
619 619
620 VAddr main_code_region_base = 0;
621 VAddr main_code_region_end = 0;
622
620 VAddr tls_io_region_base = 0; 623 VAddr tls_io_region_base = 0;
621 VAddr tls_io_region_end = 0; 624 VAddr tls_io_region_end = 0;
622 625
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index c750d70ac..9c44e27c6 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -215,7 +215,21 @@ IDisplayController::IDisplayController() : ServiceFramework("IDisplayController"
215 215
216IDisplayController::~IDisplayController() = default; 216IDisplayController::~IDisplayController() = default;
217 217
218IDebugFunctions::IDebugFunctions() : ServiceFramework("IDebugFunctions") {} 218IDebugFunctions::IDebugFunctions() : ServiceFramework{"IDebugFunctions"} {
219 // clang-format off
220 static const FunctionInfo functions[] = {
221 {0, nullptr, "NotifyMessageToHomeMenuForDebug"},
222 {1, nullptr, "OpenMainApplication"},
223 {10, nullptr, "EmulateButtonEvent"},
224 {20, nullptr, "InvalidateTransitionLayer"},
225 {30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"},
226 {40, nullptr, "GetAppletResourceUsageInfo"},
227 };
228 // clang-format on
229
230 RegisterHandlers(functions);
231}
232
219IDebugFunctions::~IDebugFunctions() = default; 233IDebugFunctions::~IDebugFunctions() = default;
220 234
221ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) 235ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h
index 929035034..e584b92ec 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.h
+++ b/src/core/hle/service/hid/controllers/debug_pad.h
@@ -41,20 +41,20 @@ private:
41 struct PadState { 41 struct PadState {
42 union { 42 union {
43 u32_le raw{}; 43 u32_le raw{};
44 BitField<0, 1, u32_le> a; 44 BitField<0, 1, u32> a;
45 BitField<1, 1, u32_le> b; 45 BitField<1, 1, u32> b;
46 BitField<2, 1, u32_le> x; 46 BitField<2, 1, u32> x;
47 BitField<3, 1, u32_le> y; 47 BitField<3, 1, u32> y;
48 BitField<4, 1, u32_le> l; 48 BitField<4, 1, u32> l;
49 BitField<5, 1, u32_le> r; 49 BitField<5, 1, u32> r;
50 BitField<6, 1, u32_le> zl; 50 BitField<6, 1, u32> zl;
51 BitField<7, 1, u32_le> zr; 51 BitField<7, 1, u32> zr;
52 BitField<8, 1, u32_le> plus; 52 BitField<8, 1, u32> plus;
53 BitField<9, 1, u32_le> minus; 53 BitField<9, 1, u32> minus;
54 BitField<10, 1, u32_le> d_left; 54 BitField<10, 1, u32> d_left;
55 BitField<11, 1, u32_le> d_up; 55 BitField<11, 1, u32> d_up;
56 BitField<12, 1, u32_le> d_right; 56 BitField<12, 1, u32> d_right;
57 BitField<13, 1, u32_le> d_down; 57 BitField<13, 1, u32> d_down;
58 }; 58 };
59 }; 59 };
60 static_assert(sizeof(PadState) == 0x4, "PadState is an invalid size"); 60 static_assert(sizeof(PadState) == 0x4, "PadState is an invalid size");
@@ -62,7 +62,7 @@ private:
62 struct Attributes { 62 struct Attributes {
63 union { 63 union {
64 u32_le raw{}; 64 u32_le raw{};
65 BitField<0, 1, u32_le> connected; 65 BitField<0, 1, u32> connected;
66 }; 66 };
67 }; 67 };
68 static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); 68 static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size");
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 18c7a94e6..4ff50b3cd 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -39,13 +39,13 @@ public:
39 union { 39 union {
40 u32_le raw{}; 40 u32_le raw{};
41 41
42 BitField<0, 1, u32_le> pro_controller; 42 BitField<0, 1, u32> pro_controller;
43 BitField<1, 1, u32_le> handheld; 43 BitField<1, 1, u32> handheld;
44 BitField<2, 1, u32_le> joycon_dual; 44 BitField<2, 1, u32> joycon_dual;
45 BitField<3, 1, u32_le> joycon_left; 45 BitField<3, 1, u32> joycon_left;
46 BitField<4, 1, u32_le> joycon_right; 46 BitField<4, 1, u32> joycon_right;
47 47
48 BitField<6, 1, u32_le> pokeball; // TODO(ogniK): Confirm when possible 48 BitField<6, 1, u32> pokeball; // TODO(ogniK): Confirm when possible
49 }; 49 };
50 }; 50 };
51 static_assert(sizeof(NPadType) == 4, "NPadType is an invalid size"); 51 static_assert(sizeof(NPadType) == 4, "NPadType is an invalid size");
@@ -150,43 +150,43 @@ private:
150 union { 150 union {
151 u64_le raw{}; 151 u64_le raw{};
152 // Button states 152 // Button states
153 BitField<0, 1, u64_le> a; 153 BitField<0, 1, u64> a;
154 BitField<1, 1, u64_le> b; 154 BitField<1, 1, u64> b;
155 BitField<2, 1, u64_le> x; 155 BitField<2, 1, u64> x;
156 BitField<3, 1, u64_le> y; 156 BitField<3, 1, u64> y;
157 BitField<4, 1, u64_le> l_stick; 157 BitField<4, 1, u64> l_stick;
158 BitField<5, 1, u64_le> r_stick; 158 BitField<5, 1, u64> r_stick;
159 BitField<6, 1, u64_le> l; 159 BitField<6, 1, u64> l;
160 BitField<7, 1, u64_le> r; 160 BitField<7, 1, u64> r;
161 BitField<8, 1, u64_le> zl; 161 BitField<8, 1, u64> zl;
162 BitField<9, 1, u64_le> zr; 162 BitField<9, 1, u64> zr;
163 BitField<10, 1, u64_le> plus; 163 BitField<10, 1, u64> plus;
164 BitField<11, 1, u64_le> minus; 164 BitField<11, 1, u64> minus;
165 165
166 // D-Pad 166 // D-Pad
167 BitField<12, 1, u64_le> d_left; 167 BitField<12, 1, u64> d_left;
168 BitField<13, 1, u64_le> d_up; 168 BitField<13, 1, u64> d_up;
169 BitField<14, 1, u64_le> d_right; 169 BitField<14, 1, u64> d_right;
170 BitField<15, 1, u64_le> d_down; 170 BitField<15, 1, u64> d_down;
171 171
172 // Left JoyStick 172 // Left JoyStick
173 BitField<16, 1, u64_le> l_stick_left; 173 BitField<16, 1, u64> l_stick_left;
174 BitField<17, 1, u64_le> l_stick_up; 174 BitField<17, 1, u64> l_stick_up;
175 BitField<18, 1, u64_le> l_stick_right; 175 BitField<18, 1, u64> l_stick_right;
176 BitField<19, 1, u64_le> l_stick_down; 176 BitField<19, 1, u64> l_stick_down;
177 177
178 // Right JoyStick 178 // Right JoyStick
179 BitField<20, 1, u64_le> r_stick_left; 179 BitField<20, 1, u64> r_stick_left;
180 BitField<21, 1, u64_le> r_stick_up; 180 BitField<21, 1, u64> r_stick_up;
181 BitField<22, 1, u64_le> r_stick_right; 181 BitField<22, 1, u64> r_stick_right;
182 BitField<23, 1, u64_le> r_stick_down; 182 BitField<23, 1, u64> r_stick_down;
183 183
184 // Not always active? 184 // Not always active?
185 BitField<24, 1, u64_le> left_sl; 185 BitField<24, 1, u64> left_sl;
186 BitField<25, 1, u64_le> left_sr; 186 BitField<25, 1, u64> left_sr;
187 187
188 BitField<26, 1, u64_le> right_sl; 188 BitField<26, 1, u64> right_sl;
189 BitField<27, 1, u64_le> right_sr; 189 BitField<27, 1, u64> right_sr;
190 }; 190 };
191 }; 191 };
192 static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size"); 192 static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size");
@@ -200,12 +200,12 @@ private:
200 struct ConnectionState { 200 struct ConnectionState {
201 union { 201 union {
202 u32_le raw{}; 202 u32_le raw{};
203 BitField<0, 1, u32_le> IsConnected; 203 BitField<0, 1, u32> IsConnected;
204 BitField<1, 1, u32_le> IsWired; 204 BitField<1, 1, u32> IsWired;
205 BitField<2, 1, u32_le> IsLeftJoyConnected; 205 BitField<2, 1, u32> IsLeftJoyConnected;
206 BitField<3, 1, u32_le> IsLeftJoyWired; 206 BitField<3, 1, u32> IsLeftJoyWired;
207 BitField<4, 1, u32_le> IsRightJoyConnected; 207 BitField<4, 1, u32> IsRightJoyConnected;
208 BitField<5, 1, u32_le> IsRightJoyWired; 208 BitField<5, 1, u32> IsRightJoyWired;
209 }; 209 };
210 }; 210 };
211 static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size"); 211 static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size");
@@ -240,23 +240,23 @@ private:
240 struct NPadProperties { 240 struct NPadProperties {
241 union { 241 union {
242 s64_le raw{}; 242 s64_le raw{};
243 BitField<11, 1, s64_le> is_vertical; 243 BitField<11, 1, s64> is_vertical;
244 BitField<12, 1, s64_le> is_horizontal; 244 BitField<12, 1, s64> is_horizontal;
245 BitField<13, 1, s64_le> use_plus; 245 BitField<13, 1, s64> use_plus;
246 BitField<14, 1, s64_le> use_minus; 246 BitField<14, 1, s64> use_minus;
247 }; 247 };
248 }; 248 };
249 249
250 struct NPadDevice { 250 struct NPadDevice {
251 union { 251 union {
252 u32_le raw{}; 252 u32_le raw{};
253 BitField<0, 1, s32_le> pro_controller; 253 BitField<0, 1, s32> pro_controller;
254 BitField<1, 1, s32_le> handheld; 254 BitField<1, 1, s32> handheld;
255 BitField<2, 1, s32_le> handheld_left; 255 BitField<2, 1, s32> handheld_left;
256 BitField<3, 1, s32_le> handheld_right; 256 BitField<3, 1, s32> handheld_right;
257 BitField<4, 1, s32_le> joycon_left; 257 BitField<4, 1, s32> joycon_left;
258 BitField<5, 1, s32_le> joycon_right; 258 BitField<5, 1, s32> joycon_right;
259 BitField<6, 1, s32_le> pokeball; 259 BitField<6, 1, s32> pokeball;
260 }; 260 };
261 }; 261 };
262 262
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
index 012b6e0dd..76fc340e9 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.h
+++ b/src/core/hle/service/hid/controllers/touchscreen.h
@@ -33,8 +33,8 @@ private:
33 struct Attributes { 33 struct Attributes {
34 union { 34 union {
35 u32 raw{}; 35 u32 raw{};
36 BitField<0, 1, u32_le> start_touch; 36 BitField<0, 1, u32> start_touch;
37 BitField<1, 1, u32_le> end_touch; 37 BitField<1, 1, u32> end_touch;
38 }; 38 };
39 }; 39 };
40 static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); 40 static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size");
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 7cc58db4c..498602de5 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -4,6 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/hle/service/hid/controllers/controller_base.h"
8#include "core/hle/service/service.h"
9
7#include "controllers/controller_base.h" 10#include "controllers/controller_base.h"
8#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
9 12
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index 9df7ac50f..d65693fc7 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -319,15 +319,14 @@ public:
319 } 319 }
320 320
321 ASSERT(vm_manager 321 ASSERT(vm_manager
322 .MirrorMemory(*map_address, nro_addr, nro_size, 322 .MirrorMemory(*map_address, nro_addr, nro_size, Kernel::MemoryState::ModuleCode)
323 Kernel::MemoryState::ModuleCodeStatic)
324 .IsSuccess()); 323 .IsSuccess());
325 ASSERT(vm_manager.UnmapRange(nro_addr, nro_size).IsSuccess()); 324 ASSERT(vm_manager.UnmapRange(nro_addr, nro_size).IsSuccess());
326 325
327 if (bss_size > 0) { 326 if (bss_size > 0) {
328 ASSERT(vm_manager 327 ASSERT(vm_manager
329 .MirrorMemory(*map_address + nro_size, bss_addr, bss_size, 328 .MirrorMemory(*map_address + nro_size, bss_addr, bss_size,
330 Kernel::MemoryState::ModuleCodeStatic) 329 Kernel::MemoryState::ModuleCode)
331 .IsSuccess()); 330 .IsSuccess());
332 ASSERT(vm_manager.UnmapRange(bss_addr, bss_size).IsSuccess()); 331 ASSERT(vm_manager.UnmapRange(bss_addr, bss_size).IsSuccess());
333 } 332 }
@@ -388,8 +387,7 @@ public:
388 const auto& nro_size = iter->second.size; 387 const auto& nro_size = iter->second.size;
389 388
390 ASSERT(vm_manager 389 ASSERT(vm_manager
391 .MirrorMemory(heap_addr, mapped_addr, nro_size, 390 .MirrorMemory(heap_addr, mapped_addr, nro_size, Kernel::MemoryState::ModuleCode)
392 Kernel::MemoryState::ModuleCodeStatic)
393 .IsSuccess()); 391 .IsSuccess());
394 ASSERT(vm_manager.UnmapRange(mapped_addr, nro_size).IsSuccess()); 392 ASSERT(vm_manager.UnmapRange(mapped_addr, nro_size).IsSuccess());
395 393
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp
index 1f462e087..2a61593e2 100644
--- a/src/core/hle/service/lm/lm.cpp
+++ b/src/core/hle/service/lm/lm.cpp
@@ -42,7 +42,7 @@ private:
42 union { 42 union {
43 BitField<0, 16, Flags> flags; 43 BitField<0, 16, Flags> flags;
44 BitField<16, 8, Severity> severity; 44 BitField<16, 8, Severity> severity;
45 BitField<24, 8, u32_le> verbosity; 45 BitField<24, 8, u32> verbosity;
46 }; 46 };
47 u32_le payload_size; 47 u32_le payload_size;
48 48
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h
index 0f02a1a18..4f6042b00 100644
--- a/src/core/hle/service/nvdrv/devices/nvdevice.h
+++ b/src/core/hle/service/nvdrv/devices/nvdevice.h
@@ -19,11 +19,11 @@ public:
19 virtual ~nvdevice() = default; 19 virtual ~nvdevice() = default;
20 union Ioctl { 20 union Ioctl {
21 u32_le raw; 21 u32_le raw;
22 BitField<0, 8, u32_le> cmd; 22 BitField<0, 8, u32> cmd;
23 BitField<8, 8, u32_le> group; 23 BitField<8, 8, u32> group;
24 BitField<16, 14, u32_le> length; 24 BitField<16, 14, u32> length;
25 BitField<30, 1, u32_le> is_in; 25 BitField<30, 1, u32> is_in;
26 BitField<31, 1, u32_le> is_out; 26 BitField<31, 1, u32> is_out;
27 }; 27 };
28 28
29 /** 29 /**
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 6057c7f26..8b1920f22 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -9,6 +9,7 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/file_util.h" 10#include "common/file_util.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "core/hle/kernel/code_set.h"
12#include "core/hle/kernel/process.h" 13#include "core/hle/kernel/process.h"
13#include "core/hle/kernel/vm_manager.h" 14#include "core/hle/kernel/vm_manager.h"
14#include "core/loader/elf.h" 15#include "core/loader/elf.h"
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 4fad0c0dd..5de02a94b 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -14,6 +14,7 @@
14#include "core/file_sys/romfs_factory.h" 14#include "core/file_sys/romfs_factory.h"
15#include "core/file_sys/vfs_offset.h" 15#include "core/file_sys/vfs_offset.h"
16#include "core/gdbstub/gdbstub.h" 16#include "core/gdbstub/gdbstub.h"
17#include "core/hle/kernel/code_set.h"
17#include "core/hle/kernel/process.h" 18#include "core/hle/kernel/process.h"
18#include "core/hle/kernel/vm_manager.h" 19#include "core/hle/kernel/vm_manager.h"
19#include "core/hle/service/filesystem/filesystem.h" 20#include "core/hle/service/filesystem/filesystem.h"
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 6ded0b707..0eb9fd7f7 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -7,10 +7,13 @@
7#include <lz4.h> 7#include <lz4.h>
8#include "common/common_funcs.h" 8#include "common/common_funcs.h"
9#include "common/file_util.h" 9#include "common/file_util.h"
10#include "common/hex_util.h"
10#include "common/logging/log.h" 11#include "common/logging/log.h"
11#include "common/swap.h" 12#include "common/swap.h"
13#include "core/core.h"
12#include "core/file_sys/patch_manager.h" 14#include "core/file_sys/patch_manager.h"
13#include "core/gdbstub/gdbstub.h" 15#include "core/gdbstub/gdbstub.h"
16#include "core/hle/kernel/code_set.h"
14#include "core/hle/kernel/process.h" 17#include "core/hle/kernel/process.h"
15#include "core/hle/kernel/vm_manager.h" 18#include "core/hle/kernel/vm_manager.h"
16#include "core/loader/nso.h" 19#include "core/loader/nso.h"
@@ -164,6 +167,16 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
164 std::memcpy(program_image.data(), pi_header.data() + 0x100, program_image.size()); 167 std::memcpy(program_image.data(), pi_header.data() + 0x100, program_image.size());
165 } 168 }
166 169
170 // Apply cheats if they exist and the program has a valid title ID
171 if (pm) {
172 const auto cheats = pm->CreateCheatList(nso_header.build_id);
173 if (!cheats.empty()) {
174 Core::System::GetInstance().RegisterCheatList(
175 cheats, Common::HexArrayToString(nso_header.build_id), load_base,
176 load_base + program_image.size());
177 }
178 }
179
167 // Load codeset for current process 180 // Load codeset for current process
168 codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image)); 181 codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image));
169 process.LoadModule(std::move(codeset), load_base); 182 process.LoadModule(std::move(codeset), load_base);
diff --git a/src/core/memory.h b/src/core/memory.h
index 3f60d868c..1d38cdca8 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -6,9 +6,6 @@
6 6
7#include <cstddef> 7#include <cstddef>
8#include <string> 8#include <string>
9#include <tuple>
10#include <vector>
11#include <boost/icl/interval_map.hpp>
12#include "common/common_types.h" 9#include "common/common_types.h"
13 10
14namespace Common { 11namespace Common {
diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h
index 02a8d2e2c..d7f24c68a 100644
--- a/src/input_common/sdl/sdl.h
+++ b/src/input_common/sdl/sdl.h
@@ -24,17 +24,19 @@ namespace InputCommon::SDL {
24 24
25class State { 25class State {
26public: 26public:
27 /// Unresisters SDL device factories and shut them down. 27 using Pollers = std::vector<std::unique_ptr<Polling::DevicePoller>>;
28
29 /// Unregisters SDL device factories and shut them down.
28 virtual ~State() = default; 30 virtual ~State() = default;
29 31
30 virtual std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> GetPollers( 32 virtual Pollers GetPollers(Polling::DeviceType type) = 0;
31 InputCommon::Polling::DeviceType type) = 0;
32}; 33};
33 34
34class NullState : public State { 35class NullState : public State {
35public: 36public:
36 std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> GetPollers( 37 Pollers GetPollers(Polling::DeviceType type) override {
37 InputCommon::Polling::DeviceType type) override {} 38 return {};
39 }
38}; 40};
39 41
40std::unique_ptr<State> Init(); 42std::unique_ptr<State> Init();
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 6e8376549..b132d77f5 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -650,9 +650,9 @@ private:
650}; 650};
651} // namespace Polling 651} // namespace Polling
652 652
653std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> SDLState::GetPollers( 653SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
654 InputCommon::Polling::DeviceType type) { 654 Pollers pollers;
655 std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> pollers; 655
656 switch (type) { 656 switch (type) {
657 case InputCommon::Polling::DeviceType::Analog: 657 case InputCommon::Polling::DeviceType::Analog:
658 pollers.emplace_back(std::make_unique<Polling::SDLAnalogPoller>(*this)); 658 pollers.emplace_back(std::make_unique<Polling::SDLAnalogPoller>(*this));
@@ -660,8 +660,9 @@ std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> SDLState::GetPo
660 case InputCommon::Polling::DeviceType::Button: 660 case InputCommon::Polling::DeviceType::Button:
661 pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this)); 661 pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this));
662 break; 662 break;
663 return pollers;
664 } 663 }
664
665 return pollers;
665} 666}
666 667
667} // namespace SDL 668} // namespace SDL
diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h
index fec82fbe6..2579741d6 100644
--- a/src/input_common/sdl/sdl_impl.h
+++ b/src/input_common/sdl/sdl_impl.h
@@ -25,7 +25,7 @@ public:
25 /// Initializes and registers SDL device factories 25 /// Initializes and registers SDL device factories
26 SDLState(); 26 SDLState();
27 27
28 /// Unresisters SDL device factories and shut them down. 28 /// Unregisters SDL device factories and shut them down.
29 ~SDLState() override; 29 ~SDLState() override;
30 30
31 /// Handle SDL_Events for joysticks from SDL_PollEvent 31 /// Handle SDL_Events for joysticks from SDL_PollEvent
@@ -35,8 +35,7 @@ public:
35 std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port); 35 std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port);
36 36
37 /// Get all DevicePoller that use the SDL backend for a specific device type 37 /// Get all DevicePoller that use the SDL backend for a specific device type
38 std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> GetPollers( 38 Pollers GetPollers(Polling::DeviceType type) override;
39 InputCommon::Polling::DeviceType type) override;
40 39
41 /// Used by the Pollers during config 40 /// Used by the Pollers during config
42 std::atomic<bool> polling = false; 41 std::atomic<bool> polling = false;
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 37f09ce5f..d0284bdf4 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -1,4 +1,5 @@
1add_executable(tests 1add_executable(tests
2 common/bit_field.cpp
2 common/param_package.cpp 3 common/param_package.cpp
3 common/ring_buffer.cpp 4 common/ring_buffer.cpp
4 core/arm/arm_test_common.cpp 5 core/arm/arm_test_common.cpp
diff --git a/src/tests/common/bit_field.cpp b/src/tests/common/bit_field.cpp
new file mode 100644
index 000000000..8ca1889f9
--- /dev/null
+++ b/src/tests/common/bit_field.cpp
@@ -0,0 +1,90 @@
1// Copyright 2019 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <array>
6#include <cstring>
7#include <type_traits>
8#include <catch2/catch.hpp>
9#include "common/bit_field.h"
10
11TEST_CASE("BitField", "[common]") {
12 enum class TestEnum : u32 {
13 A = 0b10111101,
14 B = 0b10101110,
15 C = 0b00001111,
16 };
17
18 union LEBitField {
19 u32_le raw;
20 BitField<0, 6, u32> a;
21 BitField<6, 4, s32> b;
22 BitField<10, 8, TestEnum> c;
23 BitField<18, 14, u32> d;
24 } le_bitfield;
25
26 union BEBitField {
27 u32_be raw;
28 BitFieldBE<0, 6, u32> a;
29 BitFieldBE<6, 4, s32> b;
30 BitFieldBE<10, 8, TestEnum> c;
31 BitFieldBE<18, 14, u32> d;
32 } be_bitfield;
33
34 static_assert(sizeof(LEBitField) == sizeof(u32));
35 static_assert(sizeof(BEBitField) == sizeof(u32));
36 static_assert(std::is_trivially_copyable_v<LEBitField>);
37 static_assert(std::is_trivially_copyable_v<BEBitField>);
38
39 std::array<u8, 4> raw{{
40 0b01101100,
41 0b11110110,
42 0b10111010,
43 0b11101100,
44 }};
45
46 std::memcpy(&le_bitfield, &raw, sizeof(raw));
47 std::memcpy(&be_bitfield, &raw, sizeof(raw));
48
49 // bit fields: 11101100101110'10111101'1001'101100
50 REQUIRE(le_bitfield.raw == 0b11101100'10111010'11110110'01101100);
51 REQUIRE(le_bitfield.a == 0b101100);
52 REQUIRE(le_bitfield.b == -7); // 1001 as two's complement
53 REQUIRE(le_bitfield.c == TestEnum::A);
54 REQUIRE(le_bitfield.d == 0b11101100101110);
55
56 le_bitfield.a.Assign(0b000111);
57 le_bitfield.b.Assign(-1);
58 le_bitfield.c.Assign(TestEnum::C);
59 le_bitfield.d.Assign(0b01010101010101);
60 std::memcpy(&raw, &le_bitfield, sizeof(raw));
61 // bit fields: 01010101010101'00001111'1111'000111
62 REQUIRE(le_bitfield.raw == 0b01010101'01010100'00111111'11000111);
63 REQUIRE(raw == std::array<u8, 4>{{
64 0b11000111,
65 0b00111111,
66 0b01010100,
67 0b01010101,
68 }});
69
70 // bit fields: 01101100111101'10101110'1011'101100
71 REQUIRE(be_bitfield.raw == 0b01101100'11110110'10111010'11101100);
72 REQUIRE(be_bitfield.a == 0b101100);
73 REQUIRE(be_bitfield.b == -5); // 1011 as two's complement
74 REQUIRE(be_bitfield.c == TestEnum::B);
75 REQUIRE(be_bitfield.d == 0b01101100111101);
76
77 be_bitfield.a.Assign(0b000111);
78 be_bitfield.b.Assign(-1);
79 be_bitfield.c.Assign(TestEnum::C);
80 be_bitfield.d.Assign(0b01010101010101);
81 std::memcpy(&raw, &be_bitfield, sizeof(raw));
82 // bit fields: 01010101010101'00001111'1111'000111
83 REQUIRE(be_bitfield.raw == 0b01010101'01010100'00111111'11000111);
84 REQUIRE(raw == std::array<u8, 4>{{
85 0b01010101,
86 0b01010100,
87 0b00111111,
88 0b11000111,
89 }});
90}
diff --git a/src/video_core/rasterizer_cache.h b/src/video_core/rasterizer_cache.h
index ecd9986a0..9fc9f3056 100644
--- a/src/video_core/rasterizer_cache.h
+++ b/src/video_core/rasterizer_cache.h
@@ -132,7 +132,7 @@ protected:
132 } 132 }
133 133
134 /// Register an object into the cache 134 /// Register an object into the cache
135 void Register(const T& object) { 135 virtual void Register(const T& object) {
136 std::lock_guard<std::recursive_mutex> lock{mutex}; 136 std::lock_guard<std::recursive_mutex> lock{mutex};
137 137
138 object->SetIsRegistered(true); 138 object->SetIsRegistered(true);
@@ -142,7 +142,7 @@ protected:
142 } 142 }
143 143
144 /// Unregisters an object from the cache 144 /// Unregisters an object from the cache
145 void Unregister(const T& object) { 145 virtual void Unregister(const T& object) {
146 std::lock_guard<std::recursive_mutex> lock{mutex}; 146 std::lock_guard<std::recursive_mutex> lock{mutex};
147 147
148 object->SetIsRegistered(false); 148 object->SetIsRegistered(false);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 39dcf71ce..0235317c0 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -933,7 +933,7 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres
933 // If surface parameters changed and we care about keeping the previous data, recreate 933 // If surface parameters changed and we care about keeping the previous data, recreate
934 // the surface from the old one 934 // the surface from the old one
935 Surface new_surface{RecreateSurface(surface, params)}; 935 Surface new_surface{RecreateSurface(surface, params)};
936 UnregisterSurface(surface); 936 Unregister(surface);
937 Register(new_surface); 937 Register(new_surface);
938 if (new_surface->IsUploaded()) { 938 if (new_surface->IsUploaded()) {
939 RegisterReinterpretSurface(new_surface); 939 RegisterReinterpretSurface(new_surface);
@@ -941,7 +941,7 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres
941 return new_surface; 941 return new_surface;
942 } else { 942 } else {
943 // Delete the old surface before creating a new one to prevent collisions. 943 // Delete the old surface before creating a new one to prevent collisions.
944 UnregisterSurface(surface); 944 Unregister(surface);
945 } 945 }
946 } 946 }
947 947
@@ -1295,12 +1295,12 @@ static bool IsReinterpretInvalidSecond(const Surface render_surface,
1295bool RasterizerCacheOpenGL::PartialReinterpretSurface(Surface triggering_surface, 1295bool RasterizerCacheOpenGL::PartialReinterpretSurface(Surface triggering_surface,
1296 Surface intersect) { 1296 Surface intersect) {
1297 if (IsReinterpretInvalid(triggering_surface, intersect)) { 1297 if (IsReinterpretInvalid(triggering_surface, intersect)) {
1298 UnregisterSurface(intersect); 1298 Unregister(intersect);
1299 return false; 1299 return false;
1300 } 1300 }
1301 if (!LayerFitReinterpretSurface(*this, triggering_surface, intersect)) { 1301 if (!LayerFitReinterpretSurface(*this, triggering_surface, intersect)) {
1302 if (IsReinterpretInvalidSecond(triggering_surface, intersect)) { 1302 if (IsReinterpretInvalidSecond(triggering_surface, intersect)) {
1303 UnregisterSurface(intersect); 1303 Unregister(intersect);
1304 return false; 1304 return false;
1305 } 1305 }
1306 FlushObject(intersect); 1306 FlushObject(intersect);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 0efcafd07..c644271d0 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -538,13 +538,17 @@ private:
538 return nullptr; 538 return nullptr;
539 } 539 }
540 540
541 void Register(const Surface& object) {
542 RasterizerCache<Surface>::Register(object);
543 }
544
541 /// Unregisters an object from the cache 545 /// Unregisters an object from the cache
542 void UnregisterSurface(const Surface& object) { 546 void Unregister(const Surface& object) {
543 if (object->IsReinterpreted()) { 547 if (object->IsReinterpreted()) {
544 auto interval = GetReinterpretInterval(object); 548 auto interval = GetReinterpretInterval(object);
545 reinterpreted_surfaces.erase(interval); 549 reinterpreted_surfaces.erase(interval);
546 } 550 }
547 Unregister(object); 551 RasterizerCache<Surface>::Unregister(object);
548 } 552 }
549}; 553};
550 554