mirror of
https://github.com/radareorg/radare2.git
synced 2025-02-21 06:40:33 +00:00
Add gprobe:// flash commands ##io
This commit is contained in:
parent
8edc9faa62
commit
40daf8603c
@ -1,7 +1,7 @@
|
||||
What is GProbe?
|
||||
===============
|
||||
GProbe is a protocol to communicate with various parts from
|
||||
Genesis/STMicro/MegaChips that are mostly used in video chipsets.
|
||||
Genesis/STMicro/MegaChips/Kinetic Technologies that are mostly used in video chipsets.
|
||||
|
||||
These chips have an integrated Turbo186 core. With GProbe you can read and write
|
||||
RAM, reset the CPU, execute code in RAM, ...
|
||||
@ -21,11 +21,12 @@ What is implemented?
|
||||
- RunCode
|
||||
- GetDeviceId
|
||||
- GetInformation
|
||||
- Flash commands
|
||||
- Listen command to dump Print-messages from the chip
|
||||
|
||||
TODOs
|
||||
-----
|
||||
- DisplayPort AUX Channel protocol wrapper
|
||||
- Flash commands
|
||||
|
||||
What is tested?
|
||||
---------------
|
||||
@ -35,6 +36,7 @@ What is tested?
|
||||
- communication via DDC2Bi3
|
||||
- controlling a MegaChips RD1-4320 DisplayPort 1.2a splitter reference board
|
||||
- controlling a DELL U2410 connected via DVI
|
||||
- flashing a STDP2600 with RC3.3 firmware on MNT RHDP board(mntre.com)
|
||||
|
||||
How to use for dummies?
|
||||
-----------------------
|
||||
@ -58,3 +60,21 @@ Now enjoy all the great stuff that r2 offers, like:
|
||||
- Visual mode with V, including cursor mode and insert hexpairs
|
||||
- dumping segments to file
|
||||
- disassembly and analysis
|
||||
|
||||
How to flash?
|
||||
-------------
|
||||
To flash you need three things:
|
||||
- a flasher program that gets uploaded to the chip
|
||||
- since it as a hexfile with multiple sections, you can convert it to .rapatch with hex2rapatch.py
|
||||
- alternatively you can use ihex://, list the sections in json with :j and write them to gprobe:// using a script
|
||||
- a binary firmware blob that gets flashed
|
||||
- parameters (probably supplied in the gprobe script that comes with the firmware):
|
||||
- load and start address for flasher program (0x1800 in the example)
|
||||
- Maximum chunksize for flashing (0x200 in the example)
|
||||
- flash address for binary blob (0x40000 in the example)
|
||||
|
||||
- :reset 0
|
||||
- wp isp.rapatch
|
||||
- :runcode 0x1800
|
||||
- :flasherase 0xffff
|
||||
- :flashwrite 0x200 0x400000 STDP2600_HDMI2DP_STD_RC3_3.bin
|
||||
|
@ -77,6 +77,9 @@ enum {
|
||||
GPROBE_NACK = 0x0b,
|
||||
GPROBE_ACK = 0x0c,
|
||||
GPROBE_PRINT = 0x0D,
|
||||
GPROBE_FAST_FLASH_WRITE = 0x10,
|
||||
GPROBE_FLASH_ERASE = 0x19,
|
||||
GPROBE_FLASH_ID_CRC = 0x1c,
|
||||
GPROBE_RESET = 0x20,
|
||||
GPROBE_GET_DEVICE_ID = 0x30,
|
||||
GPROBE_GET_INFORMATION = 0x40,
|
||||
@ -968,6 +971,264 @@ fail:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int gprobe_flasherase(struct gport *port, ut16 sector) {
|
||||
if (!port) {
|
||||
return -1;
|
||||
}
|
||||
RBuffer *request = r_buf_new ();
|
||||
RBuffer *reply = NULL;
|
||||
const ut8 cmd = GPROBE_FLASH_ERASE;
|
||||
|
||||
if (!request) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r_buf_append_bytes (request, &cmd, 1);
|
||||
r_buf_append_bytes (request, (const ut8 *)§or, 2);
|
||||
|
||||
port->frame (request);
|
||||
|
||||
if (port->send_request (port, request)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
RBuffer *reply = NULL;
|
||||
|
||||
int res = get_reply (port, GPROBE_ACK, &reply);
|
||||
|
||||
if (reply)
|
||||
r_buf_free (reply);
|
||||
|
||||
if (!res)
|
||||
break;
|
||||
|
||||
if (r_cons_is_breaked ())
|
||||
break;
|
||||
}
|
||||
|
||||
r_buf_free (request);
|
||||
r_buf_free (reply);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
r_buf_free (request);
|
||||
r_buf_free (reply);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int gprobe_flashid(struct gport *port) {
|
||||
if (!port) {
|
||||
return -1;
|
||||
}
|
||||
RBuffer *request = r_buf_new ();
|
||||
RBuffer *reply = NULL;
|
||||
const ut8 cmd = GPROBE_FLASH_ID_CRC;
|
||||
const ut8 rsvd0[] = { 0xff, 0x00, 0x00 };
|
||||
const ut8 rsvd1[] = { 0x20, 0x00, 0x00 };
|
||||
|
||||
if (!request) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r_buf_append_bytes (request, &cmd, 1);
|
||||
r_buf_append_bytes (request, rsvd0, 3);
|
||||
r_buf_append_bytes (request, rsvd1, 3);
|
||||
|
||||
port->frame (request);
|
||||
|
||||
if (port->send_request (port, request)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
int res = get_reply (port, cmd, &reply);
|
||||
if (res)
|
||||
goto fail;
|
||||
|
||||
ut16 id = r_buf_read_be16_at (reply, 0);
|
||||
printf ("%04x\n", id);
|
||||
|
||||
r_buf_free (request);
|
||||
r_buf_free (reply);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
r_buf_free (request);
|
||||
r_buf_free (reply);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int gprobe_flashcrc(struct gport *port, ut32 address, ut32 count) {
|
||||
if (!port) {
|
||||
return -1;
|
||||
}
|
||||
RBuffer *request = r_buf_new ();
|
||||
RBuffer *reply = NULL;
|
||||
const ut8 cmd = GPROBE_FLASH_ID_CRC;
|
||||
|
||||
if (!request) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r_buf_append_bytes (request, &cmd, 1);
|
||||
r_buf_append_ut8 (request, (address >> 16) & 0xff);
|
||||
r_buf_append_ut8 (request, (address >> 8) & 0xff);
|
||||
r_buf_append_ut8 (request, (address >> 0) & 0xff);
|
||||
r_buf_append_ut8 (request, (count >> 16) & 0xff);
|
||||
r_buf_append_ut8 (request, (count >> 8) & 0xff);
|
||||
r_buf_append_ut8 (request, (count >> 0) & 0xff);
|
||||
|
||||
port->frame (request);
|
||||
|
||||
if (port->send_request (port, request)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (get_reply (port, cmd, &reply)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ut16 id = r_buf_read_be16_at (reply, 0);
|
||||
printf ("0x%04x\n", id);
|
||||
|
||||
r_buf_free (request);
|
||||
r_buf_free (reply);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
r_buf_free (request);
|
||||
r_buf_free (reply);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static ut16 calculate_crc_16(const void *buf, size_t buf_size) {
|
||||
const ut8 *byte_buf;
|
||||
ut16 crc;
|
||||
ut8 data;
|
||||
unsigned int i;
|
||||
ut8 flag;
|
||||
|
||||
byte_buf = (const unsigned char *)buf;
|
||||
crc = 0x1021;
|
||||
for (; buf_size > 0; --buf_size) {
|
||||
data = *byte_buf++;
|
||||
for (i = 8; i > 0; --i) {
|
||||
flag = data ^ (crc >> 8);
|
||||
crc <<= 1;
|
||||
if (flag & 0x80)
|
||||
crc ^= 0x1021;
|
||||
data <<= 1;
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
static int fast_flash_write(struct gport *port, ut32 address, ut8 *buf, size_t size) {
|
||||
RBuffer *request = r_buf_new ();
|
||||
RBuffer *reply = NULL;
|
||||
const ut8 cmd = GPROBE_FAST_FLASH_WRITE;
|
||||
|
||||
if (!request) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* send primer */
|
||||
r_buf_append_bytes (request, &cmd, 1);
|
||||
|
||||
port->frame (request);
|
||||
|
||||
if (port->send_request (port, request)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r_buf_free (request);
|
||||
|
||||
r_sys_usleep (5000);
|
||||
|
||||
/* send data packet */
|
||||
request = r_buf_new ();
|
||||
|
||||
if (!request) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r_buf_append_ut8 (request, (address >> 24) & 0xff);
|
||||
r_buf_append_ut8 (request, (address >> 16) & 0xff);
|
||||
r_buf_append_ut8 (request, (address >> 8) & 0xff);
|
||||
r_buf_append_ut8 (request, (address >> 0) & 0xff);
|
||||
|
||||
r_buf_append_ut8 (request, (size >> 24) & 0xff);
|
||||
r_buf_append_ut8 (request, (size >> 16) & 0xff);
|
||||
r_buf_append_ut8 (request, (size >> 8) & 0xff);
|
||||
r_buf_append_ut8 (request, (size >> 0) & 0xff);
|
||||
|
||||
r_buf_append_bytes (request, buf, size);
|
||||
|
||||
ut16 crc = calculate_crc_16 (buf, size);
|
||||
|
||||
r_buf_append_ut8 (request, (crc >> 24) & 0xff);
|
||||
r_buf_append_ut8 (request, (crc >> 16) & 0xff);
|
||||
r_buf_append_ut8 (request, (crc >> 8) & 0xff);
|
||||
r_buf_append_ut8 (request, (crc >> 0) & 0xff);
|
||||
|
||||
if (port->send_request (port, request)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r_buf_free (request);
|
||||
|
||||
if (get_reply (port, GPROBE_ACK, &reply)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r_buf_free (reply);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
r_buf_free (request);
|
||||
r_buf_free (reply);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int gprobe_flashwrite(struct gport *port, ut32 max_chunksize, ut32 address, const char *filename) {
|
||||
const char *arg = filename + ((filename[0] == ' ')? 1: 0);
|
||||
char *pa, *a = r_str_trim_dup (arg);
|
||||
pa = strchr (a, ' ');
|
||||
if (pa) {
|
||||
*pa++ = 0;
|
||||
}
|
||||
|
||||
if (!port) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t size;
|
||||
ut8 *buf = (ut8 *)r_file_slurp (arg, &size);
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
ut8 *p = buf;
|
||||
while (size > 0) {
|
||||
int chunk_size = size > max_chunksize? max_chunksize: size;
|
||||
if (fast_flash_write (port, address, p, chunk_size)) {
|
||||
free (buf);
|
||||
return -1;
|
||||
}
|
||||
size -= chunk_size;
|
||||
address += chunk_size;
|
||||
p += chunk_size;
|
||||
r_sys_usleep (5000);
|
||||
}
|
||||
|
||||
free (buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gprobe_getdeviceid(struct gport *port, ut8 index) {
|
||||
if (!port) {
|
||||
return -1;
|
||||
@ -1051,6 +1312,30 @@ fail:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int gprobe_listen(struct gport *port) {
|
||||
if (!port) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
r_cons_break_push (NULL, NULL);
|
||||
|
||||
while (1) {
|
||||
RBuffer *reply = NULL;
|
||||
|
||||
get_reply (port, GPROBE_RESET, &reply);
|
||||
|
||||
if (reply)
|
||||
r_buf_free (reply);
|
||||
|
||||
if (r_cons_is_breaked ())
|
||||
break;
|
||||
}
|
||||
|
||||
r_cons_break_pop ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __write(RIO *io, RIODesc *fd, const ut8 *buf, int count) {
|
||||
RIOGprobe *gprobe;
|
||||
int res;
|
||||
@ -1196,8 +1481,13 @@ static char *__system(RIO *io, RIODesc *fd, const char *cmd) {
|
||||
" :debugon\n"
|
||||
" :debugoff\n"
|
||||
" :runcode address\n"
|
||||
" :flasherase sector(0xffff for complete flash)\n"
|
||||
" :flashid\n"
|
||||
" :flashcrc address count\n"
|
||||
" :flashwrite max_chunksize address filename\n"
|
||||
" :getdeviceid\n"
|
||||
" :getinformation\n");
|
||||
" :getinformation\n"
|
||||
" :listen\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1229,6 +1519,50 @@ static char *__system(RIO *io, RIODesc *fd, const char *cmd) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (r_str_startswith (cmd, "flasherase") && (strlen (cmd) > 10)) {
|
||||
ut32 sector = (ut32)strtoul (cmd + 10, NULL, 0);
|
||||
|
||||
gprobe_flasherase (&gprobe->gport, sector);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (r_str_startswith (cmd, "flashid")) {
|
||||
gprobe_flashid (&gprobe->gport);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (r_str_startswith (cmd, "flashcrc") && (strlen (cmd) > 8)) {
|
||||
char *endptr;
|
||||
ut32 address = (ut32)strtoul (cmd + 8, &endptr, 0);
|
||||
ut32 count;
|
||||
|
||||
if (endptr)
|
||||
count = (ut32)strtoul (endptr, NULL, 0);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
gprobe_flashcrc (&gprobe->gport, address, count);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (r_str_startswith (cmd, "flashwrite") && (strlen (cmd) > 10)) {
|
||||
char *endptr;
|
||||
ut32 max_chunksize = (ut32)strtoul (cmd + 10, &endptr, 0);
|
||||
ut32 address;
|
||||
|
||||
if (endptr)
|
||||
address = (ut32)strtoul (endptr, &endptr, 0);
|
||||
else
|
||||
return NULL;
|
||||
|
||||
gprobe_flashwrite (&gprobe->gport, max_chunksize, address, endptr);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (r_str_startswith (cmd, "getdeviceid")) {
|
||||
ut8 index = 0;
|
||||
while (!gprobe_getdeviceid (&gprobe->gport, index++)) {
|
||||
@ -1243,6 +1577,12 @@ static char *__system(RIO *io, RIODesc *fd, const char *cmd) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (r_str_startswith (cmd, "listen")) {
|
||||
gprobe_listen (&gprobe->gport);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printf ("Try: ':?'\n");
|
||||
|
||||
return NULL;
|
||||
|
26
sys/hex2rapatch.py
Executable file
26
sys/hex2rapatch.py
Executable file
@ -0,0 +1,26 @@
|
||||
!/usr/bin/env python
|
||||
|
||||
""" Portable python script to convert Intel hex file to rapatch """
|
||||
|
||||
from intelhex import IntelHex
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
prog='ihex2rapatch',
|
||||
description='Convert Intel hex file to radare2 patch file')
|
||||
|
||||
parser.add_argument('source', help='Intel Hex source file')
|
||||
parser.add_argument('target', help='radare2 patch target file')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
f = open(args.target, 'w')
|
||||
|
||||
ih = IntelHex(args.source)
|
||||
for segment in ih.segments():
|
||||
f.write(hex(segment[0]) + ': ')
|
||||
for x in range(segment[0],segment[1]):
|
||||
f.write(f'{ih[x]:02x}')
|
||||
f.write('\n')
|
||||
|
||||
f.close()
|
Loading…
x
Reference in New Issue
Block a user