diff --git a/atmel-samd/access_vfs.c b/atmel-samd/access_vfs.c index 72b56526bb..5dc47a7a11 100644 --- a/atmel-samd/access_vfs.c +++ b/atmel-samd/access_vfs.c @@ -42,6 +42,17 @@ #define VFS_INDEX 0 +static fs_user_mount_t* get_vfs(int index) { + mp_vfs_mount_t* current_mount = MP_STATE_VM(vfs_mount_table); + for (uint8_t i = 0; current_mount != NULL; i++) { + if (i == VFS_INDEX) { + return (fs_user_mount_t *) current_mount->obj; + } + current_mount = current_mount->next; + } + return NULL; +} + //! This function tests memory state, and starts memory initialization //! @return Ctrl_status //! It is ready -> CTRL_GOOD @@ -50,12 +61,9 @@ //! An error occurred -> CTRL_FAIL Ctrl_status vfs_test_unit_ready(void) { - mp_vfs_mount_t* current_mount = MP_STATE_VM(vfs_mount_table); - for (uint8_t i = 0; current_mount != NULL; i++) { - if (i == VFS_INDEX) { - return CTRL_GOOD; - } - current_mount = current_mount->next; + fs_user_mount_t* current_mount = get_vfs(VFS_INDEX); + if (current_mount != NULL) { + return CTRL_GOOD; } return CTRL_NO_PRESENT; } @@ -69,7 +77,9 @@ Ctrl_status vfs_test_unit_ready(void) //! An error occurred -> CTRL_FAIL Ctrl_status vfs_read_capacity(uint32_t *last_valid_sector) { - if (disk_ioctl(VFS_INDEX, GET_SECTOR_COUNT, last_valid_sector) != RES_OK) { + fs_user_mount_t * vfs = get_vfs(VFS_INDEX); + if (vfs == NULL || + disk_ioctl(vfs, GET_SECTOR_COUNT, last_valid_sector) != RES_OK) { return CTRL_FAIL; } // Subtract one from the sector count to get the last valid sector. @@ -83,20 +93,9 @@ Ctrl_status vfs_read_capacity(uint32_t *last_valid_sector) //! bool vfs_wr_protect(void) { - mp_vfs_mount_t* current_mount = MP_STATE_VM(vfs_mount_table); - for (uint8_t i = 0; current_mount != NULL; i++) { - if (i == VFS_INDEX) { - break; - } - current_mount = current_mount->next; - } - if (current_mount == NULL) { - return true; - } - fs_user_mount_t *vfs = (fs_user_mount_t *) current_mount->obj; - + fs_user_mount_t * vfs = get_vfs(VFS_INDEX); // This is used to determine the writeability of the disk from USB. - if (vfs->writeblocks[0] == MP_OBJ_NULL || + if (vfs == NULL || vfs->writeblocks[0] == MP_OBJ_NULL || (vfs->flags & FSUSER_USB_WRITEABLE) == 0) { return true; } @@ -112,11 +111,6 @@ bool vfs_removal(void) return true; } -bool vfs_unload(bool unload) -{ - return unload; -} - // TODO(tannewt): Transfer more than a single sector at a time if we need more // speed. //! This function transfers the memory data to the USB MSC interface @@ -132,9 +126,10 @@ bool vfs_unload(bool unload) //! Ctrl_status vfs_usb_read_10(uint32_t addr, volatile uint16_t nb_sector) { + fs_user_mount_t * vfs = get_vfs(VFS_INDEX); uint8_t sector_buffer[FILESYSTEM_BLOCK_SIZE]; for (uint16_t sector = 0; sector < nb_sector; sector++) { - DRESULT result = disk_read(VFS_INDEX, sector_buffer, addr + sector, 1); + DRESULT result = disk_read(vfs, sector_buffer, addr + sector, 1); if (result == RES_PARERR) { return CTRL_NO_PRESENT; } @@ -161,13 +156,17 @@ Ctrl_status vfs_usb_read_10(uint32_t addr, volatile uint16_t nb_sector) //! Ctrl_status vfs_usb_write_10(uint32_t addr, volatile uint16_t nb_sector) { + if (vfs_wr_protect()) { + return CTRL_FAIL; + } + fs_user_mount_t * vfs = get_vfs(VFS_INDEX); uint8_t sector_buffer[FILESYSTEM_BLOCK_SIZE]; for (uint16_t sector = 0; sector < nb_sector; sector++) { if (!udi_msc_trans_block(false, sector_buffer, FILESYSTEM_BLOCK_SIZE, NULL)) { return CTRL_FAIL; // transfer aborted } uint32_t sector_address = addr + sector; - DRESULT result = disk_write(VFS_INDEX, sector_buffer, sector_address, 1); + DRESULT result = disk_write(vfs, sector_buffer, sector_address, 1); if (result == RES_PARERR) { return CTRL_NO_PRESENT; } @@ -176,18 +175,6 @@ Ctrl_status vfs_usb_write_10(uint32_t addr, volatile uint16_t nb_sector) } // Since by getting here we assume the mount is read-only to MicroPython // lets update the cached FatFs sector if its the one we just wrote. - mp_vfs_mount_t* current_mount = MP_STATE_VM(vfs_mount_table); - for (uint8_t i = 0; current_mount != NULL; i++) { - if (i == VFS_INDEX) { - break; - } - current_mount = current_mount->next; - } - if (current_mount == NULL) { - return CTRL_NO_PRESENT; - } - fs_user_mount_t *vfs = (fs_user_mount_t *) current_mount->obj; - #if _MAX_SS != _MIN_SS if (vfs->ssize == FILESYSTEM_BLOCK_SIZE) { #else diff --git a/atmel-samd/access_vfs.h b/atmel-samd/access_vfs.h index 07af89e229..c1cd635fcb 100644 --- a/atmel-samd/access_vfs.h +++ b/atmel-samd/access_vfs.h @@ -36,7 +36,6 @@ Ctrl_status vfs_test_unit_ready(void); Ctrl_status vfs_read_capacity(uint32_t *u32_nb_sector); bool vfs_wr_protect(void); bool vfs_removal(void); -bool vfs_unload(bool); Ctrl_status vfs_usb_read_10(uint32_t addr, uint16_t nb_sector); Ctrl_status vfs_usb_write_10(uint32_t addr, uint16_t nb_sector); diff --git a/atmel-samd/main.c b/atmel-samd/main.c index 1f3c3405c5..1a0ee9dcac 100644 --- a/atmel-samd/main.c +++ b/atmel-samd/main.c @@ -104,10 +104,7 @@ void init_flash_fs(void) { } else if (res != FR_OK) { return; } - mp_vfs_mount_t *vfs = m_new_obj_maybe(mp_vfs_mount_t); - if (vfs == NULL) { - return; - } + mp_vfs_mount_t *vfs = &mp_vfs_mount_flash; vfs->str = "/"; vfs->len = 1; vfs->obj = MP_OBJ_FROM_PTR(vfs_fat); @@ -584,9 +581,6 @@ int main(void) { mp_stack_ctrl_init(); mp_stack_set_limit((char*)&_estack - (char*)&_ebss - 1024); - // Initialise the local flash filesystem after the gc in case we need to - // grab memory from it. Create it if needed, mount in on /flash, and set it - // as current dir. init_flash_fs(); // Reset everything and prep MicroPython to run boot.py. @@ -599,7 +593,7 @@ int main(void) { // If not in safe mode, run boot before initing USB and capture output in a // file. - if (safe_mode == NO_SAFE_MODE) { + if (safe_mode == NO_SAFE_MODE && MP_STATE_VM(vfs_mount_table) != NULL) { new_status_color(BOOT_RUNNING); #ifdef CIRCUITPY_BOOT_OUTPUT_FILE FIL file_pointer; @@ -680,6 +674,10 @@ void gc_collect(void) { // pointers from CPU registers, and thus may function incorrectly. void *dummy; gc_collect_start(); + // This collects root pointers from the first VFS entry which is statically + // allocated. This way we can do VFS operations prior to setting up the heap. + // This also means it can be done once on boot and not repeatedly. + gc_collect_root((void**)&mp_vfs_mount_flash, sizeof(mp_vfs_mount_t) / sizeof(mp_uint_t)); // This naively collects all object references from an approximate stack // range. gc_collect_root(&dummy, ((mp_uint_t)&_estack - (mp_uint_t)&dummy) / sizeof(mp_uint_t)); @@ -687,11 +685,13 @@ void gc_collect(void) { } void NORETURN nlr_jump_fail(void *val) { - while (1); + HardFault_Handler(); + while (true) {} } void NORETURN __fatal_error(const char *msg) { - while (1); + HardFault_Handler(); + while (true) {} } #ifndef NDEBUG diff --git a/atmel-samd/spi_flash.c b/atmel-samd/spi_flash.c index 7f3c8984c7..bf1f190c88 100644 --- a/atmel-samd/spi_flash.c +++ b/atmel-samd/spi_flash.c @@ -662,7 +662,10 @@ const mp_obj_type_t spi_flash_type = { }; void flash_init_vfs(fs_user_mount_t *vfs) { + vfs->base.type = &mp_fat_vfs_type; vfs->flags |= FSUSER_NATIVE | FSUSER_HAVE_IOCTL; + vfs->fatfs.drv = vfs; + vfs->fatfs.part = 1; // flash filesystem lives on first partition vfs->readblocks[0] = (mp_obj_t)&spi_flash_obj_readblocks_obj; vfs->readblocks[1] = (mp_obj_t)&spi_flash_obj; vfs->readblocks[2] = (mp_obj_t)spi_flash_read_blocks; // native version diff --git a/py/runtime.c b/py/runtime.c index 5fe132ae7b..504c17c15d 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -29,6 +29,8 @@ #include #include +#include "extmod/vfs.h" + #include "py/mpstate.h" #include "py/nlr.h" #include "py/parsenum.h" @@ -114,10 +116,25 @@ void mp_init(void) { #endif #if MICROPY_VFS + #if MICROPY_FATFS_NUM_PERSISTENT > 0 + mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); + if (vfs != NULL) { + MP_STATE_VM(vfs_cur) = vfs; + } + // Skip forward until the vfs->next pointer is the first vfs that shouldn't + // persist. + uint8_t i = 1; + while (vfs != NULL && i < MICROPY_FATFS_NUM_PERSISTENT) { + vfs = vfs->next; + i++; + } + vfs->next = NULL; + #else // initialise the VFS sub-system MP_STATE_VM(vfs_cur) = NULL; MP_STATE_VM(vfs_mount_table) = NULL; #endif + #endif #if MICROPY_PY_THREAD_GIL mp_thread_mutex_init(&MP_STATE_VM(gil_mutex));