Skip to content

Commit ca0eec3

Browse files
authored
Merge pull request #10122 from tannewt/saves_partition
Add support for saves partition
2 parents 6f609bf + c6de848 commit ca0eec3

File tree

7 files changed

+198
-97
lines changed

7 files changed

+198
-97
lines changed

Diff for: extmod/vfs.h

+4
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ typedef struct _mp_vfs_proto_t {
7171
typedef struct _mp_vfs_blockdev_t {
7272
uint16_t flags;
7373
size_t block_size;
74+
#if CIRCUITPY_SAVES_PARTITION_SIZE > 0
75+
size_t offset;
76+
int size;
77+
#endif
7478
mp_obj_t readblocks[5];
7579
mp_obj_t writeblocks[5];
7680
// new protocol uses just ioctl, old uses sync (optional) and count

Diff for: main.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,10 @@ static void stop_mp(void) {
214214
vfs = vfs->next;
215215
}
216216
MP_STATE_VM(vfs_mount_table) = vfs;
217+
// The last vfs is CIRCUITPY and the root directory.
218+
while (vfs->next != NULL) {
219+
vfs = vfs->next;
220+
}
217221
MP_STATE_VM(vfs_cur) = vfs;
218222
#endif
219223

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

864868
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
865869
// Get the base filesystem.
866-
fs_user_mount_t *vfs = (fs_user_mount_t *)MP_STATE_VM(vfs_mount_table)->obj;
870+
fs_user_mount_t *vfs = filesystem_circuitpy();
867871
FATFS *fs = &vfs->fatfs;
868872

869873
boot_output = NULL;

Diff for: ports/raspberrypi/boards/adafruit_fruit_jam/mpconfigboard.h

+2
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,5 @@
3636
// #define CIRCUITPY_CONSOLE_UART_RX (&pin_GPIO45)
3737

3838
// #define CIRCUITPY_DEBUG_TINYUSB 0
39+
40+
#define CIRCUITPY_SAVES_PARTITION_SIZE (2 * 1024 * 1024)

Diff for: py/circuitpy_mpconfig.h

+4
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,10 @@ void background_callback_run_all(void);
615615
#define CIRCUITPY_MIN_GCC_VERSION 13
616616
#endif
617617

618+
#ifndef CIRCUITPY_SAVES_PARTITION_SIZE
619+
#define CIRCUITPY_SAVES_PARTITION_SIZE 0
620+
#endif
621+
618622
#if defined(__GNUC__) && !defined(__ZEPHYR__)
619623
#if __GNUC__ < CIRCUITPY_MIN_GCC_VERSION
620624
// (the 3 level scheme here is required to get expansion & stringization

Diff for: supervisor/shared/filesystem.c

+83-32
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,13 @@
1515
#include "supervisor/flash.h"
1616
#include "supervisor/linker.h"
1717

18-
static mp_vfs_mount_t _mp_vfs;
19-
static fs_user_mount_t _internal_vfs;
18+
static mp_vfs_mount_t _circuitpy_vfs;
19+
static fs_user_mount_t _circuitpy_usermount;
20+
21+
#if CIRCUITPY_SAVES_PARTITION_SIZE > 0
22+
static mp_vfs_mount_t _saves_vfs;
23+
static fs_user_mount_t _saves_usermount;
24+
#endif
2025

2126
static volatile uint32_t filesystem_flush_interval_ms = CIRCUITPY_FILESYSTEM_FLUSH_INTERVAL_MS;
2227
volatile bool filesystem_flush_requested = false;
@@ -73,23 +78,37 @@ static void make_file_with_contents(FATFS *fatfs, const char *filename, const by
7378
// want it to be executed without using stack within main() function
7479
bool filesystem_init(bool create_allowed, bool force_create) {
7580
// init the vfs object
76-
fs_user_mount_t *vfs_fat = &_internal_vfs;
77-
vfs_fat->blockdev.flags = 0;
78-
supervisor_flash_init_vfs(vfs_fat);
81+
fs_user_mount_t *circuitpy = &_circuitpy_usermount;
82+
circuitpy->blockdev.flags = 0;
83+
supervisor_flash_init_vfs(circuitpy);
84+
85+
#if CIRCUITPY_SAVES_PARTITION_SIZE > 0
86+
// SAVES is placed before CIRCUITPY so that CIRCUITPY takes up the remaining space.
87+
circuitpy->blockdev.offset = CIRCUITPY_SAVES_PARTITION_SIZE;
88+
circuitpy->blockdev.size = -1;
89+
90+
fs_user_mount_t *saves = &_saves_usermount;
91+
saves->blockdev.flags = 0;
92+
saves->blockdev.offset = 0;
93+
saves->blockdev.size = CIRCUITPY_SAVES_PARTITION_SIZE;
94+
supervisor_flash_init_vfs(saves);
95+
filesystem_set_concurrent_write_protection(saves, true);
96+
filesystem_set_writable_by_usb(saves, false);
97+
#endif
7998

80-
mp_vfs_mount_t *vfs = &_mp_vfs;
81-
vfs->len = 0;
99+
mp_vfs_mount_t *circuitpy_vfs = &_circuitpy_vfs;
100+
circuitpy_vfs->len = 0;
82101

83102
// try to mount the flash
84-
FRESULT res = f_mount(&vfs_fat->fatfs);
103+
FRESULT res = f_mount(&circuitpy->fatfs);
85104
if ((res == FR_NO_FILESYSTEM && create_allowed) || force_create) {
86105
// No filesystem so create a fresh one, or reformat has been requested.
87106
uint8_t working_buf[FF_MAX_SS];
88107
BYTE formats = FM_FAT;
89108
#if FF_FS_EXFAT
90109
formats |= FM_EXFAT | FM_FAT32;
91110
#endif
92-
res = f_mkfs(&vfs_fat->fatfs, formats, 0, working_buf, sizeof(working_buf));
111+
res = f_mkfs(&circuitpy->fatfs, formats, 0, working_buf, sizeof(working_buf));
93112
if (res != FR_OK) {
94113
return false;
95114
}
@@ -98,46 +117,66 @@ bool filesystem_init(bool create_allowed, bool force_create) {
98117

99118
// set label
100119
#ifdef CIRCUITPY_DRIVE_LABEL
101-
res = f_setlabel(&vfs_fat->fatfs, CIRCUITPY_DRIVE_LABEL);
120+
res = f_setlabel(&circuitpy->fatfs, CIRCUITPY_DRIVE_LABEL);
102121
#else
103-
res = f_setlabel(&vfs_fat->fatfs, "CIRCUITPY");
122+
res = f_setlabel(&circuitpy->fatfs, "CIRCUITPY");
104123
#endif
105124
if (res != FR_OK) {
106125
return false;
107126
}
108127

109128
#if CIRCUITPY_USB_DEVICE
110129
// inhibit file indexing on MacOS
111-
res = f_mkdir(&vfs_fat->fatfs, "/.fseventsd");
130+
res = f_mkdir(&circuitpy->fatfs, "/.fseventsd");
112131
if (res != FR_OK) {
113132
return false;
114133
}
115-
make_empty_file(&vfs_fat->fatfs, "/.fseventsd/no_log");
116-
make_empty_file(&vfs_fat->fatfs, "/.metadata_never_index");
134+
make_empty_file(&circuitpy->fatfs, "/.fseventsd/no_log");
135+
make_empty_file(&circuitpy->fatfs, "/.metadata_never_index");
117136

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

124143
#if CIRCUITPY_SDCARDIO || CIRCUITPY_SDIOIO
125-
res = f_mkdir(&vfs_fat->fatfs, "/sd");
144+
res = f_mkdir(&circuitpy->fatfs, "/sd");
126145
#if CIRCUITPY_FULL_BUILD
127-
MAKE_FILE_WITH_OPTIONAL_CONTENTS(&vfs_fat->fatfs, "/sd/placeholder.txt",
146+
MAKE_FILE_WITH_OPTIONAL_CONTENTS(&circuitpy->fatfs, "/sd/placeholder.txt",
128147
"SD cards mounted at /sd will hide this file from Python."
129148
" SD cards are not visible via USB CIRCUITPY.\n");
130149
#endif
131150
#endif
132151

152+
#if CIRCUITPY_SAVES_PARTITION_SIZE > 0
153+
res = f_mkfs(&saves->fatfs, formats, 0, working_buf, sizeof(working_buf));
154+
if (res == FR_OK) {
155+
// Flush the new file system to make sure it's repaired immediately.
156+
supervisor_flash_flush();
157+
res = f_setlabel(&saves->fatfs, "CPSAVES");
158+
}
159+
160+
if (res == FR_OK) {
161+
res = f_mkdir(&circuitpy->fatfs, "/saves");
162+
}
163+
#if CIRCUITPY_FULL_BUILD
164+
if (res == FR_OK) {
165+
MAKE_FILE_WITH_OPTIONAL_CONTENTS(&circuitpy->fatfs, "/saves/placeholder.txt",
166+
"A separate filesystem mounted at /saves will hide this file from Python."
167+
" Saves are visible via USB CPSAVES.\n");
168+
}
169+
#endif
170+
#endif
171+
133172
#if CIRCUITPY_OS_GETENV
134-
make_empty_file(&vfs_fat->fatfs, "/settings.toml");
173+
make_empty_file(&circuitpy->fatfs, "/settings.toml");
135174
#endif
136175
// make a sample code.py file
137-
MAKE_FILE_WITH_OPTIONAL_CONTENTS(&vfs_fat->fatfs, "/code.py", "print(\"Hello World!\")\n");
176+
MAKE_FILE_WITH_OPTIONAL_CONTENTS(&circuitpy->fatfs, "/code.py", "print(\"Hello World!\")\n");
138177

139178
// create empty lib directory
140-
res = f_mkdir(&vfs_fat->fatfs, "/lib");
179+
res = f_mkdir(&circuitpy->fatfs, "/lib");
141180
if (res != FR_OK) {
142181
return false;
143182
}
@@ -148,16 +187,28 @@ bool filesystem_init(bool create_allowed, bool force_create) {
148187
return false;
149188
}
150189

151-
vfs->str = "/";
152-
vfs->len = 1;
153-
vfs->obj = MP_OBJ_FROM_PTR(vfs_fat);
154-
vfs->next = NULL;
155-
156-
MP_STATE_VM(vfs_mount_table) = vfs;
190+
circuitpy_vfs->str = "/";
191+
circuitpy_vfs->len = 1;
192+
circuitpy_vfs->obj = MP_OBJ_FROM_PTR(circuitpy);
193+
circuitpy_vfs->next = NULL;
194+
195+
MP_STATE_VM(vfs_mount_table) = circuitpy_vfs;
196+
197+
#if CIRCUITPY_SAVES_PARTITION_SIZE > 0
198+
res = f_mount(&saves->fatfs);
199+
if (res == FR_OK) {
200+
mp_vfs_mount_t *saves_vfs = &_saves_vfs;
201+
saves_vfs->str = "/saves";
202+
saves_vfs->len = 6;
203+
saves_vfs->obj = MP_OBJ_FROM_PTR(&_saves_usermount);
204+
saves_vfs->next = MP_STATE_VM(vfs_mount_table);
205+
MP_STATE_VM(vfs_mount_table) = saves_vfs;
206+
}
207+
#endif
157208

158209
// The current directory is used as the boot up directory.
159210
// It is set to the internal flash filesystem by default.
160-
MP_STATE_PORT(vfs_cur) = vfs;
211+
MP_STATE_PORT(vfs_cur) = circuitpy_vfs;
161212

162213
#if CIRCUITPY_STORAGE_EXTEND
163214
supervisor_flash_update_extended();
@@ -175,7 +226,7 @@ void PLACE_IN_ITCM(filesystem_flush)(void) {
175226
}
176227

177228
void filesystem_set_internal_writable_by_usb(bool writable) {
178-
fs_user_mount_t *vfs = &_internal_vfs;
229+
fs_user_mount_t *vfs = &_circuitpy_usermount;
179230

180231
filesystem_set_writable_by_usb(vfs, writable);
181232
}
@@ -199,7 +250,7 @@ bool filesystem_is_writable_by_usb(fs_user_mount_t *vfs) {
199250
}
200251

201252
void filesystem_set_internal_concurrent_write_protection(bool concurrent_write_protection) {
202-
filesystem_set_concurrent_write_protection(&_internal_vfs, concurrent_write_protection);
253+
filesystem_set_concurrent_write_protection(&_circuitpy_usermount, concurrent_write_protection);
203254
}
204255

205256
void filesystem_set_concurrent_write_protection(fs_user_mount_t *vfs, bool concurrent_write_protection) {
@@ -211,14 +262,14 @@ void filesystem_set_concurrent_write_protection(fs_user_mount_t *vfs, bool concu
211262
}
212263

213264
bool filesystem_present(void) {
214-
return _mp_vfs.len > 0;
265+
return _circuitpy_vfs.len > 0;
215266
}
216267

217268
fs_user_mount_t *filesystem_circuitpy(void) {
218269
if (!filesystem_present()) {
219270
return NULL;
220271
}
221-
return &_internal_vfs;
272+
return &_circuitpy_usermount;
222273
}
223274

224275
fs_user_mount_t *filesystem_for_path(const char *path_in, const char **path_under_mount) {

0 commit comments

Comments
 (0)