dmnt_cheat_vm.cpp 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206
  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. #include "common/assert.h"
  24. #include "common/scope_exit.h"
  25. #include "core/memory/dmnt_cheat_types.h"
  26. #include "core/memory/dmnt_cheat_vm.h"
  27. namespace Memory {
  28. void DmntCheatVm::DebugLog(u32 log_id, u64 value) {
  29. callbacks->DebugLog(static_cast<u8>(log_id), value);
  30. }
  31. void DmntCheatVm::LogOpcode(const CheatVmOpcode& opcode) {
  32. switch (opcode.opcode) {
  33. case CheatVmOpcodeType_StoreStatic:
  34. this->LogToDebugFile("Opcode: Store Static\n");
  35. this->LogToDebugFile("Bit Width: %x\n", opcode.store_static.bit_width);
  36. this->LogToDebugFile("Mem Type: %x\n", opcode.store_static.mem_type);
  37. this->LogToDebugFile("Reg Idx: %x\n", opcode.store_static.offset_register);
  38. this->LogToDebugFile("Rel Addr: %lx\n", opcode.store_static.rel_address);
  39. this->LogToDebugFile("Value: %lx\n", opcode.store_static.value.bit64);
  40. break;
  41. case CheatVmOpcodeType_BeginConditionalBlock:
  42. this->LogToDebugFile("Opcode: Begin Conditional\n");
  43. this->LogToDebugFile("Bit Width: %x\n", opcode.begin_cond.bit_width);
  44. this->LogToDebugFile("Mem Type: %x\n", opcode.begin_cond.mem_type);
  45. this->LogToDebugFile("Cond Type: %x\n", opcode.begin_cond.cond_type);
  46. this->LogToDebugFile("Rel Addr: %lx\n", opcode.begin_cond.rel_address);
  47. this->LogToDebugFile("Value: %lx\n", opcode.begin_cond.value.bit64);
  48. break;
  49. case CheatVmOpcodeType_EndConditionalBlock:
  50. this->LogToDebugFile("Opcode: End Conditional\n");
  51. break;
  52. case CheatVmOpcodeType_ControlLoop:
  53. if (opcode.ctrl_loop.start_loop) {
  54. this->LogToDebugFile("Opcode: Start Loop\n");
  55. this->LogToDebugFile("Reg Idx: %x\n", opcode.ctrl_loop.reg_index);
  56. this->LogToDebugFile("Num Iters: %x\n", opcode.ctrl_loop.num_iters);
  57. } else {
  58. this->LogToDebugFile("Opcode: End Loop\n");
  59. this->LogToDebugFile("Reg Idx: %x\n", opcode.ctrl_loop.reg_index);
  60. }
  61. break;
  62. case CheatVmOpcodeType_LoadRegisterStatic:
  63. this->LogToDebugFile("Opcode: Load Register Static\n");
  64. this->LogToDebugFile("Reg Idx: %x\n", opcode.ldr_static.reg_index);
  65. this->LogToDebugFile("Value: %lx\n", opcode.ldr_static.value);
  66. break;
  67. case CheatVmOpcodeType_LoadRegisterMemory:
  68. this->LogToDebugFile("Opcode: Load Register Memory\n");
  69. this->LogToDebugFile("Bit Width: %x\n", opcode.ldr_memory.bit_width);
  70. this->LogToDebugFile("Reg Idx: %x\n", opcode.ldr_memory.reg_index);
  71. this->LogToDebugFile("Mem Type: %x\n", opcode.ldr_memory.mem_type);
  72. this->LogToDebugFile("From Reg: %d\n", opcode.ldr_memory.load_from_reg);
  73. this->LogToDebugFile("Rel Addr: %lx\n", opcode.ldr_memory.rel_address);
  74. break;
  75. case CheatVmOpcodeType_StoreStaticToAddress:
  76. this->LogToDebugFile("Opcode: Store Static to Address\n");
  77. this->LogToDebugFile("Bit Width: %x\n", opcode.str_static.bit_width);
  78. this->LogToDebugFile("Reg Idx: %x\n", opcode.str_static.reg_index);
  79. if (opcode.str_static.add_offset_reg) {
  80. this->LogToDebugFile("O Reg Idx: %x\n", opcode.str_static.offset_reg_index);
  81. }
  82. this->LogToDebugFile("Incr Reg: %d\n", opcode.str_static.increment_reg);
  83. this->LogToDebugFile("Value: %lx\n", opcode.str_static.value);
  84. break;
  85. case CheatVmOpcodeType_PerformArithmeticStatic:
  86. this->LogToDebugFile("Opcode: Perform Static Arithmetic\n");
  87. this->LogToDebugFile("Bit Width: %x\n", opcode.perform_math_static.bit_width);
  88. this->LogToDebugFile("Reg Idx: %x\n", opcode.perform_math_static.reg_index);
  89. this->LogToDebugFile("Math Type: %x\n", opcode.perform_math_static.math_type);
  90. this->LogToDebugFile("Value: %lx\n", opcode.perform_math_static.value);
  91. break;
  92. case CheatVmOpcodeType_BeginKeypressConditionalBlock:
  93. this->LogToDebugFile("Opcode: Begin Keypress Conditional\n");
  94. this->LogToDebugFile("Key Mask: %x\n", opcode.begin_keypress_cond.key_mask);
  95. break;
  96. case CheatVmOpcodeType_PerformArithmeticRegister:
  97. this->LogToDebugFile("Opcode: Perform Register Arithmetic\n");
  98. this->LogToDebugFile("Bit Width: %x\n", opcode.perform_math_reg.bit_width);
  99. this->LogToDebugFile("Dst Idx: %x\n", opcode.perform_math_reg.dst_reg_index);
  100. this->LogToDebugFile("Src1 Idx: %x\n", opcode.perform_math_reg.src_reg_1_index);
  101. if (opcode.perform_math_reg.has_immediate) {
  102. this->LogToDebugFile("Value: %lx\n", opcode.perform_math_reg.value.bit64);
  103. } else {
  104. this->LogToDebugFile("Src2 Idx: %x\n", opcode.perform_math_reg.src_reg_2_index);
  105. }
  106. break;
  107. case CheatVmOpcodeType_StoreRegisterToAddress:
  108. this->LogToDebugFile("Opcode: Store Register to Address\n");
  109. this->LogToDebugFile("Bit Width: %x\n", opcode.str_register.bit_width);
  110. this->LogToDebugFile("S Reg Idx: %x\n", opcode.str_register.str_reg_index);
  111. this->LogToDebugFile("A Reg Idx: %x\n", opcode.str_register.addr_reg_index);
  112. this->LogToDebugFile("Incr Reg: %d\n", opcode.str_register.increment_reg);
  113. switch (opcode.str_register.ofs_type) {
  114. case StoreRegisterOffsetType_None:
  115. break;
  116. case StoreRegisterOffsetType_Reg:
  117. this->LogToDebugFile("O Reg Idx: %x\n", opcode.str_register.ofs_reg_index);
  118. break;
  119. case StoreRegisterOffsetType_Imm:
  120. this->LogToDebugFile("Rel Addr: %lx\n", opcode.str_register.rel_address);
  121. break;
  122. case StoreRegisterOffsetType_MemReg:
  123. this->LogToDebugFile("Mem Type: %x\n", opcode.str_register.mem_type);
  124. break;
  125. case StoreRegisterOffsetType_MemImm:
  126. case StoreRegisterOffsetType_MemImmReg:
  127. this->LogToDebugFile("Mem Type: %x\n", opcode.str_register.mem_type);
  128. this->LogToDebugFile("Rel Addr: %lx\n", opcode.str_register.rel_address);
  129. break;
  130. }
  131. break;
  132. case CheatVmOpcodeType_BeginRegisterConditionalBlock:
  133. this->LogToDebugFile("Opcode: Begin Register Conditional\n");
  134. this->LogToDebugFile("Bit Width: %x\n", opcode.begin_reg_cond.bit_width);
  135. this->LogToDebugFile("Cond Type: %x\n", opcode.begin_reg_cond.cond_type);
  136. this->LogToDebugFile("V Reg Idx: %x\n", opcode.begin_reg_cond.val_reg_index);
  137. switch (opcode.begin_reg_cond.comp_type) {
  138. case CompareRegisterValueType_StaticValue:
  139. this->LogToDebugFile("Comp Type: Static Value\n");
  140. this->LogToDebugFile("Value: %lx\n", opcode.begin_reg_cond.value.bit64);
  141. break;
  142. case CompareRegisterValueType_OtherRegister:
  143. this->LogToDebugFile("Comp Type: Other Register\n");
  144. this->LogToDebugFile("X Reg Idx: %x\n", opcode.begin_reg_cond.other_reg_index);
  145. break;
  146. case CompareRegisterValueType_MemoryRelAddr:
  147. this->LogToDebugFile("Comp Type: Memory Relative Address\n");
  148. this->LogToDebugFile("Mem Type: %x\n", opcode.begin_reg_cond.mem_type);
  149. this->LogToDebugFile("Rel Addr: %lx\n", opcode.begin_reg_cond.rel_address);
  150. break;
  151. case CompareRegisterValueType_MemoryOfsReg:
  152. this->LogToDebugFile("Comp Type: Memory Offset Register\n");
  153. this->LogToDebugFile("Mem Type: %x\n", opcode.begin_reg_cond.mem_type);
  154. this->LogToDebugFile("O Reg Idx: %x\n", opcode.begin_reg_cond.ofs_reg_index);
  155. break;
  156. case CompareRegisterValueType_RegisterRelAddr:
  157. this->LogToDebugFile("Comp Type: Register Relative Address\n");
  158. this->LogToDebugFile("A Reg Idx: %x\n", opcode.begin_reg_cond.addr_reg_index);
  159. this->LogToDebugFile("Rel Addr: %lx\n", opcode.begin_reg_cond.rel_address);
  160. break;
  161. case CompareRegisterValueType_RegisterOfsReg:
  162. this->LogToDebugFile("Comp Type: Register Offset Register\n");
  163. this->LogToDebugFile("A Reg Idx: %x\n", opcode.begin_reg_cond.addr_reg_index);
  164. this->LogToDebugFile("O Reg Idx: %x\n", opcode.begin_reg_cond.ofs_reg_index);
  165. break;
  166. }
  167. break;
  168. case CheatVmOpcodeType_SaveRestoreRegister:
  169. this->LogToDebugFile("Opcode: Save or Restore Register\n");
  170. this->LogToDebugFile("Dst Idx: %x\n", opcode.save_restore_reg.dst_index);
  171. this->LogToDebugFile("Src Idx: %x\n", opcode.save_restore_reg.src_index);
  172. this->LogToDebugFile("Op Type: %d\n", opcode.save_restore_reg.op_type);
  173. break;
  174. case CheatVmOpcodeType_SaveRestoreRegisterMask:
  175. this->LogToDebugFile("Opcode: Save or Restore Register Mask\n");
  176. this->LogToDebugFile("Op Type: %d\n", opcode.save_restore_regmask.op_type);
  177. for (size_t i = 0; i < NumRegisters; i++) {
  178. this->LogToDebugFile("Act[%02x]: %d\n", i,
  179. opcode.save_restore_regmask.should_operate[i]);
  180. }
  181. break;
  182. case CheatVmOpcodeType_DebugLog:
  183. this->LogToDebugFile("Opcode: Debug Log\n");
  184. this->LogToDebugFile("Bit Width: %x\n", opcode.debug_log.bit_width);
  185. this->LogToDebugFile("Log ID: %x\n", opcode.debug_log.log_id);
  186. this->LogToDebugFile("Val Type: %x\n", opcode.debug_log.val_type);
  187. switch (opcode.debug_log.val_type) {
  188. case DebugLogValueType_RegisterValue:
  189. this->LogToDebugFile("Val Type: Register Value\n");
  190. this->LogToDebugFile("X Reg Idx: %x\n", opcode.debug_log.val_reg_index);
  191. break;
  192. case DebugLogValueType_MemoryRelAddr:
  193. this->LogToDebugFile("Val Type: Memory Relative Address\n");
  194. this->LogToDebugFile("Mem Type: %x\n", opcode.debug_log.mem_type);
  195. this->LogToDebugFile("Rel Addr: %lx\n", opcode.debug_log.rel_address);
  196. break;
  197. case DebugLogValueType_MemoryOfsReg:
  198. this->LogToDebugFile("Val Type: Memory Offset Register\n");
  199. this->LogToDebugFile("Mem Type: %x\n", opcode.debug_log.mem_type);
  200. this->LogToDebugFile("O Reg Idx: %x\n", opcode.debug_log.ofs_reg_index);
  201. break;
  202. case DebugLogValueType_RegisterRelAddr:
  203. this->LogToDebugFile("Val Type: Register Relative Address\n");
  204. this->LogToDebugFile("A Reg Idx: %x\n", opcode.debug_log.addr_reg_index);
  205. this->LogToDebugFile("Rel Addr: %lx\n", opcode.debug_log.rel_address);
  206. break;
  207. case DebugLogValueType_RegisterOfsReg:
  208. this->LogToDebugFile("Val Type: Register Offset Register\n");
  209. this->LogToDebugFile("A Reg Idx: %x\n", opcode.debug_log.addr_reg_index);
  210. this->LogToDebugFile("O Reg Idx: %x\n", opcode.debug_log.ofs_reg_index);
  211. break;
  212. }
  213. default:
  214. this->LogToDebugFile("Unknown opcode: %x\n", opcode.opcode);
  215. break;
  216. }
  217. }
  218. DmntCheatVm::Callbacks::~Callbacks() = default;
  219. bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
  220. /* If we've ever seen a decode failure, return false. */
  221. bool valid = this->decode_success;
  222. CheatVmOpcode opcode = {};
  223. SCOPE_EXIT({
  224. this->decode_success &= valid;
  225. if (valid) {
  226. out = opcode;
  227. }
  228. });
  229. /* Helper function for getting instruction dwords. */
  230. auto GetNextDword = [&]() {
  231. if (this->instruction_ptr >= this->num_opcodes) {
  232. valid = false;
  233. return static_cast<u32>(0);
  234. }
  235. return this->program[this->instruction_ptr++];
  236. };
  237. /* Helper function for parsing a VmInt. */
  238. auto GetNextVmInt = [&](const u32 bit_width) {
  239. VmInt val = {0};
  240. const u32 first_dword = GetNextDword();
  241. switch (bit_width) {
  242. case 1:
  243. val.bit8 = (u8)first_dword;
  244. break;
  245. case 2:
  246. val.bit16 = (u16)first_dword;
  247. break;
  248. case 4:
  249. val.bit32 = first_dword;
  250. break;
  251. case 8:
  252. val.bit64 = (((u64)first_dword) << 32ul) | ((u64)GetNextDword());
  253. break;
  254. }
  255. return val;
  256. };
  257. /* Read opcode. */
  258. const u32 first_dword = GetNextDword();
  259. if (!valid) {
  260. return valid;
  261. }
  262. opcode.opcode = (CheatVmOpcodeType)(((first_dword >> 28) & 0xF));
  263. if (opcode.opcode >= CheatVmOpcodeType_ExtendedWidth) {
  264. opcode.opcode =
  265. (CheatVmOpcodeType)((((u32)opcode.opcode) << 4) | ((first_dword >> 24) & 0xF));
  266. }
  267. if (opcode.opcode >= CheatVmOpcodeType_DoubleExtendedWidth) {
  268. opcode.opcode =
  269. (CheatVmOpcodeType)((((u32)opcode.opcode) << 4) | ((first_dword >> 20) & 0xF));
  270. }
  271. /* detect condition start. */
  272. switch (opcode.opcode) {
  273. case CheatVmOpcodeType_BeginConditionalBlock:
  274. case CheatVmOpcodeType_BeginKeypressConditionalBlock:
  275. case CheatVmOpcodeType_BeginRegisterConditionalBlock:
  276. opcode.begin_conditional_block = true;
  277. break;
  278. default:
  279. opcode.begin_conditional_block = false;
  280. break;
  281. }
  282. switch (opcode.opcode) {
  283. case CheatVmOpcodeType_StoreStatic: {
  284. /* 0TMR00AA AAAAAAAA YYYYYYYY (YYYYYYYY) */
  285. /* Read additional words. */
  286. const u32 second_dword = GetNextDword();
  287. opcode.store_static.bit_width = (first_dword >> 24) & 0xF;
  288. opcode.store_static.mem_type = (MemoryAccessType)((first_dword >> 20) & 0xF);
  289. opcode.store_static.offset_register = ((first_dword >> 16) & 0xF);
  290. opcode.store_static.rel_address = ((u64)(first_dword & 0xFF) << 32ul) | ((u64)second_dword);
  291. opcode.store_static.value = GetNextVmInt(opcode.store_static.bit_width);
  292. } break;
  293. case CheatVmOpcodeType_BeginConditionalBlock: {
  294. /* 1TMC00AA AAAAAAAA YYYYYYYY (YYYYYYYY) */
  295. /* Read additional words. */
  296. const u32 second_dword = GetNextDword();
  297. opcode.begin_cond.bit_width = (first_dword >> 24) & 0xF;
  298. opcode.begin_cond.mem_type = (MemoryAccessType)((first_dword >> 20) & 0xF);
  299. opcode.begin_cond.cond_type = (ConditionalComparisonType)((first_dword >> 16) & 0xF);
  300. opcode.begin_cond.rel_address = ((u64)(first_dword & 0xFF) << 32ul) | ((u64)second_dword);
  301. opcode.begin_cond.value = GetNextVmInt(opcode.store_static.bit_width);
  302. } break;
  303. case CheatVmOpcodeType_EndConditionalBlock: {
  304. /* 20000000 */
  305. /* There's actually nothing left to process here! */
  306. } break;
  307. case CheatVmOpcodeType_ControlLoop: {
  308. /* 300R0000 VVVVVVVV */
  309. /* 310R0000 */
  310. /* Parse register, whether loop start or loop end. */
  311. opcode.ctrl_loop.start_loop = ((first_dword >> 24) & 0xF) == 0;
  312. opcode.ctrl_loop.reg_index = ((first_dword >> 20) & 0xF);
  313. /* Read number of iters if loop start. */
  314. if (opcode.ctrl_loop.start_loop) {
  315. opcode.ctrl_loop.num_iters = GetNextDword();
  316. }
  317. } break;
  318. case CheatVmOpcodeType_LoadRegisterStatic: {
  319. /* 400R0000 VVVVVVVV VVVVVVVV */
  320. /* Read additional words. */
  321. opcode.ldr_static.reg_index = ((first_dword >> 16) & 0xF);
  322. opcode.ldr_static.value = (((u64)GetNextDword()) << 32ul) | ((u64)GetNextDword());
  323. } break;
  324. case CheatVmOpcodeType_LoadRegisterMemory: {
  325. /* 5TMRI0AA AAAAAAAA */
  326. /* Read additional words. */
  327. const u32 second_dword = GetNextDword();
  328. opcode.ldr_memory.bit_width = (first_dword >> 24) & 0xF;
  329. opcode.ldr_memory.mem_type = (MemoryAccessType)((first_dword >> 20) & 0xF);
  330. opcode.ldr_memory.reg_index = ((first_dword >> 16) & 0xF);
  331. opcode.ldr_memory.load_from_reg = ((first_dword >> 12) & 0xF) != 0;
  332. opcode.ldr_memory.rel_address = ((u64)(first_dword & 0xFF) << 32ul) | ((u64)second_dword);
  333. } break;
  334. case CheatVmOpcodeType_StoreStaticToAddress: {
  335. /* 6T0RIor0 VVVVVVVV VVVVVVVV */
  336. /* Read additional words. */
  337. opcode.str_static.bit_width = (first_dword >> 24) & 0xF;
  338. opcode.str_static.reg_index = ((first_dword >> 16) & 0xF);
  339. opcode.str_static.increment_reg = ((first_dword >> 12) & 0xF) != 0;
  340. opcode.str_static.add_offset_reg = ((first_dword >> 8) & 0xF) != 0;
  341. opcode.str_static.offset_reg_index = ((first_dword >> 4) & 0xF);
  342. opcode.str_static.value = (((u64)GetNextDword()) << 32ul) | ((u64)GetNextDword());
  343. } break;
  344. case CheatVmOpcodeType_PerformArithmeticStatic: {
  345. /* 7T0RC000 VVVVVVVV */
  346. /* Read additional words. */
  347. opcode.perform_math_static.bit_width = (first_dword >> 24) & 0xF;
  348. opcode.perform_math_static.reg_index = ((first_dword >> 16) & 0xF);
  349. opcode.perform_math_static.math_type = (RegisterArithmeticType)((first_dword >> 12) & 0xF);
  350. opcode.perform_math_static.value = GetNextDword();
  351. } break;
  352. case CheatVmOpcodeType_BeginKeypressConditionalBlock: {
  353. /* 8kkkkkkk */
  354. /* Just parse the mask. */
  355. opcode.begin_keypress_cond.key_mask = first_dword & 0x0FFFFFFF;
  356. } break;
  357. case CheatVmOpcodeType_PerformArithmeticRegister: {
  358. /* 9TCRSIs0 (VVVVVVVV (VVVVVVVV)) */
  359. opcode.perform_math_reg.bit_width = (first_dword >> 24) & 0xF;
  360. opcode.perform_math_reg.math_type = (RegisterArithmeticType)((first_dword >> 20) & 0xF);
  361. opcode.perform_math_reg.dst_reg_index = ((first_dword >> 16) & 0xF);
  362. opcode.perform_math_reg.src_reg_1_index = ((first_dword >> 12) & 0xF);
  363. opcode.perform_math_reg.has_immediate = ((first_dword >> 8) & 0xF) != 0;
  364. if (opcode.perform_math_reg.has_immediate) {
  365. opcode.perform_math_reg.src_reg_2_index = 0;
  366. opcode.perform_math_reg.value = GetNextVmInt(opcode.perform_math_reg.bit_width);
  367. } else {
  368. opcode.perform_math_reg.src_reg_2_index = ((first_dword >> 4) & 0xF);
  369. }
  370. } break;
  371. case CheatVmOpcodeType_StoreRegisterToAddress: {
  372. /* ATSRIOxa (aaaaaaaa) */
  373. /* A = opcode 10 */
  374. /* T = bit width */
  375. /* S = src register index */
  376. /* R = address register index */
  377. /* I = 1 if increment address register, 0 if not increment address register */
  378. /* O = offset type, 0 = None, 1 = Register, 2 = Immediate, 3 = Memory Region,
  379. 4 = Memory Region + Relative Address (ignore address register), 5 = Memory Region +
  380. Relative Address */
  381. /* x = offset register (for offset type 1), memory type (for offset type 3) */
  382. /* a = relative address (for offset type 2+3) */
  383. opcode.str_register.bit_width = (first_dword >> 24) & 0xF;
  384. opcode.str_register.str_reg_index = ((first_dword >> 20) & 0xF);
  385. opcode.str_register.addr_reg_index = ((first_dword >> 16) & 0xF);
  386. opcode.str_register.increment_reg = ((first_dword >> 12) & 0xF) != 0;
  387. opcode.str_register.ofs_type = (StoreRegisterOffsetType)(((first_dword >> 8) & 0xF));
  388. opcode.str_register.ofs_reg_index = ((first_dword >> 4) & 0xF);
  389. switch (opcode.str_register.ofs_type) {
  390. case StoreRegisterOffsetType_None:
  391. case StoreRegisterOffsetType_Reg:
  392. /* Nothing more to do */
  393. break;
  394. case StoreRegisterOffsetType_Imm:
  395. opcode.str_register.rel_address =
  396. (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword()));
  397. break;
  398. case StoreRegisterOffsetType_MemReg:
  399. opcode.str_register.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF);
  400. break;
  401. case StoreRegisterOffsetType_MemImm:
  402. case StoreRegisterOffsetType_MemImmReg:
  403. opcode.str_register.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF);
  404. opcode.str_register.rel_address =
  405. (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword()));
  406. break;
  407. default:
  408. opcode.str_register.ofs_type = StoreRegisterOffsetType_None;
  409. break;
  410. }
  411. } break;
  412. case CheatVmOpcodeType_BeginRegisterConditionalBlock: {
  413. /* C0TcSX## */
  414. /* C0TcS0Ma aaaaaaaa */
  415. /* C0TcS1Mr */
  416. /* C0TcS2Ra aaaaaaaa */
  417. /* C0TcS3Rr */
  418. /* C0TcS400 VVVVVVVV (VVVVVVVV) */
  419. /* C0TcS5X0 */
  420. /* C0 = opcode 0xC0 */
  421. /* T = bit width */
  422. /* c = condition type. */
  423. /* S = source register. */
  424. /* X = value operand type, 0 = main/heap with relative offset, 1 = main/heap with offset
  425. * register, */
  426. /* 2 = register with relative offset, 3 = register with offset register, 4 = static
  427. * value, 5 = other register. */
  428. /* M = memory type. */
  429. /* R = address register. */
  430. /* a = relative address. */
  431. /* r = offset register. */
  432. /* X = other register. */
  433. /* V = value. */
  434. opcode.begin_reg_cond.bit_width = (first_dword >> 20) & 0xF;
  435. opcode.begin_reg_cond.cond_type = (ConditionalComparisonType)((first_dword >> 16) & 0xF);
  436. opcode.begin_reg_cond.val_reg_index = ((first_dword >> 12) & 0xF);
  437. opcode.begin_reg_cond.comp_type = (CompareRegisterValueType)((first_dword >> 8) & 0xF);
  438. switch (opcode.begin_reg_cond.comp_type) {
  439. case CompareRegisterValueType_StaticValue:
  440. opcode.begin_reg_cond.value = GetNextVmInt(opcode.begin_reg_cond.bit_width);
  441. break;
  442. case CompareRegisterValueType_OtherRegister:
  443. opcode.begin_reg_cond.other_reg_index = ((first_dword >> 4) & 0xF);
  444. break;
  445. case CompareRegisterValueType_MemoryRelAddr:
  446. opcode.begin_reg_cond.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF);
  447. opcode.begin_reg_cond.rel_address =
  448. (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword()));
  449. break;
  450. case CompareRegisterValueType_MemoryOfsReg:
  451. opcode.begin_reg_cond.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF);
  452. opcode.begin_reg_cond.ofs_reg_index = (first_dword & 0xF);
  453. break;
  454. case CompareRegisterValueType_RegisterRelAddr:
  455. opcode.begin_reg_cond.addr_reg_index = ((first_dword >> 4) & 0xF);
  456. opcode.begin_reg_cond.rel_address =
  457. (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword()));
  458. break;
  459. case CompareRegisterValueType_RegisterOfsReg:
  460. opcode.begin_reg_cond.addr_reg_index = ((first_dword >> 4) & 0xF);
  461. opcode.begin_reg_cond.ofs_reg_index = (first_dword & 0xF);
  462. break;
  463. }
  464. } break;
  465. case CheatVmOpcodeType_SaveRestoreRegister: {
  466. /* C10D0Sx0 */
  467. /* C1 = opcode 0xC1 */
  468. /* D = destination index. */
  469. /* S = source index. */
  470. /* x = 3 if clearing reg, 2 if clearing saved value, 1 if saving a register, 0 if restoring
  471. * a register. */
  472. /* NOTE: If we add more save slots later, current encoding is backwards compatible. */
  473. opcode.save_restore_reg.dst_index = (first_dword >> 16) & 0xF;
  474. opcode.save_restore_reg.src_index = (first_dword >> 8) & 0xF;
  475. opcode.save_restore_reg.op_type = (SaveRestoreRegisterOpType)((first_dword >> 4) & 0xF);
  476. } break;
  477. case CheatVmOpcodeType_SaveRestoreRegisterMask: {
  478. /* C2x0XXXX */
  479. /* C2 = opcode 0xC2 */
  480. /* x = 3 if clearing reg, 2 if clearing saved value, 1 if saving, 0 if restoring. */
  481. /* X = 16-bit bitmask, bit i --> save or restore register i. */
  482. opcode.save_restore_regmask.op_type =
  483. (SaveRestoreRegisterOpType)((first_dword >> 20) & 0xF);
  484. for (size_t i = 0; i < NumRegisters; i++) {
  485. opcode.save_restore_regmask.should_operate[i] = (first_dword & (1u << i)) != 0;
  486. }
  487. } break;
  488. case CheatVmOpcodeType_DebugLog: {
  489. /* FFFTIX## */
  490. /* FFFTI0Ma aaaaaaaa */
  491. /* FFFTI1Mr */
  492. /* FFFTI2Ra aaaaaaaa */
  493. /* FFFTI3Rr */
  494. /* FFFTI4X0 */
  495. /* FFF = opcode 0xFFF */
  496. /* T = bit width. */
  497. /* I = log id. */
  498. /* X = value operand type, 0 = main/heap with relative offset, 1 = main/heap with offset
  499. * register, */
  500. /* 2 = register with relative offset, 3 = register with offset register, 4 = register
  501. * value. */
  502. /* M = memory type. */
  503. /* R = address register. */
  504. /* a = relative address. */
  505. /* r = offset register. */
  506. /* X = value register. */
  507. opcode.debug_log.bit_width = (first_dword >> 16) & 0xF;
  508. opcode.debug_log.log_id = ((first_dword >> 12) & 0xF);
  509. opcode.debug_log.val_type = (DebugLogValueType)((first_dword >> 8) & 0xF);
  510. switch (opcode.debug_log.val_type) {
  511. case DebugLogValueType_RegisterValue:
  512. opcode.debug_log.val_reg_index = ((first_dword >> 4) & 0xF);
  513. break;
  514. case DebugLogValueType_MemoryRelAddr:
  515. opcode.debug_log.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF);
  516. opcode.debug_log.rel_address =
  517. (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword()));
  518. break;
  519. case DebugLogValueType_MemoryOfsReg:
  520. opcode.debug_log.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF);
  521. opcode.debug_log.ofs_reg_index = (first_dword & 0xF);
  522. break;
  523. case DebugLogValueType_RegisterRelAddr:
  524. opcode.debug_log.addr_reg_index = ((first_dword >> 4) & 0xF);
  525. opcode.debug_log.rel_address =
  526. (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword()));
  527. break;
  528. case DebugLogValueType_RegisterOfsReg:
  529. opcode.debug_log.addr_reg_index = ((first_dword >> 4) & 0xF);
  530. opcode.debug_log.ofs_reg_index = (first_dword & 0xF);
  531. break;
  532. }
  533. } break;
  534. case CheatVmOpcodeType_ExtendedWidth:
  535. case CheatVmOpcodeType_DoubleExtendedWidth:
  536. default:
  537. /* Unrecognized instruction cannot be decoded. */
  538. valid = false;
  539. break;
  540. }
  541. /* End decoding. */
  542. return valid;
  543. }
  544. void DmntCheatVm::SkipConditionalBlock() {
  545. if (this->condition_depth > 0) {
  546. /* We want to continue until we're out of the current block. */
  547. const size_t desired_depth = this->condition_depth - 1;
  548. CheatVmOpcode skip_opcode{};
  549. while (this->condition_depth > desired_depth && this->DecodeNextOpcode(skip_opcode)) {
  550. /* Decode instructions until we see end of the current conditional block. */
  551. /* NOTE: This is broken in gateway's implementation. */
  552. /* Gateway currently checks for "0x2" instead of "0x20000000" */
  553. /* In addition, they do a linear scan instead of correctly decoding opcodes. */
  554. /* This causes issues if "0x2" appears as an immediate in the conditional block... */
  555. /* We also support nesting of conditional blocks, and Gateway does not. */
  556. if (skip_opcode.begin_conditional_block) {
  557. this->condition_depth++;
  558. } else if (skip_opcode.opcode == CheatVmOpcodeType_EndConditionalBlock) {
  559. this->condition_depth--;
  560. }
  561. }
  562. } else {
  563. /* Skipping, but this->condition_depth = 0. */
  564. /* This is an error condition. */
  565. /* However, I don't actually believe it is possible for this to happen. */
  566. /* I guess we'll throw a fatal error here, so as to encourage me to fix the VM */
  567. /* in the event that someone triggers it? I don't know how you'd do that. */
  568. UNREACHABLE_MSG("Invalid condition depth in DMNT Cheat VM");
  569. }
  570. }
  571. u64 DmntCheatVm::GetVmInt(VmInt value, u32 bit_width) {
  572. switch (bit_width) {
  573. case 1:
  574. return value.bit8;
  575. case 2:
  576. return value.bit16;
  577. case 4:
  578. return value.bit32;
  579. case 8:
  580. return value.bit64;
  581. default:
  582. /* Invalid bit width -> return 0. */
  583. return 0;
  584. }
  585. }
  586. u64 DmntCheatVm::GetCheatProcessAddress(const CheatProcessMetadata& metadata,
  587. MemoryAccessType mem_type, u64 rel_address) {
  588. switch (mem_type) {
  589. case MemoryAccessType_MainNso:
  590. default:
  591. return metadata.main_nso_extents.base + rel_address;
  592. case MemoryAccessType_Heap:
  593. return metadata.heap_extents.base + rel_address;
  594. }
  595. }
  596. void DmntCheatVm::ResetState() {
  597. for (size_t i = 0; i < DmntCheatVm::NumRegisters; i++) {
  598. this->registers[i] = 0;
  599. this->saved_values[i] = 0;
  600. this->loop_tops[i] = 0;
  601. }
  602. this->instruction_ptr = 0;
  603. this->condition_depth = 0;
  604. this->decode_success = true;
  605. }
  606. bool DmntCheatVm::LoadProgram(const std::vector<CheatEntry>& entries) {
  607. /* Reset opcode count. */
  608. this->num_opcodes = 0;
  609. for (size_t i = 0; i < entries.size(); i++) {
  610. if (entries[i].enabled) {
  611. /* Bounds check. */
  612. if (entries[i].definition.num_opcodes + this->num_opcodes > MaximumProgramOpcodeCount) {
  613. this->num_opcodes = 0;
  614. return false;
  615. }
  616. for (size_t n = 0; n < entries[i].definition.num_opcodes; n++) {
  617. this->program[this->num_opcodes++] = entries[i].definition.opcodes[n];
  618. }
  619. }
  620. }
  621. return true;
  622. }
  623. void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) {
  624. CheatVmOpcode cur_opcode{};
  625. /* Get Keys down. */
  626. u64 kDown = callbacks->HidKeysDown();
  627. this->LogToDebugFile("Started VM execution.\n");
  628. this->LogToDebugFile("Main NSO: %012lx\n", metadata.main_nso_extents.base);
  629. this->LogToDebugFile("Heap: %012lx\n", metadata.main_nso_extents.base);
  630. this->LogToDebugFile("Keys Down: %08x\n", (u32)(kDown & 0x0FFFFFFF));
  631. /* Clear VM state. */
  632. this->ResetState();
  633. /* Loop until program finishes. */
  634. while (this->DecodeNextOpcode(cur_opcode)) {
  635. this->LogToDebugFile("Instruction Ptr: %04x\n", (u32)this->instruction_ptr);
  636. for (size_t i = 0; i < NumRegisters; i++) {
  637. this->LogToDebugFile("Registers[%02x]: %016lx\n", i, this->registers[i]);
  638. }
  639. for (size_t i = 0; i < NumRegisters; i++) {
  640. this->LogToDebugFile("SavedRegs[%02x]: %016lx\n", i, this->saved_values[i]);
  641. }
  642. this->LogOpcode(cur_opcode);
  643. /* Increment conditional depth, if relevant. */
  644. if (cur_opcode.begin_conditional_block) {
  645. this->condition_depth++;
  646. }
  647. switch (cur_opcode.opcode) {
  648. case CheatVmOpcodeType_StoreStatic: {
  649. /* Calculate address, write value to memory. */
  650. u64 dst_address = GetCheatProcessAddress(
  651. metadata, cur_opcode.store_static.mem_type,
  652. cur_opcode.store_static.rel_address +
  653. this->registers[cur_opcode.store_static.offset_register]);
  654. u64 dst_value =
  655. GetVmInt(cur_opcode.store_static.value, cur_opcode.store_static.bit_width);
  656. switch (cur_opcode.store_static.bit_width) {
  657. case 1:
  658. case 2:
  659. case 4:
  660. case 8:
  661. callbacks->MemoryWrite(dst_address, &dst_value, cur_opcode.store_static.bit_width);
  662. break;
  663. }
  664. } break;
  665. case CheatVmOpcodeType_BeginConditionalBlock: {
  666. /* Read value from memory. */
  667. u64 src_address = GetCheatProcessAddress(metadata, cur_opcode.begin_cond.mem_type,
  668. cur_opcode.begin_cond.rel_address);
  669. u64 src_value = 0;
  670. switch (cur_opcode.store_static.bit_width) {
  671. case 1:
  672. case 2:
  673. case 4:
  674. case 8:
  675. callbacks->MemoryRead(src_address, &src_value, cur_opcode.begin_cond.bit_width);
  676. break;
  677. }
  678. /* Check against condition. */
  679. u64 cond_value = GetVmInt(cur_opcode.begin_cond.value, cur_opcode.begin_cond.bit_width);
  680. bool cond_met = false;
  681. switch (cur_opcode.begin_cond.cond_type) {
  682. case ConditionalComparisonType_GT:
  683. cond_met = src_value > cond_value;
  684. break;
  685. case ConditionalComparisonType_GE:
  686. cond_met = src_value >= cond_value;
  687. break;
  688. case ConditionalComparisonType_LT:
  689. cond_met = src_value < cond_value;
  690. break;
  691. case ConditionalComparisonType_LE:
  692. cond_met = src_value <= cond_value;
  693. break;
  694. case ConditionalComparisonType_EQ:
  695. cond_met = src_value == cond_value;
  696. break;
  697. case ConditionalComparisonType_NE:
  698. cond_met = src_value != cond_value;
  699. break;
  700. }
  701. /* Skip conditional block if condition not met. */
  702. if (!cond_met) {
  703. this->SkipConditionalBlock();
  704. }
  705. } break;
  706. case CheatVmOpcodeType_EndConditionalBlock:
  707. /* Decrement the condition depth. */
  708. /* We will assume, graciously, that mismatched conditional block ends are a nop. */
  709. if (this->condition_depth > 0) {
  710. this->condition_depth--;
  711. }
  712. break;
  713. case CheatVmOpcodeType_ControlLoop:
  714. if (cur_opcode.ctrl_loop.start_loop) {
  715. /* Start a loop. */
  716. this->registers[cur_opcode.ctrl_loop.reg_index] = cur_opcode.ctrl_loop.num_iters;
  717. this->loop_tops[cur_opcode.ctrl_loop.reg_index] = this->instruction_ptr;
  718. } else {
  719. /* End a loop. */
  720. this->registers[cur_opcode.ctrl_loop.reg_index]--;
  721. if (this->registers[cur_opcode.ctrl_loop.reg_index] != 0) {
  722. this->instruction_ptr = this->loop_tops[cur_opcode.ctrl_loop.reg_index];
  723. }
  724. }
  725. break;
  726. case CheatVmOpcodeType_LoadRegisterStatic:
  727. /* Set a register to a static value. */
  728. this->registers[cur_opcode.ldr_static.reg_index] = cur_opcode.ldr_static.value;
  729. break;
  730. case CheatVmOpcodeType_LoadRegisterMemory: {
  731. /* Choose source address. */
  732. u64 src_address;
  733. if (cur_opcode.ldr_memory.load_from_reg) {
  734. src_address = this->registers[cur_opcode.ldr_memory.reg_index] +
  735. cur_opcode.ldr_memory.rel_address;
  736. } else {
  737. src_address = GetCheatProcessAddress(metadata, cur_opcode.ldr_memory.mem_type,
  738. cur_opcode.ldr_memory.rel_address);
  739. }
  740. /* Read into register. Gateway only reads on valid bitwidth. */
  741. switch (cur_opcode.ldr_memory.bit_width) {
  742. case 1:
  743. case 2:
  744. case 4:
  745. case 8:
  746. callbacks->MemoryRead(src_address,
  747. &this->registers[cur_opcode.ldr_memory.reg_index],
  748. cur_opcode.ldr_memory.bit_width);
  749. break;
  750. }
  751. } break;
  752. case CheatVmOpcodeType_StoreStaticToAddress: {
  753. /* Calculate address. */
  754. u64 dst_address = this->registers[cur_opcode.str_static.reg_index];
  755. u64 dst_value = cur_opcode.str_static.value;
  756. if (cur_opcode.str_static.add_offset_reg) {
  757. dst_address += this->registers[cur_opcode.str_static.offset_reg_index];
  758. }
  759. /* Write value to memory. Gateway only writes on valid bitwidth. */
  760. switch (cur_opcode.str_static.bit_width) {
  761. case 1:
  762. case 2:
  763. case 4:
  764. case 8:
  765. callbacks->MemoryWrite(dst_address, &dst_value, cur_opcode.str_static.bit_width);
  766. break;
  767. }
  768. /* Increment register if relevant. */
  769. if (cur_opcode.str_static.increment_reg) {
  770. this->registers[cur_opcode.str_static.reg_index] += cur_opcode.str_static.bit_width;
  771. }
  772. } break;
  773. case CheatVmOpcodeType_PerformArithmeticStatic: {
  774. /* Do requested math. */
  775. switch (cur_opcode.perform_math_static.math_type) {
  776. case RegisterArithmeticType_Addition:
  777. this->registers[cur_opcode.perform_math_static.reg_index] +=
  778. (u64)cur_opcode.perform_math_static.value;
  779. break;
  780. case RegisterArithmeticType_Subtraction:
  781. this->registers[cur_opcode.perform_math_static.reg_index] -=
  782. (u64)cur_opcode.perform_math_static.value;
  783. break;
  784. case RegisterArithmeticType_Multiplication:
  785. this->registers[cur_opcode.perform_math_static.reg_index] *=
  786. (u64)cur_opcode.perform_math_static.value;
  787. break;
  788. case RegisterArithmeticType_LeftShift:
  789. this->registers[cur_opcode.perform_math_static.reg_index] <<=
  790. (u64)cur_opcode.perform_math_static.value;
  791. break;
  792. case RegisterArithmeticType_RightShift:
  793. this->registers[cur_opcode.perform_math_static.reg_index] >>=
  794. (u64)cur_opcode.perform_math_static.value;
  795. break;
  796. default:
  797. /* Do not handle extensions here. */
  798. break;
  799. }
  800. /* Apply bit width. */
  801. switch (cur_opcode.perform_math_static.bit_width) {
  802. case 1:
  803. this->registers[cur_opcode.perform_math_static.reg_index] =
  804. static_cast<u8>(this->registers[cur_opcode.perform_math_static.reg_index]);
  805. break;
  806. case 2:
  807. this->registers[cur_opcode.perform_math_static.reg_index] =
  808. static_cast<u16>(this->registers[cur_opcode.perform_math_static.reg_index]);
  809. break;
  810. case 4:
  811. this->registers[cur_opcode.perform_math_static.reg_index] =
  812. static_cast<u32>(this->registers[cur_opcode.perform_math_static.reg_index]);
  813. break;
  814. case 8:
  815. this->registers[cur_opcode.perform_math_static.reg_index] =
  816. static_cast<u64>(this->registers[cur_opcode.perform_math_static.reg_index]);
  817. break;
  818. }
  819. } break;
  820. case CheatVmOpcodeType_BeginKeypressConditionalBlock:
  821. /* Check for keypress. */
  822. if ((cur_opcode.begin_keypress_cond.key_mask & kDown) !=
  823. cur_opcode.begin_keypress_cond.key_mask) {
  824. /* Keys not pressed. Skip conditional block. */
  825. this->SkipConditionalBlock();
  826. }
  827. break;
  828. case CheatVmOpcodeType_PerformArithmeticRegister: {
  829. const u64 operand_1_value =
  830. this->registers[cur_opcode.perform_math_reg.src_reg_1_index];
  831. const u64 operand_2_value =
  832. cur_opcode.perform_math_reg.has_immediate
  833. ? GetVmInt(cur_opcode.perform_math_reg.value,
  834. cur_opcode.perform_math_reg.bit_width)
  835. : this->registers[cur_opcode.perform_math_reg.src_reg_2_index];
  836. u64 res_val = 0;
  837. /* Do requested math. */
  838. switch (cur_opcode.perform_math_reg.math_type) {
  839. case RegisterArithmeticType_Addition:
  840. res_val = operand_1_value + operand_2_value;
  841. break;
  842. case RegisterArithmeticType_Subtraction:
  843. res_val = operand_1_value - operand_2_value;
  844. break;
  845. case RegisterArithmeticType_Multiplication:
  846. res_val = operand_1_value * operand_2_value;
  847. break;
  848. case RegisterArithmeticType_LeftShift:
  849. res_val = operand_1_value << operand_2_value;
  850. break;
  851. case RegisterArithmeticType_RightShift:
  852. res_val = operand_1_value >> operand_2_value;
  853. break;
  854. case RegisterArithmeticType_LogicalAnd:
  855. res_val = operand_1_value & operand_2_value;
  856. break;
  857. case RegisterArithmeticType_LogicalOr:
  858. res_val = operand_1_value | operand_2_value;
  859. break;
  860. case RegisterArithmeticType_LogicalNot:
  861. res_val = ~operand_1_value;
  862. break;
  863. case RegisterArithmeticType_LogicalXor:
  864. res_val = operand_1_value ^ operand_2_value;
  865. break;
  866. case RegisterArithmeticType_None:
  867. res_val = operand_1_value;
  868. break;
  869. }
  870. /* Apply bit width. */
  871. switch (cur_opcode.perform_math_reg.bit_width) {
  872. case 1:
  873. res_val = static_cast<u8>(res_val);
  874. break;
  875. case 2:
  876. res_val = static_cast<u16>(res_val);
  877. break;
  878. case 4:
  879. res_val = static_cast<u32>(res_val);
  880. break;
  881. case 8:
  882. res_val = static_cast<u64>(res_val);
  883. break;
  884. }
  885. /* Save to register. */
  886. this->registers[cur_opcode.perform_math_reg.dst_reg_index] = res_val;
  887. } break;
  888. case CheatVmOpcodeType_StoreRegisterToAddress: {
  889. /* Calculate address. */
  890. u64 dst_value = this->registers[cur_opcode.str_register.str_reg_index];
  891. u64 dst_address = this->registers[cur_opcode.str_register.addr_reg_index];
  892. switch (cur_opcode.str_register.ofs_type) {
  893. case StoreRegisterOffsetType_None:
  894. /* Nothing more to do */
  895. break;
  896. case StoreRegisterOffsetType_Reg:
  897. dst_address += this->registers[cur_opcode.str_register.ofs_reg_index];
  898. break;
  899. case StoreRegisterOffsetType_Imm:
  900. dst_address += cur_opcode.str_register.rel_address;
  901. break;
  902. case StoreRegisterOffsetType_MemReg:
  903. dst_address =
  904. GetCheatProcessAddress(metadata, cur_opcode.str_register.mem_type,
  905. this->registers[cur_opcode.str_register.addr_reg_index]);
  906. break;
  907. case StoreRegisterOffsetType_MemImm:
  908. dst_address = GetCheatProcessAddress(metadata, cur_opcode.str_register.mem_type,
  909. cur_opcode.str_register.rel_address);
  910. break;
  911. case StoreRegisterOffsetType_MemImmReg:
  912. dst_address =
  913. GetCheatProcessAddress(metadata, cur_opcode.str_register.mem_type,
  914. this->registers[cur_opcode.str_register.addr_reg_index] +
  915. cur_opcode.str_register.rel_address);
  916. break;
  917. }
  918. /* Write value to memory. Write only on valid bitwidth. */
  919. switch (cur_opcode.str_register.bit_width) {
  920. case 1:
  921. case 2:
  922. case 4:
  923. case 8:
  924. callbacks->MemoryWrite(dst_address, &dst_value, cur_opcode.str_register.bit_width);
  925. break;
  926. }
  927. /* Increment register if relevant. */
  928. if (cur_opcode.str_register.increment_reg) {
  929. this->registers[cur_opcode.str_register.addr_reg_index] +=
  930. cur_opcode.str_register.bit_width;
  931. }
  932. } break;
  933. case CheatVmOpcodeType_BeginRegisterConditionalBlock: {
  934. /* Get value from register. */
  935. u64 src_value = 0;
  936. switch (cur_opcode.begin_reg_cond.bit_width) {
  937. case 1:
  938. src_value = static_cast<u8>(
  939. this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFul);
  940. break;
  941. case 2:
  942. src_value = static_cast<u16>(
  943. this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFFFul);
  944. break;
  945. case 4:
  946. src_value = static_cast<u32>(
  947. this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFFFFFFFul);
  948. break;
  949. case 8:
  950. src_value =
  951. static_cast<u64>(this->registers[cur_opcode.begin_reg_cond.val_reg_index] &
  952. 0xFFFFFFFFFFFFFFFFul);
  953. break;
  954. }
  955. /* Read value from memory. */
  956. u64 cond_value = 0;
  957. if (cur_opcode.begin_reg_cond.comp_type == CompareRegisterValueType_StaticValue) {
  958. cond_value =
  959. GetVmInt(cur_opcode.begin_reg_cond.value, cur_opcode.begin_reg_cond.bit_width);
  960. } else if (cur_opcode.begin_reg_cond.comp_type ==
  961. CompareRegisterValueType_OtherRegister) {
  962. switch (cur_opcode.begin_reg_cond.bit_width) {
  963. case 1:
  964. cond_value = static_cast<u8>(
  965. this->registers[cur_opcode.begin_reg_cond.other_reg_index] & 0xFFul);
  966. break;
  967. case 2:
  968. cond_value = static_cast<u16>(
  969. this->registers[cur_opcode.begin_reg_cond.other_reg_index] & 0xFFFFul);
  970. break;
  971. case 4:
  972. cond_value = static_cast<u32>(
  973. this->registers[cur_opcode.begin_reg_cond.other_reg_index] & 0xFFFFFFFFul);
  974. break;
  975. case 8:
  976. cond_value = static_cast<u64>(
  977. this->registers[cur_opcode.begin_reg_cond.other_reg_index] &
  978. 0xFFFFFFFFFFFFFFFFul);
  979. break;
  980. }
  981. } else {
  982. u64 cond_address = 0;
  983. switch (cur_opcode.begin_reg_cond.comp_type) {
  984. case CompareRegisterValueType_MemoryRelAddr:
  985. cond_address =
  986. GetCheatProcessAddress(metadata, cur_opcode.begin_reg_cond.mem_type,
  987. cur_opcode.begin_reg_cond.rel_address);
  988. break;
  989. case CompareRegisterValueType_MemoryOfsReg:
  990. cond_address = GetCheatProcessAddress(
  991. metadata, cur_opcode.begin_reg_cond.mem_type,
  992. this->registers[cur_opcode.begin_reg_cond.ofs_reg_index]);
  993. break;
  994. case CompareRegisterValueType_RegisterRelAddr:
  995. cond_address = this->registers[cur_opcode.begin_reg_cond.addr_reg_index] +
  996. cur_opcode.begin_reg_cond.rel_address;
  997. break;
  998. case CompareRegisterValueType_RegisterOfsReg:
  999. cond_address = this->registers[cur_opcode.begin_reg_cond.addr_reg_index] +
  1000. this->registers[cur_opcode.begin_reg_cond.ofs_reg_index];
  1001. break;
  1002. default:
  1003. break;
  1004. }
  1005. switch (cur_opcode.begin_reg_cond.bit_width) {
  1006. case 1:
  1007. case 2:
  1008. case 4:
  1009. case 8:
  1010. callbacks->MemoryRead(cond_address, &cond_value,
  1011. cur_opcode.begin_reg_cond.bit_width);
  1012. break;
  1013. }
  1014. }
  1015. /* Check against condition. */
  1016. bool cond_met = false;
  1017. switch (cur_opcode.begin_reg_cond.cond_type) {
  1018. case ConditionalComparisonType_GT:
  1019. cond_met = src_value > cond_value;
  1020. break;
  1021. case ConditionalComparisonType_GE:
  1022. cond_met = src_value >= cond_value;
  1023. break;
  1024. case ConditionalComparisonType_LT:
  1025. cond_met = src_value < cond_value;
  1026. break;
  1027. case ConditionalComparisonType_LE:
  1028. cond_met = src_value <= cond_value;
  1029. break;
  1030. case ConditionalComparisonType_EQ:
  1031. cond_met = src_value == cond_value;
  1032. break;
  1033. case ConditionalComparisonType_NE:
  1034. cond_met = src_value != cond_value;
  1035. break;
  1036. }
  1037. /* Skip conditional block if condition not met. */
  1038. if (!cond_met) {
  1039. this->SkipConditionalBlock();
  1040. }
  1041. } break;
  1042. case CheatVmOpcodeType_SaveRestoreRegister:
  1043. /* Save or restore a register. */
  1044. switch (cur_opcode.save_restore_reg.op_type) {
  1045. case SaveRestoreRegisterOpType_ClearRegs:
  1046. this->registers[cur_opcode.save_restore_reg.dst_index] = 0ul;
  1047. break;
  1048. case SaveRestoreRegisterOpType_ClearSaved:
  1049. this->saved_values[cur_opcode.save_restore_reg.dst_index] = 0ul;
  1050. break;
  1051. case SaveRestoreRegisterOpType_Save:
  1052. this->saved_values[cur_opcode.save_restore_reg.dst_index] =
  1053. this->registers[cur_opcode.save_restore_reg.src_index];
  1054. break;
  1055. case SaveRestoreRegisterOpType_Restore:
  1056. default:
  1057. this->registers[cur_opcode.save_restore_reg.dst_index] =
  1058. this->saved_values[cur_opcode.save_restore_reg.src_index];
  1059. break;
  1060. }
  1061. break;
  1062. case CheatVmOpcodeType_SaveRestoreRegisterMask:
  1063. /* Save or restore register mask. */
  1064. u64* src;
  1065. u64* dst;
  1066. switch (cur_opcode.save_restore_regmask.op_type) {
  1067. case SaveRestoreRegisterOpType_ClearSaved:
  1068. case SaveRestoreRegisterOpType_Save:
  1069. src = this->registers.data();
  1070. dst = this->saved_values.data();
  1071. break;
  1072. case SaveRestoreRegisterOpType_ClearRegs:
  1073. case SaveRestoreRegisterOpType_Restore:
  1074. default:
  1075. src = this->registers.data();
  1076. dst = this->saved_values.data();
  1077. break;
  1078. }
  1079. for (size_t i = 0; i < NumRegisters; i++) {
  1080. if (cur_opcode.save_restore_regmask.should_operate[i]) {
  1081. switch (cur_opcode.save_restore_regmask.op_type) {
  1082. case SaveRestoreRegisterOpType_ClearSaved:
  1083. case SaveRestoreRegisterOpType_ClearRegs:
  1084. dst[i] = 0ul;
  1085. break;
  1086. case SaveRestoreRegisterOpType_Save:
  1087. case SaveRestoreRegisterOpType_Restore:
  1088. default:
  1089. dst[i] = src[i];
  1090. break;
  1091. }
  1092. }
  1093. }
  1094. break;
  1095. case CheatVmOpcodeType_DebugLog: {
  1096. /* Read value from memory. */
  1097. u64 log_value = 0;
  1098. if (cur_opcode.debug_log.val_type == DebugLogValueType_RegisterValue) {
  1099. switch (cur_opcode.debug_log.bit_width) {
  1100. case 1:
  1101. log_value = static_cast<u8>(
  1102. this->registers[cur_opcode.debug_log.val_reg_index] & 0xFFul);
  1103. break;
  1104. case 2:
  1105. log_value = static_cast<u16>(
  1106. this->registers[cur_opcode.debug_log.val_reg_index] & 0xFFFFul);
  1107. break;
  1108. case 4:
  1109. log_value = static_cast<u32>(
  1110. this->registers[cur_opcode.debug_log.val_reg_index] & 0xFFFFFFFFul);
  1111. break;
  1112. case 8:
  1113. log_value = static_cast<u64>(
  1114. this->registers[cur_opcode.debug_log.val_reg_index] & 0xFFFFFFFFFFFFFFFFul);
  1115. break;
  1116. }
  1117. } else {
  1118. u64 val_address = 0;
  1119. switch (cur_opcode.debug_log.val_type) {
  1120. case DebugLogValueType_MemoryRelAddr:
  1121. val_address = GetCheatProcessAddress(metadata, cur_opcode.debug_log.mem_type,
  1122. cur_opcode.debug_log.rel_address);
  1123. break;
  1124. case DebugLogValueType_MemoryOfsReg:
  1125. val_address =
  1126. GetCheatProcessAddress(metadata, cur_opcode.debug_log.mem_type,
  1127. this->registers[cur_opcode.debug_log.ofs_reg_index]);
  1128. break;
  1129. case DebugLogValueType_RegisterRelAddr:
  1130. val_address = this->registers[cur_opcode.debug_log.addr_reg_index] +
  1131. cur_opcode.debug_log.rel_address;
  1132. break;
  1133. case DebugLogValueType_RegisterOfsReg:
  1134. val_address = this->registers[cur_opcode.debug_log.addr_reg_index] +
  1135. this->registers[cur_opcode.debug_log.ofs_reg_index];
  1136. break;
  1137. default:
  1138. break;
  1139. }
  1140. switch (cur_opcode.debug_log.bit_width) {
  1141. case 1:
  1142. case 2:
  1143. case 4:
  1144. case 8:
  1145. callbacks->MemoryRead(val_address, &log_value, cur_opcode.debug_log.bit_width);
  1146. break;
  1147. }
  1148. }
  1149. /* Log value. */
  1150. this->DebugLog(cur_opcode.debug_log.log_id, log_value);
  1151. } break;
  1152. default:
  1153. /* By default, we do a no-op. */
  1154. break;
  1155. }
  1156. }
  1157. }
  1158. } // namespace Memory