summaryrefslogtreecommitdiffstats
path: root/src/core/memory/dmnt_cheat_vm.h
diff options
context:
space:
mode:
authorZach Hilman <zachhilman@gmail.com>2019-05-31 01:34:02 +0200
committerZach Hilman <zachhilman@gmail.com>2019-09-22 03:44:22 +0200
commit12aa127df3826857149bfc4b787cfb7df3fdcafe (patch)
treeef83925202b36ab21fbf0b5c67e465a04e048b4e /src/core/memory/dmnt_cheat_vm.h
parentlog: Add logging class for Cheat Engine (diff)
downloadyuzu-12aa127df3826857149bfc4b787cfb7df3fdcafe.tar
yuzu-12aa127df3826857149bfc4b787cfb7df3fdcafe.tar.gz
yuzu-12aa127df3826857149bfc4b787cfb7df3fdcafe.tar.bz2
yuzu-12aa127df3826857149bfc4b787cfb7df3fdcafe.tar.lz
yuzu-12aa127df3826857149bfc4b787cfb7df3fdcafe.tar.xz
yuzu-12aa127df3826857149bfc4b787cfb7df3fdcafe.tar.zst
yuzu-12aa127df3826857149bfc4b787cfb7df3fdcafe.zip
Diffstat (limited to 'src/core/memory/dmnt_cheat_vm.h')
-rw-r--r--src/core/memory/dmnt_cheat_vm.h334
1 files changed, 334 insertions, 0 deletions
diff --git a/src/core/memory/dmnt_cheat_vm.h b/src/core/memory/dmnt_cheat_vm.h
new file mode 100644
index 000000000..bea451db4
--- /dev/null
+++ b/src/core/memory/dmnt_cheat_vm.h
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Adapted by DarkLordZach for use/interaction with yuzu
+ *
+ * Modifications Copyright 2019 yuzu emulator team
+ * Licensed under GPLv2 or any later version
+ * Refer to the license.txt file included.
+ */
+
+#pragma once
+
+#include <vector>
+#include <fmt/printf.h>
+#include "common/common_types.h"
+#include "core/memory/dmnt_cheat_types.h"
+
+namespace Memory {
+
+enum CheatVmOpcodeType : u32 {
+ CheatVmOpcodeType_StoreStatic = 0,
+ CheatVmOpcodeType_BeginConditionalBlock = 1,
+ CheatVmOpcodeType_EndConditionalBlock = 2,
+ CheatVmOpcodeType_ControlLoop = 3,
+ CheatVmOpcodeType_LoadRegisterStatic = 4,
+ CheatVmOpcodeType_LoadRegisterMemory = 5,
+ CheatVmOpcodeType_StoreStaticToAddress = 6,
+ CheatVmOpcodeType_PerformArithmeticStatic = 7,
+ CheatVmOpcodeType_BeginKeypressConditionalBlock = 8,
+
+ /* These are not implemented by Gateway's VM. */
+ CheatVmOpcodeType_PerformArithmeticRegister = 9,
+ CheatVmOpcodeType_StoreRegisterToAddress = 10,
+ CheatVmOpcodeType_Reserved11 = 11,
+
+ /* This is a meta entry, and not a real opcode. */
+ /* This is to facilitate multi-nybble instruction decoding. */
+ CheatVmOpcodeType_ExtendedWidth = 12,
+
+ /* Extended width opcodes. */
+ CheatVmOpcodeType_BeginRegisterConditionalBlock = 0xC0,
+ CheatVmOpcodeType_SaveRestoreRegister = 0xC1,
+ CheatVmOpcodeType_SaveRestoreRegisterMask = 0xC2,
+
+ /* This is a meta entry, and not a real opcode. */
+ /* This is to facilitate multi-nybble instruction decoding. */
+ CheatVmOpcodeType_DoubleExtendedWidth = 0xF0,
+
+ /* Double-extended width opcodes. */
+ CheatVmOpcodeType_DebugLog = 0xFFF,
+};
+
+enum MemoryAccessType : u32 {
+ MemoryAccessType_MainNso = 0,
+ MemoryAccessType_Heap = 1,
+};
+
+enum ConditionalComparisonType : u32 {
+ ConditionalComparisonType_GT = 1,
+ ConditionalComparisonType_GE = 2,
+ ConditionalComparisonType_LT = 3,
+ ConditionalComparisonType_LE = 4,
+ ConditionalComparisonType_EQ = 5,
+ ConditionalComparisonType_NE = 6,
+};
+
+enum RegisterArithmeticType : u32 {
+ RegisterArithmeticType_Addition = 0,
+ RegisterArithmeticType_Subtraction = 1,
+ RegisterArithmeticType_Multiplication = 2,
+ RegisterArithmeticType_LeftShift = 3,
+ RegisterArithmeticType_RightShift = 4,
+
+ /* These are not supported by Gateway's VM. */
+ RegisterArithmeticType_LogicalAnd = 5,
+ RegisterArithmeticType_LogicalOr = 6,
+ RegisterArithmeticType_LogicalNot = 7,
+ RegisterArithmeticType_LogicalXor = 8,
+
+ RegisterArithmeticType_None = 9,
+};
+
+enum StoreRegisterOffsetType : u32 {
+ StoreRegisterOffsetType_None = 0,
+ StoreRegisterOffsetType_Reg = 1,
+ StoreRegisterOffsetType_Imm = 2,
+ StoreRegisterOffsetType_MemReg = 3,
+ StoreRegisterOffsetType_MemImm = 4,
+ StoreRegisterOffsetType_MemImmReg = 5,
+};
+
+enum CompareRegisterValueType : u32 {
+ CompareRegisterValueType_MemoryRelAddr = 0,
+ CompareRegisterValueType_MemoryOfsReg = 1,
+ CompareRegisterValueType_RegisterRelAddr = 2,
+ CompareRegisterValueType_RegisterOfsReg = 3,
+ CompareRegisterValueType_StaticValue = 4,
+ CompareRegisterValueType_OtherRegister = 5,
+};
+
+enum SaveRestoreRegisterOpType : u32 {
+ SaveRestoreRegisterOpType_Restore = 0,
+ SaveRestoreRegisterOpType_Save = 1,
+ SaveRestoreRegisterOpType_ClearSaved = 2,
+ SaveRestoreRegisterOpType_ClearRegs = 3,
+};
+
+enum DebugLogValueType : u32 {
+ DebugLogValueType_MemoryRelAddr = 0,
+ DebugLogValueType_MemoryOfsReg = 1,
+ DebugLogValueType_RegisterRelAddr = 2,
+ DebugLogValueType_RegisterOfsReg = 3,
+ DebugLogValueType_RegisterValue = 4,
+};
+
+union VmInt {
+ u8 bit8;
+ u16 bit16;
+ u32 bit32;
+ u64 bit64;
+};
+
+struct StoreStaticOpcode {
+ u32 bit_width;
+ MemoryAccessType mem_type;
+ u32 offset_register;
+ u64 rel_address;
+ VmInt value;
+};
+
+struct BeginConditionalOpcode {
+ u32 bit_width;
+ MemoryAccessType mem_type;
+ ConditionalComparisonType cond_type;
+ u64 rel_address;
+ VmInt value;
+};
+
+struct EndConditionalOpcode {};
+
+struct ControlLoopOpcode {
+ bool start_loop;
+ u32 reg_index;
+ u32 num_iters;
+};
+
+struct LoadRegisterStaticOpcode {
+ u32 reg_index;
+ u64 value;
+};
+
+struct LoadRegisterMemoryOpcode {
+ u32 bit_width;
+ MemoryAccessType mem_type;
+ u32 reg_index;
+ bool load_from_reg;
+ u64 rel_address;
+};
+
+struct StoreStaticToAddressOpcode {
+ u32 bit_width;
+ u32 reg_index;
+ bool increment_reg;
+ bool add_offset_reg;
+ u32 offset_reg_index;
+ u64 value;
+};
+
+struct PerformArithmeticStaticOpcode {
+ u32 bit_width;
+ u32 reg_index;
+ RegisterArithmeticType math_type;
+ u32 value;
+};
+
+struct BeginKeypressConditionalOpcode {
+ u32 key_mask;
+};
+
+struct PerformArithmeticRegisterOpcode {
+ u32 bit_width;
+ RegisterArithmeticType math_type;
+ u32 dst_reg_index;
+ u32 src_reg_1_index;
+ u32 src_reg_2_index;
+ bool has_immediate;
+ VmInt value;
+};
+
+struct StoreRegisterToAddressOpcode {
+ u32 bit_width;
+ u32 str_reg_index;
+ u32 addr_reg_index;
+ bool increment_reg;
+ StoreRegisterOffsetType ofs_type;
+ MemoryAccessType mem_type;
+ u32 ofs_reg_index;
+ u64 rel_address;
+};
+
+struct BeginRegisterConditionalOpcode {
+ u32 bit_width;
+ ConditionalComparisonType cond_type;
+ u32 val_reg_index;
+ CompareRegisterValueType comp_type;
+ MemoryAccessType mem_type;
+ u32 addr_reg_index;
+ u32 other_reg_index;
+ u32 ofs_reg_index;
+ u64 rel_address;
+ VmInt value;
+};
+
+struct SaveRestoreRegisterOpcode {
+ u32 dst_index;
+ u32 src_index;
+ SaveRestoreRegisterOpType op_type;
+};
+
+struct SaveRestoreRegisterMaskOpcode {
+ SaveRestoreRegisterOpType op_type;
+ std::array<bool, 0x10> should_operate;
+};
+
+struct DebugLogOpcode {
+ u32 bit_width;
+ u32 log_id;
+ DebugLogValueType val_type;
+ MemoryAccessType mem_type;
+ u32 addr_reg_index;
+ u32 val_reg_index;
+ u32 ofs_reg_index;
+ u64 rel_address;
+};
+
+struct CheatVmOpcode {
+ CheatVmOpcodeType opcode;
+ bool begin_conditional_block;
+ union {
+ StoreStaticOpcode store_static;
+ BeginConditionalOpcode begin_cond;
+ EndConditionalOpcode end_cond;
+ ControlLoopOpcode ctrl_loop;
+ LoadRegisterStaticOpcode ldr_static;
+ LoadRegisterMemoryOpcode ldr_memory;
+ StoreStaticToAddressOpcode str_static;
+ PerformArithmeticStaticOpcode perform_math_static;
+ BeginKeypressConditionalOpcode begin_keypress_cond;
+ PerformArithmeticRegisterOpcode perform_math_reg;
+ StoreRegisterToAddressOpcode str_register;
+ BeginRegisterConditionalOpcode begin_reg_cond;
+ SaveRestoreRegisterOpcode save_restore_reg;
+ SaveRestoreRegisterMaskOpcode save_restore_regmask;
+ DebugLogOpcode debug_log;
+ };
+};
+
+class DmntCheatVm {
+public:
+ /// Helper Type for DmntCheatVm <=> yuzu Interface
+ class Callbacks {
+ public:
+ virtual ~Callbacks();
+
+ virtual void MemoryRead(VAddr address, void* data, u64 size) = 0;
+ virtual void MemoryWrite(VAddr address, const void* data, u64 size) = 0;
+
+ virtual u64 HidKeysDown() = 0;
+
+ virtual void DebugLog(u8 id, u64 value) = 0;
+ virtual void CommandLog(std::string_view data) = 0;
+ };
+
+ constexpr static size_t MaximumProgramOpcodeCount = 0x400;
+ constexpr static size_t NumRegisters = 0x10;
+
+private:
+ std::unique_ptr<Callbacks> callbacks;
+
+ size_t num_opcodes = 0;
+ size_t instruction_ptr = 0;
+ size_t condition_depth = 0;
+ bool decode_success = false;
+ std::array<u32, MaximumProgramOpcodeCount> program{};
+ std::array<u64, NumRegisters> registers{};
+ std::array<u64, NumRegisters> saved_values{};
+ std::array<size_t, NumRegisters> loop_tops{};
+
+private:
+ bool DecodeNextOpcode(CheatVmOpcode& out);
+ void SkipConditionalBlock();
+ void ResetState();
+
+ /* For implementing the DebugLog opcode. */
+ void DebugLog(u32 log_id, u64 value);
+
+ /* For debugging. These will be IFDEF'd out normally. */
+ template <typename... Args>
+ void LogToDebugFile(const char* format, const Args&... args) {
+ callbacks->CommandLog(fmt::sprintf(format, args...));
+ }
+
+ void LogOpcode(const CheatVmOpcode& opcode);
+
+ static u64 GetVmInt(VmInt value, u32 bit_width);
+ static u64 GetCheatProcessAddress(const CheatProcessMetadata& metadata,
+ MemoryAccessType mem_type, u64 rel_address);
+
+public:
+ DmntCheatVm(std::unique_ptr<Callbacks> callbacks) : callbacks(std::move(callbacks)) {}
+
+ size_t GetProgramSize() {
+ return this->num_opcodes;
+ }
+
+ bool LoadProgram(const std::vector<CheatEntry>& cheats);
+ void Execute(const CheatProcessMetadata& metadata);
+};
+
+}; // namespace Memory