aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Tamper/Operations
diff options
context:
space:
mode:
authorCaian Benedicto <caianbene@gmail.com>2021-03-27 11:12:05 -0300
committerGitHub <noreply@github.com>2021-03-27 15:12:05 +0100
commit0c1ea1212af4f4c3490f548e7764c4a24234ba7f (patch)
treeef4b0f099e0e0f82b1d135373a013a596ac23dd8 /Ryujinx.HLE/HOS/Tamper/Operations
parenta5d5ca06357e2fe1ee2cf880460109ce9da5fe4e (diff)
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
Diffstat (limited to 'Ryujinx.HLE/HOS/Tamper/Operations')
-rw-r--r--Ryujinx.HLE/HOS/Tamper/Operations/Block.cs27
-rw-r--r--Ryujinx.HLE/HOS/Tamper/Operations/ForBlock.cs42
-rw-r--r--Ryujinx.HLE/HOS/Tamper/Operations/IOperand.cs8
-rw-r--r--Ryujinx.HLE/HOS/Tamper/Operations/IOperation.cs7
-rw-r--r--Ryujinx.HLE/HOS/Tamper/Operations/IfBlock.cs35
-rw-r--r--Ryujinx.HLE/HOS/Tamper/Operations/OpAdd.cs21
-rw-r--r--Ryujinx.HLE/HOS/Tamper/Operations/OpAnd.cs21
-rw-r--r--Ryujinx.HLE/HOS/Tamper/Operations/OpLog.cs21
-rw-r--r--Ryujinx.HLE/HOS/Tamper/Operations/OpLsh.cs21
-rw-r--r--Ryujinx.HLE/HOS/Tamper/Operations/OpMov.cs19
-rw-r--r--Ryujinx.HLE/HOS/Tamper/Operations/OpMul.cs21
-rw-r--r--Ryujinx.HLE/HOS/Tamper/Operations/OpNot.cs19
-rw-r--r--Ryujinx.HLE/HOS/Tamper/Operations/OpOr.cs21
-rw-r--r--Ryujinx.HLE/HOS/Tamper/Operations/OpProcCtrl.cs26
-rw-r--r--Ryujinx.HLE/HOS/Tamper/Operations/OpRsh.cs21
-rw-r--r--Ryujinx.HLE/HOS/Tamper/Operations/OpSub.cs21
-rw-r--r--Ryujinx.HLE/HOS/Tamper/Operations/OpXor.cs21
17 files changed, 372 insertions, 0 deletions
diff --git a/Ryujinx.HLE/HOS/Tamper/Operations/Block.cs b/Ryujinx.HLE/HOS/Tamper/Operations/Block.cs
new file mode 100644
index 00000000..d81daa90
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Tamper/Operations/Block.cs
@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+
+namespace Ryujinx.HLE.HOS.Tamper.Operations
+{
+ class Block : IOperation
+ {
+ private IEnumerable<IOperation> _operations;
+
+ public Block(IEnumerable<IOperation> operations)
+ {
+ _operations = operations;
+ }
+
+ public Block(params IOperation[] operations)
+ {
+ _operations = operations;
+ }
+
+ public void Execute()
+ {
+ foreach (IOperation op in _operations)
+ {
+ op.Execute();
+ }
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Tamper/Operations/ForBlock.cs b/Ryujinx.HLE/HOS/Tamper/Operations/ForBlock.cs
new file mode 100644
index 00000000..a478991b
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Tamper/Operations/ForBlock.cs
@@ -0,0 +1,42 @@
+using Ryujinx.HLE.HOS.Tamper.Conditions;
+using System.Collections.Generic;
+
+namespace Ryujinx.HLE.HOS.Tamper.Operations
+{
+ class ForBlock : IOperation
+ {
+ private ulong _count;
+ private Register _register;
+ private IEnumerable<IOperation> _operations;
+
+ public ForBlock(ulong count, Register register, IEnumerable<IOperation> operations)
+ {
+ _count = count;
+ _register = register;
+ _operations = operations;
+ }
+
+ public ForBlock(ulong count, Register register, params IOperation[] operations)
+ {
+ _count = count;
+ _register = register;
+ _operations = operations;
+ }
+
+ public void Execute()
+ {
+ for (ulong i = 0; i < _count; i++)
+ {
+ // Set the register and execute the operations so that changing the
+ // register during runtime does not break iteration.
+
+ _register.Set<ulong>(i);
+
+ foreach (IOperation op in _operations)
+ {
+ op.Execute();
+ }
+ }
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Tamper/Operations/IOperand.cs b/Ryujinx.HLE/HOS/Tamper/Operations/IOperand.cs
new file mode 100644
index 00000000..1aadda0b
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Tamper/Operations/IOperand.cs
@@ -0,0 +1,8 @@
+namespace Ryujinx.HLE.HOS.Tamper.Operations
+{
+ interface IOperand
+ {
+ public T Get<T>() where T : unmanaged;
+ public void Set<T>(T value) where T : unmanaged;
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Tamper/Operations/IOperation.cs b/Ryujinx.HLE/HOS/Tamper/Operations/IOperation.cs
new file mode 100644
index 00000000..a4474979
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Tamper/Operations/IOperation.cs
@@ -0,0 +1,7 @@
+namespace Ryujinx.HLE.HOS.Tamper.Operations
+{
+ interface IOperation
+ {
+ void Execute();
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Tamper/Operations/IfBlock.cs b/Ryujinx.HLE/HOS/Tamper/Operations/IfBlock.cs
new file mode 100644
index 00000000..0ba0f8c3
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Tamper/Operations/IfBlock.cs
@@ -0,0 +1,35 @@
+using Ryujinx.HLE.HOS.Tamper.Conditions;
+using System.Collections.Generic;
+
+namespace Ryujinx.HLE.HOS.Tamper.Operations
+{
+ class IfBlock : IOperation
+ {
+ private ICondition _condition;
+ private IEnumerable<IOperation> _operations;
+
+ public IfBlock(ICondition condition, IEnumerable<IOperation> operations)
+ {
+ _condition = condition;
+ _operations = operations;
+ }
+
+ public IfBlock(ICondition condition, params IOperation[] operations)
+ {
+ _operations = operations;
+ }
+
+ public void Execute()
+ {
+ if (!_condition.Evaluate())
+ {
+ return;
+ }
+
+ foreach (IOperation op in _operations)
+ {
+ op.Execute();
+ }
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Tamper/Operations/OpAdd.cs b/Ryujinx.HLE/HOS/Tamper/Operations/OpAdd.cs
new file mode 100644
index 00000000..214518d7
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Tamper/Operations/OpAdd.cs
@@ -0,0 +1,21 @@
+namespace Ryujinx.HLE.HOS.Tamper.Operations
+{
+ class OpAdd<T> : IOperation where T : unmanaged
+ {
+ IOperand _destination;
+ IOperand _lhs;
+ IOperand _rhs;
+
+ public OpAdd(IOperand destination, IOperand lhs, IOperand rhs)
+ {
+ _destination = destination;
+ _lhs = lhs;
+ _rhs = rhs;
+ }
+
+ public void Execute()
+ {
+ _destination.Set((T)((dynamic)_lhs.Get<T>() + (dynamic)_rhs.Get<T>()));
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Tamper/Operations/OpAnd.cs b/Ryujinx.HLE/HOS/Tamper/Operations/OpAnd.cs
new file mode 100644
index 00000000..366a82b0
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Tamper/Operations/OpAnd.cs
@@ -0,0 +1,21 @@
+namespace Ryujinx.HLE.HOS.Tamper.Operations
+{
+ class OpAnd<T> : IOperation where T : unmanaged
+ {
+ IOperand _destination;
+ IOperand _lhs;
+ IOperand _rhs;
+
+ public OpAnd(IOperand destination, IOperand lhs, IOperand rhs)
+ {
+ _destination = destination;
+ _lhs = lhs;
+ _rhs = rhs;
+ }
+
+ public void Execute()
+ {
+ _destination.Set((T)((dynamic)_lhs.Get<T>() & (dynamic)_rhs.Get<T>()));
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Tamper/Operations/OpLog.cs b/Ryujinx.HLE/HOS/Tamper/Operations/OpLog.cs
new file mode 100644
index 00000000..49f8b41e
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Tamper/Operations/OpLog.cs
@@ -0,0 +1,21 @@
+using Ryujinx.Common.Logging;
+
+namespace Ryujinx.HLE.HOS.Tamper.Operations
+{
+ class OpLog<T> : IOperation where T : unmanaged
+ {
+ int _logId;
+ IOperand _source;
+
+ public OpLog(int logId, IOperand source)
+ {
+ _logId = logId;
+ _source = source;
+ }
+
+ public void Execute()
+ {
+ Logger.Debug?.Print(LogClass.TamperMachine, $"Tamper debug log id={_logId} value={(dynamic)_source.Get<T>():X}");
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Tamper/Operations/OpLsh.cs b/Ryujinx.HLE/HOS/Tamper/Operations/OpLsh.cs
new file mode 100644
index 00000000..34e7c81a
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Tamper/Operations/OpLsh.cs
@@ -0,0 +1,21 @@
+namespace Ryujinx.HLE.HOS.Tamper.Operations
+{
+ class OpLsh<T> : IOperation where T : unmanaged
+ {
+ IOperand _destination;
+ IOperand _lhs;
+ IOperand _rhs;
+
+ public OpLsh(IOperand destination, IOperand lhs, IOperand rhs)
+ {
+ _destination = destination;
+ _lhs = lhs;
+ _rhs = rhs;
+ }
+
+ public void Execute()
+ {
+ _destination.Set((T)((dynamic)_lhs.Get<T>() << (dynamic)_rhs.Get<T>()));
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Tamper/Operations/OpMov.cs b/Ryujinx.HLE/HOS/Tamper/Operations/OpMov.cs
new file mode 100644
index 00000000..5fad38f9
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Tamper/Operations/OpMov.cs
@@ -0,0 +1,19 @@
+namespace Ryujinx.HLE.HOS.Tamper.Operations
+{
+ class OpMov<T> : IOperation where T : unmanaged
+ {
+ IOperand _destination;
+ IOperand _source;
+
+ public OpMov(IOperand destination, IOperand source)
+ {
+ _destination = destination;
+ _source = source;
+ }
+
+ public void Execute()
+ {
+ _destination.Set(_source.Get<T>());
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Tamper/Operations/OpMul.cs b/Ryujinx.HLE/HOS/Tamper/Operations/OpMul.cs
new file mode 100644
index 00000000..5aa0e34e
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Tamper/Operations/OpMul.cs
@@ -0,0 +1,21 @@
+namespace Ryujinx.HLE.HOS.Tamper.Operations
+{
+ class OpMul<T> : IOperation where T : unmanaged
+ {
+ IOperand _destination;
+ IOperand _lhs;
+ IOperand _rhs;
+
+ public OpMul(IOperand destination, IOperand lhs, IOperand rhs)
+ {
+ _destination = destination;
+ _lhs = lhs;
+ _rhs = rhs;
+ }
+
+ public void Execute()
+ {
+ _destination.Set((T)((dynamic)_lhs.Get<T>() * (dynamic)_rhs.Get<T>()));
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Tamper/Operations/OpNot.cs b/Ryujinx.HLE/HOS/Tamper/Operations/OpNot.cs
new file mode 100644
index 00000000..8a97c3fe
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Tamper/Operations/OpNot.cs
@@ -0,0 +1,19 @@
+namespace Ryujinx.HLE.HOS.Tamper.Operations
+{
+ class OpNot<T> : IOperation where T : unmanaged
+ {
+ IOperand _destination;
+ IOperand _source;
+
+ public OpNot(IOperand destination, IOperand source)
+ {
+ _destination = destination;
+ _source = source;
+ }
+
+ public void Execute()
+ {
+ _destination.Set((T)(~(dynamic)_source.Get<T>()));
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Tamper/Operations/OpOr.cs b/Ryujinx.HLE/HOS/Tamper/Operations/OpOr.cs
new file mode 100644
index 00000000..d074de1c
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Tamper/Operations/OpOr.cs
@@ -0,0 +1,21 @@
+namespace Ryujinx.HLE.HOS.Tamper.Operations
+{
+ class OpOr<T> : IOperation where T : unmanaged
+ {
+ IOperand _destination;
+ IOperand _lhs;
+ IOperand _rhs;
+
+ public OpOr(IOperand destination, IOperand lhs, IOperand rhs)
+ {
+ _destination = destination;
+ _lhs = lhs;
+ _rhs = rhs;
+ }
+
+ public void Execute()
+ {
+ _destination.Set((T)((dynamic)_lhs.Get<T>() | (dynamic)_rhs.Get<T>()));
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Tamper/Operations/OpProcCtrl.cs b/Ryujinx.HLE/HOS/Tamper/Operations/OpProcCtrl.cs
new file mode 100644
index 00000000..1b89f450
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Tamper/Operations/OpProcCtrl.cs
@@ -0,0 +1,26 @@
+namespace Ryujinx.HLE.HOS.Tamper.Operations
+{
+ class OpProcCtrl : IOperation
+ {
+ private ITamperedProcess _process;
+ private bool _pause;
+
+ public OpProcCtrl(ITamperedProcess process, bool pause)
+ {
+ _process = process;
+ _pause = pause;
+ }
+
+ public void Execute()
+ {
+ if (_pause)
+ {
+ _process.PauseProcess();
+ }
+ else
+ {
+ _process.ResumeProcess();
+ }
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Tamper/Operations/OpRsh.cs b/Ryujinx.HLE/HOS/Tamper/Operations/OpRsh.cs
new file mode 100644
index 00000000..b08dd957
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Tamper/Operations/OpRsh.cs
@@ -0,0 +1,21 @@
+namespace Ryujinx.HLE.HOS.Tamper.Operations
+{
+ class OpRsh<T> : IOperation where T : unmanaged
+ {
+ IOperand _destination;
+ IOperand _lhs;
+ IOperand _rhs;
+
+ public OpRsh(IOperand destination, IOperand lhs, IOperand rhs)
+ {
+ _destination = destination;
+ _lhs = lhs;
+ _rhs = rhs;
+ }
+
+ public void Execute()
+ {
+ _destination.Set((T)((dynamic)_lhs.Get<T>() >> (dynamic)_rhs.Get<T>()));
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Tamper/Operations/OpSub.cs b/Ryujinx.HLE/HOS/Tamper/Operations/OpSub.cs
new file mode 100644
index 00000000..b9c67d04
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Tamper/Operations/OpSub.cs
@@ -0,0 +1,21 @@
+namespace Ryujinx.HLE.HOS.Tamper.Operations
+{
+ class OpSub<T> : IOperation where T : unmanaged
+ {
+ IOperand _destination;
+ IOperand _lhs;
+ IOperand _rhs;
+
+ public OpSub(IOperand destination, IOperand lhs, IOperand rhs)
+ {
+ _destination = destination;
+ _lhs = lhs;
+ _rhs = rhs;
+ }
+
+ public void Execute()
+ {
+ _destination.Set((T)((dynamic)_lhs.Get<T>() - (dynamic)_rhs.Get<T>()));
+ }
+ }
+}
diff --git a/Ryujinx.HLE/HOS/Tamper/Operations/OpXor.cs b/Ryujinx.HLE/HOS/Tamper/Operations/OpXor.cs
new file mode 100644
index 00000000..3bbb76a1
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Tamper/Operations/OpXor.cs
@@ -0,0 +1,21 @@
+namespace Ryujinx.HLE.HOS.Tamper.Operations
+{
+ class OpXor<T> : IOperation where T : unmanaged
+ {
+ IOperand _destination;
+ IOperand _lhs;
+ IOperand _rhs;
+
+ public OpXor(IOperand destination, IOperand lhs, IOperand rhs)
+ {
+ _destination = destination;
+ _lhs = lhs;
+ _rhs = rhs;
+ }
+
+ public void Execute()
+ {
+ _destination.Set((T)((dynamic)_lhs.Get<T>() ^ (dynamic)_rhs.Get<T>()));
+ }
+ }
+}