diff --git a/stratosphere/dmnt/source/dmnt_cheat_vm.cpp b/stratosphere/dmnt/source/dmnt_cheat_vm.cpp index 3a7b95625..269b4a437 100644 --- a/stratosphere/dmnt/source/dmnt_cheat_vm.cpp +++ b/stratosphere/dmnt/source/dmnt_cheat_vm.cpp @@ -95,15 +95,15 @@ void DmntCheatVm::LogOpcode(const CheatVmOpcode *opcode) { this->LogToDebugFile("From Reg: %d\n", opcode->ldr_memory.load_from_reg); this->LogToDebugFile("Rel Addr: %lx\n", opcode->ldr_memory.rel_address); break; - case CheatVmOpcodeType_StoreToRegisterAddress: - this->LogToDebugFile("Opcode: Store Static to Register Address\n"); - this->LogToDebugFile("Bit Width: %x\n", opcode->str_regaddr.bit_width); - this->LogToDebugFile("Reg Idx: %x\n", opcode->str_regaddr.reg_index); - if (opcode->str_regaddr.add_offset_reg) { - this->LogToDebugFile("O Reg Idx: %x\n", opcode->str_regaddr.offset_reg_index); + case CheatVmOpcodeType_StoreStaticToAddress: + this->LogToDebugFile("Opcode: Store Static to Address\n"); + this->LogToDebugFile("Bit Width: %x\n", opcode->str_static.bit_width); + this->LogToDebugFile("Reg Idx: %x\n", opcode->str_static.reg_index); + if (opcode->str_static.add_offset_reg) { + this->LogToDebugFile("O Reg Idx: %x\n", opcode->str_static.offset_reg_index); } - this->LogToDebugFile("Incr Reg: %d\n", opcode->str_regaddr.increment_reg); - this->LogToDebugFile("Value: %lx\n", opcode->str_regaddr.value); + this->LogToDebugFile("Incr Reg: %d\n", opcode->str_static.increment_reg); + this->LogToDebugFile("Value: %lx\n", opcode->str_static.value); break; case CheatVmOpcodeType_PerformArithmeticStatic: this->LogToDebugFile("Opcode: Perform Static Arithmetic\n"); @@ -127,6 +127,23 @@ void DmntCheatVm::LogOpcode(const CheatVmOpcode *opcode) { this->LogToDebugFile("Src2 Idx: %x\n", opcode->perform_math_reg.src_reg_2_index); } break; + case CheatVmOpcodeType_StoreRegisterToAddress: + this->LogToDebugFile("Opcode: Store Register to Address\n"); + this->LogToDebugFile("Bit Width: %x\n", opcode->str_register.bit_width); + this->LogToDebugFile("S Reg Idx: %x\n", opcode->str_register.str_reg_index); + this->LogToDebugFile("A Reg Idx: %x\n", opcode->str_register.addr_reg_index); + this->LogToDebugFile("Incr Reg: %d\n", opcode->str_register.increment_reg); + switch (opcode->str_register.ofs_type) { + case StoreRegisterOffsetType_None: + break; + case StoreRegisterOffsetType_Reg: + this->LogToDebugFile("O Reg Idx: %x\n", opcode->str_register.ofs_reg_index); + break; + case StoreRegisterOffsetType_Imm: + this->LogToDebugFile("Rel Addr: %lx\n", opcode->str_register.rel_address); + break; + } + break; default: this->LogToDebugFile("Unknown opcode: %x\n", opcode->opcode); break; @@ -252,16 +269,16 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode *out) { opcode.ldr_memory.rel_address = ((u64)(first_dword & 0xFF) << 32ul) | ((u64)second_dword); } break; - case CheatVmOpcodeType_StoreToRegisterAddress: + case CheatVmOpcodeType_StoreStaticToAddress: { /* 6T0RIor0 VVVVVVVV VVVVVVVV */ /* Read additional words. */ - opcode.str_regaddr.bit_width = (first_dword >> 24) & 0xF; - opcode.str_regaddr.reg_index = ((first_dword >> 16) & 0xF); - opcode.str_regaddr.increment_reg = ((first_dword >> 12) & 0xF) != 0; - opcode.str_regaddr.add_offset_reg = ((first_dword >> 8) & 0xF) != 0; - opcode.str_regaddr.offset_reg_index = ((first_dword >> 4) & 0xF); - opcode.str_regaddr.value = (((u64)GetNextDword()) << 32ul) | ((u64)GetNextDword()); + opcode.str_static.bit_width = (first_dword >> 24) & 0xF; + opcode.str_static.reg_index = ((first_dword >> 16) & 0xF); + opcode.str_static.increment_reg = ((first_dword >> 12) & 0xF) != 0; + opcode.str_static.add_offset_reg = ((first_dword >> 8) & 0xF) != 0; + opcode.str_static.offset_reg_index = ((first_dword >> 4) & 0xF); + opcode.str_static.value = (((u64)GetNextDword()) << 32ul) | ((u64)GetNextDword()); } break; case CheatVmOpcodeType_PerformArithmeticStatic: @@ -297,6 +314,37 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode *out) { } } break; + case CheatVmOpcodeType_StoreRegisterToAddress: + { + /* ATSRIOra (aaaaaaaa) */ + /* A = opcode 10 */ + /* T = bit width */ + /* S = src register index */ + /* R = address register index */ + /* I = 1 if increment address register, 0 if not increment address register */ + /* O = offset type, 0 = None, 1 = Register, 2 = Immediate */ + /* r = offset register (for offset type 1) */ + /* a = relative address (for offset type 2) */ + opcode.str_register.bit_width = (first_dword >> 24) & 0xF; + opcode.str_register.str_reg_index = ((first_dword >> 20) & 0xF); + opcode.str_register.addr_reg_index = ((first_dword >> 16) & 0xF); + opcode.str_register.increment_reg = ((first_dword >> 12) & 0xF) != 0; + opcode.str_register.ofs_type = (StoreRegisterOffsetType)(((first_dword >> 8) & 0xF)); + opcode.str_register.ofs_reg_index = ((first_dword >> 4) & 0xF); + switch (opcode.str_register.ofs_type) { + case StoreRegisterOffsetType_None: + case StoreRegisterOffsetType_Reg: + /* Nothing more to do */ + break; + case StoreRegisterOffsetType_Imm: + opcode.str_register.rel_address = (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword())); + break; + default: + opcode.str_register.ofs_type = StoreRegisterOffsetType_None; + break; + } + } + break; case CheatVmOpcodeType_ExtendedWidth: default: /* Unrecognized instruction cannot be decoded. */ @@ -502,26 +550,26 @@ void DmntCheatVm::Execute(const CheatProcessMetadata *metadata) { } } break; - case CheatVmOpcodeType_StoreToRegisterAddress: + case CheatVmOpcodeType_StoreStaticToAddress: { /* Calculate address. */ - u64 dst_address = this->registers[cur_opcode.str_regaddr.reg_index]; - u64 dst_value = cur_opcode.str_regaddr.value; - if (cur_opcode.str_regaddr.add_offset_reg) { - dst_address += this->registers[cur_opcode.str_regaddr.offset_reg_index]; + u64 dst_address = this->registers[cur_opcode.str_static.reg_index]; + u64 dst_value = cur_opcode.str_static.value; + if (cur_opcode.str_static.add_offset_reg) { + dst_address += this->registers[cur_opcode.str_static.offset_reg_index]; } /* Write value to memory. Gateway only writes on valid bitwidth. */ - switch (cur_opcode.str_regaddr.bit_width) { + switch (cur_opcode.str_static.bit_width) { case 1: case 2: case 4: case 8: - DmntCheatManager::WriteCheatProcessMemoryForVm(dst_address, &dst_value, cur_opcode.str_regaddr.bit_width); + DmntCheatManager::WriteCheatProcessMemoryForVm(dst_address, &dst_value, cur_opcode.str_static.bit_width); break; } /* Increment register if relevant. */ - if (cur_opcode.str_regaddr.increment_reg) { - this->registers[cur_opcode.str_regaddr.reg_index] += cur_opcode.str_regaddr.bit_width; + if (cur_opcode.str_static.increment_reg) { + this->registers[cur_opcode.str_static.reg_index] += cur_opcode.str_static.bit_width; } } break; @@ -635,6 +683,39 @@ void DmntCheatVm::Execute(const CheatProcessMetadata *metadata) { this->registers[cur_opcode.perform_math_reg.dst_reg_index] = res_val; } break; + case CheatVmOpcodeType_StoreRegisterToAddress: + { + /* Calculate address. */ + u64 dst_value = this->registers[cur_opcode.str_register.str_reg_index]; + u64 dst_address = this->registers[cur_opcode.str_register.addr_reg_index]; + switch (cur_opcode.str_register.ofs_type) { + case StoreRegisterOffsetType_None: + /* Nothing more to do */ + break; + case StoreRegisterOffsetType_Reg: + dst_address += this->registers[cur_opcode.str_register.ofs_reg_index]; + break; + case StoreRegisterOffsetType_Imm: + dst_address += cur_opcode.str_register.rel_address; + break; + } + + /* Write value to memory. Write only on valid bitwidth. */ + switch (cur_opcode.str_register.bit_width) { + case 1: + case 2: + case 4: + case 8: + DmntCheatManager::WriteCheatProcessMemoryForVm(dst_address, &dst_value, cur_opcode.str_register.bit_width); + break; + } + + /* Increment register if relevant. */ + if (cur_opcode.str_register.increment_reg) { + this->registers[cur_opcode.str_register.addr_reg_index] += cur_opcode.str_register.bit_width; + } + } + break; default: /* By default, we do a no-op. */ break; diff --git a/stratosphere/dmnt/source/dmnt_cheat_vm.hpp b/stratosphere/dmnt/source/dmnt_cheat_vm.hpp index d892479bc..e9cffa8bc 100644 --- a/stratosphere/dmnt/source/dmnt_cheat_vm.hpp +++ b/stratosphere/dmnt/source/dmnt_cheat_vm.hpp @@ -28,12 +28,13 @@ enum CheatVmOpcodeType : u32 { CheatVmOpcodeType_ControlLoop = 3, CheatVmOpcodeType_LoadRegisterStatic = 4, CheatVmOpcodeType_LoadRegisterMemory = 5, - CheatVmOpcodeType_StoreToRegisterAddress = 6, + CheatVmOpcodeType_StoreStaticToAddress = 6, CheatVmOpcodeType_PerformArithmeticStatic = 7, CheatVmOpcodeType_BeginKeypressConditionalBlock = 8, /* These are not implemented by Gateway's VM. */ CheatVmOpcodeType_PerformArithmeticRegister = 9, + CheatVmOpcodeType_StoreRegisterToAddress = 10, /* This is a meta entry, and not a real opcode. */ /* This is to facilitate multi-nybble instruction decoding in the future. */ @@ -70,6 +71,12 @@ enum RegisterArithmeticType : u32 { RegisterArithmeticType_None = 9, }; +enum StoreRegisterOffsetType : u32 { + StoreRegisterOffsetType_None = 0, + StoreRegisterOffsetType_Reg = 1, + StoreRegisterOffsetType_Imm = 2, +}; + union VmInt { u8 bit8; u16 bit16; @@ -114,7 +121,7 @@ struct LoadRegisterMemoryOpcode { u64 rel_address; }; -struct StoreToRegisterAddressOpcode { +struct StoreStaticToAddressOpcode { u32 bit_width; u32 reg_index; bool increment_reg; @@ -144,6 +151,17 @@ struct PerformArithmeticRegisterOpcode { VmInt value; }; +struct StoreRegisterToAddressOpcode { + u32 bit_width; + u32 str_reg_index; + u32 addr_reg_index; + bool increment_reg; + StoreRegisterOffsetType ofs_type; + u32 ofs_reg_index; + u64 rel_address; +}; + + struct CheatVmOpcode { CheatVmOpcodeType opcode; union { @@ -153,10 +171,11 @@ struct CheatVmOpcode { ControlLoopOpcode ctrl_loop; LoadRegisterStaticOpcode ldr_static; LoadRegisterMemoryOpcode ldr_memory; - StoreToRegisterAddressOpcode str_regaddr; + StoreStaticToAddressOpcode str_static; PerformArithmeticStaticOpcode perform_math_static; BeginKeypressConditionalOpcode begin_keypress_cond; PerformArithmeticRegisterOpcode perform_math_reg; + StoreRegisterToAddressOpcode str_register; }; };