summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/stm32/mboot/Makefile15
-rw-r--r--ports/stm32/mboot/README.md55
-rw-r--r--ports/stm32/mboot/diskio.c80
-rw-r--r--ports/stm32/mboot/elem.c44
-rw-r--r--ports/stm32/mboot/ffconf.h63
-rw-r--r--ports/stm32/mboot/fsload.c291
-rw-r--r--ports/stm32/mboot/main.c42
-rw-r--r--ports/stm32/mboot/mboot.h58
-rw-r--r--ports/stm32/mboot/stm32_generic.ld4
9 files changed, 636 insertions, 16 deletions
diff --git a/ports/stm32/mboot/Makefile b/ports/stm32/mboot/Makefile
index 445287b5a..a59a21082 100644
--- a/ports/stm32/mboot/Makefile
+++ b/ports/stm32/mboot/Makefile
@@ -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 \
diff --git a/ports/stm32/mboot/README.md b/ports/stm32/mboot/README.md
index 0abb5051d..14bfc66f9 100644
--- a/ports/stm32/mboot/README.md
+++ b/ports/stm32/mboot/README.md
@@ -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
-------------------------
diff --git a/ports/stm32/mboot/diskio.c b/ports/stm32/mboot/diskio.c
new file mode 100644
index 000000000..2426f9329
--- /dev/null
+++ b/ports/stm32/mboot/diskio.c
@@ -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
diff --git a/ports/stm32/mboot/elem.c b/ports/stm32/mboot/elem.c
new file mode 100644
index 000000000..a8484e657
--- /dev/null
+++ b/ports/stm32/mboot/elem.c
@@ -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;
+}
diff --git a/ports/stm32/mboot/ffconf.h b/ports/stm32/mboot/ffconf.h
new file mode 100644
index 000000000..7c45266a0
--- /dev/null
+++ b/ports/stm32/mboot/ffconf.h
@@ -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
diff --git a/ports/stm32/mboot/fsload.c b/ports/stm32/mboot/fsload.c
new file mode 100644
index 000000000..5e7d96842
--- /dev/null
+++ b/ports/stm32/mboot/fsload.c
@@ -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
diff --git a/ports/stm32/mboot/main.c b/ports/stm32/mboot/main.c
index b040d4bac..0d39b7153 100644
--- a/ports/stm32/mboot/main.c
+++ b/ports/stm32/mboot/main.c
@@ -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());
diff --git a/ports/stm32/mboot/mboot.h b/ports/stm32/mboot/mboot.h
new file mode 100644
index 000000000..f3b8f1ec8
--- /dev/null
+++ b/ports/stm32/mboot/mboot.h
@@ -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);
diff --git a/ports/stm32/mboot/stm32_generic.ld b/ports/stm32/mboot/stm32_generic.ld
index 8585c6873..4b1522e7b 100644
--- a/ports/stm32/mboot/stm32_generic.ld
+++ b/ports/stm32/mboot/stm32_generic.ld
@@ -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 */