gadget-flash-extractor/main.c
Daniele Lacamera 7bbae2db46 Initial import
2019-05-24 09:26:55 +02:00

478 lines
13 KiB
C

/*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* this software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Daniele Lacamera
*
*
*/
#include <unicore-mx/stm32/gpio.h>
#include <unicore-mx/stm32/rcc.h>
#include <unicore-mx/stm32/usart.h>
#include <unicore-mx/cm3/nvic.h>
#include <unicore-mx/usbd/usbd.h>
#include <unicore-mx/usbd/class/msc.h>
#include <unicore-mx/stm32/otg_fs.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include "system.h"
#include "timer.h"
#include "cbuf.h"
#include "spi_flash.h"
#include "spi_drv_stm32f4.h"
#define LED2CTL GPIO14 // A
#define LED0CTL GPIO13 // A
#define LED1CTL GPIO15 // A
#define LED3CTL GPIO4 // B
#define SECTOR_SIZE 512
#define USART_BUF 128
#define SAMPLES 10
#define SLEEPTIME
static uint8_t spi_page_cache[SPI_FLASH_SECTOR_SIZE];
static uint32_t spi_page_address = (uint32_t)-1;
static uint16_t spi_in_page_wr_offset = 0;
struct cbuf *inbuf[3];
volatile int timer_elapsed = 0;
volatile uint32_t tim2_ticks = 0;
volatile uint32_t cpu_freq = 168000000;
volatile int powersave = 0;
static struct usbd_device *usbd_dev = NULL;
static void led_setup(void) {
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_GPIOB);
rcc_periph_clock_enable(RCC_GPIOC);
/* Wifi switch + 2 leds */
gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO15 | GPIO14 | GPIO13 );
gpio_set_output_options(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO15 | GPIO14 | GPIO13);
gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLDOWN, GPIO4);
gpio_set_output_options(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO4);
gpio_clear(GPIOA, GPIO15 | GPIO14 | GPIO13);
gpio_clear(GPIOB, GPIO4);
gpio_clear(GPIOA, LED0CTL);
}
enum main_state {
ST_IDLE = 0,
ST_START,
ST_SENSE,
ST_FLASH_OK,
ST_READ,
ST_WRITE
};
static enum main_state main_state = ST_IDLE;
static const char VID[] = "0001";
static const char PID[] = "0002";
static const char PR[] = "0003";
static void flash_write_block_final(void)
{
if (spi_page_address == (uint32_t)(-1))
return;
asm volatile ("cpsid i");
spi_flash_sector_erase(spi_page_address);
spi_flash_write(spi_page_address, spi_page_cache, SPI_FLASH_SECTOR_SIZE);
gpio_clear(GPIOA, LED0CTL);
spi_in_page_wr_offset = 0;
memset(spi_page_cache, 0xFF, SPI_FLASH_SECTOR_SIZE);
spi_page_address = (uint32_t)-1;
main_state = ST_FLASH_OK;
asm volatile ("cpsie i");
}
static int flash_read_block(const usbd_msc_backend *backend, uint32_t lba, void *copy_to)
{
uint8_t *copy_to_byte = copy_to;
flash_write_block_final();
asm volatile ("cpsid i");
memset(copy_to, 0, SECTOR_SIZE);
if (lba > get_flash_size()) {
gpio_set(GPIOA, LED0CTL);
return -1;
}
gpio_set(GPIOA, LED2CTL);
spi_flash_read(lba * SECTOR_SIZE, copy_to, SECTOR_SIZE);
asm volatile ("cpsie i");
return 0;
}
static int flash_write_block(const usbd_msc_backend *backend, uint32_t lba, const void *copy_from)
{
uint32_t page_address;
uint32_t offset;
if (lba > get_flash_size())
return -1;
page_address = (lba >> 3) * SPI_FLASH_SECTOR_SIZE;
offset = (lba & 0x07) * SECTOR_SIZE;
if (page_address != spi_page_address) {
flash_write_block_final();
gpio_set(GPIOA, LED2CTL);
spi_flash_read(page_address, spi_page_cache, SPI_FLASH_SECTOR_SIZE);
gpio_clear(GPIOA, LED2CTL);
gpio_set(GPIOA, LED0CTL);
spi_page_address = page_address;
spi_in_page_wr_offset = 0;
}
if (spi_in_page_wr_offset != offset)
return 0;
memcpy(spi_page_cache + offset, copy_from, SECTOR_SIZE);
spi_in_page_wr_offset += SECTOR_SIZE;
if (spi_in_page_wr_offset == SPI_FLASH_SECTOR_SIZE)
flash_write_block_final();
return 0;
}
struct usbd_msc_backend flash_backend = {
.vendor_id = VID,
.product_id = PID,
.product_rev = PR,
.block_count = 1,
.read_block = flash_read_block,
.write_block = flash_write_block,
};
const usbd_backend *msc_target_usb_driver(void)
{
return USBD_STM32_OTG_FS;
}
static const struct usb_string_descriptor string_lang_list = {
.bLength = USB_DT_STRING_SIZE(1),
.bDescriptorType = USB_DT_STRING,
.wData = {
USB_LANGID_ENGLISH_UNITED_STATES
}
};
const struct usb_string_descriptor usb_string_manuf = {
.bLength = USB_DT_STRING_SIZE(10),
.bDescriptorType = USB_DT_STRING,
/* danielinux */
.wData = {
0x0064, 0x0061, 0x006e, 0x0069, 0x0065, 0x006c, 0x0069, 0x006e, 0x0075, 0x0078
}
};
static const struct usb_string_descriptor usb_string_name = {
.bLength = USB_DT_STRING_SIZE(26),
.bDescriptorType = USB_DT_STRING,
/* On the fly ROM dump gadget */
.wData = {
0x004f, 0x006e, 0x0020, 0x0074, 0x0068, 0x0065, 0x0020, 0x0066, 0x006c, 0x0079,
0x0020, 0x0052, 0x004f, 0x004d, 0x0020, 0x0064, 0x0075, 0x006d, 0x0070, 0x0020,
0x0067, 0x0061, 0x0064, 0x0067, 0x0065, 0x0074
}
};
static const struct usb_string_descriptor usb_serialn = {
.bLength = USB_DT_STRING_SIZE(3),
.bDescriptorType = USB_DT_STRING,
/* 666 */
.wData = {
0x0036, 0x0036, 0x0036
}
};
static const struct usb_string_descriptor **string_data[1] = {
(const struct usb_string_descriptor *[]) {
&usb_string_manuf,
&usb_string_name,
&usb_serialn
}
};
static const struct usb_device_descriptor msc_dev_desc= {
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = 0x0110,
.bDeviceClass = 0,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
.bMaxPacketSize0 = 64,
.idVendor = 0x1d50,
.idProduct = 0xDAD0,
.bcdDevice = 0x0200,
.iManufacturer = 1,
.iProduct = 2,
.iSerialNumber = 3,
.bNumConfigurations = 1
};
static const struct __attribute__((packed)) {
struct usb_config_descriptor config;
struct usb_interface_descriptor msc_iface;
struct usb_endpoint_descriptor msc_endp[2];
} msc_config = {
.config = {
.bLength = USB_DT_CONFIGURATION_SIZE,
.bDescriptorType = USB_DT_CONFIGURATION,
.wTotalLength = sizeof(msc_config),
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.iConfiguration = 0,
.bmAttributes = 0x80,
.bMaxPower = 0x32
},
.msc_iface = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_MSC,
.bInterfaceSubClass = USB_MSC_SUBCLASS_SCSI,
.bInterfaceProtocol = USB_MSC_PROTOCOL_BBB,
.iInterface = 0
},
.msc_endp = {{
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x01,
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
.wMaxPacketSize = 64,
.bInterval = 0,
}, {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x82,
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
.wMaxPacketSize = 64,
.bInterval = 0,
}}
};
static usbd_msc *ms;
static void msc_ep_set_config(usbd_device *usbd_dev,
const struct usb_config_descriptor *cfg)
{
(void)cfg;
usbd_ep_prepare(usbd_dev, 0x01, USBD_EP_BULK, 64, USBD_INTERVAL_NA, USBD_EP_DOUBLE_BUFFER);
usbd_ep_prepare(usbd_dev, 0x82, USBD_EP_BULK, 64, USBD_INTERVAL_NA, USBD_EP_DOUBLE_BUFFER);
usbd_msc_start(ms);
}
static const struct usbd_info_string msc_string = {
.lang_list = &string_lang_list,
.count = 3,
.data = string_data
};
static const struct usbd_info msc_info = {
.device = {
.desc = &msc_dev_desc,
.string = &msc_string
},
.config = {{
.desc = (const struct usb_config_descriptor *) &msc_config,
.string = &msc_string
}}
};
static void setup_callback(usbd_device *usbd_dev, uint8_t ep_addr,
const struct usb_setup_data *setup_data)
{
(void) ep_addr; /* assuming ep_addr == 0 */
if (!usbd_msc_setup_ep0(ms, setup_data)) {
usbd_ep0_setup(usbd_dev, setup_data);
}
}
void usb_fs_init(void)
{
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_OTGFS);
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE,
GPIO9 | GPIO11 | GPIO12);
gpio_set_af(GPIOA, GPIO_AF10, GPIO9 | GPIO11 | GPIO12);
nvic_enable_irq(NVIC_OTG_FS_IRQ);
}
void main(void) {
uint32_t timeout_counter = 0;
uint32_t sense_counter = 0;
uint8_t sensor_rawdata[USART_BUF];
int sensor_rawdata_size = 0;
int n;
uint8_t byte;
rcc_clock_setup_hse_3v3(&rcc_hse_12mhz_3v3[RCC_CLOCK_3V3_168MHZ]);
led_setup();
timer_init(cpu_freq, 1, 800);
while(1) {
switch(main_state) {
case ST_IDLE:
{
}
break;
case ST_START:
{
uint8_t manuf;
spi_flash_probe();
manuf = get_flash_manuf();
if (manuf == 0xBF || manuf == 0xEF)
{
gpio_clear(GPIOA, LED0CTL);
gpio_set(GPIOA, LED2CTL);
gpio_set(GPIOB, LED2CTL);
main_state = ST_SENSE;
} else {
gpio_set(GPIOA, LED0CTL);
gpio_clear(GPIOA, LED2CTL);
gpio_clear(GPIOB, LED3CTL);
main_state = ST_IDLE;
}
}
break;
case ST_SENSE:
{
usb_fs_init();
flash_backend.block_count = get_flash_size();
usbd_dev = usbd_init(msc_target_usb_driver(), NULL, &msc_info);
ms = usbd_msc_init(usbd_dev, 0x82, 64, 0x01, 64, &flash_backend);
usbd_register_set_config_callback(usbd_dev, msc_ep_set_config);
usbd_register_setup_callback(usbd_dev, setup_callback);
gpio_clear(GPIOA, LED0CTL);
gpio_clear(GPIOA, LED2CTL);
gpio_set(GPIOB, LED2CTL);
main_state = ST_FLASH_OK;
}
break;
case ST_FLASH_OK:
case ST_READ:
case ST_WRITE:
break;
}
if (usbd_dev) {
usbd_poll(usbd_dev, 0);
}
WFI();
}
}
#define TIM2_SR (*(volatile uint32_t *)(TIM2_BASE + 0x10))
#define TIM_SR_UIF (1 << 0)
void isr_tim2(void) {
TIM2_SR &= ~TIM_SR_UIF;
tim2_ticks++;
timer_elapsed++;
if (main_state == ST_IDLE) {
gpio_clear(GPIOA, LED1CTL);
gpio_set(GPIOA, LED2CTL); // G
gpio_clear(GPIOA, LED0CTL);
gpio_toggle(GPIOB, LED3CTL);
main_state = ST_START;
} else if (main_state == ST_START) {
gpio_clear(GPIOA, LED1CTL);
gpio_clear(GPIOA, LED2CTL);
gpio_clear(GPIOA, LED0CTL);
gpio_toggle(GPIOB, LED3CTL);
} else {
gpio_clear(GPIOA, LED1CTL);
gpio_clear(GPIOA, LED2CTL);
gpio_clear(GPIOA, LED0CTL);
gpio_set(GPIOB, LED3CTL);
}
}
void isr_usart1(void) {
char c;
gpio_toggle(GPIOA, LED0CTL);
if (cbuf_bytesfree(inbuf[0]) == 0) {
c = usart_recv(USART1);
usart_send(USART1, c);
return;
}
if (usart_is_recv_ready(USART1)) {
c = usart_recv(USART1);
usart_send(USART1, c);
cbuf_writebyte(inbuf[0], c);
}
nvic_clear_pending_irq(NVIC_USART1_IRQ);
}
void isr_usart2(void) {
nvic_clear_pending_irq(NVIC_USART2_IRQ);
gpio_toggle(GPIOA, LED0CTL);
if (cbuf_bytesfree(inbuf[1]) == 0) {
usart_recv(USART2);
return;
}
if (usart_is_recv_ready(USART2))
cbuf_writebyte(inbuf[1], (uint8_t)usart_recv(USART2));
}
void isr_usart6(void) {
char c;
nvic_clear_pending_irq(NVIC_USART6_IRQ);
gpio_toggle(GPIOA, LED0CTL);
if (cbuf_bytesfree(inbuf[2]) == 0) {
c = usart_recv(USART6);
return;
}
if (usart_is_recv_ready(USART6)) {
c = usart_recv(USART6);
cbuf_writebyte(inbuf[2], c);
}
}
int _write(void *r, uint8_t *text, int len)
{
char *p = (char *)text;
int i = 0;
volatile uint32_t reg;
while(*p && (i < len)) {
usart_send_blocking(USART1, *(p++));
i++;
}
return len;
}
void otg_fs_isr(void)
{
if (usbd_dev)
usbd_poll(usbd_dev, 0);
}