stm32/mboot: Add support for loading gzip'd firmware from a filesystem.

This adds support to mboot to load and program application firmware from
a .dfu.gz file on the board's filesystem.  See mboot/README.md for details.
This commit is contained in:
Damien George 2019-02-15 14:31:48 +11:00
parent 4daee31706
commit ff04b78ffd
9 changed files with 636 additions and 16 deletions

View File

@ -54,6 +54,7 @@ CFLAGS += -I$(BOARD_DIR)
CFLAGS += -DSTM32_HAL_H='<stm32$(MCU_SERIES)xx_hal.h>'
CFLAGS += -DBOARD_$(BOARD)
CFLAGS += -DAPPLICATION_ADDR=$(TEXT0_ADDR)
CFLAGS += -DFFCONF_H=\"ports/stm32/mboot/ffconf.h\"
LDFLAGS = -nostdlib -L . -T stm32_generic.ld -Map=$(@:.elf=.map) --cref
LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
@ -70,12 +71,20 @@ else
COPT += -Os -DNDEBUG
endif
SRC_LIB = $(addprefix lib/,\
libc/string0.c \
)
SRC_LIB = \
lib/libc/string0.c \
lib/oofatfs/ff.c \
lib/oofatfs/option/unicode.c \
extmod/uzlib/crc32.c \
extmod/uzlib/adler32.c \
extmod/uzlib/tinflate.c \
extmod/uzlib/tinfgzip.c
SRC_C = \
main.c \
elem.c \
fsload.c \
diskio.c \
drivers/bus/softspi.c \
drivers/bus/softqspi.c \
drivers/memory/spiflash.c \

View File

@ -4,7 +4,9 @@ Mboot - MicroPython boot loader
Mboot is a custom bootloader for STM32 MCUs, and currently supports the
STM32F4xx and STM32F7xx families. It can provide a standard USB DFU interface
on either the FS or HS peripherals, as well as a sophisticated, custom I2C
interface. It fits in 16k of flash space.
interface. It can also load and program firmware in .dfu.gz format from a
filesystem. It can fit in 16k of flash space, but all features enabled requires
32k.
How to use
----------
@ -57,6 +59,10 @@ How to use
second one use the same configuration names as above but with
`SPIFLASH2`, ie `MBOOT_SPIFLASH2_ADDR` etc.
To enable loading firmware from a filesystem use:
#define MBOOT_FSLOAD (1)
2. Build the board's main application firmware as usual.
3. Build mboot via:
@ -77,6 +83,53 @@ How to use
to communicate with the I2C boot loader interface. It should be run on a
pyboard connected via I2C to the target board.
Entering Mboot from application code
------------------------------------
To enter Mboot from a running application do the following:
1. Make sure I and D caches are disabled.
2. Load register r0 with the value 0x70ad0000. The lower 7 bits can be
optionally or'd with the desired I2C address.
3. Load the MSP with the value held at 0x08000000.
4. Jump to the value held at 0x08000004.
Additional data can be passed to Mboot from application code by storing this
data in a special region of RAM. This region begins at the address held at
location 0x08000000 (which will point to just after Mboot's stack). A
maximum of 1024 bytes can be stored here. To indicate to Mboot that this
region is valid load register r0 with 0x70ad0080 (instead of step 2 above),
optionally or'd with the desired I2C address.
Data in this region is a sequence of elements. Each element has the form:
<type:u8> <len:u8> <payload...>
where `type` and `len` are bytes (designated by `u8`) and `payload` is 0 or
more bytes. `len` must be the number of bytes in `payload`.
The last element in the data sequence must be the end element:
* END: type=1, len=0
Loading firmware from a filesystem
----------------------------------
To get Mboot to load firmware from a filesystem and automatically program it
requires passing data elements (see above) which tell where the filesystems
are located and what filename to program. The elements to use are:
* MOUNT: type=2, len=10, payload=(<mount-point:u8> <fs-type:u8> <base-addr:u32> <byte-len:u32>)
* FSLOAD: type=3, len=1+n, payload=(<mount-point:u8> <filename...>)
`u32` means unsigned 32-bit little-endian integer.
The firmware to load must be a gzip'd DfuSe file (.dfu.gz).
Example: Mboot on PYBv1.x
-------------------------

View File

@ -0,0 +1,80 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "py/mphal.h"
#include "lib/oofatfs/ff.h"
#include "lib/oofatfs/diskio.h"
#include "mboot.h"
#if MBOOT_FSLOAD
#if _MAX_SS == _MIN_SS
#define SECSIZE (_MIN_SS)
#else
#error Unsupported
#endif
DRESULT disk_read(void *pdrv, BYTE *buf, DWORD sector, UINT count) {
fsload_bdev_t *bdev = pdrv;
if (0 <= sector && sector < bdev->byte_len / 512) {
do_read(bdev->base_addr + sector * SECSIZE, count * SECSIZE, buf);
return RES_OK;
}
return RES_PARERR;
}
DRESULT disk_ioctl(void *pdrv, BYTE cmd, void *buf) {
fsload_bdev_t *bdev = pdrv;
switch (cmd) {
case CTRL_SYNC:
return RES_OK;
case GET_SECTOR_COUNT:
*((DWORD*)buf) = bdev->byte_len / SECSIZE;
return RES_OK;
case GET_SECTOR_SIZE:
*((WORD*)buf) = SECSIZE;
return RES_OK;
case GET_BLOCK_SIZE:
*((DWORD*)buf) = 1; // erase block size in units of sector size
return RES_OK;
case IOCTL_INIT:
case IOCTL_STATUS:
*((DSTATUS*)buf) = STA_PROTECT;
return RES_OK;
default:
return RES_PARERR;
}
}
#endif // MBOOT_FSLOAD

44
ports/stm32/mboot/elem.c Normal file
View File

@ -0,0 +1,44 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "mboot.h"
// Elements are of the form: (type:u8, len:u8, payload)
const uint8_t *elem_search(const uint8_t *elem, uint8_t elem_id) {
while (elem + 2 + elem[1] <= ELEM_DATA_MAX) {
if (elem[0] == elem_id) {
// Found element, return a pointer to the element data
return elem + 2;
}
if (elem[0] == ELEM_TYPE_END) {
// End of elements
return NULL;
}
elem += 2 + elem[1];
}
return NULL;
}

View File

@ -0,0 +1,63 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#define _FFCONF 68020
#define _FS_READONLY 1
#define _FS_MINIMIZE 0
#define _USE_STRFUNC 0
#define _USE_FIND 0
#define _USE_MKFS 0
#define _USE_FASTSEEK 0
#define _USE_EXPAND 0
#define _USE_CHMOD 0
#define _USE_LABEL 0
#define _USE_FORWARD 0
#define _CODE_PAGE 437
#define _USE_LFN 1
#define _MAX_LFN 255
#define _LFN_UNICODE 0
#define _STRF_ENCODE 3
#define _FS_RPATH 0
#define _VOLUMES 1
#define _STR_VOLUME_ID 0
#define _MULTI_PARTITION 0
#define _MIN_SS 512
#define _MAX_SS 512
#define _USE_TRIM 0
#define _FS_NOFSINFO 0
#define _FS_TINY 1
#define _FS_EXFAT 0
#define _FS_NORTC 1
#define _NORTC_MON 1
#define _NORTC_MDAY 1
#define _NORTC_YEAR 2019
#define _FS_LOCK 0
#define _FS_REENTRANT 0

291
ports/stm32/mboot/fsload.c Normal file
View File

@ -0,0 +1,291 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <string.h>
#include "py/mphal.h"
#include "lib/oofatfs/ff.h"
#include "extmod/uzlib/uzlib.h"
#include "mboot.h"
#if MBOOT_FSLOAD
#define DICT_SIZE (1 << 15)
typedef struct _gz_stream_t {
FIL fp;
TINF_DATA tinf;
uint8_t buf[512];
uint8_t dict[DICT_SIZE];
} gz_stream_t;
static gz_stream_t gz_stream;
static int gz_stream_read_src(TINF_DATA *tinf) {
UINT n;
FRESULT res = f_read(&gz_stream.fp, gz_stream.buf, sizeof(gz_stream.buf), &n);
if (res != FR_OK) {
return -1;
}
if (n == 0) {
return -1;
}
tinf->source = gz_stream.buf + 1;
tinf->source_limit = gz_stream.buf + n;
return gz_stream.buf[0];
}
static int gz_stream_open(FATFS *fatfs, const char *filename) {
FRESULT res = f_open(fatfs, &gz_stream.fp, filename, FA_READ);
if (res != FR_OK) {
return -1;
}
memset(&gz_stream.tinf, 0, sizeof(gz_stream.tinf));
gz_stream.tinf.readSource = gz_stream_read_src;
int st = uzlib_gzip_parse_header(&gz_stream.tinf);
if (st != TINF_OK) {
f_close(&gz_stream.fp);
return -1;
}
uzlib_uncompress_init(&gz_stream.tinf, gz_stream.dict, DICT_SIZE);
return 0;
}
static int gz_stream_read(size_t len, uint8_t *buf) {
gz_stream.tinf.dest = buf;
gz_stream.tinf.dest_limit = buf + len;
int st = uzlib_uncompress_chksum(&gz_stream.tinf);
if (st == TINF_DONE) {
return 0;
}
if (st < 0) {
return st;
}
return gz_stream.tinf.dest - buf;
}
static int fsload_program_file(FATFS *fatfs, const char *filename, bool write_to_flash) {
int res = gz_stream_open(fatfs, filename);
if (res != 0) {
return res;
}
// Parse DFU
uint8_t buf[512];
size_t file_offset;
// Read file header, <5sBIB
res = gz_stream_read(11, buf);
if (res != 11) {
return -1;
}
file_offset = 11;
// Validate header, version 1
if (memcmp(buf, "DfuSe\x01", 6) != 0) {
return -1;
}
// Must have only 1 target
if (buf[10] != 1) {
return -2;
}
// Get total size
uint32_t total_size = get_le32(buf + 6);
// Read target header, <6sBi255sII
res = gz_stream_read(274, buf);
if (res != 274) {
return -1;
}
file_offset += 274;
// Validate target header, with alt being 0
if (memcmp(buf, "Target\x00", 7) != 0) {
return -1;
}
// Get target size and number of elements
uint32_t target_size = get_le32(buf + 266);
uint32_t num_elems = get_le32(buf + 270);
size_t file_offset_target = file_offset;
// Parse each element
for (size_t elem = 0; elem < num_elems; ++elem) {
// Read element header, <II
res = gz_stream_read(8, buf);
if (res != 8) {
return -1;
}
file_offset += 8;
// Get element destination address and size
uint32_t elem_addr = get_le32(buf);
uint32_t elem_size = get_le32(buf + 4);
// Erase flash before writing
if (write_to_flash) {
uint32_t addr = elem_addr;
while (addr < elem_addr + elem_size) {
res = do_page_erase(addr, &addr);
if (res != 0) {
return res;
}
}
}
// Read element data and possibly write to flash
for (uint32_t s = elem_size; s;) {
uint32_t l = s;
if (l > sizeof(buf)) {
l = sizeof(buf);
}
res = gz_stream_read(l, buf);
if (res != l) {
return -1;
}
if (write_to_flash) {
res = do_write(elem_addr, buf, l);
if (res != 0) {
return -1;
}
elem_addr += l;
}
s -= l;
}
file_offset += elem_size;
}
if (target_size != file_offset - file_offset_target) {
return -1;
}
if (total_size != file_offset) {
return -1;
}
// Read trailing info
res = gz_stream_read(16, buf);
if (res != 16) {
return -1;
}
// TODO validate CRC32
return 0;
}
static int fsload_process_fatfs(uint32_t base_addr, uint32_t byte_len, size_t fname_len, const char *fname) {
fsload_bdev_t bdev = {base_addr, byte_len};
FATFS fatfs;
fatfs.drv = &bdev;
FRESULT res = f_mount(&fatfs);
if (res != FR_OK) {
return -1;
}
FF_DIR dp;
res = f_opendir(&fatfs, &dp, "/");
if (res != FR_OK) {
return -1;
}
// Search for firmware file with correct name
int r;
for (;;) {
FILINFO fno;
res = f_readdir(&dp, &fno);
char *fn = fno.fname;
if (res != FR_OK || fn[0] == 0) {
// Finished listing dir, no firmware found
r = -1;
break;
}
if (memcmp(fn, fname, fname_len) == 0 && fn[fname_len] == '\0') {
// Found firmware
led_state_all(2);
r = fsload_program_file(&fatfs, fn, false);
if (r == 0) {
// Firmware is valid, program it
led_state_all(4);
r = fsload_program_file(&fatfs, fn, true);
}
break;
}
}
return r;
}
int fsload_process(void) {
const uint8_t *elem = elem_search(ELEM_DATA_START, ELEM_TYPE_FSLOAD);
if (elem == NULL || elem[-1] < 2) {
return -1;
}
uint8_t mount_point = elem[0];
uint8_t fname_len = elem[-1] - 1;
const char *fname = (const char*)&elem[1];
elem = ELEM_DATA_START;
for (;;) {
elem = elem_search(elem, ELEM_TYPE_MOUNT);
if (elem == NULL || elem[-1] != 10) {
// End of elements, or invalid MOUNT element
return -1;
}
if (elem[0] == mount_point) {
uint32_t base_addr = get_le32(&elem[2]);
uint32_t byte_len = get_le32(&elem[6]);
if (elem[1] == ELEM_MOUNT_FAT) {
int ret = fsload_process_fatfs(base_addr, byte_len, fname_len, fname);
// Flash LEDs based on success/failure of update
for (int i = 0; i < 4; ++i) {
if (ret == 0) {
led_state_all(7);
} else {
led_state_all(1);
}
mp_hal_delay_ms(100);
led_state_all(0);
mp_hal_delay_ms(100);
}
return ret;
}
// Unknown filesystem type
return -1;
}
elem += elem[-1];
}
}
#endif // MBOOT_FSLOAD

View File

@ -32,6 +32,7 @@
#include "usbd_core.h"
#include "storage.h"
#include "i2cslave.h"
#include "mboot.h"
// Using polling is about 10% faster than not using it (and using IRQ instead)
// This DFU code with polling runs in about 70% of the time of the ST bootloader
@ -76,7 +77,7 @@
static void do_reset(void);
static uint32_t get_le32(const uint8_t *b) {
uint32_t get_le32(const uint8_t *b) {
return b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24;
}
@ -382,7 +383,7 @@ static const flash_layout_t flash_layout[] = {
#endif
static uint32_t flash_get_sector_index(uint32_t addr) {
static uint32_t flash_get_sector_index(uint32_t addr, uint32_t *sector_size) {
if (addr >= flash_layout[0].base_address) {
uint32_t sector_index = 0;
for (int i = 0; i < MP_ARRAY_SIZE(flash_layout); ++i) {
@ -390,6 +391,7 @@ static uint32_t flash_get_sector_index(uint32_t addr) {
uint32_t sector_start_next = flash_layout[i].base_address
+ (j + 1) * flash_layout[i].sector_size;
if (addr < sector_start_next) {
*sector_size = flash_layout[i].sector_size;
return sector_index;
}
++sector_index;
@ -404,13 +406,16 @@ static int flash_mass_erase(void) {
return -1;
}
static int flash_page_erase(uint32_t addr) {
uint32_t sector = flash_get_sector_index(addr);
static int flash_page_erase(uint32_t addr, uint32_t *next_addr) {
uint32_t sector_size = 0;
uint32_t sector = flash_get_sector_index(addr, &sector_size);
if (sector == 0) {
// Don't allow to erase the sector with this bootloader in it
return -1;
}
*next_addr = addr + sector_size;
HAL_FLASH_Unlock();
// Clear pending flags (if any)
@ -484,11 +489,12 @@ static int spiflash_page_erase(mp_spiflash_t *spif, uint32_t addr, uint32_t n_bl
}
#endif
static int do_page_erase(uint32_t addr) {
int do_page_erase(uint32_t addr, uint32_t *next_addr) {
led_state(LED0, 1);
#if defined(MBOOT_SPIFLASH_ADDR)
if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) {
*next_addr = addr + MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE * MP_SPIFLASH_ERASE_BLOCK_SIZE;
return spiflash_page_erase(MBOOT_SPIFLASH_SPIFLASH,
addr - MBOOT_SPIFLASH_ADDR, MBOOT_SPIFLASH_ERASE_BLOCKS_PER_PAGE);
}
@ -496,15 +502,16 @@ static int do_page_erase(uint32_t addr) {
#if defined(MBOOT_SPIFLASH2_ADDR)
if (MBOOT_SPIFLASH2_ADDR <= addr && addr < MBOOT_SPIFLASH2_ADDR + MBOOT_SPIFLASH2_BYTE_SIZE) {
*next_addr = addr + MBOOT_SPIFLASH2_ERASE_BLOCKS_PER_PAGE * MP_SPIFLASH_ERASE_BLOCK_SIZE;
return spiflash_page_erase(MBOOT_SPIFLASH2_SPIFLASH,
addr - MBOOT_SPIFLASH2_ADDR, MBOOT_SPIFLASH2_ERASE_BLOCKS_PER_PAGE);
}
#endif
return flash_page_erase(addr);
return flash_page_erase(addr, next_addr);
}
static void do_read(uint32_t addr, int len, uint8_t *buf) {
void do_read(uint32_t addr, int len, uint8_t *buf) {
#if defined(MBOOT_SPIFLASH_ADDR)
if (MBOOT_SPIFLASH_ADDR <= addr && addr < MBOOT_SPIFLASH_ADDR + MBOOT_SPIFLASH_BYTE_SIZE) {
mp_spiflash_read(MBOOT_SPIFLASH_SPIFLASH, addr - MBOOT_SPIFLASH_ADDR, len, buf);
@ -522,7 +529,7 @@ static void do_read(uint32_t addr, int len, uint8_t *buf) {
memcpy(buf, (void*)addr, len);
}
static int do_write(uint32_t addr, const uint8_t *src8, size_t len) {
int do_write(uint32_t addr, const uint8_t *src8, size_t len) {
static uint32_t led_tog = 0;
led_state(LED0, (led_tog++) & 4);
@ -634,7 +641,8 @@ void i2c_slave_process_rx_end(void) {
} else if (buf[0] == I2C_CMD_MASSERASE && len == 0) {
len = do_mass_erase();
} else if (buf[0] == I2C_CMD_PAGEERASE && len == 4) {
len = do_page_erase(get_le32(buf + 1));
uint32_t next_addr;
len = do_page_erase(get_le32(buf + 1), &next_addr);
} else if (buf[0] == I2C_CMD_SETRDADDR && len == 4) {
i2c_obj.cmd_rdaddr = get_le32(buf + 1);
len = 0;
@ -764,7 +772,8 @@ static int dfu_process_dnload(void) {
ret = do_mass_erase();
} else if (dfu_state.wLength == 5) {
// erase page
ret = do_page_erase(get_le32(&dfu_state.buf[1]));
uint32_t next_addr;
ret = do_page_erase(get_le32(&dfu_state.buf[1]), &next_addr);
}
} else if (dfu_state.wLength >= 1 && dfu_state.buf[0] == 0x21) {
if (dfu_state.wLength == 5) {
@ -1255,6 +1264,19 @@ enter_bootloader:
mp_spiflash_init(MBOOT_SPIFLASH2_SPIFLASH);
#endif
#if MBOOT_FSLOAD
if ((initial_r0 & 0xffffff80) == 0x70ad0080) {
// Application passed through elements, validate then process them
const uint8_t *elem_end = elem_search(ELEM_DATA_START, ELEM_TYPE_END);
if (elem_end != NULL && elem_end[-1] == 0) {
fsload_process();
}
// Always reset because the application is expecting to resume
led_state_all(0);
NVIC_SystemReset();
}
#endif
dfu_init();
pyb_usbdd_init(&pyb_usbdd, pyb_usbdd_detect_port());

58
ports/stm32/mboot/mboot.h Normal file
View File

@ -0,0 +1,58 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Damien P. George
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdint.h>
#include <stddef.h>
#define ELEM_DATA_START (&_estack)
#define ELEM_DATA_MAX (ELEM_DATA_START + 1024)
enum {
ELEM_TYPE_END = 1,
ELEM_TYPE_MOUNT,
ELEM_TYPE_FSLOAD,
};
enum {
ELEM_MOUNT_FAT = 1,
};
typedef struct _fsload_bdev_t {
uint32_t base_addr;
uint32_t byte_len;
} fsload_bdev_t;
extern uint8_t _estack;
uint32_t get_le32(const uint8_t *b);
void led_state_all(unsigned int mask);
int do_page_erase(uint32_t addr, uint32_t *next_addr);
void do_read(uint32_t addr, int len, uint8_t *buf);
int do_write(uint32_t addr, const uint8_t *src8, size_t len);
const uint8_t *elem_search(const uint8_t *elem, uint8_t elem_id);
int fsload_process(void);

View File

@ -5,8 +5,8 @@
/* Specify the memory areas */
MEMORY
{
FLASH_BL (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* sector 0 (can be 32K) */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K
FLASH_BL (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* sector 0 (can be 32K) */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
}
/* produce a link error if there is not this amount of RAM for these sections */