dmnt_cheat_vm.h 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /*
  2. * Copyright (c) 2018-2019 Atmosphère-NX
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms and conditions of the GNU General Public License,
  6. * version 2, as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope it will be useful, but WITHOUT
  9. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  11. * more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. /*
  17. * Adapted by DarkLordZach for use/interaction with yuzu
  18. *
  19. * Modifications Copyright 2019 yuzu emulator team
  20. * Licensed under GPLv2 or any later version
  21. * Refer to the license.txt file included.
  22. */
  23. #pragma once
  24. #include <variant>
  25. #include <vector>
  26. #include <fmt/printf.h>
  27. #include "common/common_types.h"
  28. #include "core/memory/dmnt_cheat_types.h"
  29. namespace Core::Memory {
  30. enum class CheatVmOpcodeType : u32 {
  31. StoreStatic = 0,
  32. BeginConditionalBlock = 1,
  33. EndConditionalBlock = 2,
  34. ControlLoop = 3,
  35. LoadRegisterStatic = 4,
  36. LoadRegisterMemory = 5,
  37. StoreStaticToAddress = 6,
  38. PerformArithmeticStatic = 7,
  39. BeginKeypressConditionalBlock = 8,
  40. // These are not implemented by Gateway's VM.
  41. PerformArithmeticRegister = 9,
  42. StoreRegisterToAddress = 10,
  43. Reserved11 = 11,
  44. // This is a meta entry, and not a real opcode.
  45. // This is to facilitate multi-nybble instruction decoding.
  46. ExtendedWidth = 12,
  47. // Extended width opcodes.
  48. BeginRegisterConditionalBlock = 0xC0,
  49. SaveRestoreRegister = 0xC1,
  50. SaveRestoreRegisterMask = 0xC2,
  51. ReadWriteStaticRegister = 0xC3,
  52. // This is a meta entry, and not a real opcode.
  53. // This is to facilitate multi-nybble instruction decoding.
  54. DoubleExtendedWidth = 0xF0,
  55. // Double-extended width opcodes.
  56. DebugLog = 0xFFF,
  57. };
  58. enum class MemoryAccessType : u32 {
  59. MainNso = 0,
  60. Heap = 1,
  61. };
  62. enum class ConditionalComparisonType : u32 {
  63. GT = 1,
  64. GE = 2,
  65. LT = 3,
  66. LE = 4,
  67. EQ = 5,
  68. NE = 6,
  69. };
  70. enum class RegisterArithmeticType : u32 {
  71. Addition = 0,
  72. Subtraction = 1,
  73. Multiplication = 2,
  74. LeftShift = 3,
  75. RightShift = 4,
  76. // These are not supported by Gateway's VM.
  77. LogicalAnd = 5,
  78. LogicalOr = 6,
  79. LogicalNot = 7,
  80. LogicalXor = 8,
  81. None = 9,
  82. };
  83. enum class StoreRegisterOffsetType : u32 {
  84. None = 0,
  85. Reg = 1,
  86. Imm = 2,
  87. MemReg = 3,
  88. MemImm = 4,
  89. MemImmReg = 5,
  90. };
  91. enum class CompareRegisterValueType : u32 {
  92. MemoryRelAddr = 0,
  93. MemoryOfsReg = 1,
  94. RegisterRelAddr = 2,
  95. RegisterOfsReg = 3,
  96. StaticValue = 4,
  97. OtherRegister = 5,
  98. };
  99. enum class SaveRestoreRegisterOpType : u32 {
  100. Restore = 0,
  101. Save = 1,
  102. ClearSaved = 2,
  103. ClearRegs = 3,
  104. };
  105. enum class DebugLogValueType : u32 {
  106. MemoryRelAddr = 0,
  107. MemoryOfsReg = 1,
  108. RegisterRelAddr = 2,
  109. RegisterOfsReg = 3,
  110. RegisterValue = 4,
  111. };
  112. union VmInt {
  113. u8 bit8;
  114. u16 bit16;
  115. u32 bit32;
  116. u64 bit64;
  117. };
  118. struct StoreStaticOpcode {
  119. u32 bit_width{};
  120. MemoryAccessType mem_type{};
  121. u32 offset_register{};
  122. u64 rel_address{};
  123. VmInt value{};
  124. };
  125. struct BeginConditionalOpcode {
  126. u32 bit_width{};
  127. MemoryAccessType mem_type{};
  128. ConditionalComparisonType cond_type{};
  129. u64 rel_address{};
  130. VmInt value{};
  131. };
  132. struct EndConditionalOpcode {};
  133. struct ControlLoopOpcode {
  134. bool start_loop{};
  135. u32 reg_index{};
  136. u32 num_iters{};
  137. };
  138. struct LoadRegisterStaticOpcode {
  139. u32 reg_index{};
  140. u64 value{};
  141. };
  142. struct LoadRegisterMemoryOpcode {
  143. u32 bit_width{};
  144. MemoryAccessType mem_type{};
  145. u32 reg_index{};
  146. bool load_from_reg{};
  147. u64 rel_address{};
  148. };
  149. struct StoreStaticToAddressOpcode {
  150. u32 bit_width{};
  151. u32 reg_index{};
  152. bool increment_reg{};
  153. bool add_offset_reg{};
  154. u32 offset_reg_index{};
  155. u64 value{};
  156. };
  157. struct PerformArithmeticStaticOpcode {
  158. u32 bit_width{};
  159. u32 reg_index{};
  160. RegisterArithmeticType math_type{};
  161. u32 value{};
  162. };
  163. struct BeginKeypressConditionalOpcode {
  164. u32 key_mask{};
  165. };
  166. struct PerformArithmeticRegisterOpcode {
  167. u32 bit_width{};
  168. RegisterArithmeticType math_type{};
  169. u32 dst_reg_index{};
  170. u32 src_reg_1_index{};
  171. u32 src_reg_2_index{};
  172. bool has_immediate{};
  173. VmInt value{};
  174. };
  175. struct StoreRegisterToAddressOpcode {
  176. u32 bit_width{};
  177. u32 str_reg_index{};
  178. u32 addr_reg_index{};
  179. bool increment_reg{};
  180. StoreRegisterOffsetType ofs_type{};
  181. MemoryAccessType mem_type{};
  182. u32 ofs_reg_index{};
  183. u64 rel_address{};
  184. };
  185. struct BeginRegisterConditionalOpcode {
  186. u32 bit_width{};
  187. ConditionalComparisonType cond_type{};
  188. u32 val_reg_index{};
  189. CompareRegisterValueType comp_type{};
  190. MemoryAccessType mem_type{};
  191. u32 addr_reg_index{};
  192. u32 other_reg_index{};
  193. u32 ofs_reg_index{};
  194. u64 rel_address{};
  195. VmInt value{};
  196. };
  197. struct SaveRestoreRegisterOpcode {
  198. u32 dst_index{};
  199. u32 src_index{};
  200. SaveRestoreRegisterOpType op_type{};
  201. };
  202. struct SaveRestoreRegisterMaskOpcode {
  203. SaveRestoreRegisterOpType op_type{};
  204. std::array<bool, 0x10> should_operate{};
  205. };
  206. struct ReadWriteStaticRegisterOpcode {
  207. u32 static_idx{};
  208. u32 idx{};
  209. };
  210. struct DebugLogOpcode {
  211. u32 bit_width{};
  212. u32 log_id{};
  213. DebugLogValueType val_type{};
  214. MemoryAccessType mem_type{};
  215. u32 addr_reg_index{};
  216. u32 val_reg_index{};
  217. u32 ofs_reg_index{};
  218. u64 rel_address{};
  219. };
  220. struct UnrecognizedInstruction {
  221. CheatVmOpcodeType opcode{};
  222. };
  223. struct CheatVmOpcode {
  224. bool begin_conditional_block{};
  225. std::variant<StoreStaticOpcode, BeginConditionalOpcode, EndConditionalOpcode, ControlLoopOpcode,
  226. LoadRegisterStaticOpcode, LoadRegisterMemoryOpcode, StoreStaticToAddressOpcode,
  227. PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode,
  228. PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode,
  229. BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode,
  230. SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, DebugLogOpcode,
  231. UnrecognizedInstruction>
  232. opcode{};
  233. };
  234. class DmntCheatVm {
  235. public:
  236. /// Helper Type for DmntCheatVm <=> yuzu Interface
  237. class Callbacks {
  238. public:
  239. virtual ~Callbacks();
  240. virtual void MemoryRead(VAddr address, void* data, u64 size) = 0;
  241. virtual void MemoryWrite(VAddr address, const void* data, u64 size) = 0;
  242. virtual u64 HidKeysDown() = 0;
  243. virtual void DebugLog(u8 id, u64 value) = 0;
  244. virtual void CommandLog(std::string_view data) = 0;
  245. };
  246. static constexpr std::size_t MaximumProgramOpcodeCount = 0x400;
  247. static constexpr std::size_t NumRegisters = 0x10;
  248. static constexpr std::size_t NumReadableStaticRegisters = 0x80;
  249. static constexpr std::size_t NumWritableStaticRegisters = 0x80;
  250. static constexpr std::size_t NumStaticRegisters =
  251. NumReadableStaticRegisters + NumWritableStaticRegisters;
  252. explicit DmntCheatVm(std::unique_ptr<Callbacks> callbacks_);
  253. ~DmntCheatVm();
  254. std::size_t GetProgramSize() const {
  255. return this->num_opcodes;
  256. }
  257. bool LoadProgram(const std::vector<CheatEntry>& cheats);
  258. void Execute(const CheatProcessMetadata& metadata);
  259. private:
  260. std::unique_ptr<Callbacks> callbacks;
  261. std::size_t num_opcodes = 0;
  262. std::size_t instruction_ptr = 0;
  263. std::size_t condition_depth = 0;
  264. bool decode_success = false;
  265. std::array<u32, MaximumProgramOpcodeCount> program{};
  266. std::array<u64, NumRegisters> registers{};
  267. std::array<u64, NumRegisters> saved_values{};
  268. std::array<u64, NumStaticRegisters> static_registers{};
  269. std::array<std::size_t, NumRegisters> loop_tops{};
  270. bool DecodeNextOpcode(CheatVmOpcode& out);
  271. void SkipConditionalBlock();
  272. void ResetState();
  273. // For implementing the DebugLog opcode.
  274. void DebugLog(u32 log_id, u64 value);
  275. void LogOpcode(const CheatVmOpcode& opcode);
  276. static u64 GetVmInt(VmInt value, u32 bit_width);
  277. static u64 GetCheatProcessAddress(const CheatProcessMetadata& metadata,
  278. MemoryAccessType mem_type, u64 rel_address);
  279. };
  280. }; // namespace Core::Memory