mirror of
				https://github.com/Atmosphere-NX/Atmosphere.git
				synced 2025-10-25 01:35:51 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			332 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			332 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2018-2020 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/>.
 | |
|  */
 | |
| #pragma once
 | |
| #include <stratosphere.hpp>
 | |
| 
 | |
| namespace ams::dmnt::cheat::impl {
 | |
| 
 | |
|     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,
 | |
|         CheatVmOpcodeType_ReadWriteStaticRegister = 0xC3,
 | |
| 
 | |
|         /* 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_PauseProcess = 0xFF0,
 | |
|         CheatVmOpcodeType_ResumeProcess = 0xFF1,
 | |
|         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;
 | |
|         bool should_operate[0x10];
 | |
|     };
 | |
| 
 | |
|     struct ReadWriteStaticRegisterOpcode {
 | |
|         u32 static_idx;
 | |
|         u32 idx;
 | |
|     };
 | |
| 
 | |
|     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;
 | |
|             ReadWriteStaticRegisterOpcode rw_static_reg;
 | |
|             DebugLogOpcode debug_log;
 | |
|         };
 | |
|     };
 | |
| 
 | |
|     class CheatVirtualMachine {
 | |
|         public:
 | |
|             constexpr static size_t MaximumProgramOpcodeCount = 0x400;
 | |
|             constexpr static size_t NumRegisters = 0x10;
 | |
|             constexpr static size_t NumReadableStaticRegisters = 0x80;
 | |
|             constexpr static size_t NumWritableStaticRegisters = 0x80;
 | |
|             constexpr static size_t NumStaticRegisters = NumReadableStaticRegisters + NumWritableStaticRegisters;
 | |
|         private:
 | |
|             size_t num_opcodes = 0;
 | |
|             size_t instruction_ptr = 0;
 | |
|             size_t condition_depth = 0;
 | |
|             bool decode_success = false;
 | |
|             u32 program[MaximumProgramOpcodeCount] = {0};
 | |
|             u64 registers[NumRegisters] = {0};
 | |
|             u64 saved_values[NumRegisters] = {0};
 | |
|             u64 static_registers[NumStaticRegisters] = {0};
 | |
|             size_t loop_tops[NumRegisters] = {0};
 | |
|         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. */
 | |
|             void OpenDebugLogFile();
 | |
|             void CloseDebugLogFile();
 | |
|             void LogToDebugFile(const char *format, ...);
 | |
|             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:
 | |
|             CheatVirtualMachine() { }
 | |
| 
 | |
|             size_t GetProgramSize() {
 | |
|                 return this->num_opcodes;
 | |
|             }
 | |
| 
 | |
|             bool LoadProgram(const CheatEntry *cheats, size_t num_cheats);
 | |
|             void Execute(const CheatProcessMetadata *metadata);
 | |
| 
 | |
|             u64 GetStaticRegister(size_t which) const {
 | |
|                 return this->static_registers[which];
 | |
|             }
 | |
| 
 | |
|             void SetStaticRegister(size_t which, u64 value) {
 | |
|                 this->static_registers[which] = value;
 | |
|             }
 | |
| 
 | |
|             void ResetStaticRegisters() {
 | |
|                 std::memset(this->static_registers, 0, sizeof(this->static_registers));
 | |
|             }
 | |
|     #ifdef DMNT_CHEAT_VM_DEBUG_LOG
 | |
|         private:
 | |
|             fs::FileHandle debug_log_file;
 | |
|             s64 debug_log_file_offset;
 | |
|             bool has_debug_log_file;
 | |
|             char debug_log_format_buf[0x100];
 | |
|     #endif
 | |
|     };
 | |
| 
 | |
| }
 |