Skip to content

Instantly share code, notes, and snippets.

@hcs64
Created July 10, 2014 06:28
Show Gist options
  • Save hcs64/c612fbccac417531ead4 to your computer and use it in GitHub Desktop.
Save hcs64/c612fbccac417531ead4 to your computer and use it in GitHub Desktop.
gsuploader via arduino
#include <string.h>
#define DIRECT 1
#define VERIFY 0
const int out_pins[5] = {3,2,0,1,4};
const int in_pins[5] = {22,21,20,19,18};
void setup_pins() {
for (int i = 0; i < 5; i++) {
pinMode(out_pins[i], OUTPUT);
pinMode(in_pins[i], INPUT);
}
}
unsigned char do_read() {
#if DIRECT
unsigned char v = PINF;
if (!(v & 2)) {
return 0;
}
return (v>>4)|0x10;
#else
unsigned char v = 0;
v |= digitalRead(in_pins[1]) == HIGH ? 1 : 0;
v |= digitalRead(in_pins[2]) == HIGH ? 2 : 0;
v |= digitalRead(in_pins[3]) == HIGH ? 4 : 0;
v |= digitalRead(in_pins[4]) == HIGH ? 8 : 0;
if (digitalRead(in_pins[0]) == LOW) {
return 0;
}
return v|0x10;
#endif
}
void do_clear() {
#if DIRECT
PORTD &= ~0x1f;
#else
digitalWrite(out_pins[4], LOW);
digitalWrite(out_pins[3], LOW);
digitalWrite(out_pins[2], LOW);
digitalWrite(out_pins[1], LOW);
digitalWrite(out_pins[0], LOW);
#endif
}
void do_write(unsigned char val) {
#if DIRECT
PORTD = (PORTD & ~0x1f) | (0x10|(val&0xf));
#else
// don't change while flag is set
digitalWrite(out_pins[4], LOW);
digitalWrite(out_pins[0], val & 1 ? HIGH : LOW);
digitalWrite(out_pins[1], val & 2 ? HIGH : LOW);
digitalWrite(out_pins[2], val & 4 ? HIGH : LOW);
digitalWrite(out_pins[3], val & 8 ? HIGH : LOW);
digitalWrite(out_pins[4], HIGH);
#endif
}
unsigned char ReadWriteNibble(unsigned char x) {
do_write(x & 0xf);
while ((do_read()&0x10) == 0) ;
unsigned char retval = do_read()&0xf;
do_clear();
while ((do_read()&0x10) == 0x10) ;
return retval;
}
unsigned char ReadWriteByte(unsigned char b) {
return (ReadWriteNibble(b>>4)<<4)|ReadWriteNibble(b);
}
unsigned char ReadByte(void) {
return ReadWriteByte(0);
}
unsigned long ReadWrite32(unsigned long v) {
return (((unsigned long)ReadWriteByte(v>>24))<<24) |
(((unsigned long)ReadWriteByte(v>>16))<<16) |
(((unsigned long)ReadWriteByte(v>> 8))<< 8) |
ReadWriteByte(v);
}
void InitGSCommsNoisy(int noisy) {
int quiet = !noisy;
if (!quiet) Serial.println("Sync...");
while (1) {
do_write(3);
delay(10);
unsigned char retval = do_read()&0xf;
do_clear();
delay(10);
do_write(3);
delay(10);
retval = (retval << 4) | (do_read()&0xf);
do_clear();
delay(10);
if (retval == 'g') break;
if (!quiet) {
Serial.print("Sync got ");
Serial.print((int)retval);
Serial.println(", retrying");
}
// try to get back in sync
do_write(3);
delay(100);
do_clear();
delay(100);
}
Handshake(quiet);
}
void Handshake(int quiet) {
if (!quiet) Serial.println("Handshake...");
while (1) {
if (ReadWriteByte('G') != 'g') continue;
if (ReadWriteByte('T') == 't') break;
}
if (!quiet) Serial.println("OK");
}
void InitGSComms() {
InitGSCommsNoisy(0);
}
char * GetGSVersion() {
ReadWriteByte('f');
ReadByte();
ReadByte();
ReadByte();
unsigned char length = ReadByte();
char * vs = (char*)malloc(length+1);
for (unsigned char i = 0; i < length; i++) {
vs[i] = ReadByte();
}
vs[length] = '\0';
return vs;
}
unsigned char EndTransaction(unsigned char checksum) {
ReadWrite32(0);
ReadWrite32(0);
return ReadWriteByte(checksum);
}
void ReadRAM(unsigned char *buf, unsigned long address, unsigned long length) {
ReadWriteByte(1);
ReadWrite32(address);
ReadWrite32(length);
for (unsigned long i = 0; i < length; i++) {
if (buf) {
buf[i] = ReadByte();
} else {
ReadByte();
}
}
EndTransaction(0);
}
void ReadRAMHexToSerial(unsigned long address, unsigned long length) {
ReadWriteByte(1);
ReadWrite32(address);
ReadWrite32(length);
Serial.print("$");
for (unsigned long i = 0; i < length; i++) {
unsigned char b = ReadByte();
Serial.print(b>>4, HEX);
Serial.print(b&0xf, HEX);
}
Serial.println("");
EndTransaction(0);
}
void WriteRAM(const unsigned char *buf, unsigned long address, unsigned long length) {
ReadWriteByte(2);
ReadWrite32(address);
ReadWrite32(length);
for (unsigned long i = 0; i < length; i++) {
if (buf) {
ReadWriteByte(buf[i]);
} else {
ReadByte();
}
}
EndTransaction(0);
}
void WriteRAMFromSerial(unsigned long address, unsigned long length) {
ReadWriteByte(2);
ReadWrite32(address);
ReadWrite32(length);
for (unsigned long i = 0; i < length; i++) {
while (!Serial.available()) ;
ReadWriteByte(Serial.read());
}
EndTransaction(0);
}
void Disconnect() {
InitGSComms();
ReadWriteByte('d');
}
void readDecimalBytes(unsigned char * buffer, int count) {
for (int i = 0; i < count; i++) {
buffer[i] = Serial.parseInt();
}
}
unsigned long serialRead32BE() {
unsigned char buf[4]={0xff,0xff,0xff,0xff};
Serial.readBytes((char*)buf, 4);
return (((unsigned long)buf[0])<<24) |
(((unsigned long)buf[1])<<16) |
(((unsigned long)buf[2])<< 8) |
(((unsigned long)buf[3]));
}
void setup() {
setup_pins();
do_clear();
}
void loop() {
Serial.begin(57600);
while (!Serial) {}
Serial.println("******* gsupload_arduino_direct (build 79) *******");
unsigned long wait_start = millis();
while (!Serial.available() && (millis() - wait_start) < 10*1000) {
}
// read incoming handshake
while (Serial && Serial.available()) {
if (Serial.read() != 0xde) continue;
if (Serial.read() != 0xad) continue;
if (Serial.read() != 0xbe) continue;
if (Serial.read() == 0xef) break;
}
if (!Serial || !Serial.available()) {
Serial.end();
return;
}
Serial.println("OK!");
InitGSCommsNoisy(1);
#if 0
char *ver = GetGSVersion();
Serial.println(ver);
free(ver);
Disconnect();
Serial.println("That's all, folks!");
Serial.flush();
while (Serial) {}
Serial.end();
return;
#endif
// process commands
while (Serial) {
unsigned long sz, addr;
int write = 1;
sz = serialRead32BE();
if (sz == 0) break;
if (0x80000000UL & sz) {
write = 0;
}
addr = serialRead32BE();
InitGSComms();
if (write) {
// write a block, read from serial in raw
#if !VERIFY
WriteRAMFromSerial(addr, sz);
#else
const int bufsize = 1024;
unsigned char copy_buf[bufsize], verify_buf[bufsize];
while (sz > 0) {
int to_read, actual;
if (sz < bufsize) to_read = sz;
else to_read = bufsize;
delay(10);
Serial.readBytes((char*)copy_buf, to_read);
actual = to_read;
int retry_count = 32;
retry:
//InitGSCommsNoisy(1);
Handshake(1);
WriteRAM((const unsigned char *)copy_buf, addr, actual);
//InitGSCommsNoisy(1);
Handshake(1);
ReadRAM((unsigned char *)verify_buf, addr, actual);
if (memcmp((void*)copy_buf, (void*)verify_buf, actual)) {
if (retry_count > 0) {
Serial.print("verify mismatch of ");
Serial.print(actual);
Serial.println(" bytes, retrying");
retry_count--;
InitGSComms();
goto retry;
} else {
Serial.print("verify of ");
Serial.print(actual);
Serial.println(" bytes failed, aborting");
goto fail;
}
}
sz -= actual;
addr += actual;
//Serial.print(actual);
//Serial.print(", ");
//Serial.print(sz);
//Serial.println(" left");
}
#endif
} else { // not writing
// read a block, return to the client as hex dump
// line format: $001122EABF etc
sz &= 0x7fffffffUL;
ReadRAMHexToSerial(addr, sz);
}
}
Serial.println("done");
fail:
Disconnect();
Serial.end();
}
#!/usr/bin/python2
# port of ppcasm's N64 HomeBrew Loader
from serial import Serial
import sys
from struct import pack
from binascii import a2b_hex
def sendIntro(quiet=False):
port.write("\xde\xad\xbe\xef")
if not quiet:
print '> ' + port.readline(),
def readRAM(size, address, quiet=False):
port.write(pack('>LL', size|0x80000000, address))
while True:
line = port.readline()
if line[0] == '$':
if not quiet:
print '$%08x='%address + line,
break
else:
if not quiet:
print '> ' + line,
return a2b_hex(line[1:].rstrip())
def writeRAM(address, payload, quiet=False):
port.write(pack('>LL', len(payload), address) + payload)
def sendOutro():
port.write(pack('>L', 0))
def dumpPort(quiet=False):
while port.inWaiting() > 0:
print port.readline()
# mips.h stuff for generating code
MIPS_R0 = 0
MIPS_AT = 1
MIPS_V0 = 2
MIPS_V1 = 3
MIPS_A0 = 4
MIPS_A1 = 5
MIPS_A2 = 6
MIPS_A3 = 7
MIPS_T0 = 8
MIPS_T1 = 9
MIPS_T2 = 10
MIPS_T3 = 11
MIPS_T4 = 12
MIPS_T5 = 13
MIPS_T6 = 14
MIPS_T7 = 15
MIPS_S0 = 16
MIPS_S1 = 17
MIPS_S2 = 18
MIPS_S3 = 19
MIPS_S4 = 20
MIPS_S5 = 21
MIPS_S6 = 22
MIPS_S7 = 23
MIPS_T8 = 24
MIPS_T9 = 25
MIPS_K0 = 26
MIPS_K1 = 27
MIPS_GP = 28
MIPS_SP = 29
MIPS_FP = 30
MIPS_RA = 31
def OP(opcode, special=0):
return (opcode << 26) | special
def RD(x):
return x << 11
def RT(x):
return x << 16
def RS(x):
return x << 21
def IM(x):
return x&0xffff
def JT(x):
return (x>>2)&0x3ffffff
def MFC0(rt, rd): return OP(0x10) | RS(0x00) | RT(rt) | RD(rd)
def MTC0(rt, rd): return OP(0x10) | RS(0x04) | RT(rt) | RD(rd)
def ADDIU(rt, rs, immd): return OP(0x09) | RS(rs) | RT(rt) | IM(immd)
def ORI(rt, rs, immd): return OP(0x0d) | RS(rs) | RT(rt) | IM(immd)
def AND(rd, rs, rt): return OP(0x00, 0x24) | RS(rs) | RT(rt) | RD(rd)
def LUI(rt, immd): return OP(0x0F) | RT(rt) | IM(immd)
def SW(rt, off, base): return OP(0x2B) | RS(base) | RT(rt) | IM(off)
ERET = OP(0x10, 0x18) | (1 << 25)
SYNC = 0xf
NOP = 0
def makejump(address): return OP(2) | JT(address)
INSN_PATCH_ADDR = 0xA07C5C00
GLOBAL_OFFSET_TABLE = 0xA0000200
# build loader
UPLOAD_ADDR = 0x80000400
EMBED_ADDR = 0x80300000
loader = ''.join(pack(">L", dw) for dw in \
[
# Stop GameShark traps
MTC0(MIPS_R0, 18),
NOP,
MTC0(MIPS_R0, 19),
NOP,
# Disable Interrupts
MFC0(MIPS_T0, 12),
ADDIU(MIPS_T1, MIPS_R0, 0xfffe),
AND(MIPS_T0, MIPS_T0, MIPS_T1),
MTC0(MIPS_T0, 12),
# Modify EPC
LUI(MIPS_K0, UPLOAD_ADDR>>16),
ORI(MIPS_K0, MIPS_K0, UPLOAD_ADDR),
NOP,
MTC0(MIPS_K0, 14),
NOP,
# Patch back modified code handler
LUI(MIPS_K1, 0x3c1a),
ORI(MIPS_K1, MIPS_K1, 0x8000),
NOP,
LUI(MIPS_K0, 0xa07c),
ORI(MIPS_K0, MIPS_K0, 0x5c00),
NOP,
SW(MIPS_K1, 0, MIPS_K0),
NOP,
SYNC,
NOP,
# Halt RSP
LUI(MIPS_T1, 2),
LUI(MIPS_T0, 0xa404),
ORI(MIPS_T0, MIPS_T0, 0x0010),
NOP,
SW(MIPS_T1, 0, MIPS_T0),
NOP,
# Halt RDP
LUI(MIPS_T1, 1|4|0x10|0x40|0x80|0x100|0x200),
LUI(MIPS_T0, 0xa410),
ORI(MIPS_T0, MIPS_T0, 0x000c),
NOP,
SW(MIPS_T1, 0, MIPS_T0),
NOP,
# Return from interrupt - execute code
ERET,
NOP
])
def hex_string(s):
if type(s) == int:
return '%02x'%s
else:
return ''.join('%02x'%ord(c) for c in s)
######
#s = hex_string(loader)
#for i in range(0,len(s),8):
# print s[i:i+8]
deviceName = "/dev/ttyACM1"
port = Serial(deviceName, 57600)
infile = open(sys.argv[1], "rb")
data = infile.read()
infile.close()
sendIntro()
dumpPort()
# upload payload
print "send payload"
writeRAM(UPLOAD_ADDR, data)
dumpPort()
print "done"
sendOutro()
port.close()
###
port.open()
sendIntro()
# upload embedded code
print "send embedded code"
writeRAM(EMBED_ADDR, loader)
dumpPort()
print "done"
sendOutro()
port.close()
port.open()
sendIntro()
# set patch
print "set patch"
writeRAM(INSN_PATCH_ADDR, pack(">L", makejump(EMBED_ADDR)))
print "done"
dumpPort()
# not sure why this is necessary
readRAM(4, 0xA0000000)
sendOutro()
dumpPort()
dumpPort()
port.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment