Skip to content

Instantly share code, notes, and snippets.

@yifanlu yifanlu/dump_bootrom.bin Secret
Last active Jun 7, 2019

Embed
What would you like to do?
PlayStation Classic bootrom dumper
// arm-none-eabi-gcc -o dump_brom.elf -nostdlib -nostartfiles -nodefaultlibs -pie -Os -fPIE -std=gnu99 -T linker.x -N -fdelete-null-pointer-checks dump_brom.c
// arm-none-eabi-objcopy -O binary dump_brom.elf dump_brom.bin
#define REG32(reg) ((volatile unsigned int *)(reg))
static inline void magic_setup_uart(void)
{
*REG32(0x11005008) |= 7;
*REG32(0x11005024) = 3;
*REG32(0x11005000) = 1;
*REG32(0x11005004) = 0;
*REG32(0x11005028) = 27;
*REG32(0x1100502C) = 13;
volatile int x = *REG32(0x11005000);
*REG32(0x1100500C) = 3;
}
static inline void writech(char c) {
while (!(*REG32(0x11005014) & 0x20));
if (c == '\n')
*REG32(0x11005000) = '\r';
*REG32(0x11005000) = c;
while (!(*REG32(0x11005014) & 0x40));
}
static inline char nibble2char(unsigned int c) {
return (c > 9) ? 'A' + (c - 10) : '0' + c;
}
static inline void printhex(unsigned char ch) {
unsigned char ch1, ch2;
ch1 = ((ch & 0xF0) >> 4);
ch2 = ch & 0xF;
writech(nibble2char(ch1));
writech(nibble2char(ch2));
}
void __attribute__((section(".text.start"))) _start(void) {
magic_setup_uart();
for (unsigned addr = 0; addr < 0x14000; addr += 4) {
unsigned dat = *(volatile unsigned *)addr;
printhex((dat >> 0) & 0xFF);
printhex((dat >> 8) & 0xFF);
printhex((dat >> 16) & 0xFF);
printhex((dat >> 24) & 0xFF);
for (volatile int i = 0; i < 5000; i++);
}
writech('\r');
writech('\n');
while (1);
}
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SECTIONS
{
.text : { *(.text.start) *(.text .text.* .gnu.linkonce.t.*) *(.sceStub.text.*) }
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.data : { *(.data .data.* .gnu.linkonce.d.*) }
.bss : { *(.bss .bss.* .gnu.linkonce.b.*) *(COMMON) }
}
#!/usr/bin/env python3
""" Taken from https://gitlab.com/zeroepoch/aftv2-tools
Usage: python3 mtk-download-payload.py payload.bin
Where `payload.bin` is a raw ARM payload. Then plug in
your USB cable and enter bootrom download mode.
On the PlayStation Classic, this requires shorting the
two large pads on the top left of the board (under the
left USB port) while plugging in the cable.
"""
import sys
import time
import serial
import glob
import struct
BAUD = 115200
def serial_ports ():
""" Lists available serial ports
:raises EnvironmentError:
On unsupported or unknown platforms
:returns:
A set containing the serial ports available on the system
"""
if sys.platform.startswith("win"):
ports = [ "COM{0:d}".format(i + 1) for i in range(10) ]
elif sys.platform.startswith("linux"):
ports = glob.glob("/dev/ttyACM*")
elif sys.platform.startswith("darwin"):
ports = glob.glob("/dev/cu.usbmodem*")
else:
raise EnvironmentError("Unsupported platform")
result = set()
for port in ports:
try:
s = serial.Serial(port)
s.close()
result.add(port)
except (OSError, serial.SerialException):
pass
return result
# serial checker
def check (test, gold):
if test != gold:
sys.stderr.write("ERROR: Serial protocol mismatch\n")
sys.exit(1)
# write then read 1 byte
def write8 (out_str):
dev.write(out_str)
in_str = dev.read()
return in_str
def print_hex_byte (data):
print(len(data), end=": ")
print(" ".join("0x{:02x}".format(x) for x in data))
def print_hex_word (data):
print(len(data), end=": ")
print(" ".join("0x{:08x}".format(x) for x in data))
# initiate mtk preloader handshake
def handshake ():
# look for start byte
while True:
c = write8(b'\xa0')
if c == b'\x5f':
break
dev.flushInput()
# complete sequence
check(write8(b'\x0a'), b'\xf5')
check(write8(b'\x50'), b'\xaf')
check(write8(b'\x05'), b'\xfa')
def send_da (addr, data):
result = []
size = len(data)
dev.write(b'\xd7')
print_hex_byte(dev.read(1))
dev.write(struct.pack('>I', addr))
print_hex_byte(dev.read(4))
dev.write(struct.pack('>I', size))
print_hex_byte(dev.read(4))
dev.write(struct.pack('>I', 0)) # sig len
print_hex_byte(dev.read(4))
status = dev.read(2)
print_hex_byte(status) # status
int_status = struct.unpack('>H', status)[0]
if int_status == 0:
print("<===")
while data:
dev.write(data[:1024])
data = data[1024:]
print("<===")
chksum = dev.read(2)
print_hex_byte(chksum)
status = dev.read(2)
int_status = struct.unpack('>H', status)[0]
print_hex_byte(status) # status
print()
return int_status
def jump_da (addr):
dev.write(b'\xd5')
print_hex_byte(dev.read(1))
dev.write(struct.pack('>I', addr))
print_hex_byte(dev.read(4))
status = dev.read(2)
print_hex_byte(status) # status
int_status = struct.unpack('>H', status)[0]
return int_status
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: " + os.path.basename(sys.argv[0]) + " payload.bin")
sys.exit(1)
port = None
print("Waiting for boot rom...")
# detect boot rom port
old = serial_ports()
while True:
new = serial_ports()
# port added
if new > old:
port = (new - old).pop()
break
# port removed
elif old > new:
old = new
time.sleep(0.25)
print("Found port = " + port)
dev = serial.Serial(port, BAUD, timeout=5)
handshake()
print("Handshake complete!")
with open(sys.argv[1], "rb") as f:
data = f.read()
print("Sending payload...")
send_da(0x00200000, data)
print("Jumping to payload...")
jump_da(0x00200000)
print("Done!")
# vim: ai et ts=4 sts=4 sw=4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.