Created
July 10, 2014 06:28
-
-
Save hcs64/c612fbccac417531ead4 to your computer and use it in GitHub Desktop.
gsuploader via arduino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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