1
0
Fork 0
mirror of https://github.com/Atmosphere-NX/Atmosphere.git synced 2024-12-28 21:26:14 +00:00

dmnt-cheat: Add register conditional vm instruction

This commit is contained in:
Michael Scire 2019-03-15 13:45:35 -07:00
parent e5ecd243f2
commit 5d79952bdd
2 changed files with 184 additions and 1 deletions

View file

@ -144,6 +144,37 @@ void DmntCheatVm::LogOpcode(const CheatVmOpcode *opcode) {
break; break;
} }
break; break;
case CheatVmOpcodeType_BeginRegisterConditionalBlock:
this->LogToDebugFile("Opcode: Begin Register Conditional\n");
this->LogToDebugFile("Bit Width: %x\n", opcode->begin_reg_cond.bit_width);
this->LogToDebugFile("V Reg Idx: %x\n", opcode->begin_reg_cond.val_reg_index);
switch (opcode->begin_reg_cond.comp_type) {
case CompareRegisterValueType_StaticValue:
this->LogToDebugFile("Comp Type: Static Value\n");
this->LogToDebugFile("Value: %lx\n", opcode->begin_reg_cond.value.bit64);
break;
case CompareRegisterValueType_MemoryRelAddr:
this->LogToDebugFile("Comp Type: Memory Relative Address\n");
this->LogToDebugFile("Mem Type: %x\n", opcode->begin_reg_cond.mem_type);
this->LogToDebugFile("Rel Addr: %lx\n", opcode->begin_reg_cond.rel_address);
break;
case CompareRegisterValueType_MemoryOfsReg:
this->LogToDebugFile("Comp Type: Memory Offset Register\n");
this->LogToDebugFile("Mem Type: %x\n", opcode->begin_reg_cond.mem_type);
this->LogToDebugFile("O Reg Idx: %x\n", opcode->begin_reg_cond.ofs_reg_index);
break;
case CompareRegisterValueType_RegisterRelAddr:
this->LogToDebugFile("Comp Type: Register Relative Address\n");
this->LogToDebugFile("A Reg Idx: %x\n", opcode->begin_reg_cond.addr_reg_index);
this->LogToDebugFile("Rel Addr: %lx\n", opcode->begin_reg_cond.rel_address);
break;
case CompareRegisterValueType_RegisterOfsReg:
this->LogToDebugFile("Comp Type: Register Offset Register\n");
this->LogToDebugFile("A Reg Idx: %x\n", opcode->begin_reg_cond.addr_reg_index);
this->LogToDebugFile("O Reg Idx: %x\n", opcode->begin_reg_cond.ofs_reg_index);
break;
}
break;
default: default:
this->LogToDebugFile("Unknown opcode: %x\n", opcode->opcode); this->LogToDebugFile("Unknown opcode: %x\n", opcode->opcode);
break; break;
@ -208,6 +239,7 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode *out) {
switch (opcode.opcode) { switch (opcode.opcode) {
case CheatVmOpcodeType_BeginConditionalBlock: case CheatVmOpcodeType_BeginConditionalBlock:
case CheatVmOpcodeType_BeginKeypressConditionalBlock: case CheatVmOpcodeType_BeginKeypressConditionalBlock:
case CheatVmOpcodeType_BeginRegisterConditionalBlock:
opcode.begin_conditional_block = true; opcode.begin_conditional_block = true;
break; break;
default: default:
@ -356,6 +388,52 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode *out) {
} }
} }
break; break;
case CheatVmOpcodeType_BeginRegisterConditionalBlock:
{
/* C0TcSX## */
/* C0TcS0Ma aaaaaaaa */
/* C0TcS1Mr */
/* C0TcS2Ra aaaaaaaa */
/* C0TcS3Rr */
/* C0TcS400 VVVVVVVV (VVVVVVVV) */
/* C0 = opcode 0xC0 */
/* T = bit width */
/* c = condition type. */
/* S = source register. */
/* X = value operand type, 0 = main/heap with relative offset, 1 = main/heap with offset register, */
/* 1 = register with relative offset, 2 = register with offset register, 3 = static value. */
/* M = memory type. */
/* a = relative address. */
/* r = offset register. */
/* V = value */
opcode.begin_reg_cond.bit_width = (first_dword >> 20) & 0xF;
opcode.begin_reg_cond.cond_type = (ConditionalComparisonType)((first_dword >> 16) & 0xF);
opcode.begin_reg_cond.val_reg_index = ((first_dword >> 12) & 0xF);
opcode.begin_reg_cond.comp_type = (CompareRegisterValueType)((first_dword >> 8) & 0xF);
switch (opcode.begin_reg_cond.comp_type) {
case CompareRegisterValueType_StaticValue:
opcode.begin_reg_cond.value = GetNextVmInt(opcode.begin_reg_cond.bit_width);
break;
case CompareRegisterValueType_MemoryRelAddr:
opcode.begin_reg_cond.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF);
opcode.begin_reg_cond.rel_address = (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword()));
break;
case CompareRegisterValueType_MemoryOfsReg:
opcode.begin_reg_cond.mem_type = (MemoryAccessType)((first_dword >> 4) & 0xF);
opcode.begin_reg_cond.ofs_reg_index = (first_dword & 0xF);
break;
case CompareRegisterValueType_RegisterRelAddr:
opcode.begin_reg_cond.addr_reg_index = ((first_dword >> 4) & 0xF);
opcode.begin_reg_cond.rel_address = (((u64)(first_dword & 0xF) << 32ul) | ((u64)GetNextDword()));
break;
case CompareRegisterValueType_RegisterOfsReg:
opcode.begin_reg_cond.addr_reg_index = ((first_dword >> 4) & 0xF);
opcode.begin_reg_cond.ofs_reg_index = (first_dword & 0xF);
break;
}
}
break;
case CheatVmOpcodeType_ExtendedWidth: case CheatVmOpcodeType_ExtendedWidth:
default: default:
/* Unrecognized instruction cannot be decoded. */ /* Unrecognized instruction cannot be decoded. */
@ -754,6 +832,86 @@ void DmntCheatVm::Execute(const CheatProcessMetadata *metadata) {
} }
} }
break; break;
case CheatVmOpcodeType_BeginRegisterConditionalBlock:
{
/* Get value from register. */
u64 src_value = 0;
switch (cur_opcode.begin_reg_cond.bit_width) {
case 1:
src_value = static_cast<u8>(this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFul);
break;
case 2:
src_value = static_cast<u16>(this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFFFul);
break;
case 4:
src_value = static_cast<u32>(this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFFFFFFFul);
break;
case 8:
src_value = static_cast<u64>(this->registers[cur_opcode.begin_reg_cond.val_reg_index] & 0xFFFFFFFFFFFFFFFFul);
break;
}
/* Read value from memory. */
u64 cond_value = 0;
if (cur_opcode.begin_reg_cond.comp_type == CompareRegisterValueType_StaticValue) {
cond_value = GetVmInt(cur_opcode.begin_reg_cond.value, cur_opcode.begin_reg_cond.bit_width);
} else {
u64 cond_address = 0;
switch (cur_opcode.begin_reg_cond.comp_type) {
case CompareRegisterValueType_MemoryRelAddr:
cond_address = GetCheatProcessAddress(metadata, cur_opcode.begin_reg_cond.mem_type, cur_opcode.begin_reg_cond.rel_address);
break;
case CompareRegisterValueType_MemoryOfsReg:
cond_address = GetCheatProcessAddress(metadata, cur_opcode.begin_reg_cond.mem_type, this->registers[cur_opcode.begin_reg_cond.ofs_reg_index]);
break;
case CompareRegisterValueType_RegisterRelAddr:
cond_address = this->registers[cur_opcode.begin_reg_cond.addr_reg_index] + cur_opcode.begin_reg_cond.rel_address;
break;
case CompareRegisterValueType_RegisterOfsReg:
cond_address = this->registers[cur_opcode.begin_reg_cond.addr_reg_index] + this->registers[cur_opcode.begin_reg_cond.ofs_reg_index];
break;
default:
break;
}
switch (cur_opcode.begin_reg_cond.bit_width) {
case 1:
case 2:
case 4:
case 8:
DmntCheatManager::ReadCheatProcessMemoryForVm(cond_address, &cond_value, cur_opcode.begin_reg_cond.bit_width);
break;
}
}
/* Check against condition. */
bool cond_met = false;
switch (cur_opcode.begin_reg_cond.cond_type) {
case ConditionalComparisonType_GT:
cond_met = src_value > cond_value;
break;
case ConditionalComparisonType_GE:
cond_met = src_value >= cond_value;
break;
case ConditionalComparisonType_LT:
cond_met = src_value < cond_value;
break;
case ConditionalComparisonType_LE:
cond_met = src_value <= cond_value;
break;
case ConditionalComparisonType_EQ:
cond_met = src_value == cond_value;
break;
case ConditionalComparisonType_NE:
cond_met = src_value != cond_value;
break;
}
/* Skip conditional block if condition not met. */
if (!cond_met) {
this->SkipConditionalBlock();
}
}
break;
default: default:
/* By default, we do a no-op. */ /* By default, we do a no-op. */
break; break;

View file

@ -35,10 +35,14 @@ enum CheatVmOpcodeType : u32 {
/* These are not implemented by Gateway's VM. */ /* These are not implemented by Gateway's VM. */
CheatVmOpcodeType_PerformArithmeticRegister = 9, CheatVmOpcodeType_PerformArithmeticRegister = 9,
CheatVmOpcodeType_StoreRegisterToAddress = 10, CheatVmOpcodeType_StoreRegisterToAddress = 10,
CheatVmOpcodeType_Reserved11 = 11,
/* This is a meta entry, and not a real opcode. */ /* This is a meta entry, and not a real opcode. */
/* This is to facilitate multi-nybble instruction decoding in the future. */ /* This is to facilitate multi-nybble instruction decoding. */
CheatVmOpcodeType_ExtendedWidth = 12, CheatVmOpcodeType_ExtendedWidth = 12,
/* Extended width opcodes. */
CheatVmOpcodeType_BeginRegisterConditionalBlock = 0xC0,
}; };
enum MemoryAccessType : u32 { enum MemoryAccessType : u32 {
@ -77,6 +81,14 @@ enum StoreRegisterOffsetType : u32 {
StoreRegisterOffsetType_Imm = 2, StoreRegisterOffsetType_Imm = 2,
}; };
enum CompareRegisterValueType : u32 {
CompareRegisterValueType_MemoryRelAddr = 0,
CompareRegisterValueType_MemoryOfsReg = 1,
CompareRegisterValueType_RegisterRelAddr = 2,
CompareRegisterValueType_RegisterOfsReg = 3,
CompareRegisterValueType_StaticValue = 4,
};
union VmInt { union VmInt {
u8 bit8; u8 bit8;
u16 bit16; u16 bit16;
@ -161,6 +173,18 @@ struct StoreRegisterToAddressOpcode {
u64 rel_address; 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 ofs_reg_index;
u64 rel_address;
VmInt value;
};
struct CheatVmOpcode { struct CheatVmOpcode {
CheatVmOpcodeType opcode; CheatVmOpcodeType opcode;
@ -177,6 +201,7 @@ struct CheatVmOpcode {
BeginKeypressConditionalOpcode begin_keypress_cond; BeginKeypressConditionalOpcode begin_keypress_cond;
PerformArithmeticRegisterOpcode perform_math_reg; PerformArithmeticRegisterOpcode perform_math_reg;
StoreRegisterToAddressOpcode str_register; StoreRegisterToAddressOpcode str_register;
BeginRegisterConditionalOpcode begin_reg_cond;
}; };
}; };