Skip to content

Commit

Permalink
Add support for saves partition
Browse files Browse the repository at this point in the history
Suggested in #10045
  • Loading branch information
tannewt committed Mar 7, 2025
1 parent 2af397e commit 5616fc2
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 101 deletions.
4 changes: 4 additions & 0 deletions extmod/vfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ typedef struct _mp_vfs_proto_t {
typedef struct _mp_vfs_blockdev_t {
uint16_t flags;
size_t block_size;
#if CIRCUITPY_SAVES_PARTITION_SIZE > 0
size_t offset;
int size;
#endif
mp_obj_t readblocks[5];
mp_obj_t writeblocks[5];
// new protocol uses just ioctl, old uses sync (optional) and count
Expand Down
4 changes: 0 additions & 4 deletions extmod/vfs_blockdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,6 @@ void mp_vfs_blockdev_init(mp_vfs_blockdev_t *self, mp_obj_t bdev) {

int mp_vfs_blockdev_read(mp_vfs_blockdev_t *self, size_t block_num, size_t num_blocks, uint8_t *buf) {
if (self->flags & MP_BLOCKDEV_FLAG_NATIVE) {
// CIRCUITPY-CHANGE: Pass the blockdev object into native readblocks so
// it has the corresponding state.
mp_uint_t (*f)(mp_obj_t self, uint8_t *, uint32_t, uint32_t) = (void *)(uintptr_t)self->readblocks[2];
return f(self->readblocks[1], buf, block_num, num_blocks);
} else {
Expand Down Expand Up @@ -112,8 +110,6 @@ int mp_vfs_blockdev_write(mp_vfs_blockdev_t *self, size_t block_num, size_t num_
}

if (self->flags & MP_BLOCKDEV_FLAG_NATIVE) {
// CIRCUITPY-CHANGE: Pass the blockdev object into native readblocks so
// it has the corresponding state.
mp_uint_t (*f)(mp_obj_t self, const uint8_t *, uint32_t, uint32_t) = (void *)(uintptr_t)self->writeblocks[2];
return f(self->writeblocks[1], buf, block_num, num_blocks);
} else {
Expand Down
6 changes: 5 additions & 1 deletion main.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@ static void stop_mp(void) {
vfs = vfs->next;
}
MP_STATE_VM(vfs_mount_table) = vfs;
// The last vfs is CIRCUITPY and the root directory.
while (vfs->next != NULL) {
vfs = vfs->next;
}
MP_STATE_VM(vfs_cur) = vfs;
#endif

Expand Down Expand Up @@ -863,7 +867,7 @@ static void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {

#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
// Get the base filesystem.
fs_user_mount_t *vfs = (fs_user_mount_t *)MP_STATE_VM(vfs_mount_table)->obj;
fs_user_mount_t *vfs = filesystem_circuitpy();
FATFS *fs = &vfs->fatfs;

boot_output = NULL;
Expand Down
2 changes: 2 additions & 0 deletions ports/raspberrypi/boards/adafruit_fruit_jam/mpconfigboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@
// #define CIRCUITPY_CONSOLE_UART_RX (&pin_GPIO45)

// #define CIRCUITPY_DEBUG_TINYUSB 0

#define CIRCUITPY_SAVES_PARTITION_SIZE (2 * 1024 * 1024)
4 changes: 4 additions & 0 deletions py/circuitpy_mpconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,10 @@ void background_callback_run_all(void);
#define CIRCUITPY_MIN_GCC_VERSION 13
#endif

#ifndef CIRCUITPY_SAVES_PARTITION_SIZE
#define CIRCUITPY_SAVES_PARTITION_SIZE 0
#endif

#if defined(__GNUC__) && !defined(__ZEPHYR__)
#if __GNUC__ < CIRCUITPY_MIN_GCC_VERSION
// (the 3 level scheme here is required to get expansion & stringization
Expand Down
115 changes: 83 additions & 32 deletions supervisor/shared/filesystem.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@
#include "supervisor/flash.h"
#include "supervisor/linker.h"

static mp_vfs_mount_t _mp_vfs;
static fs_user_mount_t _internal_vfs;
static mp_vfs_mount_t _circuitpy_vfs;
static fs_user_mount_t _circuitpy_usermount;

#if CIRCUITPY_SAVES_PARTITION_SIZE > 0
static mp_vfs_mount_t _saves_vfs;
static fs_user_mount_t _saves_usermount;
#endif

static volatile uint32_t filesystem_flush_interval_ms = CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS;
volatile bool filesystem_flush_requested = false;
Expand Down Expand Up @@ -73,23 +78,37 @@ static void make_file_with_contents(FATFS *fatfs, const char *filename, const by
// want it to be executed without using stack within main() function
bool filesystem_init(bool create_allowed, bool force_create) {
// init the vfs object
fs_user_mount_t *vfs_fat = &_internal_vfs;
vfs_fat->blockdev.flags = 0;
supervisor_flash_init_vfs(vfs_fat);
fs_user_mount_t *circuitpy = &_circuitpy_usermount;
circuitpy->blockdev.flags = 0;
supervisor_flash_init_vfs(circuitpy);

#if CIRCUITPY_SAVES_PARTITION_SIZE > 0
// SAVES is placed before CIRCUITPY so that CIRCUITPY takes up the remaining space.
circuitpy->blockdev.offset = CIRCUITPY_SAVES_PARTITION_SIZE;
circuitpy->blockdev.size = -1;

fs_user_mount_t *saves = &_saves_usermount;
saves->blockdev.flags = 0;
saves->blockdev.offset = 0;
saves->blockdev.size = CIRCUITPY_SAVES_PARTITION_SIZE;
supervisor_flash_init_vfs(saves);
filesystem_set_concurrent_write_protection(saves, true);
filesystem_set_writable_by_usb(saves, false);
#endif

mp_vfs_mount_t *vfs = &_mp_vfs;
vfs->len = 0;
mp_vfs_mount_t *circuitpy_vfs = &_circuitpy_vfs;
circuitpy_vfs->len = 0;

// try to mount the flash
FRESULT res = f_mount(&vfs_fat->fatfs);
FRESULT res = f_mount(&circuitpy->fatfs);
if ((res == FR_NO_FILESYSTEM && create_allowed) || force_create) {
// No filesystem so create a fresh one, or reformat has been requested.
uint8_t working_buf[FF_MAX_SS];
BYTE formats = FM_FAT;
#if FF_FS_EXFAT
formats |= FM_EXFAT | FM_FAT32;
#endif
res = f_mkfs(&vfs_fat->fatfs, formats, 0, working_buf, sizeof(working_buf));
res = f_mkfs(&circuitpy->fatfs, formats, 0, working_buf, sizeof(working_buf));
if (res != FR_OK) {
return false;
}
Expand All @@ -98,46 +117,66 @@ bool filesystem_init(bool create_allowed, bool force_create) {

// set label
#ifdef CIRCUITPY_DRIVE_LABEL
res = f_setlabel(&vfs_fat->fatfs, CIRCUITPY_DRIVE_LABEL);
res = f_setlabel(&circuitpy->fatfs, CIRCUITPY_DRIVE_LABEL);
#else
res = f_setlabel(&vfs_fat->fatfs, "CIRCUITPY");
res = f_setlabel(&circuitpy->fatfs, "CIRCUITPY");
#endif
if (res != FR_OK) {
return false;
}

#if CIRCUITPY_USB_DEVICE
// inhibit file indexing on MacOS
res = f_mkdir(&vfs_fat->fatfs, "/.fseventsd");
res = f_mkdir(&circuitpy->fatfs, "/.fseventsd");
if (res != FR_OK) {
return false;
}
make_empty_file(&vfs_fat->fatfs, "/.fseventsd/no_log");
make_empty_file(&vfs_fat->fatfs, "/.metadata_never_index");
make_empty_file(&circuitpy->fatfs, "/.fseventsd/no_log");
make_empty_file(&circuitpy->fatfs, "/.metadata_never_index");

// Prevent storing trash on all OSes.
make_empty_file(&vfs_fat->fatfs, "/.Trashes"); // MacOS
make_empty_file(&vfs_fat->fatfs, "/.Trash-1000"); // Linux, XDG trash spec:
make_empty_file(&circuitpy->fatfs, "/.Trashes"); // MacOS
make_empty_file(&circuitpy->fatfs, "/.Trash-1000"); // Linux, XDG trash spec:
// https://specifications.freedesktop.org/trash-spec/trashspec-latest.html
#endif

#if CIRCUITPY_SDCARDIO || CIRCUITPY_SDIOIO
res = f_mkdir(&vfs_fat->fatfs, "/sd");
res = f_mkdir(&circuitpy->fatfs, "/sd");
#if CIRCUITPY_FULL_BUILD
MAKE_FILE_WITH_OPTIONAL_CONTENTS(&vfs_fat->fatfs, "/sd/placeholder.txt",
MAKE_FILE_WITH_OPTIONAL_CONTENTS(&circuitpy->fatfs, "/sd/placeholder.txt",
"SD cards mounted at /sd will hide this file from Python."
" SD cards are not visible via USB CIRCUITPY.\n");
#endif
#endif

#if CIRCUITPY_SAVES_PARTITION_SIZE > 0
res = f_mkfs(&saves->fatfs, formats, 0, working_buf, sizeof(working_buf));
if (res == FR_OK) {
// Flush the new file system to make sure it's repaired immediately.
supervisor_flash_flush();
res = f_setlabel(&saves->fatfs, "CPSAVES");
}

if (res == FR_OK) {
res = f_mkdir(&circuitpy->fatfs, "/saves");
}
#if CIRCUITPY_FULL_BUILD
if (res == FR_OK) {
MAKE_FILE_WITH_OPTIONAL_CONTENTS(&circuitpy->fatfs, "/saves/placeholder.txt",
"A separate filesystem mounted at /saves will hide this file from Python."
" Saves are visible via USB CPSAVES.\n");
}
#endif
#endif

#if CIRCUITPY_OS_GETENV
make_empty_file(&vfs_fat->fatfs, "/settings.toml");
make_empty_file(&circuitpy->fatfs, "/settings.toml");
#endif
// make a sample code.py file
MAKE_FILE_WITH_OPTIONAL_CONTENTS(&vfs_fat->fatfs, "/code.py", "print(\"Hello World!\")\n");
MAKE_FILE_WITH_OPTIONAL_CONTENTS(&circuitpy->fatfs, "/code.py", "print(\"Hello World!\")\n");

// create empty lib directory
res = f_mkdir(&vfs_fat->fatfs, "/lib");
res = f_mkdir(&circuitpy->fatfs, "/lib");
if (res != FR_OK) {
return false;
}
Expand All @@ -148,16 +187,28 @@ bool filesystem_init(bool create_allowed, bool force_create) {
return false;
}

vfs->str = "/";
vfs->len = 1;
vfs->obj = MP_OBJ_FROM_PTR(vfs_fat);
vfs->next = NULL;

MP_STATE_VM(vfs_mount_table) = vfs;
circuitpy_vfs->str = "/";
circuitpy_vfs->len = 1;
circuitpy_vfs->obj = MP_OBJ_FROM_PTR(circuitpy);
circuitpy_vfs->next = NULL;

MP_STATE_VM(vfs_mount_table) = circuitpy_vfs;

#if CIRCUITPY_SAVES_PARTITION_SIZE > 0
res = f_mount(&saves->fatfs);
if (res == FR_OK) {
mp_vfs_mount_t *saves_vfs = &_saves_vfs;
saves_vfs->str = "/saves";
saves_vfs->len = 6;
saves_vfs->obj = MP_OBJ_FROM_PTR(&_saves_usermount);
saves_vfs->next = MP_STATE_VM(vfs_mount_table);
MP_STATE_VM(vfs_mount_table) = saves_vfs;
}
#endif

// The current directory is used as the boot up directory.
// It is set to the internal flash filesystem by default.
MP_STATE_PORT(vfs_cur) = vfs;
MP_STATE_PORT(vfs_cur) = circuitpy_vfs;

#if CIRCUITPY_STORAGE_EXTEND
supervisor_flash_update_extended();
Expand All @@ -175,7 +226,7 @@ void PLACE_IN_ITCM(filesystem_flush)(void) {
}

void filesystem_set_internal_writable_by_usb(bool writable) {
fs_user_mount_t *vfs = &_internal_vfs;
fs_user_mount_t *vfs = &_circuitpy_usermount;

filesystem_set_writable_by_usb(vfs, writable);
}
Expand All @@ -199,7 +250,7 @@ bool filesystem_is_writable_by_usb(fs_user_mount_t *vfs) {
}

void filesystem_set_internal_concurrent_write_protection(bool concurrent_write_protection) {
filesystem_set_concurrent_write_protection(&_internal_vfs, concurrent_write_protection);
filesystem_set_concurrent_write_protection(&_circuitpy_usermount, concurrent_write_protection);
}

void filesystem_set_concurrent_write_protection(fs_user_mount_t *vfs, bool concurrent_write_protection) {
Expand All @@ -211,14 +262,14 @@ void filesystem_set_concurrent_write_protection(fs_user_mount_t *vfs, bool concu
}

bool filesystem_present(void) {
return _mp_vfs.len > 0;
return _circuitpy_vfs.len > 0;
}

fs_user_mount_t *filesystem_circuitpy(void) {
if (!filesystem_present()) {
return NULL;
}
return &_internal_vfs;
return &_circuitpy_usermount;
}

fs_user_mount_t *filesystem_for_path(const char *path_in, const char **path_under_mount) {
Expand Down
Loading

0 comments on commit 5616fc2

Please sign in to comment.