write soft flasher

master
Firmware Batman 2017-07-24 15:16:22 -07:00
parent a4191a553a
commit 9a1c1b692f
8 changed files with 241 additions and 111 deletions

View File

@ -1,5 +1,8 @@
#define BOOTSTUB
#include "config.h"
#include "obj/gitversion.h"
#ifdef STM32F4
#define PANDA
#include "stm32f4xx.h"
@ -14,6 +17,7 @@
#include "drivers/drivers.h"
#include "drivers/spi.h"
#include "drivers/usb.h"
#include "crypto/rsa.h"
#include "crypto/sha.h"
@ -22,35 +26,30 @@
#include "spi_flasher.h"
int puts(const char *a) { return 0; }
void puth(unsigned int i) {}
void __initialize_hardware_early() {
early();
if (is_entering_bootmode) {
spi_flasher();
}
}
void fail() {
#ifdef PANDA
// detect usb host
int no_usb = detect_with_pull(GPIOA, 11, PULL_UP);
if (no_usb) {
// no usb host, go to SPI flasher
spi_flasher();
}
#else
enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC;
NVIC_SystemReset();
#endif
soft_flasher_start();
}
// know where to sig check
extern void *_app_start[];
int main() {
__disable_irq();
clock_init();
if (enter_bootloader_mode == ENTER_SOFTLOADER_MAGIC) {
enter_bootloader_mode = 0;
soft_flasher_start();
}
// validate length
int len = (int)_app_start[0];
if ((len < 8) || (((uint32_t)&_app_start[0] + RSANUMBYTES) >= 0x8100000)) fail();

View File

@ -38,6 +38,8 @@ recover: obj/bootstub.$(PROJ_NAME).bin obj/$(PROJ_NAME).bin
ota: obj/$(PROJ_NAME).bin
curl http://192.168.0.10/stupdate --upload-file $<
bin: obj/$(PROJ_NAME).bin
ifneq ($(wildcard ../.git/HEAD),)
obj/gitversion.h: ../.git/HEAD ../.git/index
echo "const uint8_t gitversion[] = \"$(shell git rev-parse HEAD)\";" > $@

View File

@ -13,8 +13,14 @@
#endif
#define USB_VID 0xbbaa
#define USB_PID 0xddcc
#ifdef BOOTSTUB
#define USB_PID 0xddee
#else
#define USB_PID 0xddcc
#endif
#include <stdbool.h>
#define NULL ((void*)0)
#define COMPILE_TIME_ASSERT(pred) switch(0){case 0:case pred:;}
@ -28,4 +34,7 @@
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
#define MAX_RESP_LEN 0x40
#endif

View File

@ -48,7 +48,6 @@ USB_OTG_GlobalTypeDef *USBx = USB_OTG_FS;
#define USB_OTG_SPEED_FULL 3
#define MAX_RESP_LEN 0x40
uint8_t resp[MAX_RESP_LEN];
// descriptor types

View File

@ -369,6 +369,7 @@ void gpio_init() {
// ********************* early bringup *********************
#define ENTER_BOOTLOADER_MAGIC 0xdeadbeef
#define ENTER_SOFTLOADER_MAGIC 0xdeadc0de
#define POST_BOOTLOADER_MAGIC 0xdeadb111
extern void *g_pfnVectors;
@ -406,6 +407,9 @@ void early() {
// early GPIOs float everything
RCC->AHB1ENR = RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN;
RCC->APB2ENR = 0;
RCC->AHB2ENR = 0;
GPIOA->MODER = 0; GPIOB->MODER = 0; GPIOC->MODER = 0;
GPIOA->ODR = 0; GPIOB->ODR = 0; GPIOC->ODR = 0;
GPIOA->PUPDR = 0; GPIOB->PUPDR = 0; GPIOC->PUPDR = 0;
@ -429,5 +433,9 @@ void early() {
jump_to_bootloader();
}
if (is_entering_bootmode) {
enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC;
}
}

View File

@ -1,8 +1,4 @@
#include "config.h"
#include <stdbool.h>
// *** end config ***
#include "obj/gitversion.h"
// ********************* includes *********************
@ -178,9 +174,17 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) {
case 0xd1:
// this allows reflashing of the bootstub
// so it's blocked over wifi
if (hardwired) {
enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC;
NVIC_SystemReset();
switch (setup->b.wValue.w) {
case 0:
if (hardwired) {
enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC;
NVIC_SystemReset();
}
break;
case 1:
enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC;
NVIC_SystemReset();
break;
}
break;
// **** 0xd2: get health packet

View File

@ -1,100 +1,152 @@
// can't go on the stack cause it's DMAed
uint8_t spi_tx_buf[0x44];
uint32_t *prog_ptr;
// flasher state variables
uint32_t *prog_ptr = NULL;
int unlocked = 0;
int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) {
// get serial number even in bootstub mode
if (memcmp("\x00\x00\x00\x00\x40\xD0\x00\x00\x00\x00\x20\x00", data, 0xC) == 0) {
memcpy(data_out, (void *)0x1fff79e0, 0x20);
return 0x20;
}
int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) {
int resp_len = 0;
// flasher mode
if (data[0] == (0xff^data[1]) &&
data[2] == (0xff^data[3])) {
int sec;
memset(data_out, 0, 4);
memcpy(data_out+4, "\xde\xad\xd0\x0d", 4);
data_out[0] = 0xff;
data_out[2] = data[0];
data_out[3] = data[1];
switch (data[0]) {
case 0xf:
// echo
data_out[1] = 0xff;
break;
case 0x10:
// unlock flash
if (FLASH->CR & FLASH_CR_LOCK) {
FLASH->KEYR = 0x45670123;
FLASH->KEYR = 0xCDEF89AB;
data_out[1] = 0xff;
}
set_led(LED_GREEN, 1);
unlocked = 1;
prog_ptr = (uint32_t *)0x8004000;
break;
case 0x11:
// erase
sec = data[2] & 0xF;
// don't erase the bootloader
if (sec != 0 && sec < 12 && unlocked) {
FLASH->CR = (sec << 3) | FLASH_CR_SER;
FLASH->CR |= FLASH_CR_STRT;
while (FLASH->SR & FLASH_SR_BSY);
data_out[1] = 0xff;
}
break;
case 0x12:
if (data[2] <= 4 && unlocked) {
set_led(LED_RED, 0);
for (int i = 0; i < data[2]; i++) {
// program byte 1
FLASH->CR = FLASH_CR_PSIZE_1 | FLASH_CR_PG;
// flasher machine
memset(resp, 0, 4);
memcpy(resp+4, "\xde\xad\xd0\x0d", 4);
resp[0] = 0xff;
resp[2] = setup->b.bRequest;
resp[3] = ~setup->b.bRequest;
*((uint32_t **)&resp[8]) = prog_ptr;
resp_len = 0xc;
*prog_ptr = *(uint32_t*)(data+4+(i*4));
while (FLASH->SR & FLASH_SR_BSY);
//*(uint64_t*)(&spi_tx_buf[0x30+(i*4)]) = *prog_ptr;
prog_ptr++;
}
set_led(LED_RED, 1);
data_out[1] = 0xff;
int sec;
switch (setup->b.bRequest) {
// **** 0xb0: flasher echo
case 0xb0:
resp[1] = 0xff;
break;
// **** 0xb1: unlock flash
case 0xb1:
if (FLASH->CR & FLASH_CR_LOCK) {
FLASH->KEYR = 0x45670123;
FLASH->KEYR = 0xCDEF89AB;
resp[1] = 0xff;
}
set_led(LED_GREEN, 1);
unlocked = 1;
prog_ptr = (uint32_t *)0x8004000;
break;
// **** 0xb2: erase sector
case 0xb2:
sec = setup->b.wValue.w;
// don't erase the bootloader
if (sec != 0 && sec < 12 && unlocked) {
FLASH->CR = (sec << 3) | FLASH_CR_SER;
FLASH->CR |= FLASH_CR_STRT;
while (FLASH->SR & FLASH_SR_BSY);
resp[1] = 0xff;
}
break;
// **** 0xd0: fetch serial number
case 0xd0:
#ifdef PANDA
// addresses are OTP
if (setup->b.wValue.w == 1) {
memcpy(resp, (void *)0x1fff79c0, 0x10);
resp_len = 0x10;
} else {
memcpy(resp, (void *)0x1fff79e0, 0x20);
resp_len = 0x20;
}
break;
case 0x13:
// reset
#endif
break;
// **** 0xd1: enter bootloader mode
case 0xd1:
// this allows reflashing of the bootstub
// so it's blocked over wifi
if (hardwired) {
enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC;
NVIC_SystemReset();
break;
default:
break;
}
}
break;
// **** 0xd6: get version
case 0xd6:
COMPILE_TIME_ASSERT(sizeof(gitversion) <= MAX_RESP_LEN)
memcpy(resp, gitversion, sizeof(gitversion));
resp_len = sizeof(gitversion);
break;
// **** 0xd8: reset ST
case 0xd8:
NVIC_SystemReset();
break;
}
return 8;
return resp_len;
}
void spi_flasher() {
__disable_irq();
int usb_cb_ep1_in(uint8_t *usbdata, int len, int hardwired) { return 0; }
void usb_cb_ep3_out(uint8_t *usbdata, int len, int hardwired) { }
void usb_cb_enumeration_complete() { }
void usb_cb_ep2_out(uint8_t *usbdata, int len, int hardwired) {
set_led(LED_RED, 0);
for (int i = 0; i < len/4; i++) {
// program byte 1
FLASH->CR = FLASH_CR_PSIZE_1 | FLASH_CR_PG;
*prog_ptr = *(uint32_t*)(usbdata+(i*4));
while (FLASH->SR & FLASH_SR_BSY);
//*(uint64_t*)(&spi_tx_buf[0x30+(i*4)]) = *prog_ptr;
prog_ptr++;
}
set_led(LED_RED, 1);
}
int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) {
int resp_len = 0;
switch (data[0]) {
case 0:
// control transfer
resp_len = usb_cb_control_msg((USB_Setup_TypeDef *)(data+4), data_out, 0);
break;
case 2:
// ep 2, flash!
usb_cb_ep2_out(data+4, data[2], 0);
break;
}
return resp_len;
}
void soft_flasher_start() {
// safe to call twice?
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN;
// setup SPI
GPIOA->MODER = GPIO_MODER_MODER4_1 | GPIO_MODER_MODER5_1 |
GPIO_MODER_MODER6_1 | GPIO_MODER_MODER7_1;
GPIOA->AFR[0] = GPIO_AF5_SPI1 << (4*4) | GPIO_AF5_SPI1 << (5*4) |
GPIO_AF5_SPI1 << (6*4) | GPIO_AF5_SPI1 << (7*4);
// A4,A5,A6,A7: setup SPI
set_gpio_alternate(GPIOA, 4, GPIO_AF5_SPI1);
set_gpio_alternate(GPIOA, 5, GPIO_AF5_SPI1);
set_gpio_alternate(GPIOA, 6, GPIO_AF5_SPI1);
set_gpio_alternate(GPIOA, 7, GPIO_AF5_SPI1);
// A11,A12: USB
set_gpio_alternate(GPIOA, 11, GPIO_AF10_OTG_FS);
set_gpio_alternate(GPIOA, 12, GPIO_AF10_OTG_FS);
GPIOA->OSPEEDR = GPIO_OSPEEDER_OSPEEDR11 | GPIO_OSPEEDER_OSPEEDR12;
// flasher
spi_init();
// blue LED on for flashing
set_led(LED_BLUE, 1);
// flasher
spi_init();
// enable USB
usb_init();
__enable_irq();
while (1) { }
while (1) {
// blink the blue LED fast
set_led(LED_BLUE, 0);
delay(500000);
set_led(LED_BLUE, 1);
delay(500000);
}
}

View File

@ -10,6 +10,8 @@ import time
__version__ = '0.0.3'
BASEDIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../")
def parse_can_buffer(dat):
ret = []
for j in range(0, len(dat), 0x10):
@ -91,7 +93,18 @@ class Panda(object):
def __init__(self, serial=None, claim=True):
self._serial = serial
if serial == "WIFI":
self._handle = None
self.connect(claim)
def close(self):
self._handle.close()
self._handle = None
def connect(self, claim=True):
if self._handle != None:
self.close()
if self._serial == "WIFI":
self._handle = WifiHandle()
print("opening WIFI device")
else:
@ -99,23 +112,67 @@ class Panda(object):
self._handle = None
for device in context.getDeviceList(skip_on_error=True):
if device.getVendorID() == 0xbbaa and device.getProductID() == 0xddcc:
if serial is None or device.getSerialNumber() == serial:
if device.getVendorID() == 0xbbaa and device.getProductID() in [0xddcc, 0xddee]:
if self._serial is None or device.getSerialNumber() == self._serial:
print("opening device", device.getSerialNumber())
self.bootstub = device.getProductID() == 0xddee
self.legacy = (device.getbcdDevice() != 0x2300)
self._handle = device.open()
if claim:
self._handle.claimInterface(0)
#self._handle.setInterfaceAltSetting(0, 0) #Issue in USB stack
break
assert self._handle != None
assert(self._handle != None)
def reset(self, enter_bootstub=False):
# reset
try:
if enter_bootstub:
self._handle.controlWrite(Panda.REQUEST_IN, 0xd1, 1, 0, b'')
else:
self._handle.controlWrite(Panda.REQUEST_IN, 0xd8, 0, 0, b'')
except Exception:
pass
time.sleep(1.0)
self.connect()
def flash(self):
if not self.bootstub:
self.reset(True)
assert(self.bootstub)
ret = os.system("cd %s && make clean && make -f %s bin" % (os.path.join(BASEDIR, "board"), "Makefile.legacy" if self.legacy else "Makefile"))
# TODO: build and detect legacy
with open(os.path.join(BASEDIR, "board", "obj", "code.bin" if self.legacy else "panda.bin")) as f:
dat = f.read()
fr = self._handle.controlRead(Panda.REQUEST_IN, 0xb0, 0, 0, 0xc)
from hexdump import hexdump
hexdump(str(fr))
# unlock flash
print("flash: unlocking")
self._handle.controlWrite(Panda.REQUEST_IN, 0xb1, 0, 0, b'')
# erase sectors 1 and 2
print("flash: erasing")
self._handle.controlWrite(Panda.REQUEST_IN, 0xb2, 1, 0, b'')
self._handle.controlWrite(Panda.REQUEST_IN, 0xb2, 2, 0, b'')
# flash over EP2
print("flash: flashing")
for i in range(0, len(dat), 0x40):
self._handle.bulkWrite(2, dat[i:i+0x40])
# reset
print("flash: resetting")
self.reset()
def close(self):
self._handle.close()
@staticmethod
def program(clean=False, legacy=False):
BASEDIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../")
# TODO: check for legacy board
if clean:
cmd = "make clean"