Skip to content
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

Add support for saves partition #10122

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
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