mirror of
https://wiilab.wiimart.org/wiimart/WiiMart-Patcher
synced 2025-09-04 04:21:19 +02:00
Add PowerPC instruction encoding
With this, we can write assembly directly within patches. This assists for easier tweaks of code, and no need to manually assemble for rapid prototyping.
This commit is contained in:
parent
88142b2269
commit
957d69f118
78
patches.go
78
patches.go
@ -30,9 +30,11 @@ var OverwriteIOSPatch = PatchSet{
|
|||||||
padding,
|
padding,
|
||||||
}.toBytes(),
|
}.toBytes(),
|
||||||
|
|
||||||
// We wish to clear these so that our custom overwriteIOSMemory
|
// We wish to clear extraneous blrs so that our custom overwriteIOSMemory
|
||||||
// function does not somehow conflict.
|
// function does not somehow conflict. We only preserve onSE.
|
||||||
After: emptyBytes(64),
|
After: append(Instructions{
|
||||||
|
BLR(),
|
||||||
|
}.toBytes(), emptyBytes(60)...),
|
||||||
},
|
},
|
||||||
Patch{
|
Patch{
|
||||||
Name: "Repair textinput::EventObserver vtable",
|
Name: "Repair textinput::EventObserver vtable",
|
||||||
@ -73,70 +75,62 @@ var OverwriteIOSPatch = PatchSet{
|
|||||||
|
|
||||||
// This area should be cleared.
|
// This area should be cleared.
|
||||||
Before: emptyBytes(48),
|
Before: emptyBytes(48),
|
||||||
After: []byte{
|
After: Instructions{
|
||||||
// We want r9 to store the location of MEM_PROT at 0x0d8b420a.
|
// We want r9 to store the location of MEM_PROT at 0x0d8b420a.
|
||||||
// For us, this is mapped to 0xcd8b420a.
|
// For us, this is mapped to 0xcd8b420a.
|
||||||
// lis r9, 0xcd8b
|
LIS(R9, 0xcd8b),
|
||||||
0x3D, 0x20, 0xCD, 0x8B,
|
ORI(R9, R9, 0x420a),
|
||||||
// ori r9, r9, 0x420a
|
|
||||||
0x61, 0x29, 0x42, 0x0A,
|
|
||||||
|
|
||||||
// We want to write 0x2 and unlock everything.
|
// We want to write 0x2 and unlock everything.
|
||||||
// li r10, 0x02
|
LI(R10, 0x02),
|
||||||
0x39, 0x40, 0x00, 0x02,
|
|
||||||
|
|
||||||
// Write!
|
// Write!
|
||||||
// sth r10, 0x0(r9)
|
STH(R10, 0x0, R9),
|
||||||
0xB1, 0x49, 0x00, 0x00,
|
|
||||||
// Flush memory
|
// Flush memory
|
||||||
// eieio
|
EIEIO(),
|
||||||
0x7C, 0x00, 0x06, 0xAC,
|
|
||||||
|
|
||||||
// Location of IOSC_VerifyPublicKeySign
|
// Location of IOSC_VerifyPublicKeySign
|
||||||
// lis r9, 0xd3a7
|
LIS(R9, 0xd3a7),
|
||||||
0x3D, 0x20, 0xD3, 0xA7,
|
ORI(R9, R9, 0x3ad4),
|
||||||
// ori r9, r9, 0x3ad4
|
|
||||||
0x61, 0x29, 0x3A, 0xD4,
|
|
||||||
|
|
||||||
// Write our custom THUMB.
|
// Write our custom THUMB.
|
||||||
// 0x20004770 is equivalent to:
|
// 0x20004770 is equivalent to:
|
||||||
// mov r0, #0x0
|
// mov r0, #0x0
|
||||||
// bx lr
|
// bx lr
|
||||||
// lis r10, 0x2000
|
LIS(R10, 0x2000),
|
||||||
0x3D, 0x40, 0x20, 0x00,
|
ORI(R10, R10, 0x4770),
|
||||||
// ori r10, r10, 0x4770
|
|
||||||
0x61, 0x4A, 0x47, 0x70,
|
|
||||||
|
|
||||||
// Write!
|
// Write!
|
||||||
// stw r10, 0x0(r9)
|
STW(R10, 0x0, R9),
|
||||||
0x91, 0x49, 0x00, 0x00,
|
|
||||||
// Possibly clear cache
|
// Possibly clear cache
|
||||||
// TODO(spotlightishere): Is this needed?
|
// TODO(spotlightishere): Is this needed?
|
||||||
// dcbi 0, r10
|
// dcbi 0, r10
|
||||||
0x7C, 0x00, 0x53, 0xAC,
|
Instruction{0x7C, 0x00, 0x53, 0xAC},
|
||||||
// And finish.
|
// And finish.
|
||||||
// blr
|
BLR(),
|
||||||
0x4E, 0x80, 0x00, 0x20,
|
}.toBytes(),
|
||||||
},
|
|
||||||
},
|
},
|
||||||
Patch{
|
Patch{
|
||||||
Name: "Modify ES_InitLib",
|
Name: "Modify ES_InitLib",
|
||||||
AtOffset: 2399844,
|
AtOffset: 2399844,
|
||||||
|
|
||||||
// We inject in the epilog of the function.
|
// We inject in the epilog of the function.
|
||||||
Before: []byte{
|
Before: Instructions{
|
||||||
0x80, 0x01, 0x00, 0x14, // lwz r0, local_res4(r1)
|
LWZ(R0, 0x14, R1),
|
||||||
0x7C, 0x08, 0x03, 0xA6, // mtspr LR, r0
|
// mtspr LR, r0
|
||||||
0x38, 0x21, 0x00, 0x10, // addi r1, r1, 0x10
|
Instruction{0x7C, 0x08, 0x03, 0xA6},
|
||||||
0x4E, 0x80, 0x00, 0x20, // blr
|
ADDI(R1, R1, 0x10),
|
||||||
0x00, 0x00, 0x00, 0x00, // ; empty space following function
|
BLR(),
|
||||||
},
|
padding,
|
||||||
After: []byte{
|
}.toBytes(),
|
||||||
0x80, 0x01, 0x00, 0x14, // lwz r0, local_res4(r1)
|
After: Instructions{
|
||||||
0x4B, 0xDB, 0xB1, 0x01, // bl overwriteIOSMemory @ 0x80014428
|
LWZ(R0, 0x14, R1),
|
||||||
0x7C, 0x08, 0x03, 0xA6, // mtspr LR, r0
|
// bl overwriteIOSMemory @ 0x80014428
|
||||||
0x38, 0x21, 0x00, 0x10, // addi r1, r1, 0x10
|
Instruction{0x4B, 0xDB, 0xB1, 0x01},
|
||||||
0x4E, 0x80, 0x00, 0x20, // blr
|
// mtspr LR, r0
|
||||||
},
|
Instruction{0x7C, 0x08, 0x03, 0xA6},
|
||||||
|
ADDI(R1, R1, 0x10),
|
||||||
|
BLR(),
|
||||||
|
}.toBytes(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
52
powerpc.go
52
powerpc.go
@ -20,7 +20,57 @@ func (i Instructions) toBytes() []byte {
|
|||||||
// padding is not an actual instruction - it represents 4 zeros.
|
// padding is not an actual instruction - it represents 4 zeros.
|
||||||
var padding Instruction = [4]byte{0x00, 0x00, 0x00, 0x00}
|
var padding Instruction = [4]byte{0x00, 0x00, 0x00, 0x00}
|
||||||
|
|
||||||
// BLR represents the blr PowerPC instruction.
|
// BLR represents the blr mnemonic on PowerPC.
|
||||||
func BLR() Instruction {
|
func BLR() Instruction {
|
||||||
return [4]byte{0x4E, 0x80, 0x00, 0x20}
|
return [4]byte{0x4E, 0x80, 0x00, 0x20}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ADDI represents the addi PowerPC instruction.
|
||||||
|
func ADDI(rT Register, rA Register, value uint16) Instruction {
|
||||||
|
return EncodeInstrDForm(14, rT, rA, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LI represents the li mnemonic on PowerPC.
|
||||||
|
func LI(rT Register, value uint16) Instruction {
|
||||||
|
return ADDI(rT, 0, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SUBI represents the subi mnemonic on PowerPC.
|
||||||
|
func SUBI(rT Register, rA Register, value uint16) Instruction {
|
||||||
|
return ADDI(rT, 0, -value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ADDIS represents the addis PowerPC instruction.
|
||||||
|
func ADDIS(rT Register, rA Register, value uint16) Instruction {
|
||||||
|
return EncodeInstrDForm(15, rT, rA, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LIS represents the lis mnemonic on PowerPC.
|
||||||
|
func LIS(rT Register, value uint16) Instruction {
|
||||||
|
return ADDIS(rT, 0, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ORI represents the ori PowerPC instruction.
|
||||||
|
func ORI(rS Register, rA Register, value uint16) Instruction {
|
||||||
|
return EncodeInstrDForm(24, rS, rA, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// STH represents the sth PowerPC instruction.
|
||||||
|
func STH(rS Register, offset uint16, rA Register) Instruction {
|
||||||
|
return EncodeInstrDForm(44, rS, rA, offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EIEIO represents the eieio PowerPC instruction.
|
||||||
|
func EIEIO() Instruction {
|
||||||
|
return [4]byte{0x7C, 0x00, 0x06, 0xAC}
|
||||||
|
}
|
||||||
|
|
||||||
|
// STW represents the stw PowerPC instruction.
|
||||||
|
func STW(rS Register, offset uint16, rA Register) Instruction {
|
||||||
|
return EncodeInstrDForm(36, rS, rA, offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LWZ represents the lwz PowerPC instruction.
|
||||||
|
func LWZ(rT Register, offset uint16, rA Register) Instruction {
|
||||||
|
return EncodeInstrDForm(32, rT, rA, offset)
|
||||||
|
}
|
||||||
|
130
powerpc_encoding.go
Normal file
130
powerpc_encoding.go
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Register represents a value for a PowerPC register.
|
||||||
|
type Register byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
R0 = iota
|
||||||
|
R1
|
||||||
|
R2
|
||||||
|
R3
|
||||||
|
R4
|
||||||
|
R5
|
||||||
|
R6
|
||||||
|
R7
|
||||||
|
R8
|
||||||
|
R9
|
||||||
|
R10
|
||||||
|
R11
|
||||||
|
R12
|
||||||
|
R13
|
||||||
|
R14
|
||||||
|
R15
|
||||||
|
R16
|
||||||
|
R17
|
||||||
|
R18
|
||||||
|
R19
|
||||||
|
R20
|
||||||
|
R21
|
||||||
|
R22
|
||||||
|
R23
|
||||||
|
R24
|
||||||
|
R25
|
||||||
|
R26
|
||||||
|
R27
|
||||||
|
R28
|
||||||
|
R29
|
||||||
|
R30
|
||||||
|
R31
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bits represents bits for a byte.
|
||||||
|
// If set, considered as 1. If not, 0.
|
||||||
|
type Bits [8]bool
|
||||||
|
|
||||||
|
// getBits returns a usable array of bits for the given byte.
|
||||||
|
func getBits(in byte) Bits {
|
||||||
|
return [8]bool{
|
||||||
|
(in>>7)&1 == 1,
|
||||||
|
(in>>6)&1 == 1,
|
||||||
|
(in>>5)&1 == 1,
|
||||||
|
(in>>4)&1 == 1,
|
||||||
|
(in>>3)&1 == 1,
|
||||||
|
(in>>2)&1 == 1,
|
||||||
|
(in>>1)&1 == 1,
|
||||||
|
in&1 == 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getByte returns the byte represented by these bits.
|
||||||
|
func (b Bits) getByte() byte {
|
||||||
|
var result byte
|
||||||
|
for idx, truthy := range b {
|
||||||
|
if truthy {
|
||||||
|
result |= 1 << (7 - idx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeInstrDForm handles encoding a given opcode, RT, RA and SI.
|
||||||
|
// D-form assumes:
|
||||||
|
// - 6 bits for the opcode
|
||||||
|
// - 5 for rT
|
||||||
|
// - 5 for rA
|
||||||
|
// - 16 for SI
|
||||||
|
func EncodeInstrDForm(opcode byte, rT Register, rA Register, value uint16) Instruction {
|
||||||
|
var instr [2]Bits
|
||||||
|
opBits := getBits(opcode)
|
||||||
|
rTBits := getBits(byte(rT))
|
||||||
|
rABits := getBits(byte(rA))
|
||||||
|
|
||||||
|
instr[0] = Bits{
|
||||||
|
// We need the upper six bits for our opcode.
|
||||||
|
opBits[2],
|
||||||
|
opBits[3],
|
||||||
|
opBits[4],
|
||||||
|
opBits[5],
|
||||||
|
opBits[6],
|
||||||
|
opBits[7],
|
||||||
|
// Next, the lower two bits for rT.
|
||||||
|
rTBits[3],
|
||||||
|
rTBits[4],
|
||||||
|
}
|
||||||
|
instr[1] = Bits{
|
||||||
|
// Third, the lower three bits for rT.
|
||||||
|
rTBits[5],
|
||||||
|
rTBits[6],
|
||||||
|
rTBits[7],
|
||||||
|
// Finally, all five lowest bits for rA.
|
||||||
|
rABits[3],
|
||||||
|
rABits[4],
|
||||||
|
rABits[5],
|
||||||
|
rABits[6],
|
||||||
|
rABits[7],
|
||||||
|
}
|
||||||
|
|
||||||
|
firstInstr := instr[0].getByte()
|
||||||
|
secondInstr := instr[1].getByte()
|
||||||
|
valByte := twoByte(value)
|
||||||
|
|
||||||
|
log.Println(hex.EncodeToString([]byte{
|
||||||
|
firstInstr, secondInstr, valByte[0], valByte[1],
|
||||||
|
}))
|
||||||
|
|
||||||
|
return Instruction{firstInstr, secondInstr, valByte[0], valByte[1]}
|
||||||
|
}
|
||||||
|
|
||||||
|
// twoByte converts a uint16 to two big-endian bytes.
|
||||||
|
func twoByte(passed uint16) [2]byte {
|
||||||
|
result := make([]byte, 2)
|
||||||
|
binary.BigEndian.PutUint16(result, passed)
|
||||||
|
return [2]byte{result[0], result[1]}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user