Skip to content

Commit

Permalink
Byte-accurate OTP defusing on Pico
Browse files Browse the repository at this point in the history
  • Loading branch information
shinyquagsire23 committed Apr 27, 2023
1 parent 0f424d0 commit 273229d
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 6 deletions.
59 changes: 53 additions & 6 deletions pico_defuse/src/pico_defuse.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ PIO pio_exi;
int debug_gpio_monitor_dmachan;
dma_channel_config debug_gpio_monitor_dmacfg;
uint debug_gpio_monitor_parallel_sm;
uint reset_cycle_accurate_sm;
uint exi_inject_sm;
uint exi_inject_offset;
uint debug_gpio_monitor_parallel_offset;
uint debug_gpio_monitor_serial_offset;
uint reset_cycle_accurate_offset;

#define MONITOR_SERIAL_DATA (0)
#define MONITOR_SERIAL_TEXT (1)
Expand Down Expand Up @@ -132,8 +134,21 @@ uint8_t wiiu_state = WIIU_STATE_POWERED_OFF;
uint8_t next_wiiu_state = WIIU_STATE_POWERED_OFF;
bool nrst_sense_state = false;

#define RESET_RANGE_MIN (0x440)
#define RESET_RANGE_MAX (0x480)
// Cycle-accurate JTAG enable
//#define DEFUSE_JTAG
#define DEFUSE_BYTE_UNIT (0x4)

#ifdef DEFUSE_JTAG
#define RESET_RANGE_MIN (RESET_RANGE_MAX-(DEFUSE_BYTE_UNIT*0x20))
#define RESET_RANGE_MAX (0xE9C)
#else
#define RESET_RANGE_MIN (RESET_RANGE_MAX-(DEFUSE_BYTE_UNIT*0x40))
#define RESET_RANGE_MAX (0xE8C-(DEFUSE_BYTE_UNIT*0x7D))
#endif

// Empty OTP w/ JTAG disabled
//#define RESET_RANGE_MIN (RESET_RANGE_MAX-(DEFUSE_BYTE_UNIT*0x40))
//#define RESET_RANGE_MAX (0xE8C-(DEFUSE_BYTE_UNIT*0))

void nrst_sense_callback(uint gpio, uint32_t events)
{
Expand All @@ -158,6 +173,8 @@ void nrst_sense_callback(uint gpio, uint32_t events)

void nrst_sense_set(bool is_on)
{
gpio_set_function(PIN_NRST, GPIO_FUNC_SIO);

if (is_on == nrst_sense_state) {
return;
}
Expand Down Expand Up @@ -222,16 +239,18 @@ void slow_one_time_init()
// We use two statemachines: one for the debug monitor, and one for the EXI injecting.
debug_gpio_monitor_parallel_sm = pio_claim_unused_sm(pio, true);
exi_inject_sm = pio_claim_unused_sm(pio_exi, true);
//reset_cycle_accurate_sm = pio_claim_unused_sm(pio_exi, true);

// The exi inject statemachine is only used during de_Fusing, it just watches
// for 64 EXI clks and shoves the line high so the SDboot bit gets read as 1.
exi_inject_offset = pio_add_program(pio_exi, &exi_inject_program);
//reset_cycle_accurate_offset = pio_add_program(pio_exi, &reset_cycle_accurate_program);

// The debug monitor has two programs: The parallel monitor, used to check boot0
// codes, and the serial monitor, which is used for the text console in minute/etc
debug_gpio_monitor_parallel_offset = pio_add_program(pio, &debug_gpio_monitor_parallel_program);
debug_gpio_monitor_serial_offset = pio_add_program(pio, &debug_gpio_monitor_serial_program);

// Debug monitor can start early, it's basically always on.
debug_gpio_monitor_parallel_program_init(pio, debug_gpio_monitor_parallel_sm, debug_gpio_monitor_parallel_offset, PIN_DEBUGLED_BASE, PIN_SERIALOUT_BASE, 1.0);
pio_sm_set_enabled(pio, debug_gpio_monitor_parallel_sm, true);
Expand Down Expand Up @@ -265,6 +284,9 @@ void do_normal_reset()

void de_fuse()
{
//reset_cycle_accurate_program_init(pio_exi, reset_cycle_accurate_sm, reset_cycle_accurate_offset, PIN_NRST, 0, 1.0);
//pio_sm_set_enabled(pio_exi, reset_cycle_accurate_sm, false);

// Disable NRST sensing and take control of the line.
nrst_sense_set(false);

Expand All @@ -286,7 +308,8 @@ void de_fuse()
pio_sm_set_enabled(pio, debug_gpio_monitor_parallel_sm, true);
exi_inject_program_init(pio_exi, exi_inject_sm, exi_inject_offset, PIN_CLK, PIN_DATA_BASE, 1.0);

// Read OTP fully at least once and then hold
// Read OTP fully at least once and then hold.
// We do this twice just in case.
// This boot does not need EXI injection, because
// we try to make sure it ends before it hits boot1.
gpio_put(PIN_NRST, false);
Expand All @@ -295,7 +318,17 @@ void de_fuse()
__asm volatile ("\n");
}
gpio_put(PIN_NRST, true);
for(int i = 0; i < 0x800; i++)
for(int i = 0; i < 0x4000; i++)
{
__asm volatile ("\n");
}
gpio_put(PIN_NRST, false);
for(int i = 0; i < 0x100; i++)
{
__asm volatile ("\n");
}
gpio_put(PIN_NRST, true);
for(int i = 0; i < 0x4000; i++)
{
__asm volatile ("\n");
}
Expand All @@ -305,7 +338,7 @@ void de_fuse()
__asm volatile ("\n");
}


#if 1
// The actual timing-sensitive part...
// This won't even reach boot1, it just has to get the fuse
// readout counter to a value >0x380 so that the next
Expand All @@ -321,7 +354,19 @@ void de_fuse()
// OK, we're done
gpio_put(PIN_NRST, false);
restore_interrupts(cookie);
#endif

#if 1
//reset_cycle_accurate_program_reset(pio_exi, reset_cycle_accurate_sm, reset_cycle_accurate_offset, PIN_NRST, reset_attempt, 1.0);
//pio_sm_set_enabled(pio_exi, reset_cycle_accurate_sm, true);
//sleep_ms(1);
/*for(int i = 0; i < 0x210; i++)
{
__asm volatile ("\n");
}*/
//pio_sm_set_enabled(pio_exi, reset_cycle_accurate_sm, false);
gpio_set_function(PIN_NRST, GPIO_FUNC_SIO);
#endif

// Clear out the FIFO so our results readout is clean.
for (int i = 0; i < 0x20; i++)
Expand Down Expand Up @@ -412,6 +457,7 @@ void de_fuse()
//sleep_ms(1000);
}

#ifndef DEFUSE_JTAG
// TODO: do this after trying a NAND boot1?
// If no SD card is inserted, or an invalid one is inserted, boot0 stalls.
if (!winner && error_code == 0x00 && !only_zeros) {
Expand All @@ -423,6 +469,7 @@ void de_fuse()
printf("[Pico] Wii U doesn't seem to be powered on?\n");
next_wiiu_state = WIIU_CHECK_IF_POWERED_OFF;
}
#endif
}

void post_de_fuse()
Expand Down
43 changes: 43 additions & 0 deletions pico_defuse/src/pico_defuse.pio
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,23 @@ loop:
set pins, 0xF
jmp reset

.program reset_cycle_accurate
start:
; We can't mov the value 0x40 lol, pull it in this way.
pull block
mov x, osr
mov y, x

; set it high for exactly the number of cycles given
set pins, 0x0
loop2:
jmp y--, loop2

; back to low so we can hand the GPIO back
set pins, 0x0
stall:
jmp stall

.program exi_inject
start:
; We can't mov the value 0x40 lol, pull it in this way.
Expand Down Expand Up @@ -132,6 +149,32 @@ stall:
pio_sm_init(pio, sm, offset, &c);
}

void reset_cycle_accurate_program_init(PIO pio, uint sm, uint offset, uint rst_pin, uint rst_duration, float div) {
pio_sm_config c = pio_get_default_sm_config();

sm_config_set_set_pins(&c, rst_pin, 1);

sm_config_set_in_shift(&c, false, false, 32);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);

pio_sm_set_pins(pio, sm, 0x0);
pio_sm_set_consecutive_pindirs(pio, sm, rst_pin, 1, true);

pio_sm_init(pio, sm, offset, &c);

pio_sm_put(pio, sm, rst_duration);
}

void reset_cycle_accurate_program_reset(PIO pio, uint sm, uint offset, uint rst_pin, uint rst_duration, float div) {
pio_sm_config c = pio_get_default_sm_config();

pio_sm_set_pins(pio, sm, 0x0);
pio_gpio_init(pio, rst_pin);
pio_sm_init(pio, sm, offset, &c);

pio_sm_put(pio, sm, rst_duration);
}

void exi_inject_program_init(PIO pio, uint sm, uint offset, uint pin_clk, uint pin_data, float div) {
pio_sm_config c = pio_get_default_sm_config();

Expand Down

0 comments on commit 273229d

Please sign in to comment.