From 0c1ea1212af4f4c3490f548e7764c4a24234ba7f Mon Sep 17 00:00:00 2001 From: Caian Benedicto Date: Sat, 27 Mar 2021 11:12:05 -0300 Subject: Add the TamperMachine module for runtime mods and cheats (#1928) * Add initial implementation of the Tamper Machine * Implement Atmosphere opcodes 0, 4 and 9 * Add missing TamperCompilationException class * Implement Atmosphere conditional and loop opcodes 1, 2 and 3 * Inplement input conditional opcode 8 * Add register store opcode A * Implement extended pause/resume opcodes FF0 and FF1 * Implement extended log opcode FFF * Implement extended register conditional opcode C0 * Refactor TamperProgram to an interface * Moved Atmosphere classes to a separate subdirectory * Fix OpProcCtrl class not setting process * Implement extended register save/restore opcodes C1, C2 and C3 * Refactor code emitters to separate classes * Supress memory access errors from the Tamper Machine * Add debug information to tamper register and memory writes * Add block stack check to Atmosphere Cheat compiler * Add handheld input support to Tamper Machine * Fix code styling * Fix build id and cheat case mismatch * Fix invalid immediate size selection * Print build ids of the title * Prevent Tamper Machine from change code regions * Remove Atmosphere namespace * Remove empty cheats from the list * Prevent code modification without disabling the tampering * Fix missing addressing mode in LoadRegisterWithMemory * Fix wrong addressing in RegisterConditional * Add name to the tamper machine thread * Fix code styling --- Ryujinx.HLE/HOS/Tamper/CodeEmitters/Arithmetic.cs | 105 ++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 Ryujinx.HLE/HOS/Tamper/CodeEmitters/Arithmetic.cs (limited to 'Ryujinx.HLE/HOS/Tamper/CodeEmitters/Arithmetic.cs') diff --git a/Ryujinx.HLE/HOS/Tamper/CodeEmitters/Arithmetic.cs b/Ryujinx.HLE/HOS/Tamper/CodeEmitters/Arithmetic.cs new file mode 100644 index 00000000..b7d46d3a --- /dev/null +++ b/Ryujinx.HLE/HOS/Tamper/CodeEmitters/Arithmetic.cs @@ -0,0 +1,105 @@ +using Ryujinx.HLE.Exceptions; +using Ryujinx.HLE.HOS.Tamper.Operations; +using System; +using System.Collections.Generic; + +namespace Ryujinx.HLE.HOS.Tamper.CodeEmitters +{ + /// + /// Code type 9 allows performing arithmetic on registers. + /// + class Arithmetic + { + private const int OperationWidthIndex = 1; + private const int OperationTypeIndex = 2; + private const int DestinationRegisterIndex = 3; + private const int LeftHandSideRegisterIndex = 4; + private const int UseImmediateAsRhsIndex = 5; + private const int RightHandSideRegisterIndex = 6; + private const int RightHandSideImmediateIndex = 8; + + private const int RightHandSideImmediate8 = 8; + private const int RightHandSideImmediate16 = 16; + + private const byte Add = 0; // lhs + rhs + private const byte Sub = 1; // lhs - rhs + private const byte Mul = 2; // lhs * rhs + private const byte Lsh = 3; // lhs << rhs + private const byte Rsh = 4; // lhs >> rhs + private const byte And = 5; // lhs & rhs + private const byte Or = 6; // lhs | rhs + private const byte Not = 7; // ~lhs (discards right-hand operand) + private const byte Xor = 8; // lhs ^ rhs + private const byte Mov = 9; // lhs (discards right-hand operand) + + public static void Emit(byte[] instruction, CompilationContext context) + { + // 9TCRS0s0 + // T: Width of arithmetic operation(1, 2, 4, or 8 bytes). + // C: Arithmetic operation to apply, see below. + // R: Register to store result in. + // S: Register to use as left - hand operand. + // s: Register to use as right - hand operand. + + // 9TCRS100 VVVVVVVV (VVVVVVVV) + // T: Width of arithmetic operation(1, 2, 4, or 8 bytes). + // C: Arithmetic operation to apply, see below. + // R: Register to store result in. + // S: Register to use as left - hand operand. + // V: Value to use as right - hand operand. + + byte operationWidth = instruction[OperationWidthIndex]; + byte operation = instruction[OperationTypeIndex]; + Register destinationRegister = context.GetRegister(instruction[DestinationRegisterIndex]); + Register leftHandSideRegister = context.GetRegister(instruction[LeftHandSideRegisterIndex]); + byte rightHandSideIsImmediate = instruction[UseImmediateAsRhsIndex]; + IOperand rightHandSideOperand; + + switch (rightHandSideIsImmediate) + { + case 0: + // Use a register as right-hand side. + rightHandSideOperand = context.GetRegister(instruction[RightHandSideRegisterIndex]); + break; + case 1: + // Use an immediate as right-hand side. + int immediateSize = operationWidth <= 4 ? RightHandSideImmediate8 : RightHandSideImmediate16; + ulong immediate = InstructionHelper.GetImmediate(instruction, RightHandSideImmediateIndex, immediateSize); + rightHandSideOperand = new Value(immediate); + break; + default: + throw new TamperCompilationException($"Invalid right-hand side switch {rightHandSideIsImmediate} in Atmosphere cheat"); + } + + void Emit(Type operationType, IOperand rhs = null) + { + List operandList = new List(); + operandList.Add(destinationRegister); + operandList.Add(leftHandSideRegister); + + if (rhs != null) + { + operandList.Add(rhs); + } + + InstructionHelper.Emit(operationType, operationWidth, context, operandList.ToArray()); + } + + switch (operation) + { + case Add: Emit(typeof(OpAdd<>), rightHandSideOperand); break; + case Sub: Emit(typeof(OpSub<>), rightHandSideOperand); break; + case Mul: Emit(typeof(OpMul<>), rightHandSideOperand); break; + case Lsh: Emit(typeof(OpLsh<>), rightHandSideOperand); break; + case Rsh: Emit(typeof(OpRsh<>), rightHandSideOperand); break; + case And: Emit(typeof(OpAnd<>), rightHandSideOperand); break; + case Or: Emit(typeof(OpOr<> ), rightHandSideOperand); break; + case Not: Emit(typeof(OpNot<>) ); break; + case Xor: Emit(typeof(OpXor<>), rightHandSideOperand); break; + case Mov: Emit(typeof(OpMov<>) ); break; + default: + throw new TamperCompilationException($"Invalid arithmetic operation {operation} in Atmosphere cheat"); + } + } + } +} -- cgit v1.2.3