stm32/mboot: Decouple stream, filesystem and top-level loading code.

This commit factors the code for files and streaming to separate source
files (vfs_fat.c and gzstream.c respectively) and introduces an abstract
gzstream interface to make it easier to plug in different filesystems.

Signed-off-by: Damien George <damien@micropython.org>
This commit is contained in:
Damien George 2020-06-23 22:57:16 +10:00
parent 763bd448a4
commit 390f32922d
7 changed files with 256 additions and 98 deletions

View File

@ -102,7 +102,8 @@ SRC_C = \
main.c \
elem.c \
fsload.c \
diskio.c \
gzstream.c \
vfs_fat.c \
drivers/bus/softspi.c \
drivers/bus/softqspi.c \
drivers/memory/spiflash.c \

View File

@ -27,81 +27,18 @@
#include <string.h>
#include "py/mphal.h"
#include "lib/oofatfs/ff.h"
#include "extmod/uzlib/uzlib.h"
#include "mboot.h"
#include "vfs.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 SECTION_NOZERO_BSS;
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;
}
static int fsload_program_file(bool write_to_flash) {
// Parse DFU
uint8_t buf[512];
size_t file_offset;
// Read file header, <5sBIB
res = gz_stream_read(11, buf);
int res = gz_stream_read(11, buf);
if (res != 11) {
return -1;
}
@ -204,26 +141,23 @@ static int fsload_program_file(FATFS *fatfs, const char *filename, bool write_to
return 0;
}
static int fsload_process_fatfs(uint32_t base_addr, uint32_t byte_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;
static int fsload_validate_and_program_file(void *stream, const stream_methods_t *meth, const char *fname) {
// First pass verifies the file, second pass programs it
for (unsigned int pass = 0; pass <= 1; ++pass) {
led_state_all(pass == 0 ? 2 : 4);
int res = meth->open(stream, fname);
if (res == 0) {
res = gz_stream_init(stream, meth->read);
if (res == 0) {
res = fsload_program_file(pass == 0 ? false : true);
}
}
meth->close(stream);
if (res != 0) {
return res;
}
}
// Validate firmware
led_state_all(2);
int r = fsload_program_file(&fatfs, fname, false);
if (r == 0) {
// Firmware is valid, program it
led_state_all(4);
r = fsload_program_file(&fatfs, fname, true);
}
return r;
return 0;
}
int fsload_process(void) {
@ -250,7 +184,11 @@ int fsload_process(void) {
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);
vfs_fat_context_t ctx;
int ret = vfs_fat_mount(&ctx, base_addr, byte_len);
if (ret == 0) {
ret = fsload_validate_and_program_file(&ctx, &vfs_fat_stream_methods, fname);
}
// Flash LEDs based on success/failure of update
for (int i = 0; i < 4; ++i) {
if (ret == 0) {

View File

@ -0,0 +1,94 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019-2020 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 "extmod/uzlib/uzlib.h"
#include "gzstream.h"
#include "mboot.h"
#if MBOOT_FSLOAD
#define DICT_SIZE (1 << 15)
typedef struct _gz_stream_t {
void *stream_data;
stream_read_t stream_read;
TINF_DATA tinf;
uint8_t buf[512];
uint8_t dict[DICT_SIZE];
} gz_stream_t;
static gz_stream_t gz_stream SECTION_NOZERO_BSS;
static int gz_stream_read_src(TINF_DATA *tinf) {
int n = gz_stream.stream_read(gz_stream.stream_data, gz_stream.buf, sizeof(gz_stream.buf));
if (n < 0) {
// Stream error
return -1;
}
if (n == 0) {
// No data / EOF
return -1;
}
tinf->source = gz_stream.buf + 1;
tinf->source_limit = gz_stream.buf + n;
return gz_stream.buf[0];
}
int gz_stream_init(void *stream_data, stream_read_t stream_read) {
gz_stream.stream_data = stream_data;
gz_stream.stream_read = stream_read;
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) {
return -1;
}
uzlib_uncompress_init(&gz_stream.tinf, gz_stream.dict, DICT_SIZE);
return 0;
}
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;
}
#endif // MBOOT_FSLOAD

View File

@ -0,0 +1,45 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019-2020 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.
*/
#ifndef MICROPY_INCLUDED_STM32_MBOOT_GZSTREAM_H
#define MICROPY_INCLUDED_STM32_MBOOT_GZSTREAM_H
#include <stddef.h>
#include <stdint.h>
typedef int (*stream_open_t)(void *stream, const char *fname);
typedef void (*stream_close_t)(void *stream);
typedef int (*stream_read_t)(void *stream, uint8_t *buf, size_t len);
typedef struct _stream_methods_t {
stream_open_t open;
stream_close_t close;
stream_read_t read;
} stream_methods_t;
int gz_stream_init(void *stream_data, stream_read_t stream_read);
int gz_stream_read(size_t len, uint8_t *buf);
#endif // MICROPY_INCLUDED_STM32_MBOOT_GZSTREAM_H

View File

@ -44,11 +44,6 @@ 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[ELEM_DATA_SIZE];
uint32_t get_le32(const uint8_t *b);

43
ports/stm32/mboot/vfs.h Normal file
View File

@ -0,0 +1,43 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019-2020 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.
*/
#ifndef MICROPY_INCLUDED_STM32_MBOOT_VFS_H
#define MICROPY_INCLUDED_STM32_MBOOT_VFS_H
#include "lib/oofatfs/ff.h"
#include "gzstream.h"
typedef struct _vfs_fat_context_t {
uint32_t bdev_base_addr;
uint32_t bdev_byte_len;
FATFS fatfs;
FIL fp;
} vfs_fat_context_t;
extern const stream_methods_t vfs_fat_stream_methods;
int vfs_fat_mount(vfs_fat_context_t *ctx, uint32_t base_addr, uint32_t byte_len);
#endif // MICROPY_INCLUDED_STM32_MBOOT_VFS_H

View File

@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Damien P. George
* Copyright (c) 2019-2020 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
@ -28,6 +28,7 @@
#include "lib/oofatfs/ff.h"
#include "lib/oofatfs/diskio.h"
#include "mboot.h"
#include "vfs.h"
#if MBOOT_FSLOAD
@ -38,10 +39,10 @@
#endif
DRESULT disk_read(void *pdrv, BYTE *buf, DWORD sector, UINT count) {
fsload_bdev_t *bdev = pdrv;
vfs_fat_context_t *ctx = pdrv;
if (0 <= sector && sector < bdev->byte_len / 512) {
do_read(bdev->base_addr + sector * SECSIZE, count * SECSIZE, buf);
if (0 <= sector && sector < ctx->bdev_byte_len / 512) {
do_read(ctx->bdev_base_addr + sector * SECSIZE, count * SECSIZE, buf);
return RES_OK;
}
@ -49,14 +50,14 @@ DRESULT disk_read(void *pdrv, BYTE *buf, DWORD sector, UINT count) {
}
DRESULT disk_ioctl(void *pdrv, BYTE cmd, void *buf) {
fsload_bdev_t *bdev = pdrv;
vfs_fat_context_t *ctx = pdrv;
switch (cmd) {
case CTRL_SYNC:
return RES_OK;
case GET_SECTOR_COUNT:
*((DWORD*)buf) = bdev->byte_len / SECSIZE;
*((DWORD*)buf) = ctx->bdev_byte_len / SECSIZE;
return RES_OK;
case GET_SECTOR_SIZE:
@ -77,4 +78,45 @@ DRESULT disk_ioctl(void *pdrv, BYTE cmd, void *buf) {
}
}
int vfs_fat_mount(vfs_fat_context_t *ctx, uint32_t base_addr, uint32_t byte_len) {
ctx->bdev_base_addr = base_addr;
ctx->bdev_byte_len = byte_len;
ctx->fatfs.drv = ctx;
FRESULT res = f_mount(&ctx->fatfs);
if (res != FR_OK) {
return -1;
}
return 0;
}
static int vfs_fat_stream_open(void *stream_in, const char *fname) {
vfs_fat_context_t *stream = stream_in;
FRESULT res = f_open(&stream->fatfs, &stream->fp, fname, FA_READ);
if (res != FR_OK) {
return -1;
}
return 0;
}
static void vfs_fat_stream_close(void *stream_in) {
vfs_fat_context_t *stream = stream_in;
f_close(&stream->fp);
}
static int vfs_fat_stream_read(void *stream_in, uint8_t *buf, size_t len) {
vfs_fat_context_t *stream = stream_in;
UINT n;
FRESULT res = f_read(&stream->fp, buf, len, &n);
if (res != FR_OK) {
return -1;
}
return n;
}
const stream_methods_t vfs_fat_stream_methods = {
vfs_fat_stream_open,
vfs_fat_stream_close,
vfs_fat_stream_read,
};
#endif // MBOOT_FSLOAD