forked from Mirrors/usk
Compare commits
6 commits
2.81-OLED-
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7dd3a01989 | ||
| 8eb749f6f2 | |||
|
|
71266314eb | ||
|
|
c0f8d7c186 | ||
|
|
9e2544dbe3 | ||
|
|
9cce154f9c |
11 changed files with 197 additions and 207 deletions
|
|
@ -53,7 +53,7 @@ bool wait_for_boot(int timeout_ms) {
|
||||||
else if (last_word == 0x51000000 && word == 0x0055) //read block 0
|
else if (last_word == 0x51000000 && word == 0x0055) //read block 0
|
||||||
{
|
{
|
||||||
// OLED models sometimes need more time between block 0 and block 1
|
// OLED models sometimes need more time between block 0 and block 1
|
||||||
// original was 100ms, increased to 250ms for (hopefully) better OLED compatibility
|
// original was 100ms, increased to 250ms for better OLED compatibility
|
||||||
tio_full = make_timeout_time_ms(250);
|
tio_full = make_timeout_time_ms(250);
|
||||||
was_read_zero = true;
|
was_read_zero = true;
|
||||||
} else if (was_read_zero && last_word == 0x4D000200 && word == 0x00B1) // read status - erista only
|
} else if (was_read_zero && last_word == 0x4D000200 && word == 0x00B1) // read status - erista only
|
||||||
|
|
@ -69,9 +69,8 @@ bool wait_for_boot(int timeout_ms) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// properly clean up all state machines before retrying
|
// properly clean up all state machines before retrying
|
||||||
// original deinit only disabled SM 0 and 1, but SM 2 (G_DAT0_SM) was left running
|
// SM 2 (G_DAT0_SM) must also be disabled (0x7 = 0b111 covers SM 0, 1, and 2)
|
||||||
|
pio_set_sm_mask_enabled(pio1, 0x7, false);
|
||||||
pio_set_sm_mask_enabled(pio1, 0x7, false); // disable SM 0, 1, AND 2 (0x7 = 0b111)
|
|
||||||
|
|
||||||
// clean up GPIO pins
|
// clean up GPIO pins
|
||||||
for (int i = PIN_CLK; i <= PIN_DAT; i++)
|
for (int i = PIN_CLK; i <= PIN_DAT; i++)
|
||||||
|
|
|
||||||
4
config.h
4
config.h
|
|
@ -1,10 +1,10 @@
|
||||||
#include "hardware/flash.h"
|
#include "hardware/flash.h"
|
||||||
#define OFFSET_DIV 8
|
#define OFFSET_DIV 8
|
||||||
#define OFFSET_MIN 6200
|
#define OFFSET_MIN 6200
|
||||||
#define OFFSET_MAX 6950
|
#define OFFSET_MAX 6900
|
||||||
|
|
||||||
#define VER_HI 2
|
#define VER_HI 2
|
||||||
#define VER_LO 81
|
#define VER_LO 82
|
||||||
|
|
||||||
bool is_configured();
|
bool is_configured();
|
||||||
void init_config();
|
void init_config();
|
||||||
|
|
|
||||||
9
glitch.c
9
glitch.c
|
|
@ -65,8 +65,7 @@ void init_glitch_pio() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void deinit_glitch_pio() {
|
void deinit_glitch_pio() {
|
||||||
// original code only disabled SM 0 and 1 (mask 0x3 = 0b011)
|
// SM 2 (G_DAT0_SM) is also used, so all 3 state machines need to be disabled (0x7 = 0b111)
|
||||||
// SM 2 (G_DAT0_SM) is also used, so all 3 (mask 0x7 = 0b111) need to be disabled
|
|
||||||
pio_set_sm_mask_enabled(pio1, 0x7, false);
|
pio_set_sm_mask_enabled(pio1, 0x7, false);
|
||||||
for (int i = PIN_CLK; i <= PIN_DAT; i++)
|
for (int i = PIN_CLK; i <= PIN_DAT; i++)
|
||||||
{
|
{
|
||||||
|
|
@ -136,14 +135,14 @@ int do_glitch(int delay, int width, int total_ms, int after_ms) {
|
||||||
|
|
||||||
int tries = 0;
|
int tries = 0;
|
||||||
|
|
||||||
// Green pulsing implementation.
|
// Blue pulsing implementation.
|
||||||
void inc_tries()
|
void inc_tries()
|
||||||
{
|
{
|
||||||
tries += 1;
|
tries += 1;
|
||||||
if(tries & 1)
|
if(tries & 1)
|
||||||
put_pixel(PIX_g);
|
put_pixel(PIX_b);
|
||||||
else
|
else
|
||||||
put_pixel(PIX_gre);
|
put_pixel(PIX_blu);
|
||||||
}
|
}
|
||||||
|
|
||||||
// random() for glitch offset array generation
|
// random() for glitch offset array generation
|
||||||
|
|
|
||||||
167
main.c
167
main.c
|
|
@ -21,23 +21,24 @@
|
||||||
|
|
||||||
bool write_payload();
|
bool write_payload();
|
||||||
|
|
||||||
// optimized: increased voltage for better stability at higher clock
|
// overclock to 200 MHz
|
||||||
void init_system() {
|
void init_system() {
|
||||||
vreg_set_voltage(VREG_VOLTAGE_1_30);
|
vreg_set_voltage(VREG_VOLTAGE_1_30);
|
||||||
set_sys_clock_khz(200000, true);
|
set_sys_clock_khz(200000, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// filled within "fast check" on eMMC init
|
||||||
extern uint8_t cid_buf[17];
|
extern uint8_t cid_buf[17];
|
||||||
|
|
||||||
void rewrite_payload()
|
void rewrite_payload()
|
||||||
{
|
{
|
||||||
put_pixel(PIX_whi);
|
put_pixel(PIX_whi);
|
||||||
write_payload();
|
write_payload();
|
||||||
put_pixel(PIX_gre);
|
put_pixel(PIX_blu);
|
||||||
|
// used to automatically rewrite payload when eMMC/console changes
|
||||||
init_config(cid_buf + 1);
|
init_config(cid_buf + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// optimized: reduced timeout and combined checks
|
|
||||||
bool safe_test_voltage(int pin, float target, float range)
|
bool safe_test_voltage(int pin, float target, float range)
|
||||||
{
|
{
|
||||||
gpio_enable_input_output(pin);
|
gpio_enable_input_output(pin);
|
||||||
|
|
@ -49,28 +50,34 @@ bool safe_test_voltage(int pin, float target, float range)
|
||||||
return voltage >= (target - range) && voltage <= (target + range);
|
return voltage >= (target - range) && voltage <= (target + range);
|
||||||
}
|
}
|
||||||
|
|
||||||
// optimized: reduced timeout from 2500ms to 1500ms, faster convergence
|
// test all ADC pins
|
||||||
void self_test()
|
void self_test()
|
||||||
{
|
{
|
||||||
absolute_time_t tio_time = make_timeout_time_ms(1500);
|
absolute_time_t tio_time = make_timeout_time_ms(2500);
|
||||||
adc_init();
|
adc_init();
|
||||||
uint8_t check_mask = 0; // bit flags: 0=rst, 1=cmd, 2=d0
|
bool rst_ok = false, cmd_ok = false, d0_ok = false;
|
||||||
|
while (!time_reached(tio_time)) {
|
||||||
while (!time_reached(tio_time) && check_mask != 0x07) {
|
if (!rst_ok)
|
||||||
if (!(check_mask & 0x01))
|
rst_ok |= safe_test_voltage(PIN_RST, 1.8f, 0.2f);
|
||||||
check_mask |= safe_test_voltage(PIN_RST, 1.8f, 0.2f) ? 0x01 : 0;
|
if (!cmd_ok)
|
||||||
if (!(check_mask & 0x02))
|
cmd_ok |= safe_test_voltage(PIN_CMD, 1.8f, 0.2f);
|
||||||
check_mask |= safe_test_voltage(PIN_CMD, 1.8f, 0.2f) ? 0x02 : 0;
|
if (!d0_ok)
|
||||||
if (!(check_mask & 0x04))
|
d0_ok |= safe_test_voltage(PIN_DAT, 1.8f, 0.2f);
|
||||||
check_mask |= safe_test_voltage(PIN_DAT, 1.8f, 0.2f) ? 0x04 : 0;
|
if (rst_ok && cmd_ok && d0_ok)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
if(!rst_ok)
|
||||||
if(!(check_mask & 0x01))
|
{
|
||||||
halt_with_error(0, 2);
|
halt_with_error(0, 2);
|
||||||
if(!(check_mask & 0x02))
|
}
|
||||||
|
if(!cmd_ok)
|
||||||
|
{
|
||||||
halt_with_error(1, 2);
|
halt_with_error(1, 2);
|
||||||
if(!(check_mask & 0x04))
|
}
|
||||||
|
if(!d0_ok)
|
||||||
|
{
|
||||||
halt_with_error(2, 2);
|
halt_with_error(2, 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern bool was_self_reset;
|
extern bool was_self_reset;
|
||||||
|
|
@ -79,125 +86,89 @@ int main()
|
||||||
{
|
{
|
||||||
// stop watchdog
|
// stop watchdog
|
||||||
*(uint32_t*)(0x40058000 + 0x3000) = (1 << 30);
|
*(uint32_t*)(0x40058000 + 0x3000) = (1 << 30);
|
||||||
|
// init reset, mosfet and LED
|
||||||
// init board detection
|
|
||||||
detect_board();
|
detect_board();
|
||||||
|
|
||||||
// clocks & voltage
|
// clocks & voltage
|
||||||
init_system();
|
init_system();
|
||||||
|
|
||||||
// fuses counter
|
// fuses counter
|
||||||
init_fuses();
|
init_fuses();
|
||||||
|
|
||||||
// LED & glitch & emmc PIO
|
// LED & glitch & emmc PIO
|
||||||
upload_pio();
|
upload_pio();
|
||||||
|
|
||||||
if (is_tiny())
|
if (is_tiny())
|
||||||
{
|
{
|
||||||
gpio_put(led_pin(), 0);
|
gpio_put(led_pin(), 0);
|
||||||
sleep_us(50); // optimized: reduced from 100us
|
sleep_us(100);
|
||||||
put_pixel(0);
|
put_pixel(0);
|
||||||
sleep_us(50); // optimized: reduced from 100us
|
sleep_us(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if this is the very first start
|
// check if this is the very first start
|
||||||
if (watchdog_caused_reboot() && boot_try == 0)
|
if (watchdog_caused_reboot() && boot_try == 0)
|
||||||
halt_with_error(1, 1);
|
{
|
||||||
|
halt_with_error(1, 1);
|
||||||
|
}
|
||||||
// is chip reset required
|
// is chip reset required
|
||||||
bool force_button = detect_by_pull(1, 0, 1);
|
bool force_button = detect_by_pull(1, 0, 1);
|
||||||
|
|
||||||
// start LED
|
// start LED
|
||||||
put_pixel(PIX_gre);
|
put_pixel(PIX_blu);
|
||||||
|
|
||||||
// test pins
|
// test pins
|
||||||
self_test();
|
self_test();
|
||||||
|
|
||||||
// wait till the CPU has proper power & started reading the eMMC
|
// wait till the CPU has proper power & started reading the eMMC
|
||||||
wait_for_boot(2490);
|
wait_for_boot(2500);
|
||||||
|
|
||||||
// ensure the BCT has not been overwritten by system update
|
// ensure the BCT has not been overwritten by system update
|
||||||
bool force_check = fast_check();
|
bool force_check = fast_check();
|
||||||
was_self_reset = force_button || !is_configured(cid_buf + 1);
|
was_self_reset = force_button || !is_configured(cid_buf + 1);
|
||||||
|
|
||||||
// perform payload rewrite if required
|
// perform payload rewrite if required
|
||||||
if (!force_check || was_self_reset) {
|
if (!force_check || was_self_reset) {
|
||||||
rewrite_payload();
|
rewrite_payload();
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup the glitch trigger for Mariko
|
// setup the glitch trigger for Mariko
|
||||||
if (mariko) {
|
if (mariko) {
|
||||||
pio1->instr_mem[gtrig_pio_offset + 4] = pio_encode_nop();
|
pio1->instr_mem[gtrig_pio_offset + 4] = pio_encode_nop();
|
||||||
pio1->instr_mem[gtrig_pio_offset + 5] = pio_encode_nop();
|
pio1->instr_mem[gtrig_pio_offset + 5] = pio_encode_nop();
|
||||||
}
|
}
|
||||||
|
// start from some default width
|
||||||
// optimized: start with slightly lower width for faster convergence
|
int width = 150;
|
||||||
int width = 140;
|
|
||||||
bool glitched = false;
|
bool glitched = false;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
for (int full_try = 0; full_try < 2; full_try++) {
|
||||||
// optimized: removed outer loop since it just repeats rewrite_payload
|
// try saved records
|
||||||
// try saved records first
|
for (int y = 0; (y < 2) && !glitched; y++) {
|
||||||
for (int y = 0; (y < 2) && !glitched; y++) {
|
int max_weight = -1;
|
||||||
int max_weight = -1;
|
while (1) {
|
||||||
while (1) {
|
offset = find_best_record(&max_weight);
|
||||||
offset = find_best_record(&max_weight);
|
if (offset == -1)
|
||||||
if (offset == -1)
|
break;
|
||||||
break;
|
// try glitch
|
||||||
// optimized: reduced attempts from 3 to 2 for faster iteration
|
|
||||||
glitched = glitch_try_offset(offset, &width, 2);
|
|
||||||
if (glitched)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// try random offsets if saved records failed
|
|
||||||
if (!glitched) {
|
|
||||||
for(int z = 0; (z < 2) && !glitched; z++) {
|
|
||||||
prepare_random_array();
|
|
||||||
for(int y = 0; y < OFFSET_CNT; y++)
|
|
||||||
{
|
|
||||||
offset = offsets_array[y];
|
|
||||||
// optimized: reduced attempts from 4 to 3
|
|
||||||
glitched = glitch_try_offset(offset, &width, 3);
|
glitched = glitch_try_offset(offset, &width, 3);
|
||||||
if (glitched)
|
if (glitched)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (!glitched) {
|
||||||
|
for(int z = 0; (z < 2) && !glitched; z++) {
|
||||||
// if still not glitched, try one more time with payload rewrite
|
prepare_random_array();
|
||||||
if (!glitched) {
|
for(int y = 0; y < OFFSET_CNT; y++)
|
||||||
rewrite_payload();
|
{
|
||||||
|
offset = offsets_array[y];
|
||||||
// one more attempt with saved records
|
glitched = glitch_try_offset(offset, &width, 4);
|
||||||
int max_weight = -1;
|
if (glitched)
|
||||||
for (int y = 0; (y < 3) && !glitched; y++) {
|
break;
|
||||||
offset = find_best_record(&max_weight);
|
}
|
||||||
if (offset == -1)
|
}
|
||||||
break;
|
}
|
||||||
glitched = glitch_try_offset(offset, &width, 2);
|
if (glitched) {
|
||||||
|
if ((count_fuses() & 1) != boot_slot)
|
||||||
|
{
|
||||||
|
// finish update / rollback
|
||||||
|
burn_fuse();
|
||||||
|
}
|
||||||
|
add_boot_record(offset);
|
||||||
|
halt_with_error(0, 1);
|
||||||
|
}
|
||||||
|
if (full_try == 0) {
|
||||||
|
rewrite_payload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (glitched) {
|
|
||||||
// ensure all glitching operations are complete
|
|
||||||
sleep_us(100);
|
|
||||||
// force success LED display
|
|
||||||
put_pixel(0); // clear any previous LED state
|
|
||||||
sleep_ms(50);
|
|
||||||
put_pixel(PIX_whi); // show white success
|
|
||||||
sleep_ms(200); // longer delay to ensure visibility
|
|
||||||
|
|
||||||
if ((count_fuses() & 1) != boot_slot)
|
|
||||||
{
|
|
||||||
// finish update / rollback
|
|
||||||
burn_fuse();
|
|
||||||
}
|
|
||||||
add_boot_record(offset);
|
|
||||||
halt_with_error(0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// attempts limit
|
// attempts limit
|
||||||
halt_with_error(7, 3);
|
halt_with_error(7, 3);
|
||||||
}
|
}
|
||||||
63
misc.c
63
misc.c
|
|
@ -10,14 +10,13 @@
|
||||||
|
|
||||||
extern int ws_pio_offset;
|
extern int ws_pio_offset;
|
||||||
|
|
||||||
// optimized: reduced timing constants for faster error signaling
|
#define BLINK_TIME 700
|
||||||
#define BLINK_TIME 500
|
|
||||||
#define SHORT_TIME ( BLINK_TIME * 2 / 10 )
|
#define SHORT_TIME ( BLINK_TIME * 2 / 10 )
|
||||||
#define SHORT_PAUSE_TIME ((BLINK_TIME - SHORT_TIME) / 2)
|
#define SHORT_PAUSE_TIME ((BLINK_TIME - SHORT_TIME) / 2)
|
||||||
#define LONG_TIME ( BLINK_TIME * 8 / 10 )
|
#define LONG_TIME ( BLINK_TIME * 8 / 10 )
|
||||||
#define LONG_PAUSE_TIME ((BLINK_TIME - LONG_TIME) / 2)
|
#define LONG_PAUSE_TIME ((BLINK_TIME - LONG_TIME) / 2)
|
||||||
#define PAUSE_BETWEEN 1500
|
#define PAUSE_BETWEEN 2000
|
||||||
#define PAUSE_BEFORE 500
|
#define PAUSE_BEFORE 750
|
||||||
#define CODE_REPEATS 3
|
#define CODE_REPEATS 3
|
||||||
|
|
||||||
#define GPIO_OD PADS_BANK0_GPIO0_OD_BITS
|
#define GPIO_OD PADS_BANK0_GPIO0_OD_BITS
|
||||||
|
|
@ -26,7 +25,6 @@ extern int ws_pio_offset;
|
||||||
|
|
||||||
typedef void nopar();
|
typedef void nopar();
|
||||||
|
|
||||||
// optimized: streamlined power down sequence
|
|
||||||
void __not_in_flash_func(zzz)() {
|
void __not_in_flash_func(zzz)() {
|
||||||
*(uint32_t*)(0x4000803C + 0x3000) = 1; // go to 12 MHz
|
*(uint32_t*)(0x4000803C + 0x3000) = 1; // go to 12 MHz
|
||||||
uint32_t * vreg = (uint32_t*)0x40064000;
|
uint32_t * vreg = (uint32_t*)0x40064000;
|
||||||
|
|
@ -34,27 +32,30 @@ void __not_in_flash_func(zzz)() {
|
||||||
*(uint32_t*)0x40060000 = 0x00d1e000; // disable rosc
|
*(uint32_t*)0x40060000 = 0x00d1e000; // disable rosc
|
||||||
vreg[0] = 1; // lowest possible power
|
vreg[0] = 1; // lowest possible power
|
||||||
*(uint32_t*)0x40024000 = 0x00d1e000; // disable xosc
|
*(uint32_t*)0x40024000 = 0x00d1e000; // disable xosc
|
||||||
while(1) __asm volatile("wfi"); // optimized: use WFI to save more power
|
while(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// optimized: combined loop for faster execution
|
|
||||||
void finish_pins_except_leds() {
|
void finish_pins_except_leds() {
|
||||||
for(int pin = 0; pin <= 29; pin++) {
|
for(int pin = 0; pin <= 29; pin += 1) {
|
||||||
if (pin == led_pin() || pin == pwr_pin())
|
if (pin == led_pin() || pin == pwr_pin())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (pin == PIN_GLI_PICO || pin == PIN_GLI_XIAO || pin == PIN_GLI_WS || pin == PIN_GLI_ITSY)
|
if (pin == PIN_GLI_PICO || pin == PIN_GLI_XIAO || pin == PIN_GLI_WS || pin == PIN_GLI_ITSY)
|
||||||
|
{
|
||||||
gpio_pull_down(pin);
|
gpio_pull_down(pin);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
gpio_disable_pulls(pin);
|
gpio_disable_pulls(pin);
|
||||||
|
}
|
||||||
gpio_disable_input_output(pin);
|
gpio_disable_input_output(pin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void finish_pins_leds() {
|
void finish_pins_leds() {
|
||||||
if (!is_tiny())
|
if (!is_tiny())
|
||||||
|
{
|
||||||
gpio_disable_input_output(led_pin());
|
gpio_disable_input_output(led_pin());
|
||||||
|
}
|
||||||
gpio_disable_input_output(pwr_pin());
|
gpio_disable_input_output(pwr_pin());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,62 +66,50 @@ void halt_with_error(uint32_t err, uint32_t bits)
|
||||||
pio_set_sm_mask_enabled(pio1, 0xF, false);
|
pio_set_sm_mask_enabled(pio1, 0xF, false);
|
||||||
set_sys_clock_khz(48000, true);
|
set_sys_clock_khz(48000, true);
|
||||||
vreg_set_voltage(VREG_VOLTAGE_0_95);
|
vreg_set_voltage(VREG_VOLTAGE_0_95);
|
||||||
|
|
||||||
if (bits != 1)
|
if (bits != 1)
|
||||||
{
|
{
|
||||||
put_pixel(0);
|
put_pixel(0);
|
||||||
sleep_ms(PAUSE_BEFORE);
|
sleep_ms(PAUSE_BEFORE);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int j = 0; j < CODE_REPEATS; j++)
|
for(int j = 0; j < CODE_REPEATS; j++)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < bits; i++)
|
for(int i = 0; i < bits; i++)
|
||||||
{
|
{
|
||||||
bool is_long = err & (1 << (bits - i - 1));
|
bool is_long = err & (1 << (bits - i - 1));
|
||||||
sleep_ms(is_long ? LONG_PAUSE_TIME : SHORT_PAUSE_TIME);
|
sleep_ms(is_long ? LONG_PAUSE_TIME : SHORT_PAUSE_TIME);
|
||||||
|
|
||||||
bool success = bits == 1 && is_long == 0;
|
bool success = bits == 1 && is_long == 0;
|
||||||
put_pixel(success ? PIX_whi : PIX_red);
|
if (success)
|
||||||
|
put_pixel(PIX_whi);
|
||||||
|
else
|
||||||
|
put_pixel(PIX_red);
|
||||||
sleep_ms(is_long ? LONG_TIME : success ? SHORT_TIME * 2 : SHORT_TIME);
|
sleep_ms(is_long ? LONG_TIME : success ? SHORT_TIME * 2 : SHORT_TIME);
|
||||||
put_pixel(0);
|
put_pixel(0);
|
||||||
|
|
||||||
if (i != bits - 1 || j != CODE_REPEATS - 1)
|
if (i != bits - 1 || j != CODE_REPEATS - 1)
|
||||||
sleep_ms(is_long ? LONG_PAUSE_TIME : SHORT_PAUSE_TIME);
|
sleep_ms(is_long ? LONG_PAUSE_TIME : SHORT_PAUSE_TIME);
|
||||||
if (i == bits - 1 && j != CODE_REPEATS - 1)
|
if (i == bits - 1 && j != CODE_REPEATS - 1)
|
||||||
sleep_ms(PAUSE_BETWEEN);
|
sleep_ms(PAUSE_BETWEEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
// first write case, do not repeat this kind of error code
|
// first write case, do not repeat this kind of error code
|
||||||
if (bits == 1)
|
if (bits == 1)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
finish_pins_leds();
|
finish_pins_leds();
|
||||||
zzz();
|
zzz();
|
||||||
}
|
}
|
||||||
|
|
||||||
// optimized: reduced LED delays for faster startup
|
void put_pixel(uint32_t pixel_grb)
|
||||||
void put_pixel(uint32_t pixel_rgb)
|
|
||||||
{
|
{
|
||||||
static bool led_enabled = false;
|
static bool led_enabled = false;
|
||||||
|
|
||||||
if (is_pico())
|
if (is_pico())
|
||||||
{
|
{
|
||||||
gpio_init(led_pin());
|
gpio_init(led_pin());
|
||||||
if (pixel_rgb) {
|
if (pixel_grb) {
|
||||||
gpio_set_dir(led_pin(), true);
|
gpio_set_dir(led_pin(), true);
|
||||||
gpio_put(led_pin(), 1);
|
gpio_put(led_pin(), 1);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t red = (pixel_rgb >> 16) & 0xFF;
|
|
||||||
uint8_t green = (pixel_rgb >> 8) & 0xFF;
|
|
||||||
uint8_t blue = pixel_rgb & 0xFF;
|
|
||||||
uint32_t pixel_grb = (green << 16) | (red << 8) | blue;
|
|
||||||
|
|
||||||
ws2812_program_init(pio0, 3, ws_pio_offset, led_pin(), 800000, true);
|
ws2812_program_init(pio0, 3, ws_pio_offset, led_pin(), 800000, true);
|
||||||
|
|
||||||
if (!led_enabled && pwr_pin() != 31)
|
if (!led_enabled && pwr_pin() != 31)
|
||||||
{
|
{
|
||||||
led_enabled = true;
|
led_enabled = true;
|
||||||
|
|
@ -128,40 +117,38 @@ void put_pixel(uint32_t pixel_rgb)
|
||||||
gpio_set_drive_strength(pwr_pin(), GPIO_DRIVE_STRENGTH_12MA);
|
gpio_set_drive_strength(pwr_pin(), GPIO_DRIVE_STRENGTH_12MA);
|
||||||
gpio_set_dir(pwr_pin(), true);
|
gpio_set_dir(pwr_pin(), true);
|
||||||
gpio_put(pwr_pin(), 1);
|
gpio_put(pwr_pin(), 1);
|
||||||
sleep_us(100); // optimized: reduced from 200us
|
sleep_us(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
pio_sm_put_blocking(pio0, 3, pixel_grb << 8u);
|
pio_sm_put_blocking(pio0, 3, pixel_grb << 8u);
|
||||||
sleep_us(30); // optimized: reduced from 50us
|
sleep_us(50);
|
||||||
pio_sm_set_enabled(pio0, 3, false);
|
pio_sm_set_enabled(pio0, 3, false);
|
||||||
|
|
||||||
if (!is_tiny())
|
if (!is_tiny())
|
||||||
|
{
|
||||||
gpio_init(led_pin());
|
gpio_init(led_pin());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// optimized: direct register access
|
|
||||||
void gpio_disable_input_output(int pin)
|
void gpio_disable_input_output(int pin)
|
||||||
{
|
{
|
||||||
uint32_t pad_reg = 0x4001c000 + 4 + (pin << 2); // optimized: Use shift instead of multiply
|
uint32_t pad_reg = 0x4001c000 + 4 + pin*4;
|
||||||
*(uint32_t*)(pad_reg + 0x2000) = GPIO_OD;
|
*(uint32_t*)(pad_reg + 0x2000) = GPIO_OD;
|
||||||
*(uint32_t*)(pad_reg + 0x3000) = GPIO_IE;
|
*(uint32_t*)(pad_reg + 0x3000) = GPIO_IE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpio_enable_input_output(int pin)
|
void gpio_enable_input_output(int pin)
|
||||||
{
|
{
|
||||||
uint32_t pad_reg = 0x4001c000 + 4 + (pin << 2); // optimized: Use shift instead of multiply
|
uint32_t pad_reg = 0x4001c000 + 4 + pin*4;
|
||||||
*(uint32_t*)(pad_reg + 0x3000) = GPIO_OD;
|
*(uint32_t*)(pad_reg + 0x3000) = GPIO_OD;
|
||||||
*(uint32_t*)(pad_reg + 0x2000) = GPIO_IE;
|
*(uint32_t*)(pad_reg + 0x2000) = GPIO_IE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// optimized: reduced delays for faster reset cycles
|
|
||||||
void reset_cpu() {
|
void reset_cpu() {
|
||||||
gpio_enable_input_output(PIN_RST);
|
gpio_enable_input_output(PIN_RST);
|
||||||
gpio_pull_up(PIN_RST);
|
gpio_pull_up(PIN_RST);
|
||||||
sleep_us(800); // optimized: reduced from 1000us
|
sleep_us(1000);
|
||||||
gpio_init(PIN_RST);
|
gpio_init(PIN_RST);
|
||||||
gpio_set_dir(PIN_RST, true);
|
gpio_set_dir(PIN_RST, true);
|
||||||
sleep_us(1800); // decreased slightly for button detection stability
|
sleep_us(2000);
|
||||||
gpio_deinit(PIN_RST);
|
gpio_deinit(PIN_RST);
|
||||||
gpio_disable_pulls(PIN_RST);
|
gpio_disable_pulls(PIN_RST);
|
||||||
gpio_disable_input_output(PIN_RST);
|
gpio_disable_input_output(PIN_RST);
|
||||||
|
|
|
||||||
9
misc.h
9
misc.h
|
|
@ -1,8 +1,9 @@
|
||||||
#define PIX_gre 0x16537e
|
#define RGB(r, g, b) (((g) << 16) | ((r) << 8) | (b))
|
||||||
#define PIX_red 0xc90000
|
|
||||||
#define PIX_whi 0xff9200
|
|
||||||
|
|
||||||
#define PIX_g 0x6fa8dc
|
#define PIX_blu RGB(0x16, 0x53, 0x7e) // blue (glitching)
|
||||||
|
#define PIX_b RGB(0x6f, 0xa8, 0xdc) // light blue dim (glitch pulse)
|
||||||
|
#define PIX_whi RGB(0xff, 0x92, 0x00) // amber/yellow (success + comparison)
|
||||||
|
#define PIX_red RGB(0xc9, 0x00, 0x00) // red (error codes)
|
||||||
|
|
||||||
void put_pixel(uint32_t pixel_grb);
|
void put_pixel(uint32_t pixel_grb);
|
||||||
|
|
||||||
|
|
|
||||||
106
payload.c
106
payload.c
|
|
@ -81,7 +81,7 @@ extern bool mariko;
|
||||||
|
|
||||||
static inline uint16_t crc_itu_t_byte(uint16_t crc, const uint8_t data)
|
static inline uint16_t crc_itu_t_byte(uint16_t crc, const uint8_t data)
|
||||||
{
|
{
|
||||||
return (crc << 8) ^ crc_itu_t_table[((crc >> 8) ^ data) & 0xff];
|
return (crc << 8) ^ crc_itu_t_table[((crc >> 8) ^ data) & 0xff];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t crc_itu_t(uint16_t crc, const uint8_t *buffer, size_t len)
|
uint16_t crc_itu_t(uint16_t crc, const uint8_t *buffer, size_t len)
|
||||||
|
|
@ -91,9 +91,9 @@ uint16_t crc_itu_t(uint16_t crc, const uint8_t *buffer, size_t len)
|
||||||
{
|
{
|
||||||
crc_prepare_table();
|
crc_prepare_table();
|
||||||
}
|
}
|
||||||
while (len--)
|
while (len--)
|
||||||
crc = crc_itu_t_byte(crc, *buffer++);
|
crc = crc_itu_t_byte(crc, *buffer++);
|
||||||
return crc;
|
return crc;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void zzz();
|
extern void zzz();
|
||||||
|
|
@ -108,18 +108,18 @@ uint16_t payload_crc()
|
||||||
|
|
||||||
int crc7(uint8_t *buffer, int size)
|
int crc7(uint8_t *buffer, int size)
|
||||||
{
|
{
|
||||||
uint8_t crc = 0;
|
uint8_t crc = 0;
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
uint8_t c = buffer[i];
|
uint8_t c = buffer[i];
|
||||||
for (int j = 0; j < 8; j++) {
|
for (int j = 0; j < 8; j++) {
|
||||||
crc <<= 1;
|
crc <<= 1;
|
||||||
if ((crc ^ c) & 0x80)
|
if ((crc ^ c) & 0x80)
|
||||||
crc ^= 9;
|
crc ^= 9;
|
||||||
c <<= 1;
|
c <<= 1;
|
||||||
}
|
}
|
||||||
crc &= 0x7Fu;
|
crc &= 0x7Fu;
|
||||||
}
|
}
|
||||||
return crc;
|
return crc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __time_critical_func(cmd_write)(uint8_t cmd, uint32_t argument)
|
void __time_critical_func(cmd_write)(uint8_t cmd, uint32_t argument)
|
||||||
|
|
@ -130,9 +130,9 @@ void __time_critical_func(cmd_write)(uint8_t cmd, uint32_t argument)
|
||||||
pio_sm_set_out_pins(pio0, SM_OUT, PIN_CMD, 1);
|
pio_sm_set_out_pins(pio0, SM_OUT, PIN_CMD, 1);
|
||||||
pio_sm_set_enabled(pio0, SM_OUT, true);
|
pio_sm_set_enabled(pio0, SM_OUT, true);
|
||||||
|
|
||||||
data[0] = cmd | 0x40;
|
data[0] = cmd | 0x40;
|
||||||
*(uint32_t *) &data[1] = __builtin_bswap32(argument);
|
*(uint32_t *) &data[1] = __builtin_bswap32(argument);
|
||||||
data[5] = (crc7(data, 5) << 1) | 1;
|
data[5] = (crc7(data, 5) << 1) | 1;
|
||||||
uint32_t fifo[3];
|
uint32_t fifo[3];
|
||||||
fifo[0] = 0xFFCF0000 | (data[0] << 8) | data[1];
|
fifo[0] = 0xFFCF0000 | (data[0] << 8) | data[1];
|
||||||
fifo[1] = __builtin_bswap32(*(uint32_t*)(data + 2));
|
fifo[1] = __builtin_bswap32(*(uint32_t*)(data + 2));
|
||||||
|
|
@ -151,7 +151,7 @@ bool __time_critical_func(dat_write)()
|
||||||
pio_sm_set_out_pins(pio0, SM_OUT, PIN_DAT, 1);
|
pio_sm_set_out_pins(pio0, SM_OUT, PIN_DAT, 1);
|
||||||
pio_sm_set_enabled(pio0, SM_OUT, true);
|
pio_sm_set_enabled(pio0, SM_OUT, true);
|
||||||
uint8_t * buffer = data_buf;
|
uint8_t * buffer = data_buf;
|
||||||
uint16_t crc = crc_itu_t(0, buffer, 512);
|
uint16_t crc = crc_itu_t(0, buffer, 512);
|
||||||
uint32_t words[130];
|
uint32_t words[130];
|
||||||
int size_bits = 514 * 8 + 2;
|
int size_bits = 514 * 8 + 2;
|
||||||
words[0] = ((size_bits ^ 0xFFFF) << 16) | (buffer[0] << 7) | (buffer[1] >> 1);
|
words[0] = ((size_bits ^ 0xFFFF) << 16) | (buffer[0] << 7) | (buffer[1] >> 1);
|
||||||
|
|
@ -413,13 +413,13 @@ uint32_t mmc_init_table[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
bool mmc_initialize() {
|
bool mmc_initialize() {
|
||||||
if (!init_op_cond()) {
|
if (!init_op_cond()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!cmd_exec_cid()) {
|
if (!cmd_exec_cid()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < sizeof(mmc_init_table)/sizeof(mmc_init_table[0]); i += 4)
|
for (int i = 0; i < sizeof(mmc_init_table)/sizeof(mmc_init_table[0]); i += 4)
|
||||||
{
|
{
|
||||||
uint32_t res= 0;
|
uint32_t res= 0;
|
||||||
if (!simple_cmd_exec_with_ret(mmc_init_table[i], mmc_init_table[i+1], &res)) {
|
if (!simple_cmd_exec_with_ret(mmc_init_table[i], mmc_init_table[i+1], &res)) {
|
||||||
|
|
@ -495,9 +495,9 @@ extern int boot_slot;
|
||||||
uint8_t temp_buf[512];
|
uint8_t temp_buf[512];
|
||||||
|
|
||||||
struct fw_header {
|
struct fw_header {
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
uint32_t crc;
|
uint32_t crc;
|
||||||
uint8_t data[];
|
uint8_t data[];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define fw_slot_0 ((struct fw_header *) (XIP_BASE + 0x10000))
|
#define fw_slot_0 ((struct fw_header *) (XIP_BASE + 0x10000))
|
||||||
|
|
@ -544,8 +544,19 @@ bool update_firmware(uint32_t start_block, uint32_t size_blocks) {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
struct fw_info
|
||||||
|
{
|
||||||
|
uint32_t signature;
|
||||||
|
uint32_t fw_major;
|
||||||
|
uint32_t fw_minor;
|
||||||
|
uint32_t sdloader_hash;
|
||||||
|
uint32_t firmware_hash;
|
||||||
|
uint32_t fuse_count;
|
||||||
|
uint32_t bct_sub_fingerprint; // first 4 bytes of BctNormalSub
|
||||||
|
};
|
||||||
bool was_self_reset = false;
|
bool was_self_reset = false;
|
||||||
extern int boot_try;
|
extern int boot_try;
|
||||||
|
bool check_and_resync_bct();
|
||||||
bool fast_check() {
|
bool fast_check() {
|
||||||
start_mmc();
|
start_mmc();
|
||||||
reinit_mmc();
|
reinit_mmc();
|
||||||
|
|
@ -596,6 +607,26 @@ bool fast_check() {
|
||||||
gpio_deinit(sda_pin());
|
gpio_deinit(sda_pin());
|
||||||
gpio_deinit(scl_pin());
|
gpio_deinit(scl_pin());
|
||||||
}
|
}
|
||||||
|
// check if a syscfw update has written a new BCT to BctNormalSub since the last
|
||||||
|
// write_payload(). write_descriptor() stores a fingerprint of BctNormalSub's
|
||||||
|
// pubkey at the time write_payload() ran. if this has changed, Atmosphere has dropped
|
||||||
|
// a Main write and Sub is now ahead, resync Sub> Main and trigger rewrite_payload().
|
||||||
|
// on every normal boot this reads two blocks and returns is_space_bl unchanged.
|
||||||
|
if (is_space_bl && cmd_mmc_read(0x1FFF)) {
|
||||||
|
struct fw_info * fwi = (struct fw_info *)data_buf;
|
||||||
|
if (fwi->signature == 0x9cabe959) {
|
||||||
|
uint32_t stored = fwi->bct_sub_fingerprint;
|
||||||
|
if (cmd_mmc_read(0x040)) {
|
||||||
|
uint32_t current = *(uint32_t *)(data_buf + 0x10);
|
||||||
|
if (stored != current) {
|
||||||
|
// BctNormalSub has changed since last write_payload(), resync and rewrite
|
||||||
|
check_and_resync_bct();
|
||||||
|
stop_mmc();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
stop_mmc();
|
stop_mmc();
|
||||||
return is_space_bl;
|
return is_space_bl;
|
||||||
}
|
}
|
||||||
|
|
@ -642,16 +673,6 @@ void copy_bct(int start, int end) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fw_info
|
|
||||||
{
|
|
||||||
uint32_t signature;
|
|
||||||
uint32_t fw_major;
|
|
||||||
uint32_t fw_minor;
|
|
||||||
uint32_t sdloader_hash;
|
|
||||||
uint32_t firmware_hash;
|
|
||||||
uint32_t fuse_count;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern bool do_burn_fuses;
|
extern bool do_burn_fuses;
|
||||||
|
|
||||||
void write_descriptor()
|
void write_descriptor()
|
||||||
|
|
@ -668,6 +689,11 @@ void write_descriptor()
|
||||||
fwi->fw_minor = VER_LO;
|
fwi->fw_minor = VER_LO;
|
||||||
fwi->sdloader_hash = payload_crc();
|
fwi->sdloader_hash = payload_crc();
|
||||||
fwi->firmware_hash = boot_slot ? fw_slot_1->crc : fw_slot_0->crc;
|
fwi->firmware_hash = boot_slot ? fw_slot_1->crc : fw_slot_0->crc;
|
||||||
|
// store first 4 bytes of BctNormalSub pubkey
|
||||||
|
// so we can detect on next boot if a syscfw update has written a new BCT to Sub
|
||||||
|
fwi->bct_sub_fingerprint = 0;
|
||||||
|
if (cmd_mmc_read(0x040))
|
||||||
|
fwi->bct_sub_fingerprint = *(uint32_t *)(data_buf + 0x10);
|
||||||
// write the info block
|
// write the info block
|
||||||
write_data(desc_block, temp_buf, 512);
|
write_data(desc_block, temp_buf, 512);
|
||||||
}
|
}
|
||||||
|
|
@ -745,21 +771,24 @@ static bool bct_block_has_modchip_magic(int bct_start_block) {
|
||||||
return magic == (mariko ? 0xA56CA203 : 0x69696969);
|
return magic == (mariko ? 0xA56CA203 : 0x69696969);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_and_resync_bct() {
|
bool check_and_resync_bct() {
|
||||||
// only relevant on a configured boot where space_bl magic is already present,
|
// only relevant on a configured boot where space_bl magic is already present,
|
||||||
// meaning write_payload has previously run and wrote the synthetic/fake BCT.
|
// meaning write_payload has previously run and wrote the synthetic/fake BCT.
|
||||||
// if the chip is not yet configured there is nothing to resync.
|
// if the chip is not yet configured there is nothing to resync.
|
||||||
if (!is_space_bl)
|
if (!is_space_bl)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
// check Normal BCT pair; Main has magic, Sub does not > Sub has a newer Nintendo BCT
|
// check Normal BCT pair; Main has magic, Sub does not > Sub has a newer Nintendo BCT
|
||||||
bool normal_main_magic = bct_block_has_modchip_magic(0x000);
|
bool normal_main_magic = bct_block_has_modchip_magic(0x000);
|
||||||
bool normal_sub_magic = bct_block_has_modchip_magic(0x040);
|
bool normal_sub_magic = bct_block_has_modchip_magic(0x040);
|
||||||
|
|
||||||
|
bool resynced = false;
|
||||||
|
|
||||||
if (normal_main_magic && !normal_sub_magic) {
|
if (normal_main_magic && !normal_sub_magic) {
|
||||||
// BctNormalSub was updated by a firmware update but BctNormalMain write was
|
// BctNormalSub was updated by a firmware update but BctNormalMain write was
|
||||||
// dropped by Atmosphere. copy Sub > Main to resync.
|
// dropped by Atmosphere. copy Sub > Main to resync.
|
||||||
copy_bct(0x040, 0x000);
|
copy_bct(0x040, 0x000);
|
||||||
|
resynced = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check Safe BCT pair; uses same logic
|
// check Safe BCT pair; uses same logic
|
||||||
|
|
@ -768,7 +797,10 @@ void check_and_resync_bct() {
|
||||||
|
|
||||||
if (safe_main_magic && !safe_sub_magic) {
|
if (safe_main_magic && !safe_sub_magic) {
|
||||||
copy_bct(0x060, 0x020);
|
copy_bct(0x060, 0x020);
|
||||||
|
resynced = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return resynced;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_payload() {
|
void write_payload() {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ fi
|
||||||
# detect distribution
|
# detect distribution
|
||||||
if [ -f /etc/os-release ]; then
|
if [ -f /etc/os-release ]; then
|
||||||
. /etc/os-release
|
. /etc/os-release
|
||||||
DISTRO=$ID
|
DISTRO=${ID-LIKE:-$ID}
|
||||||
else
|
else
|
||||||
echo -e "${RED}Error: Cannot detect distribution${NC}"
|
echo -e "${RED}Error: Cannot detect distribution${NC}"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ echo -e "${GREEN}=== Picofly build script (multi-distro) ===${NC}\n"
|
||||||
# detect distribution
|
# detect distribution
|
||||||
if [ -f /etc/os-release ]; then
|
if [ -f /etc/os-release ]; then
|
||||||
. /etc/os-release
|
. /etc/os-release
|
||||||
DISTRO=$ID
|
DISTRO=${ID_LIKE:-$ID}
|
||||||
else
|
else
|
||||||
echo -e "${RED}Error: Cannot detect distribution${NC}"
|
echo -e "${RED}Error: Cannot detect distribution${NC}"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
||||||
1
test123
Normal file
1
test123
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
asdöfgljkklgj
|
||||||
Loading…
Reference in a new issue