8000 Add VfsMap filesystem, mpremote deploy-mapfs, and ability to import .mpy files from ROM (WIP) by dpgeorge · Pull Request #8381 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

Add VfsMap filesystem, mpremote deploy-mapfs, and ability to import .mpy files from ROM (WIP) #8381

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 33 commits into
base: master
Choose a base branch
from
Open
8000
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
ed7c169
py/objarray: Add MP_DEFINE_MEMORYVIEW_OBJ convenience macro.
dpgeorge Jan 3, 2025
6c25351
extmod/modvfs: Add rom_ioctl function.
dpgeorge Nov 15, 2024
e8d746c
unix: Implement rom_ioctl.
dpgeorge Mar 3, 2022
7cc96ed
qemu/main: Implement rom_ioctl.
dpgeorge Dec 18, 2024
a24afb4
tools/mpremote: Add "romfs build" and "romfs deploy".
dpgeorge Mar 3, 2022
b6f9f09
tools/mpremote: Add "romfs query" subcommand.
dpgeorge Jan 16, 2025
75af92d
stm32: Enable VfsRom.
dpgeorge Mar 3, 2022
1c1e38d
stm32: Disable machine.Pin legacy on NUCLEO_F091RC.
dpgeorge Jan 3, 2025
bde499b
stm32: Increase size of NUCLEO_F091RC ROM partition.
dpgeorge Jan 3, 2025
82ed2fc
stm32: Rework ROM partition support.
dpgeorge Jan 16, 2025
5b56336
stm32/boards/ARDUINO_GIGA: Enable ROMFS.
iabdalkader Jan 14, 2025
90f5af4
stm32/boards/ARDUINO_NICLA_VISION: Enable ROMFS.
iabdalkader Jan 14, 2025
e6b2259
stm32/boards/ARDUINO_PORTENTA_H7: Enable ROMFS.
iabdalkader Jan 14, 2025
dfcb341
rp2: Enable VfsRom.
dpgeorge Mar 3, 2022
f582796
rp2/rp2_flash: Allow MICROPY_HW_ROMFS_BYTES to be configurable.
dpgeorge Nov 23, 2024
2745616
esp32: Enable VfsRom.
dpgeorge Mar 3, 2022
d0c1e6f
esp8266: Enable VfsRom.
dpgeorge Nov 15, 2024
711615a
mimxrt/mimxrt_flash: Add support for the VfsRom filesystem.
robert-hh Nov 21, 2024
b601c9e
samd: Support the VfsRom file system for SAMD21.
robert-hh Nov 19, 2024
aa05efb
samd: Support the VfsRom file system for SAMD51.
robert-hh Nov 20, 2024
a237029
nrf/modules/flashbdev: Add support for VfsRom.
robert-hh Nov 25, 2024
e75c8a6
nrf/main: Use frozen _boot.py to set up and mount the file system.
robert-hh Nov 26, 2024
877953d
renesas-ra/storage: Add support for a VfsRom file system.
robert-hh Dec 11, 2024
c5c3d04
mimxrt/Makefile: Set VfsRom size in Makefile and define vfsrom symbols.
robert-hh Dec 28, 2024
77f12f3
mimxrt: Update rom_ioctl protocol.
dpgeorge Jan 3, 2025
d9111eb
samd: Update to use new rom_ioctl protocol.
dpgeorge Jan 3, 2025
9d40ed2
nrf: Update to use new rom_ioctl protocol.
dpgeorge Jan 3, 2025
0013dae
renesas-ra: Update to use new rom_ioctl protocol.
dpgeorge Jan 3, 2025
ca78107
github/workflows: Use ubuntu-latest for stm32 CI.
dpgeorge Jan 3, 2025
31e56a2
samd/samd_flash: Add the buffer protocol to samd_flash_type.
robert-hh Jan 5, 2025
0f55bfe
samd/samd_flash: Round up number of pages.
dpgeorge Jan 6, 2025
dfeec44
Revert "github/workflows: Use ubuntu-latest for stm32 CI."
dpgeorge Jan 22, 2025
2431419
WIP: add manifest support
dpgeorge Feb 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions extmod/modvfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@
#error "MICROPY_PY_VFS requires MICROPY_VFS"
#endif

#if MICROPY_VFS_ROM
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_vfs_rom_ioctl_obj, 1, 4, mp_vfs_rom_ioctl);
#endif

static const mp_rom_map_elem_t vfs_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_vfs) },

Expand All @@ -53,6 +57,7 @@ static const mp_rom_map_elem_t vfs_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_VfsLfs2), MP_ROM_PTR(&mp_type_vfs_lfs2) },
#endif
#if MICROPY_VFS_ROM
{ MP_ROM_QSTR(MP_QSTR_rom_ioctl), MP_ROM_PTR(&mp_vfs_rom_ioctl_obj) },
{ MP_ROM_QSTR(MP_QSTR_VfsRom), MP_ROM_PTR(&mp_type_vfs_rom) },
#endif
#if MICROPY_VFS_POSIX
Expand Down
12 changes: 12 additions & 0 deletions extmod/vfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@
#define MP_BLOCKDEV_IOCTL_BLOCK_SIZE (5)
#define MP_BLOCKDEV_IOCTL_BLOCK_ERASE (6)

// Constants for vfs.rom_ioctl() function.
#define MP_VFS_ROM_IOCTL_GET_NUMBER_OF_SEGMENTS (1) // rom_ioctl(1)
#define MP_VFS_ROM_IOCTL_GET_SEGMENT (2) // rom_ioctl(2, <id>)
#define MP_VFS_ROM_IOCTL_WRITE_PREPARE (3) // rom_ioctl(3, <id>, <len>)
#define MP_VFS_ROM_IOCTL_WRITE (4) // rom_ioctl(4, <id>, <offset>, <buf>)
#define MP_VFS_ROM_IOCTL_WRITE_COMPLETE (5) // rom_ioctl(5, <id>)

// At the moment the VFS protocol just has import_stat, but could be extended to other methods
typedef struct _mp_vfs_proto_t {
mp_import_stat_t (*import_stat)(void *self, const char *path);
Expand Down Expand Up @@ -122,4 +129,9 @@ MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_rmdir_obj);
MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_stat_obj);
MP_DECLARE_CONST_FUN_OBJ_1(mp_vfs_statvfs_obj);

#if MICROPY_VFS_ROM
// A port must define this.
mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args);
#endif

#endif // MICROPY_INCLUDED_EXTMOD_VFS_H
72 changes: 72 additions & 0 deletions ports/esp32/esp32_partition.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,20 @@ typedef struct _esp32_partition_obj_t {
uint16_t block_size;
} esp32_partition_obj_t;

#if MICROPY_VFS_ROM

static esp32_partition_obj_t esp32_partition_romfs_obj = {
.base = { .type = NULL },
.part = NULL,
.cache = NULL,
.block_size = NATIVE_BLOCK_SIZE_BYTES,
};

static const void *esp32_partition_romfs_ptr = NULL;
static esp_partition_mmap_handle_t esp32_partition_romfs_handle;

#endif

static esp32_partition_obj_t *esp32_partition_new(const esp_partition_t *part, uint16_t block_size) {
if (part == NULL) {
mp_raise_OSError(MP_ENOENT);
Expand Down Expand Up @@ -114,6 +128,24 @@ static mp_obj_t esp32_partition_make_new(const mp_obj_type_t *type, size_t n_arg
return MP_OBJ_FROM_PTR(esp32_partition_new(part, block_size));
}

#if MICROPY_VFS_ROM
static mp_int_t esp32_partition_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
esp32_partition_obj_t *self = MP_OBJ_TO_PTR(self_in);
if (self == &esp32_partition_romfs_obj && flags == MP_BUFFER_READ) {
if (esp32_partition_romfs_ptr == NULL) {
check_esp_err(esp_partition_mmap(self->part, 0, self->part->size, ESP_PARTITION_MMAP_DATA, &esp32_partition_romfs_ptr, &esp32_partition_romfs_handle));
}
bufinfo->buf = (void *)esp32_partition_romfs_ptr;
bufinfo->len = self->part->size;
bufinfo->typecode = 'B';
return 0;
} else {
// Unsupported.
return 1;
}
}
#endif

static mp_obj_t esp32_partition_find(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
// Parse args
enum { ARG_type, ARG_subtype, ARG_label, ARG_block_size };
Expand Down Expand Up @@ -284,11 +316,51 @@ static const mp_rom_map_elem_t esp32_partition_locals_dict_table[] = {
};
static MP_DEFINE_CONST_DICT(esp32_partition_locals_dict, esp32_partition_locals_dict_table);

#if MICROPY_VFS_ROM
#define ESP32_PARTITION_GET_BUFFER buffer, esp32_partition_get_buffer,
#else
#define ESP32_PARTITION_GET_BUFFER
#endif

MP_DEFINE_CONST_OBJ_TYPE(
esp32_partition_type,
MP_QSTR_Partition,
MP_TYPE_FLAG_NONE,
make_new, esp32_partition_make_new,
print, esp32_partition_print,
ESP32_PARTITION_GET_BUFFER
locals_dict, &esp32_partition_locals_dict
);

/******************************************************************************/
// romfs partition

#if MICROPY_VFS_ROM

mp_obj_t mp_vfs_rom_ioctl(size_t n_args, const mp_obj_t *args) {
if (esp32_partition_romfs_obj.base.type == NULL) {
esp32_partition_romfs_obj.base.type = &esp32_partition_type;
// Get the romfs partition.
// TODO: number of segments ioctl can be used if there is more than one romfs.
esp_partition_iterator_t iter = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "romfs");
if (iter != NULL) {
esp32_partition_romfs_obj.part = esp_partition_get(iter);
}
esp_partition_iterator_release(iter);
}

if (esp32_partition_romfs_obj.part == NULL) {
return MP_OBJ_NEW_SMALL_INT(-MP_ENODEV);
}

switch (mp_obj_get_int(args[0])) {
case MP_VFS_ROM_IOCTL_GET_NUMBER_OF_SEGMENTS:
return MP_OBJ_NEW_SMALL_INT(1);
case MP_VFS_ROM_IOCTL_GET_SEGMENT:
return MP_OBJ_FROM_PTR(&esp32_partition_romfs_obj);
default:
return MP_OBJ_NEW_SMALL_INT(-MP_EINVAL);
}
}

#endif // MICROPY_VFS_ROM
9 changes: 9 additions & 0 deletions ports/esp32/modules/_boot.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import gc
import vfs
import sys
from flashbdev import bdev

try:
vfs.mount(vfs.VfsRom(vfs.rom_ioctl(2)), "/rom")
sys.path.insert(0, "/rom")
except:
pass

try:
if bdev:
vfs.mount(bdev, "/")
Expand All @@ -11,3 +18,5 @@
inisetup.setup()

gc.collect()

del sys
1 change: 1 addition & 0 deletions ports/esp32/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
#define MICROPY_USE_INTERNAL_PRINTF (0) // ESP32 SDK requires its own printf
#define MICROPY_SCHEDULER_DEPTH (8)
#define MICROPY_VFS (1)
#define MICROPY_VFS_ROM (1)

// control over Python builtins
#define MICROPY_PY_STR_BYTES_CMP_WARN (1)
Expand Down
3 changes: 2 additions & 1 deletion ports/esp32/partitions-4MiB.csv
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 0x1F0000,
factory, app, factory, 0x10000, 0x1D0000,
romfs, data, 0x8f, 0x1E0000, 0x20000,
vfs, data, fat, 0x200000, 0x200000,
9 changes: 8 additions & 1 deletion ports/esp8266/boards/ESP8266_GENERIC/_boot.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
# Minimal _boot.py for the 512kiB variant. Does not set up a block device or
# filesystem. Other variants use esp8266/modules/_boot.py.

import gc
import gc, vfs

gc.threshold((gc.mem_free() + gc.mem_alloc()) // 4)

# Try to mount the ROMFS.
try:
vfs.mount(vfs.VfsRom(vfs.rom_ioctl(2)), "/")
except:
pass

16 changes: 8 additions & 8 deletions ports/esp8266/boards/ESP8266_GENERIC/manifest_512kiB.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
module("_boot.py", opt=3)
module("apa102.py", base_path="$(PORT_DIR)/modules", opt=3)
module("port_diag.py", base_path="$(PORT_DIR)/modules", opt=3)
require("ntptime")
require("dht")
require("onewire")
require("ds18x20")
require("webrepl")
require("neopixel")
# module("apa102.py", base_path="$(PORT_DIR)/modules", opt=3)
# module("port_diag.py", base_path="$(PORT_DIR)/modules", opt=3)
# require("ntptime")
# require("dht")
# require("onewire")
# require("ds18x20")
# require("webrepl")
# require("neopixel")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we delete these instead of commenting them?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, they should be deleted.

I was using the 512k esp8266 firmware as a good example of a very constrained board which would benefit from ROMFS, and that helped drive the design of some of the parts, to make things work on this board.

IMO it makes sense to remove these frozen modules and make them part of the ROMFS, because then they are fully configurable by the user. At the moment unfortunately we don't have a way to provide default ROMFS filesystems. If we did then we could just bundle a pre-made ROMFS with the 512k esp8266 firmware and retain the same set of included modules, they just moved from frozen to ROMFS.

@projectgus do you think it's worth adding such a feature, a pre-baked ROMFS included in firmware? The issue is that if users have a custom ROMFS and then update the firmware, that firmware update will reset their ROMFS to the pre-baked one. Maybe we need separate firmware, a "first install" firmware and then "update that leaves filesystem alone".

Alternatively, can just document how a user would get back the old set of frozen files here, installed instead on the ROMFS. That's not particularly easy though. It really needs a web tool.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you think it's worth adding such a feature, a pre-baked ROMFS included in firmware? T

I think that could be useful, but the main requirement is having a migration path from "frozen into firmware" to "built into ROMFS". Building it with the firmware by default would achieve this, but I think it'd be OK to not support this provided there was a pathway to doing it in an alternative way.

I'm personally less worried about the particular case of 512kb esp8266 and more worried about the other boards where the linker scripts reduce the available app binary size on update.

Alternatively, can just document how a user would get back the old set of frozen files here, installed instead on the ROMFS. That's not particularly easy though. It really needs a web tool.

At least the users who are freezing custom files into their firmwares are doing custom builds already, so they're probably not afraid to follow a few additional command line steps.

22 changes: 13 additions & 9 deletions ports/esp8266/boards/ESP8266_GENERIC/mpconfigboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,23 @@
#define MICROPY_HW_BOARD_NAME "ESP module"
#define MICROPY_HW_MCU_NAME "ESP8266"

#define MICROPY_PERSISTENT_CODE_LOAD (1)
#define MICROPY_EMIT_XTENSA (1)
#define MICROPY_EMIT_INLINE_XTENSA (1)

#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL)

#define MICROPY_READER_VFS (MICROPY_VFS)
#define MICROPY_VFS (1)

#define MICROPY_PY_CRYPTOLIB (1)

#elif defined(MICROPY_ESP8266_1M)

#define MICROPY_HW_BOARD_NAME "ESP module (1M)"
#define MICROPY_HW_MCU_NAME "ESP8266"

#define MICROPY_PERSISTENT_CODE_LOAD (1)
#define MICROPY_EMIT_XTENSA (1)
#define MICROPY_EMIT_INLINE_XTENSA (1)

#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_NORMAL)

#define MICROPY_READER_VFS (MICROPY_VFS)
#define MICROPY_VFS (1)


#define MICROPY_PY_CRYPTOLIB (1)

#elif defined(MICROPY_ESP8266_512K)
Expand All @@ -46,5 +37,18 @@
#define MICROPY_PY_ASYNCIO (0)
#define MICROPY_PY_RE_SUB (0)
#define MICROPY_PY_FRAMEBUF (0)
#define MICROPY_PY_HEAPQ (0)

#define MICROPY_VFS_WRITABLE (0)

#define MICROPY_PY_ESP_FLASH_FUNCS (0)
#define MICROPY_PY_ESP_EXTRA_FUNCS (0)

#endif

// Configuration common to all variants.

#define MICROPY_PERSISTENT_CODE_LOAD (1)
#define MICROPY_READER_VFS (MICROPY_VFS)
#define MICROPY_VFS (1)
#define MICROPY_VFS_ROM (1)
6 changes: 4 additions & 2 deletions ports/esp8266/boards/esp8266_1MiB.ld
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

Flash layout:
0x40200000 36k header + iram/dram init
0x40209000 572k firmware (irom0)
0x40209000 556k firmware (irom0)
0x40294000 16k ROMFS
0x40298000 396k filesystem
0x402fb000 20k SDK parameters
*/
Expand All @@ -12,7 +13,8 @@ MEMORY
dport0_0_seg : org = 0x3ff00000, len = 16
dram0_0_seg : org = 0x3ffe8000, len = 80K
iram1_0_seg : org = 0x40100000, len = 32K
irom0_0_seg : org = 0x40209000, len = 572K
irom0_0_seg : org = 0x40209000, len = 556K
FLASH_ROMFS : org = 0x40294000, len = 16K
}

/* define common sections and symbols */
Expand Down
6 changes: 4 additions & 2 deletions ports/esp8266/boards/esp8266_2MiB.ld
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

Flash layout:
0x40200000 36k header + iram/dram init
0x40209000 988k firmware (irom0)
0x40209000 732k firmware (irom0)
0x402c0000 256k ROMFS
0x40300000 1M+ filesystem (not memory mapped)
* 10000 /

Expand All @@ -11,7 +12,8 @@ MEMORY
dport0_0_seg : org = 0x3ff00000, len = 16
dram0_0_seg : org = 0x3ffe8000, len = 80K
iram1_0_seg : org = 0x40100000, len = 32K
irom0_0_seg : org = 0x40209000, len = 1M - 36K
irom0_0_seg : org = 0x40209000, len = 1M - 36K - 256K
FLASH_ROMFS : org = 0x402c0000, len = 256K
}

/* define common sections and symbols */
Expand Down
6 changes: 4 additions & 2 deletions ports/esp8266/boards/esp8266_512kiB.ld
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

Flash layout:
0x40200000 36k header + iram/dram init
0x40209000 456k firmware (irom0)
0x40209000 448k firmware (irom0)
0x40279000 8k ROMFS
0x4027b000 20k SDK parameters
*/

Expand All @@ -11,7 +12,8 @@ MEMORY
dport0_0_seg : org = 0x3ff00000, len = 16
dram0_0_seg : org = 0x3ffe8000, len = 80K
iram1_0_seg : org = 0x40100000, len = 32K
irom0_0_seg : org = 0x40209000, len = 512K - 36K - 20K
irom0_0_seg : org = 0x40209000, len = 512K - 36K - 20K - 8K
FLASH_ROMFS : org = 0x4027a000, len = 8K
}

/* define common sections and symbols */
Expand Down
4 changes: 4 additions & 0 deletions ports/esp8266/boards/esp8266_common.ld
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
/* define the top of RAM */
_heap_end = ORIGIN(dram0_0_seg) + LENGTH(dram0_0_seg);

/* define ROMFS extents */
_micropy_hw_romfs_start = ORIGIN(FLASH_ROMFS);
_micropy_hw_romfs_size = LENGTH(FLASH_ROMFS);

PHDRS
{
dport0_0_phdr PT_LOAD;
Expand Down
3 changes: 2 additions & 1 deletion ports/esp8266/boards/esp8266_ota.ld
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ MEMORY
dram0_0_seg : org = 0x3ffe8000, len = 0x14000
iram1_0_seg : org = 0x40100000, len = 0x8000
/* 0x3c000 is size of bootloader, 0x9000 is size of packed RAM segments */
irom0_0_seg : org = 0x40200000 + 0x3c000 + 0x9000, len = 0x8f000
irom0_0_seg : org = 0x40200000 + 0x3c000 + 0x9000, len = 0x8f000 - 8K
FLASH_ROMFS : org = 0x402d2000, len = 8K
}

/* define common sections and symbols */
Expand Down
Loading
Loading
0