954 lines
26 KiB
C
954 lines
26 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <hardware/adc.h>
|
|
#include <hardware/clocks.h>
|
|
#include <hardware/gpio.h>
|
|
#include <hardware/pwm.h>
|
|
#include <pico/stdlib.h>
|
|
#include <pico/binary_info.h>
|
|
|
|
#include "pinout.h"
|
|
|
|
#include "tool78_hw.h"
|
|
#include "tool78_cmds.h"
|
|
#include "glitch.h"
|
|
|
|
void cli_tool78_glitch_dump(void);
|
|
void cli_tool78_glitch_paramsearch(void);
|
|
void cli_tool78_glitch_ocd_dump(void);
|
|
void cli_tool78_glitch_param_g10(void);
|
|
void cli_tool78_glitch_ocd_g10(void);
|
|
|
|
#define DUMP_OFFSET 0xef000
|
|
#define DUMP_SIZE 4096/*65536*/
|
|
|
|
// test with decoupling caps: length in 20..500(..1500) -> ok
|
|
// testing on ocd lock: length: 5..35
|
|
|
|
/*
|
|
hw inited
|
|
baudrate result=0xc1
|
|
common st=193
|
|
result: 0xc1 ver=0000
|
|
init: 193
|
|
*/
|
|
/*
|
|
baudrate result=0x06
|
|
result: 0x06. sig:
|
|
0x10 0x00 0x06 0x52 0x35 0x46 0x31 0x30 0x31 0x45 0x45 0x20 0x20 0xff 0xff 0x00 0x00 0x00 0x00 0x03 0x00 0x03
|
|
secget: 0x06
|
|
sec: flg=fe bot=03 fsws=0000 fswe=003f
|
|
*/
|
|
//void trl78_uart1_set_exclusive(bool ex);
|
|
|
|
static uint8_t databuf[DUMP_SIZE];
|
|
static struct glitch_param_randrange offset;
|
|
static struct glitch_param_randrange/*adc*/ length;
|
|
//static struct glitch_param_const length;
|
|
|
|
static bool glitch_init_core1_stuff(bool exttrig, uint glitchpin) {
|
|
offset.min = 10*1000;
|
|
offset.max = 35433*1000;
|
|
length.min = 100;
|
|
length.max = /*10*50*/26*1000;
|
|
//length.value = 5*1000; // 5 us
|
|
#if PINOUT_USE_DRAGONZAP
|
|
//length.adc_index = 0;//999;
|
|
#else
|
|
//length.adc_index = 999;
|
|
#endif
|
|
|
|
glitch_param_randrange_init(&offset);
|
|
//glitch_param_const_init(&length);
|
|
glitch_param_randrange_init(&length);
|
|
//glitch_param_adc_init(&length);
|
|
|
|
// REGC = 2.11V / 0.47..1 uF // WUFM: REGC = 1.80V // BUT: OCD mode: always 2.1!
|
|
static struct glitch_params gparam = (struct glitch_params){
|
|
//.offset_min_ns = 10*1000,
|
|
//.offset_max_ns = 35433*1000,
|
|
// with REGC & 10uF Vcc:
|
|
//.length_min_ns = -1,//10,//-1,//20,
|
|
//.length_max_ns = 10000,//*8,
|
|
// with REGC:
|
|
/*.length_min_us = 4000,
|
|
.length_max_us = 6300,*/
|
|
// without REGC:
|
|
/*.length_min_us = 20,
|
|
.length_max_us = 70,*/
|
|
// best glitch voltages (REGC: 1uF):
|
|
// * with REGC, long pulses: 1700mV
|
|
// * no REGC, short pulses: 1300mV
|
|
// * REGC@VDD, long pulses: 42mV
|
|
// * REGC@VDD, short pulses: 0V
|
|
// * with REGC, 10uF@VDD, long pulses: 0..3mV (strict upper limit)
|
|
// * 100uF@VDD: too much, even w/o REGC
|
|
.trigger_in_pin = -2,
|
|
.glitch_out_pin = -2,//glitchpin,//GLITCH_OUT_PIN,
|
|
.trigger_in_polarity = glitch_positive,
|
|
.glitch_out_polarity = glitch_positive,
|
|
.impl = glitch_impl_pio,//core1,
|
|
};
|
|
gparam.glitch_out_pin = glitchpin;
|
|
gparam.offset_ns = (struct glitch_param){
|
|
.ud = &offset,
|
|
.getter = glitch_param_randrange_fn
|
|
};
|
|
gparam.length_ns = (struct glitch_param){
|
|
.ud = &length,
|
|
.getter = glitch_param_randrange_fn,//adc_fn
|
|
};
|
|
gparam.trigger_in_pin = exttrig ? TRIGGER_IN_PIN/*7*/ : (-1);
|
|
return glitch_ready(&gparam);
|
|
}
|
|
static void glitch_init_pwm_stuff(void) {
|
|
const float dutycycle = (2.1f + 0.00f) / 3.3f + 0.0125f;//25f /* calibration (more) */;
|
|
const int PIN_PWM_VREG = 22;
|
|
const uint32_t pwm_period = /*5*/500; // 200 Hz at a 1 MHz clock freq
|
|
|
|
uint32_t sliceno = pwm_gpio_to_slice_num(PIN_PWM_VREG);
|
|
pwm_set_clkdiv_int_frac(sliceno, (uint8_t)(clock_get_hz(clk_sys)/1e6f), 0); // 1 MHz clock
|
|
pwm_set_wrap(sliceno, pwm_period); // total period
|
|
pwm_set_chan_level(sliceno, pwm_gpio_to_channel(PIN_PWM_VREG),
|
|
(uint32_t)(pwm_period*dutycycle));
|
|
pwm_set_phase_correct(sliceno, true);
|
|
pwm_set_output_polarity(sliceno, false, false);
|
|
pwm_set_clkdiv_mode(sliceno, PWM_DIV_FREE_RUNNING);
|
|
pwm_set_enabled(sliceno, true);
|
|
gpio_set_function(PIN_PWM_VREG, GPIO_FUNC_PWM);
|
|
}
|
|
|
|
static uint8_t exec_jmp_to_ram[] = {
|
|
0xfc, 0x00, 0xf9, 0x0f, // call !!ff900
|
|
0xd7, // ret
|
|
};
|
|
|
|
static uint8_t DATA_test_dbg__paramtest[102] = {
|
|
0x71, 0x7b, 0xfa, 0xf5, 0xf0, 0x02, 0xf5, 0x78, 0x00, 0x71, 0x6a, 0xa4,
|
|
0xcf, 0x76, 0x00, 0x01, 0xce, 0x22, 0x00, 0xf5, 0x62, 0x00, 0xf5, 0x77,
|
|
0x00, 0xf5, 0x79, 0x00, 0xf5, 0x75, 0x00, 0xf5, 0x7c, 0x00, 0xce, 0x02,
|
|
0x00, 0xce, 0x02, 0xff, 0x30, 0x00, 0xfa, 0x16, 0x52, 0x00, 0x53, 0xff,
|
|
0x51, 0x00, 0x81, 0x93, 0xdf, 0xfc, 0x92, 0x61, 0xf9, 0xdf, 0xf3, 0xce,
|
|
0x02, 0x00, 0x52, 0x18, 0x53, 0xff, 0x93, 0xdf, 0xfd, 0x92, 0xdf, 0xf8,
|
|
0x51, 0x48, 0xfc, 0xa1, 0xff, 0x0e, 0x51, 0x69, 0xfc, 0xa1, 0xff, 0x0e,
|
|
0x50, 0xaa, 0x52, 0x00, 0x92, 0x61, 0xe9, 0x61, 0x78, 0xfc, 0xa1, 0xff,
|
|
0x0e, 0xd2, 0xdf, 0xf4, 0xef, 0xbf
|
|
};
|
|
|
|
static uint8_t dumper_shellcode[0x26] = {
|
|
//0xe0, 0x07, 0x26, // 0xF07E0 location, 0x26 length of packet
|
|
0x41, 0x00, 0x34, 0x00, 0x00, 0x00, 0x11, 0x89, 0xFC, 0xA1, 0xFF, 0x0E, 0xA5,
|
|
0x15, 0x44, 0x00, 0x00, 0xDF, 0xF3, 0xEF, 0x04, 0x55, 0x00, 0x00, 0x00, 0x8E,
|
|
0xFD, 0x81, 0x5C, 0x0F, 0x9E, 0xFD, 0x71, 0x00, 0x90, 0x00, 0xEF, 0xE0
|
|
};
|
|
|
|
static uint8_t G1M_payload_1[] = {
|
|
0xcb, 0xf8, 0xc0, 0xfe, // movw sp, #0xfea0
|
|
0xec, 0xba, 0xff, 0x0e, // br !!0xeffba
|
|
};
|
|
static uint8_t G1M_payload_2[] = {
|
|
0xec, 0x00, 0xfe, 0x0f, // br !!ffe00
|
|
};
|
|
|
|
static uint8_t G1M_paramtest[] = {
|
|
0x71, 0x7b, 0xfa, 0x51, 0x61, 0xfc, 0xdc, 0xff, 0x0e, 0xcf, 0x77, 0x00, 0x00,
|
|
0xce, 0x00, 0x00, 0xcf, 0x30, 0x00, 0x00, 0xcf, 0x50, 0x00, 0x00, 0xcf, 0x60,
|
|
0x00, 0x7f, 0xcf, 0x20, 0xff, 0x00, 0xcf, 0xf0, 0x00, 0xe5, 0xcf, 0xf3, 0x00,
|
|
0x10, 0xce, 0x00, 0xff, 0x30, 0xe0, 0xfc, 0x16, 0x52, 0x40, 0x53, 0xff, 0x51,
|
|
0x00, 0x81, 0x93, 0xdf, 0xfc, 0x92, 0x61, 0xf9, 0xd2, 0xdf, 0xf2, 0xce, 0x00,
|
|
0x00, 0x52, 0x18, 0x53, 0xff, 0x93, 0xdf, 0xfd, 0x92, 0xdf, 0xf8, 0x51, 0x48,
|
|
0xfc, 0xdc, 0xff, 0x0e, 0x51, 0x69, 0xfc, 0xdc, 0xff, 0x0e, 0x50, 0xaa, 0x52,
|
|
0x40, 0x92, 0x61, 0xe9, 0x61, 0x78, 0xfc, 0xdc, 0xff, 0x0e, 0xd2, 0xdf, 0xf4,
|
|
0xef, 0xbe, 0xd7
|
|
|
|
};
|
|
|
|
|
|
void cli_tool78_glitch_dump(void) {
|
|
uint8_t passwd[10] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
|
uint16_t ver;
|
|
enum tool78_stat st;
|
|
int rr;
|
|
|
|
ver=0;
|
|
while (true) {
|
|
st = tool78_init_ocd(&tool78_hw_rl78_uart1, &ver, passwd);
|
|
if (st == 0xc3) {
|
|
rr = tool78_hw_rl78_uart1.recv(1, &st, 120*1000*1000);
|
|
if (rr != 1) {
|
|
printf("aaaa\n");
|
|
goto deinit_bad;
|
|
}
|
|
}
|
|
printf("result: 0x%02x ver=%04x\n", st, ver);
|
|
if (st != 0xf2 && st != 0xf0) {
|
|
printf("init: %d\n", st);
|
|
goto deinit_bad;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// can't write too much at 0xf07e0 as 0xf0800 and up contains OCD state,
|
|
// overwrite this and suddenly the OCD system resets itself
|
|
st = tool78_ocd_write(&tool78_hw_rl78_uart1, 0x07e0,
|
|
sizeof(exec_jmp_to_ram), exec_jmp_to_ram);
|
|
//printf("write shellcode res 0x%02x\n", st);
|
|
if (st != 0) {
|
|
printf("trampoline write failed: %d\n", st);
|
|
goto deinit_bad;
|
|
}
|
|
|
|
st = tool78_ocd_write(&tool78_hw_rl78_uart1, 0xf900,
|
|
sizeof(dumper_shellcode), dumper_shellcode);
|
|
//printf("write shellcode res 0x%02x\n", st);
|
|
if (st != 0) {
|
|
printf("shellcode write failed: %d\n", st);
|
|
goto deinit_bad;
|
|
}
|
|
|
|
st = tool78_ocd_exec(&tool78_hw_rl78_uart1);
|
|
//printf("exec res 0x%02x\n", st);
|
|
if (st != 0) {
|
|
printf("exec failed: %d\n", st);
|
|
goto deinit_bad;
|
|
}
|
|
|
|
for (size_t iii = 0; iii < DUMP_SIZE + DUMP_OFFSET; ++iii) {
|
|
// wait for completion
|
|
size_t off = (iii < DUMP_OFFSET) ? 0 : (iii - DUMP_OFFSET);
|
|
rr = tool78_hw_rl78_uart1.recv(1, &databuf[off], 120*1000*1000);
|
|
if (rr != 1) {
|
|
printf("exec code: no response :/ (%d)\n", rr);
|
|
goto deinit_bad;
|
|
}
|
|
}
|
|
|
|
for (size_t iii = 0; iii < DUMP_SIZE; ++iii) {
|
|
printf("%02x%s", databuf[iii], ((iii & 0xf) == 0xf) ? "\n" : " ");
|
|
}
|
|
|
|
deinit_bad:
|
|
tool78_hw_rl78_uart1.deinit();
|
|
return;
|
|
}
|
|
|
|
void cli_tool78_glitch_paramsearch(void) {
|
|
zap_picoemp_init();
|
|
|
|
if (!glitch_init_core1_stuff(true, ZAP_GLITCH_OUT/*GLITCH_OUT_PIN*/)) {
|
|
printf("bad glitcher params!\n");
|
|
return;
|
|
}
|
|
|
|
uint8_t passwd[10] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
|
uint16_t ver;
|
|
enum tool78_stat st;
|
|
int rr;
|
|
static uint8_t checkbuf[256];
|
|
bool first = true;
|
|
|
|
restart:
|
|
zap_picoemp_set_armed(false);
|
|
glitch_disarm();
|
|
/*busy_wait_ms(40);*/
|
|
|
|
zap_picoemp_set_armed(true);
|
|
while (!zap_picoemp_has_hv()) ;
|
|
|
|
ver=0;
|
|
st = tool78_init_ocd(&tool78_hw_rl78_uart1, &ver, passwd);
|
|
if (st == 0xc3) {
|
|
printf("aa\n");
|
|
st = 0;
|
|
rr = tool78_hw_rl78_uart1.recv(1, (uint8_t*)&st, 120*1000);
|
|
printf("rr=%d\n", rr);
|
|
if (rr != 1) {
|
|
printf("aaaa\n");
|
|
goto do_reset_stuff;
|
|
}
|
|
}
|
|
//printf("result: 0x%02x ver=%04x\n", st, ver);
|
|
if (st != 0xf2 && st != 0xf0) {
|
|
printf("init: 0x%02x\n", st);
|
|
goto deinit_bad;
|
|
}
|
|
if (first) printf("result: 0x%02x ver=%04x\n", st, ver);
|
|
|
|
// can't write too much at 0xf07e0 as 0xf0800 and up contains OCD state,
|
|
// overwrite this and suddenly the OCD system resets itself
|
|
st = tool78_ocd_write(&tool78_hw_rl78_uart1, 0x07e0,
|
|
sizeof(exec_jmp_to_ram), exec_jmp_to_ram);
|
|
//printf("write trampoline res 0x%02x\n", st);
|
|
if (st != 0) {
|
|
printf("trampoline write failed: %d\n", st);
|
|
goto deinit_bad;
|
|
}
|
|
st = tool78_ocd_write(&tool78_hw_rl78_uart1, 0xf900,
|
|
sizeof(DATA_test_dbg__paramtest), DATA_test_dbg__paramtest);
|
|
//printf("write code res 0x%02x\n", st);
|
|
if (st != 0) {
|
|
printf("code write failed: %d\n", st);
|
|
goto deinit_bad;
|
|
}
|
|
|
|
st = tool78_ocd_exec(&tool78_hw_rl78_uart1);
|
|
//printf("exec res 0x%02x\n", st);
|
|
if (st != 0) {
|
|
printf("exec failed: %d\n", st);
|
|
goto deinit_bad;
|
|
}
|
|
|
|
// test custom tool_tx call
|
|
/*rr = tool78_hw_rl78_uart1.recv(1, checkbuf, 1000);
|
|
printf("rr=%d\n", rr);
|
|
if (rr == 1) printf("0x%02x %c\n", stuff[0], stuff[0]);*/
|
|
|
|
// wait for completion
|
|
rr = tool78_hw_rl78_uart1.recv(2, checkbuf, 120*1000);
|
|
if (rr != 2) {
|
|
printf("exec code: no response :/ (%d)\n", rr);
|
|
goto deinit_bad;
|
|
}
|
|
|
|
if (checkbuf[0] != 'H' && checkbuf[1] != 'i') {
|
|
printf("bad response: %02x %02x\n", checkbuf[0], checkbuf[1]);
|
|
goto deinit_bad;
|
|
}
|
|
|
|
rr = tool78_hw_rl78_uart1.recv(256, checkbuf, 120*1000);
|
|
if (rr != 256) {
|
|
printf("exec code: no data sendback (%d)\n", rr);
|
|
goto deinit_bad;
|
|
}
|
|
|
|
for (size_t i = 0; i < 256; ++i) {
|
|
if (checkbuf[i] != (0xff^0xaa)) {
|
|
printf("bad value at index %zu: %02x\n", i, checkbuf[i]^0xaa);
|
|
goto deinit_bad;
|
|
}
|
|
}
|
|
if (first) printf("all set, let's go\n");
|
|
first = false;
|
|
|
|
while (true) {
|
|
glitch_arm();
|
|
rr = tool78_hw_rl78_uart1.recv(2, checkbuf, 120*1000);
|
|
glitch_disarm();
|
|
|
|
bool first_ = true;
|
|
do {
|
|
if (rr == 2 && (checkbuf[0] != 'H' || checkbuf[1] != 'i')) rr = 0;
|
|
if (rr == 2) {
|
|
rr = tool78_hw_rl78_uart1.recv(256, checkbuf, 120*1000);
|
|
}
|
|
|
|
if (rr <= 0) {
|
|
if (!first_) break;
|
|
// timeout or something
|
|
printf("X");
|
|
tool78_hw_rl78_uart1.deinit();
|
|
goto do_reset_stuff;
|
|
} else {
|
|
int firstbad = -1, lastbad = -1;
|
|
for (int i = 0; i < rr; ++i) {
|
|
if (checkbuf[i] != (0xaa^0xff)) {
|
|
if (firstbad == -1) firstbad = i;
|
|
lastbad = i;
|
|
}
|
|
}
|
|
if (firstbad >= 0) {
|
|
volatile uint32_t
|
|
*off = (volatile uint32_t*)&glitch_param_cur.offset_ns.cur,
|
|
*len = (volatile uint32_t*)&glitch_param_cur.length_ns.cur;
|
|
printf("glitch first=%d last=%d off=%lu len=%lu rr=%d v=%02x\n",
|
|
firstbad, lastbad, *off, *len, rr, checkbuf[firstbad]^0xaa);
|
|
} else {
|
|
printf(".");
|
|
}
|
|
}
|
|
|
|
first_=false;
|
|
if (!zap_picoemp_has_hv()) {
|
|
rr = tool78_hw_rl78_uart1.recv(2, checkbuf, 150*1000);
|
|
} else break;
|
|
} while (true);
|
|
}
|
|
|
|
deinit_bad:
|
|
zap_picoemp_set_armed(false);
|
|
tool78_hw_rl78_uart1.deinit();
|
|
return;
|
|
|
|
do_reset_stuff:
|
|
zap_picoemp_set_armed(false);
|
|
tool78_hw_rl78_uart1.deinit();
|
|
|
|
// glitch for way too long to power cycle
|
|
sio_hw->gpio_set = 1u << GLITCH_OUT_PIN;
|
|
busy_wait_ms(16);
|
|
sio_hw->gpio_clr = 1u << GLITCH_OUT_PIN;
|
|
|
|
goto restart;
|
|
}
|
|
|
|
void cli_tool78_glitch_ocd_dump(void) {
|
|
if (!glitch_init_core1_stuff(false, GLITCH_OUT_PIN)) {
|
|
printf("bad glitcher params!\n");
|
|
return;
|
|
}
|
|
|
|
/*gpio_set_function(2, GPIO_FUNC_SIO);
|
|
gpio_set_dir(2, GPIO_OUT);
|
|
gpio_put(2, false);*/
|
|
|
|
//gpio_set_function(3, GPIO_FUNC_SIO);
|
|
//gpio_set_dir(3, GPIO_OUT);
|
|
//gpio_put(3, false);
|
|
|
|
uint8_t passwd[10] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
|
uint16_t ver;
|
|
int st, rr/*, r0, r1, r2*/;
|
|
static uint8_t checkbuf[256];
|
|
bool first = true;
|
|
|
|
restart:
|
|
//trl78_uart1_set_exclusive(true);
|
|
//tool78_hw_rl78_uart1.rx_set_stop_bit(false);
|
|
//gpio_put(2, false);
|
|
/*glitch_disarm();
|
|
busy_wait_ms(40);*/
|
|
|
|
ver=0;
|
|
st = tool78_init_ocd(&tool78_hw_rl78_uart1, &ver, passwd);
|
|
if (st == 0xc3) {
|
|
//printf("aa\n");
|
|
st = 0;
|
|
rr = tool78_hw_rl78_uart1.recv(1, (uint8_t*)&st, 120*1000);
|
|
//printf("rr=%d\n", rr);
|
|
if (rr != 1) {
|
|
//printf("aaaa\n");
|
|
goto do_reset_stuff;
|
|
}
|
|
}
|
|
if (first) printf("result: 0x%02x ver=%04x\n", st, ver);
|
|
if (st == 0xc1) goto do_reset_stuff;
|
|
if (st != 0x10) {
|
|
printf("init: expected protect error, got %d\n", st);
|
|
goto deinit_bad;
|
|
}
|
|
busy_wait_ms(16); // leave time to recharge
|
|
|
|
// right now, the RL78 core is stuck in an infinite loop doing nothing in
|
|
// the debug monitor part of its bootrom. however, the code we need is
|
|
// right below it, so we can simply try to glitch it without having to meet
|
|
// the timing
|
|
// see https://fail0verflow.com/blog/2018/ps4-syscon/ for more info
|
|
|
|
// try up to 16 times because we can't discern between a reset and a glitch
|
|
// that had no effect. after 16 iterations without result, reset the RL78
|
|
// and try again.
|
|
// a successful glitch will output a single null byte over the TOOL0 line
|
|
|
|
// apparently we have about 95 ms until the infinite loop gets reset into
|
|
// the MCU flash automatically? somehow?? I suppose it's the WDT
|
|
if (first) printf("all set, let's go\n");
|
|
first = false;
|
|
|
|
//tool78_hw_rl78_uart1.rx_set_stop_bit(false);
|
|
glitch_arm();
|
|
for (size_t i = 0; i < 16; ++i) {
|
|
//glitch_trigger_sw_core1();
|
|
glitch_trigger_sw_pio();
|
|
rr = tool78_hw_rl78_uart1.recv(1, checkbuf, 12*1000);
|
|
if (rr != 1) {
|
|
busy_wait_ms(1); // leave time to recharge
|
|
printf(".");
|
|
continue;
|
|
}
|
|
|
|
/*printf("checkbuf: %d", checkbuf[0]);
|
|
printf("\n!!!\n");*/
|
|
tool78_hw_rl78_uart1.flags |= tool78_hw_flag_done_reset;
|
|
|
|
glitch_disarm();
|
|
goto success;
|
|
}
|
|
glitch_disarm();
|
|
|
|
printf(":");
|
|
do_reset_stuff:
|
|
tool78_hw_rl78_uart1.deinit();
|
|
|
|
// glitch for way too long to power cycle
|
|
sio_hw->gpio_set = 1u << GLITCH_OUT_PIN;
|
|
busy_wait_ms(16);
|
|
sio_hw->gpio_clr = 1u << GLITCH_OUT_PIN;
|
|
|
|
goto restart;
|
|
|
|
success:;
|
|
//gpio_put(2, true);
|
|
//busy_wait_ms(5);
|
|
// (02): read from above (checkbuf) code
|
|
// 03 06 18 00 df 03
|
|
// ^-- baud rate set response
|
|
// 00
|
|
// ^-- OCD entry response
|
|
rr = tool78_hw_rl78_uart1.recv(7, &databuf[0], 10000);
|
|
if (rr != 7) {
|
|
printf("rr=%d, wut?\n", rr);
|
|
goto do_reset_stuff;
|
|
}
|
|
|
|
busy_wait_us_32(500);
|
|
|
|
ver = 0;
|
|
st = tool78_ocd_version(&tool78_hw_rl78_uart1, &ver);
|
|
if (st) {
|
|
printf("OCD: get version failed: %d\n", st);
|
|
goto do_reset_stuff;
|
|
}
|
|
printf("got ver! %04x\n", ver);
|
|
|
|
printf("glitch len: %lu ns\n", *(volatile uint32_t*)&glitch_param_cur.length_ns.cur);
|
|
/*goto do_reset_stuff;*/
|
|
|
|
st = tool78_ocd_connect(&tool78_hw_rl78_uart1, passwd);
|
|
if (st != 0xf0 && st != 0xf2) {
|
|
printf("OCD: connect failed: %d\n", st);
|
|
goto deinit_bad;
|
|
}
|
|
printf("connect! 0x%02x\n", st);
|
|
|
|
// can't write too much at 0xf07e0 as 0xf0800 and up contains OCD state,
|
|
// overwrite this and suddenly the OCD system resets itself
|
|
st = tool78_ocd_write(&tool78_hw_rl78_uart1, 0x07e0,
|
|
sizeof(exec_jmp_to_ram), exec_jmp_to_ram);
|
|
//printf("write trampoline res 0x%02x\n", st);
|
|
if (st != 0) {
|
|
printf("trampoline write failed: %d\n", st);
|
|
goto deinit_bad;
|
|
}
|
|
st = tool78_ocd_write(&tool78_hw_rl78_uart1, 0xf900,
|
|
sizeof(dumper_shellcode), dumper_shellcode);
|
|
//printf("write code res 0x%02x\n", st);
|
|
if (st != 0) {
|
|
printf("code write failed: %d\n", st);
|
|
goto deinit_bad;
|
|
}
|
|
|
|
st = tool78_ocd_exec(&tool78_hw_rl78_uart1);
|
|
//printf("exec res 0x%02x\n", st);
|
|
if (st != 0) {
|
|
printf("exec failed: %d\n", st);
|
|
goto deinit_bad;
|
|
}
|
|
|
|
for (size_t iii = 0; iii < DUMP_SIZE + DUMP_OFFSET; ++iii) {
|
|
// wait for completion
|
|
size_t off = (iii < DUMP_OFFSET) ? 0 : (iii - DUMP_OFFSET);
|
|
rr = tool78_hw_rl78_uart1.recv(1, &databuf[off], 120*1000*1000);
|
|
if (rr != 1) {
|
|
printf("exec code: no response :/ (%d)\n", rr);
|
|
goto deinit_bad;
|
|
}
|
|
}
|
|
|
|
for (size_t iii = 0; iii < DUMP_SIZE; ++iii) {
|
|
printf("0x%02x%s", databuf[iii], ((iii & 0xf) == 0xf) ? "\n" : " ");
|
|
}
|
|
|
|
printf("\ndone!\n");
|
|
|
|
deinit_bad:
|
|
tool78_hw_rl78_uart1.deinit();
|
|
return;
|
|
}
|
|
|
|
/*static uint8_t DATA_G1M_paramtest[47] = {
|
|
0xcf, 0x77, 0x00, 0x00, 0xce, 0x00, 0x00, 0xcf, 0x30, 0x00, 0x00, 0xcf, 0x50,
|
|
0x00, 0x00, 0xcf, 0x60, 0x00, 0x7f, 0xcf, 0x20, 0xff, 0x00, 0xcf, 0xf0, 0x00,
|
|
0xe5, 0xcf, 0xf3, 0x00, 0x10, 0xce, 0x00, 0xff, 0x51, 0x48, 0xfc, 0xdc, 0xff,
|
|
0x0e, 0x51, 0x69, 0xfc, 0xdc, 0xff, 0x0e, 0xd7
|
|
};*/
|
|
|
|
void cli_tool78_glitch_param_g10(void) {
|
|
struct tool78_hw* hw = &tool78_hw_rl78g10_uart1;
|
|
|
|
zap_dac_set_enable(zap_dac_a | zap_dac_b);
|
|
#if 1 /* MCP48x2 */
|
|
zap_dac_set_mulx2(zap_dac_a | zap_dac_b);
|
|
#else
|
|
zap_dac_set_mulx2(0);
|
|
zap_dac_set_shutdown(false);
|
|
#endif
|
|
|
|
/*zap_max_use_vhi_jp300(true);
|
|
zap_max_set_inhibit(false);*/
|
|
zap_picoemp_init();
|
|
|
|
if (!glitch_init_core1_stuff(true, ZAP_GLITCH_OUT)) {
|
|
printf("bad glitcher params!\n");
|
|
return;
|
|
}
|
|
|
|
uint8_t passwd[10] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
|
enum tool78_stat st;
|
|
uint16_t vvv=0xffff;
|
|
int rr;
|
|
static uint8_t checkbuf[256];
|
|
volatile uint32_t *off, *len;
|
|
bool first = true;
|
|
|
|
restart:
|
|
zap_picoemp_set_armed(false);
|
|
glitch_disarm();
|
|
/*busy_wait_ms(40);*/
|
|
|
|
zap_picoemp_set_armed(true);
|
|
while (!zap_picoemp_has_hv()) ;
|
|
|
|
st = tool78_init_ocd(hw, NULL, passwd);
|
|
if (st == 0xc3) {
|
|
printf("aa\n");
|
|
st = 0;
|
|
rr = tool78_hw_rl78_uart1.recv(1, (uint8_t*)&st, 120*1000);
|
|
printf("rr=%d\n", rr);
|
|
if (rr != 1) {
|
|
printf("aaaa\n");
|
|
goto do_reset_stuff;
|
|
}
|
|
}
|
|
//printf("result: 0x%02x ver=%04x\n", st, ver);
|
|
if (st != 0xf2 && st != 0xf0) {
|
|
if (st == 0xf3) { // idk
|
|
//gpio_put(12, true);
|
|
printf("init: 0x%02x off=%lu len=%lu vv=%03x\n", st, *off, *len, vvv);
|
|
//gpio_put(12, false);
|
|
goto do_reset_stuff;
|
|
} else {
|
|
printf("init: 0x%02x\n", st);
|
|
}
|
|
goto deinit_bad;
|
|
}
|
|
if (first) printf("result: 0x%02x\n", st);
|
|
|
|
st = tool78_ocd_write(hw, 0xfed0,
|
|
sizeof(G1M_payload_1), G1M_payload_1);
|
|
//printf("write trampoline res 0x%02x\n", st);
|
|
if (st != 0) {
|
|
printf("payload 1 write failed: %d\n", st);
|
|
goto deinit_bad;
|
|
}
|
|
st = tool78_ocd_exec(hw);
|
|
//printf("exec res 0x%02x\n", st);
|
|
if (st != 0) {
|
|
printf("payload 1 exec failed: %d\n", st);
|
|
goto deinit_bad;
|
|
}
|
|
|
|
st = tool78_ocd_write(hw, 0xfed0,
|
|
sizeof(G1M_payload_2), G1M_payload_2);
|
|
//printf("write trampoline res 0x%02x\n", st);
|
|
if (st != 0) {
|
|
printf("payload 2 write failed: %d\n", st);
|
|
goto deinit_bad;
|
|
}
|
|
st = tool78_ocd_write(hw, 0xfe00,
|
|
sizeof(G1M_paramtest), G1M_paramtest);
|
|
//printf("write trampoline res 0x%02x\n", st);
|
|
if (st != 0) {
|
|
printf("real payload write failed: %d\n", st);
|
|
goto deinit_bad;
|
|
}
|
|
st = tool78_ocd_exec(hw);
|
|
//printf("exec res 0x%02x\n", st);
|
|
if (st != 0) {
|
|
printf("real payload exec failed: %d\n", st);
|
|
goto deinit_bad;
|
|
}
|
|
|
|
// wait for initial pong
|
|
rr = hw->recv(1, checkbuf, 120*1000);
|
|
if (rr != 1) {
|
|
printf("exec code pong: no response :/ (%d)\n", rr);
|
|
goto deinit_bad;
|
|
}
|
|
if (checkbuf[0] != 'a') {
|
|
printf("bad pong response: %02x %02x\n", checkbuf[0], checkbuf[1]);
|
|
goto deinit_bad;
|
|
}
|
|
|
|
// wait for completion
|
|
rr = hw->recv(2, checkbuf, 150*1000);
|
|
if (rr != 2) {
|
|
printf("exec code hdr: no response :/ (%d)\n", rr);
|
|
goto deinit_bad;
|
|
}
|
|
|
|
if (checkbuf[0] == 0xff) {
|
|
checkbuf[0] = checkbuf[1];
|
|
rr = hw->recv(1, &checkbuf[1], 120*1000);
|
|
if (rr != 1) {
|
|
printf("exec code hdr: no response :/ (%d)\n", rr);
|
|
goto deinit_bad;
|
|
}
|
|
}
|
|
if (checkbuf[0] != 'H' && checkbuf[1] != 'i') {
|
|
printf("bad hdr response: %02x %02x\n", checkbuf[0], checkbuf[1]);
|
|
goto deinit_bad;
|
|
}
|
|
|
|
const int lenlen = 0x40;
|
|
rr = hw->recv(lenlen, checkbuf, 120*1000);
|
|
if (rr != lenlen) {
|
|
printf("exec code: no data sendback (%d)\n", rr);
|
|
goto deinit_bad;
|
|
}
|
|
|
|
for (size_t i = 0; i < lenlen; ++i) {
|
|
if (checkbuf[i] != (0xff^0xaa)) {
|
|
printf("bad value at index %zu: %02x\n", i, checkbuf[i]^0xaa);
|
|
goto deinit_bad;
|
|
}
|
|
}
|
|
if (first) printf("all set, let's go\n");
|
|
first = false;
|
|
|
|
gpio_init(12);
|
|
gpio_set_dir(12, GPIO_OUT);
|
|
gpio_set_function(12, GPIO_FUNC_SIO);
|
|
gpio_put(12, false);
|
|
/*gpio_init(7);
|
|
gpio_set_dir(7, GPIO_IN);*/
|
|
|
|
while (true) {
|
|
/*//vvv = zap_adc_read(1);
|
|
vvv = (random() & 0x3ff) + 0x400;
|
|
zap_dac_set_b(vvv);
|
|
zap_dac_latch();*/
|
|
glitch_arm();
|
|
rr = hw->recv(2, checkbuf, 150*1000);
|
|
//printf("rr=%d cb=%02x %02x\n", rr, checkbuf[0], checkbuf[1]);
|
|
glitch_disarm();
|
|
|
|
bool first_ = true;
|
|
do {
|
|
if (rr == 2 && (checkbuf[0] != 'H' || checkbuf[1] != 'i')) rr = 0;
|
|
if (rr == 2) {
|
|
rr = hw->recv(lenlen, checkbuf, 150*1000);
|
|
//printf("recv data rr=%d\n", rr);
|
|
}
|
|
if (rr <= 0) {
|
|
if (!first_) break;
|
|
// timeout or something
|
|
printf("X");
|
|
off = (volatile uint32_t*)&glitch_param_cur.offset_ns.cur;
|
|
len = (volatile uint32_t*)&glitch_param_cur.length_ns.cur;
|
|
//printf("X off=%lu len=%lu vv=%03x\n", *off, *len, vvv);
|
|
hw->deinit();
|
|
goto do_reset_stuff;
|
|
} else {
|
|
int firstbad = -1, lastbad = -1;
|
|
for (int i = 0; i < rr; ++i) {
|
|
if (checkbuf[i] != (0xaa^0xff)) {
|
|
if (firstbad == -1) firstbad = i;
|
|
lastbad = i;
|
|
}
|
|
}
|
|
if (firstbad >= 0) {
|
|
gpio_put(12, true);
|
|
off = (volatile uint32_t*)&glitch_param_cur.offset_ns.cur;
|
|
len = (volatile uint32_t*)&glitch_param_cur.length_ns.cur;
|
|
printf("glitch first=%d last=%d off=%lu len=%lu vvv=%03x rr=%d v=%02x\n",
|
|
firstbad, lastbad, *off, *len, vvv, rr, checkbuf[firstbad]^0xaa);
|
|
gpio_put(12, false);
|
|
} else {
|
|
printf(".");
|
|
//printf("NN off=%lu len=%lu vv=%03x\n", *off, *len, vvv);
|
|
}
|
|
}
|
|
|
|
first_=false;
|
|
if (!zap_picoemp_has_hv()) {
|
|
rr = hw->recv(2, checkbuf, 150*1000);
|
|
} else break;
|
|
} while (true);
|
|
}
|
|
deinit_bad:
|
|
zap_picoemp_set_armed(false);
|
|
busy_wait_ms(500);
|
|
hw->deinit();
|
|
return;
|
|
|
|
do_reset_stuff:
|
|
zap_picoemp_set_armed(false);
|
|
busy_wait_ms(300);
|
|
hw->deinit();
|
|
|
|
// glitch for way too long to power cycle
|
|
//sio_hw->gpio_set = 1u << ZAP_GLITCH_OUT;
|
|
busy_wait_ms(16);
|
|
//sio_hw->gpio_clr = 1u << ZAP_GLITCH_OUT;
|
|
|
|
goto restart;
|
|
}
|
|
|
|
void cli_tool78_glitch_ocd_g10(void) {
|
|
// struct tool78_hw* hw = &tool78_hw_rl78g10_uart1;
|
|
//
|
|
// zap_dac_set_enable(zap_dac_a | zap_dac_b);
|
|
//#if 1 /* MCP48x2 */
|
|
// zap_dac_set_mulx2(zap_dac_a | zap_dac_b);
|
|
//#else
|
|
// zap_dac_set_mulx2(0);
|
|
// zap_dac_set_shutdown(false);
|
|
//#endif
|
|
//
|
|
// zap_max_use_vhi_jp300(true);
|
|
// zap_max_set_inhibit(false);
|
|
//
|
|
// if (!glitch_init_core1_stuff(false, ZAP_GLITCH_OUT)) {
|
|
// printf("bad glitcher params!\n");
|
|
// return;
|
|
// }
|
|
//
|
|
// gpio_set_function(2, GPIO_FUNC_SIO);
|
|
// gpio_set_dir(2, GPIO_OUT);
|
|
// gpio_put(2, false);
|
|
//
|
|
// //gpio_set_function(3, GPIO_FUNC_SIO);
|
|
// //gpio_set_dir(3, GPIO_OUT);
|
|
// //gpio_put(3, false);
|
|
//
|
|
// uint8_t passwd[10] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
|
// int st, rr/*, r0, r1, r2*/;
|
|
// static uint8_t checkbuf[256];
|
|
// bool first = true;
|
|
//
|
|
//restart:
|
|
// //trl78_uart1_set_exclusive(true);
|
|
// //hw->rx_set_stop_bit(false);
|
|
// gpio_put(2, false);
|
|
// /*glitch_disarm();
|
|
// busy_wait_ms(40);*/
|
|
//
|
|
// st = tool78_init_ocd(hw, NULL, passwd);
|
|
// if (st == 0xc3) {
|
|
// printf("aa\n");
|
|
// st = 0;
|
|
// rr = hw->recv(1, (uint8_t*)&st, 120*1000);
|
|
// printf("rr=%d\n", rr);
|
|
// if (rr != 1) {
|
|
// printf("aaaa\n");
|
|
// goto do_reset_stuff;
|
|
// }
|
|
// }
|
|
// if (first) printf("result: 0x%02x\n", st);
|
|
// if (st == 0xc1) goto do_reset_stuff;
|
|
// if (st != tool78_stat_no_ocd_status) {
|
|
// printf("init: expected status timeout error, got %d\n", st);
|
|
// goto deinit_bad;
|
|
// }
|
|
// busy_wait_ms(16); // leave time to recharge
|
|
//
|
|
// // TODO: update description
|
|
// // right now, the RL78 core is stuck in an infinite loop doing nothing in
|
|
// // the debug monitor part of its bootrom. however, the code we need is
|
|
// // right below it, so we can simply try to glitch it without having to meet
|
|
// // the timing
|
|
// // see https://fail0verflow.com/blog/2018/ps4-syscon/ for more info
|
|
//
|
|
// // try up to 16 times because we can't discern between a reset and a glitch
|
|
// // that had no effect. after 16 iterations without result, reset the RL78
|
|
// // and try again.
|
|
// // a successful glitch will output a single null byte over the TOOL0 line
|
|
//
|
|
// // apparently we have about 95 ms until the infinite loop gets reset into
|
|
// // the MCU flash automatically? somehow?? I suppose it's the WDT
|
|
// if (first) printf("all set, let's go\n");
|
|
// first = false;
|
|
//
|
|
// //hw->rx_set_stop_bit(false);
|
|
// glitch_arm();
|
|
// for (size_t i = 0; i < 16; ++i) {
|
|
// zap_dac_set_b(zap_adc_read(1));
|
|
// zap_dac_latch();
|
|
// //glitch_trigger_sw_core1();
|
|
// glitch_trigger_sw_pio();
|
|
// rr = hw->recv(1, checkbuf, 12*1000);
|
|
// if (rr != 1 || checkbuf[0] == 0xff) {
|
|
// busy_wait_ms(1); // leave time to recharge
|
|
// printf(".");
|
|
// continue;
|
|
// }
|
|
//
|
|
// printf("checkbuf: %d", checkbuf[0]);
|
|
// printf("\n!!!\n");
|
|
// hw->flags |= tool78_hw_flag_done_reset;
|
|
//
|
|
// glitch_disarm();
|
|
// goto success;
|
|
// }
|
|
// glitch_disarm();
|
|
//
|
|
// printf(":");
|
|
//do_reset_stuff:
|
|
// hw->deinit();
|
|
//
|
|
// // glitch for way too long to power cycle
|
|
// sio_hw->gpio_set = 1u << ZAP_GLITCH_OUT;
|
|
// busy_wait_ms(16);
|
|
// sio_hw->gpio_clr = 1u << ZAP_GLITCH_OUT;
|
|
//
|
|
// goto restart;
|
|
//
|
|
//success:;
|
|
// //gpio_put(2, true);
|
|
// //busy_wait_ms(5);
|
|
// // (02): read from above (checkbuf) code
|
|
// // 03 06 18 00 df 03
|
|
// // ^-- baud rate set response
|
|
// // 00
|
|
// // ^-- OCD entry response
|
|
// rr = hw->recv(4, &checkbuf[1], 10000);
|
|
// if (rr != 4) {
|
|
// printf("#");
|
|
// //printf("rr=%d, wut?\n", rr);
|
|
// goto do_reset_stuff;
|
|
// }
|
|
// printf("recv %02x %02x %02x %02x %02x\n", checkbuf[0], checkbuf[1],
|
|
// checkbuf[2], checkbuf[3], checkbuf[4]);
|
|
//
|
|
// busy_wait_us_32(500);
|
|
//
|
|
// printf("glitch len: %lu ns\n", *(volatile uint32_t*)&glitch_param_cur.length_ns.cur);
|
|
// /*goto do_reset_stuff;*/
|
|
//
|
|
// st = tool78_ocd_connect(hw, passwd);
|
|
// if (st != 0xf0 && st != 0xf2) {
|
|
// printf("OCD: connect failed: %d\n", st);
|
|
// goto deinit_bad;
|
|
// }
|
|
// printf("connect! 0x%02x\n", st);
|
|
//
|
|
// for (size_t i = 0; i < DUMP_SIZE; i += 256) {
|
|
// st = tool78_ocd_read(hw, 0x8000+i, (uint8_t)0x100, &databuf[i]);
|
|
// if (st) {
|
|
// printf("no read! st=%d\n", st);
|
|
// }
|
|
// }
|
|
// for (size_t iii = 0; iii < DUMP_SIZE; ++iii) {
|
|
// printf("%02x%s", databuf[iii], ((iii & 0xf) == 0xf) ? "\n" : " ");
|
|
// }
|
|
//
|
|
// printf("\ndone!\n");
|
|
//
|
|
//deinit_bad:
|
|
// hw->deinit();
|
|
// return;
|
|
}
|
|
|