You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2022/09/05 13:39:01 UTC
[incubator-nuttx] branch master updated: Added SMART flash filesystem to RP2040
This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 9ad75fd95d Added SMART flash filesystem to RP2040
9ad75fd95d is described below
commit 9ad75fd95dfbe91a0f4a65dd8c0a532c04fee16b
Author: curuvar <58...@users.noreply.github.com>
AuthorDate: Sun Sep 4 19:02:24 2022 -0400
Added SMART flash filesystem to RP2040
---
arch/arm/src/rp2040/Kconfig | 26 +
arch/arm/src/rp2040/Make.defs | 14 +-
arch/arm/src/rp2040/rp2040_flash_initialize.S | 195 +++++++
arch/arm/src/rp2040/rp2040_flash_mtd.c | 569 +++++++++++++++++++++
arch/arm/src/rp2040/rp2040_flash_mtd.h | 35 ++
arch/arm/src/rp2040/rp2040_rom.h | 63 +++
.../arm/rp2040/adafruit-feather-rp2040/README.txt | 3 +
.../configs/nsh-flash/defconfig | 54 ++
.../scripts/adafruit-feather-rp2040-flash.ld | 6 +
.../scripts/adafruit-feather-rp2040-sram.ld | 7 +
boards/arm/rp2040/adafruit-kb2040/README.txt | 3 +
.../adafruit-kb2040/configs/nsh-flash/defconfig | 54 ++
.../scripts/adafruit-kb2040-flash.ld | 6 +
.../scripts/adafruit-kb2040-sram.ld | 7 +
boards/arm/rp2040/adafruit-qt-py-rp2040/README.txt | 3 +
.../configs/nsh-flash/defconfig | 57 +++
.../scripts/adafruit-qt-py-rp2040-flash.ld | 6 +
.../scripts/adafruit-qt-py-rp2040-sram.ld | 7 +
boards/arm/rp2040/common/Kconfig | 15 +-
.../arm/rp2040/common/src/rp2040_common_bringup.c | 85 +++
boards/arm/rp2040/pimoroni-tiny2040/README.txt | 3 +
.../pimoroni-tiny2040/configs/nsh-flash/defconfig | 53 ++
.../scripts/pimoroni-tiny2040-flash.ld | 6 +
.../scripts/pimoroni-tiny2040-sram.ld | 7 +
boards/arm/rp2040/raspberrypi-pico-w/README.txt | 3 +
.../raspberrypi-pico-w/configs/nsh-flash/defconfig | 50 ++
.../scripts/raspberrypi-pico-flash.ld | 6 +
.../scripts/raspberrypi-pico-sram.ld | 7 +
boards/arm/rp2040/raspberrypi-pico/README.txt | 3 +
.../raspberrypi-pico/configs/nsh-flash/defconfig | 50 ++
.../scripts/raspberrypi-pico-flash.ld | 6 +
.../scripts/raspberrypi-pico-sram.ld | 7 +
drivers/mtd/smart.c | 6 +-
fs/smartfs/smartfs.h | 14 +-
fs/smartfs/smartfs_smart.c | 62 ++-
fs/smartfs/smartfs_utils.c | 36 +-
tools/rp2040/make_flash_fs.c | 480 +++++++++++++++++
37 files changed, 1980 insertions(+), 34 deletions(-)
diff --git a/arch/arm/src/rp2040/Kconfig b/arch/arm/src/rp2040/Kconfig
index 8e19f13aa0..0b2ecde902 100644
--- a/arch/arm/src/rp2040/Kconfig
+++ b/arch/arm/src/rp2040/Kconfig
@@ -689,3 +689,29 @@ config RP2040_BOARD_HAS_WS2812
---help---
See the Board Selection menu to configure the pins used
by ws2812.
+
+#####################################################################
+# Flash File System Configuration
+#####################################################################
+
+config RP2040_FLASH_FILE_SYSTEM
+ bool "Configure a read/write filesystem on unused flash memory"
+ default n
+ select MTD
+ select MTD_SMART
+ select FS_SMARTFS
+ ---help---
+ See the Board Selection menu to configure the size of the
+ flash chip for a particular board.
+
+if RP2040_FLASH_FILE_SYSTEM
+
+ config RP2040_FLASH_MOUNT_POINT
+ string "mount point for flash file system"
+ default "/flash"
+ ---help---
+ This is the mount point where the flash file system will
+ be mounted. Leave this string empty to prevent automatic
+ mounting of the filesystem.
+
+endif # RP2040_FLASH_FILE_SYSTEM
diff --git a/arch/arm/src/rp2040/Make.defs b/arch/arm/src/rp2040/Make.defs
index e950476ed3..d2dce8f239 100644
--- a/arch/arm/src/rp2040/Make.defs
+++ b/arch/arm/src/rp2040/Make.defs
@@ -78,13 +78,17 @@ ifeq ($(CONFIG_ADC),y)
CHIP_CSRCS += rp2040_adc.c
endif
-ifeq ($(CONFIG_RP2040_FLASH_BOOT),y)
-ifneq ($(PICO_SDK_PATH),)
-include chip/boot2/Make.defs
-endif
-
ifeq ($(CONFIG_IEEE80211_INFINEON_CYW43439),y)
CHIP_CSRCS += rp2040_cyw43439.c
endif
+ifeq ($(CONFIG_RP2040_FLASH_FILE_SYSTEM),y)
+CHIP_CSRCS += rp2040_flash_mtd.c
+CHIP_ASRCS += rp2040_flash_initialize.S
+endif
+
+ifeq ($(CONFIG_RP2040_FLASH_BOOT),y)
+ifneq ($(PICO_SDK_PATH),)
+include chip/boot2/Make.defs
+endif
endif
diff --git a/arch/arm/src/rp2040/rp2040_flash_initialize.S b/arch/arm/src/rp2040/rp2040_flash_initialize.S
new file mode 100644
index 0000000000..77477623f6
--- /dev/null
+++ b/arch/arm/src/rp2040/rp2040_flash_initialize.S
@@ -0,0 +1,195 @@
+/****************************************************************************
+ * arch/arm/src/rp2040/rp2040_flash_initialize.S
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Description:
+ * The low-level format of the smart filesystem for the rp2040 consists of
+ * a series of 4096-byte blocks each of which contain four 1024 byte
+ * logical sectors. Due to the way flash works the filesystem can only
+ * erase (set to all 1 bits) a whole block. It can however, write smaller
+ * amounts. On the rp2040 the smallest write is 256 bytes. The write can
+ * only flip 1 bits to 0 -- it cannot change a 0 bit to 1.
+ *
+ * Each logical sector starts with a five byte sector header. Most sectors
+ * follow this with a five byte filesystem header. Sector zero does not
+ * follow this rule; it contains the volume label.
+ *
+ * The volume will have root directory located in logical sector three. It
+ * may have additional root directories (indicated by a count in the volume
+ * label). This will be in sequential sectors starting with sector four.
+ *
+ * Actual files and other subdirectories start in logical sector twelve.
+ *
+ * == SECTOR HEADER ==
+ *
+ * Logical sector number: 2 bytes
+ * Sequence number: 2 bytes
+ * Flags: 1 byte
+ *
+ * Flag bits are: C R X S S S V V
+ * C - Set to zero if block committed 0
+ * R - Set to zero if block erased 1
+ * X - CRC status 1
+ * S - Size Code 010
+ * V - Version code 01
+ *
+ * The logical sector number does not have to match the actual position
+ * of a sector. The volume in scanned when mounted and the mapping of
+ * sector number to position in volume is maintained in ram. If a sector
+ * is written to it will be re-written to a new location.
+ *
+ * == VOLUME LABEL ==
+ *
+ * Sector zero is the volume label. It currently consists of the
+ * following fields.
+ *
+ * Smart Volume ID: 4 bytes "SMRT"
+ * Smart version: 1 byte 0x01
+ * Sector size flag: 1 byte 0x10
+ * Extra Root Directories: 1 byte 0x00
+ *
+ * == FILE SYSTEM HEADER ==
+ *
+ * File and directory sectors have a filesystem header directly following
+ * the sector header. This filesystem header consists of:
+ *
+ * Entry type: 1 byte 0x01 = Directory, 0x02 = File.
+ * Next logical sector: 2 bytes 0xff no more sectors
+ * Number of bytes used 2 bytes 0xff empty sector
+ *
+ * == DIRECTORY ENTRIES ==
+ *
+ * Directory Flags: 2 bytes
+ *
+ * == FILE ENTRIES ==
+ *
+ * File data starts following the filesystem header and extends
+ * for a number of bytes as specified in the filesystem header.
+ *
+ * Files with a length of greater that 1019 bytes will span multiple
+ * sectors, linked with the next logical sector flag.
+ ****************************************************************************/
+
+dir= 1
+file= 2
+name_length= 16
+
+/****************************************************************************
+ * Name: sector
+ *
+ * Description:
+ * This macro defines a sector header. It actually sets both the actual
+ * sector header and the filesystem header values.
+ *
+ * Parameters:
+ * num - The logical sector number. Each sector must be unique.
+ * type - The sector type. Should be 'dir' or 'file'
+ * used - The length of the data in this sector.
+ * next - The logical sector number of the next sector in a chain.
+ ****************************************************************************/
+
+ .macro sector num, type, used=0xffff, next=0xffff
+ .balign 1024, 0xff
+ .hword \num, 0
+ .byte 0b01101001, \type
+ .hword \next, \used
+ .endm
+
+/****************************************************************************
+ * Name: dir_entry
+ *
+ * Description:
+ * This macro defines a directory entry.
+ *
+ * Parameters:
+ * perm - Permission bits for this directory entry
+ * addr - Logical sector number of named entry
+ * time - entry creation time stamp
+ * name - name of this entry
+ ****************************************************************************/
+
+ .macro dir_entry perm, addr, time, name
+ .hword \perm | 0x7e00, \addr
+ .word \time
+0:
+ .ascii "\name"
+.= 0b + name_length
+ .endm
+
+/****************************************************************************
+ * Name: file_entry
+ *
+ * Description:
+ * This macro defines a directory entry.
+ *
+ * Parameters:
+ * perm - Permission bits for this directory entry
+ * addr - Logical sector number of named entry
+ * time - entry creation time stamp
+ * name - name of this entry
+ ****************************************************************************/
+
+ .macro file_entry perm, addr, time, name
+ .hword \perm | 0x5e00, \addr
+ .word \time
+0:
+ .ascii "\name"
+.= 0b + name_length
+ .endm
+
+/****************************************************************************
+ * Global name of the initial filesystem data
+ ****************************************************************************/
+
+ .cpu cortex-m0plus
+ .thumb
+
+ .section .flash.init, "ax"
+ .balign 4096
+ .global rp2040_smart_flash_start
+rp2040_smart_flash_start:
+
+/****************************************************************************
+ * Volume Label
+ ****************************************************************************/
+
+ .ascii "2040" /* magic tag for flash initialization */
+ .byte 0b01101001
+ .ascii "SMRT"
+ .byte 0x01, 0x10, 0
+
+ .balign 4096, 0xff
+
+/****************************************************************************
+ * Root directory and initial files in the filesystem
+ ****************************************************************************/
+
+ sector 3, dir
+ file_entry 0777, 4, 0, "test"
+
+ sector 4, file, used=14
+ .ascii "Hello, world!\n"
+
+
+ .balign 4096, 0xff
+ .global rp2040_smart_flash_end
+rp2040_smart_flash_end:
+
+ .end
diff --git a/arch/arm/src/rp2040/rp2040_flash_mtd.c b/arch/arm/src/rp2040/rp2040_flash_mtd.c
new file mode 100644
index 0000000000..3dc6ea1b98
--- /dev/null
+++ b/arch/arm/src/rp2040/rp2040_flash_mtd.c
@@ -0,0 +1,569 @@
+/****************************************************************************
+ * arch/arm/src/rp2040/rp2040_flash_mtd.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * This code implements a Sector Mapped Allocation for Really Tiny (SMART)
+ * filesystem in the RP2040 flash memory chip. It uses the space not
+ * otherwise used by the NuttX binary and supports both read and write
+ * access.
+ *
+ * There initial contents of this filesystem may be configured when a NuttX
+ * binary is built (using tools/rp2040/make_flash_fs.c), but any changes
+ * subsequently written to the filesystem will persist over re-boots of the
+ * RP2040.
+ *
+ * Note: Although read access to any data stored in this filesystem is very
+ * rapid; because of how the RP2040's flash access routines work with
+ * the normal execute-in-place (XIP) access to that chip, no code can
+ * access flash in the normal manner when this filesystem is erasing
+ * or writing blocks. This means that interrupts must be disabled
+ * during any such access. The main issue with this is that any
+ * application which requires precise timing or rapid response may
+ * be negatively impacted by such operations.
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/semaphore.h>
+
+#include "rp2040_flash_mtd.h"
+#include "rp2040_rom.h"
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define XIP_BASE 0x10000000
+#define XIP_NOCACHE_NOALLOC_BASE 0x13000000
+#define FLASH_BLOCK_ERASE_CMD 0x20
+#define BOOT_2_SIZE 256
+
+#define FLASH_START_OFFSET (rp2040_smart_flash_start - (uint8_t *) XIP_BASE)
+#define FLASH_END_OFFSET (rp2040_smart_flash_end - (uint8_t *) XIP_BASE)
+#define FLASH_START_READ (rp2040_smart_flash_start + 0x03000000)
+
+/* Note: There is some ambiguity in terminology when it comes to flash.
+ * Some call the chunk that can be erased a sector where others
+ * call that a block.
+ *
+ * Some call the chunk that can be written a sector where others
+ * call that a page.
+ */
+
+/* Blocks are the smallest unit that can be erased */
+
+#define FLASH_BLOCK_SIZE (4 * 1024)
+#define FLASH_BLOCK_COUNT (CONFIG_RP2040_FLASH_LENGTH - FLASH_START_OFFSET)\
+ / FLASH_BLOCK_SIZE
+
+/* Sectors are the smallest unit that can be written */
+
+#define FLASH_SECTOR_SIZE 256
+#define FLASH_SECTOR_COUNT (CONFIG_RP2040_FLASH_LENGTH - FLASH_START_OFFSET)\
+ / FLASH_SECTOR_SIZE
+
+#ifdef CONFIG_SMP
+# define OTHER_CPU (up_cpu_index() == 0 ? 1 : 0)
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+typedef struct rp2040_flash_dev_s
+{
+ struct mtd_dev_s mtd_dev; /* Embedded mdt_dev structure */
+ sem_t sem; /* file access serialization */
+ uint32_t boot_2[BOOT_2_SIZE / 4]; /* RAM copy of boot_2 */
+} rp2040_flash_dev_t;
+
+typedef void (*connect_internal_flash_f)(void);
+typedef void (*flash_exit_xip_f)(void);
+typedef void (*flash_range_erase_f)(uint32_t, size_t, uint32_t, uint8_t);
+typedef void (*flash_range_program_f)(uint32_t, const uint8_t *, size_t);
+typedef void (*flash_flush_cache_f)(void);
+typedef void (*flash_enable_xip_f)(void);
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int rp2040_flash_erase (struct mtd_dev_s *dev,
+ off_t startblock,
+ size_t nblocks);
+
+static ssize_t rp2040_flash_block_read (struct mtd_dev_s *dev,
+ off_t startblock,
+ size_t nblocks,
+ uint8_t *buffer);
+
+static ssize_t rp2040_flash_block_write(struct mtd_dev_s *dev,
+ off_t startblock,
+ size_t nblocks,
+ const uint8_t *buffer);
+
+static ssize_t rp2040_flash_byte_read (struct mtd_dev_s *dev,
+ off_t offset,
+ size_t nbytes,
+ uint8_t *buffer);
+
+static int rp2040_flash_ioctl (struct mtd_dev_s *dev,
+ int cmd,
+ unsigned long arg);
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+extern const uint8_t rp2040_smart_flash_start[256];
+extern const uint8_t rp2040_smart_flash_end[0];
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct rp2040_flash_dev_s my_dev =
+{
+ .mtd_dev =
+ {
+ rp2040_flash_erase,
+ rp2040_flash_block_read,
+ rp2040_flash_block_write,
+ rp2040_flash_byte_read,
+#ifdef CONFIG_MTD_BYTE_WRITE
+ NULL,
+#endif
+ rp2040_flash_ioctl,
+ "rp_flash"
+ }
+};
+
+static bool initialized = false;
+
+static struct
+{
+ connect_internal_flash_f connect_internal_flash;
+ flash_exit_xip_f flash_exit_xip;
+ flash_range_erase_f flash_range_erase;
+ flash_range_program_f flash_range_program;
+ flash_flush_cache_f flash_flush_cache;
+ flash_enable_xip_f flash_enable_xip;
+} rom_functions;
+
+void *boot_2_copy = NULL;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: do_erase
+ ****************************************************************************/
+
+void RAM_CODE(do_erase)(uint32_t addr, size_t count)
+{
+ /* Note: While we would prefer not to flush the cache, the
+ * flash_flush_cache call is needed to remove CSn IO force.
+ */
+
+ __asm__ volatile ("" : : : "memory");
+
+ rom_functions.connect_internal_flash();
+
+ rom_functions.flash_exit_xip();
+
+ /* The range erase will try to erase 65536-byte blocks with the 0xd8 flash
+ * command. If it cannot, because either the addr or count are not
+ * multiple of 65536, it will fall back to erasing 4096-byte blocks as
+ * needed.
+ */
+
+ rom_functions.flash_range_erase(addr, count, 65536, 0xd8);
+
+ rom_functions.flash_flush_cache();
+
+ rom_functions.flash_enable_xip();
+}
+
+/****************************************************************************
+ * Name: do_write
+ ****************************************************************************/
+
+void RAM_CODE(do_write)(uint32_t addr, const uint8_t *data, size_t count)
+{
+ /* Note: While we would prefer not to flush the cache, the
+ * flash_flush_cache call is needed to remove CSn IO force.
+ */
+
+ __asm__ volatile ("" : : : "memory");
+
+ rom_functions.connect_internal_flash();
+
+ rom_functions.flash_exit_xip();
+
+ rom_functions.flash_range_program(addr, (uint8_t *)data, count);
+
+ rom_functions.flash_flush_cache();
+
+ rom_functions.flash_enable_xip();
+}
+
+/****************************************************************************
+ * Name: rp2040_flash_erase
+ ****************************************************************************/
+
+static int rp2040_flash_erase(struct mtd_dev_s *dev,
+ off_t startblock,
+ size_t nblocks)
+{
+ rp2040_flash_dev_t *rp_dev = (rp2040_flash_dev_t *) dev;
+ irqstate_t flags;
+ int ret = OK;
+
+ finfo("FLASH: erase block: %8u (0x%08x) count:%5u (0x%08X)\n",
+ (unsigned)(startblock),
+ (unsigned)(FLASH_BLOCK_SIZE * startblock + FLASH_START_OFFSET),
+ nblocks,
+ FLASH_BLOCK_SIZE * nblocks);
+
+ usleep(500000);
+
+ ret = nxsem_wait(&(rp_dev->sem));
+
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ flags = enter_critical_section();
+
+#ifdef CONFIG_SMP
+ up_cpu_pause(OTHER_CPU);
+#endif
+
+ do_erase(FLASH_BLOCK_SIZE * startblock + FLASH_START_OFFSET,
+ FLASH_BLOCK_SIZE * nblocks);
+
+#ifdef CONFIG_SMP
+ up_cpu_resume(OTHER_CPU);
+#endif
+
+ leave_critical_section(flags);
+
+ ret = nblocks;
+
+ nxsem_post(&(rp_dev->sem));
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: rp2040_flash_block_read
+ ****************************************************************************/
+
+static ssize_t rp2040_flash_block_read(struct mtd_dev_s *dev,
+ off_t startblock,
+ size_t nblocks,
+ uint8_t *buffer)
+{
+ rp2040_flash_dev_t *rp_dev = (rp2040_flash_dev_t *) dev;
+ int start;
+ int length;
+ int ret = OK;
+
+ ret = nxsem_wait(&(rp_dev->sem));
+
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ finfo("FLASH: read sector: %8u (0x%08x) count:%5u\n",
+ (unsigned)(startblock),
+ (unsigned)(FLASH_SECTOR_SIZE * startblock + FLASH_START_OFFSET),
+ nblocks);
+
+ start = FLASH_SECTOR_SIZE * startblock;
+ length = FLASH_SECTOR_SIZE * nblocks;
+
+ /* This reads starting at XIP_NOCACHE_NOALLOC_BASE to bypass the
+ * XIP cache. This is done because flash programming does not update
+ * the cache and we don't want to read stale data. Since we expect
+ * access to the flash filesystem to be rather infrequent this isn't
+ * really much of a burden.
+ */
+
+ memcpy(buffer, FLASH_START_READ + start, length);
+
+ /* Update the file position */
+
+ nxsem_post(&(rp_dev->sem));
+
+ return nblocks;
+}
+
+/****************************************************************************
+ * Name: rp2040_flash_write
+ ****************************************************************************/
+
+static ssize_t rp2040_flash_block_write(struct mtd_dev_s *dev,
+ off_t startblock,
+ size_t nblocks,
+ const uint8_t *buffer)
+{
+ rp2040_flash_dev_t *rp_dev = (rp2040_flash_dev_t *) dev;
+ irqstate_t flags;
+ int ret = OK;
+
+ ret = nxsem_wait(&(rp_dev->sem));
+
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ flags = enter_critical_section();
+
+#ifdef CONFIG_SMP
+ up_cpu_pause(OTHER_CPU);
+#endif
+
+ do_write(FLASH_SECTOR_SIZE * startblock + FLASH_START_OFFSET,
+ buffer,
+ FLASH_SECTOR_SIZE * nblocks);
+
+#ifdef CONFIG_SMP
+ up_cpu_resume(OTHER_CPU);
+#endif
+
+ leave_critical_section(flags);
+
+ finfo("FLASH: write sector: %8u (0x%08x) count:%5u\n",
+ (unsigned)(startblock),
+ (unsigned)(FLASH_SECTOR_SIZE * startblock + FLASH_START_OFFSET),
+ nblocks);
+
+#ifdef CONFIG_DEBUG_FS_INFO
+ for (int i = 0; i < FLASH_SECTOR_SIZE * nblocks; i += 16)
+ {
+ for (int j = 0; j < 16; ++j)
+ {
+ printf("%02x, ", buffer[i + j]);
+ }
+
+ printf("\n");
+ }
+#endif
+
+ ret = nblocks;
+
+ nxsem_post(&(rp_dev->sem));
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: rp2040_flash_byte_read
+ ****************************************************************************/
+
+static ssize_t rp2040_flash_byte_read (struct mtd_dev_s *dev,
+ off_t offset,
+ size_t nbytes,
+ uint8_t *buffer)
+{
+ rp2040_flash_dev_t *rp_dev = (rp2040_flash_dev_t *) dev;
+ int length;
+ int ret = OK;
+
+ ret = nxsem_wait(&(rp_dev->sem));
+
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ length = nbytes;
+
+ finfo("FLASH: read bytes: %8u (0x%08x) count:%5u\n",
+ (unsigned)(offset),
+ (unsigned)(offset + FLASH_START_OFFSET),
+ nbytes);
+
+ /* This reads starting at XIP_NOCACHE_NOALLOC_BASE to bypass the
+ * XIP cache. This is done because flash programming does not update
+ * the cache and we don't want to read stale data. Since we expect
+ * access to the flash filesystem to be rather infrequent this isn't
+ * really much of a burden.
+ */
+
+ memcpy(buffer, FLASH_START_READ + offset, length);
+
+#ifdef CONFIG_DEBUG_FS_INFO
+ for (int j = 0; j < 16 && j < nbytes; ++j)
+ {
+ printf("%02x, ", buffer[j]);
+ }
+
+ printf("\n");
+#endif
+
+ /* Update the file position */
+
+ nxsem_post(&(rp_dev->sem));
+
+ return length;
+}
+
+/****************************************************************************
+ * Name: rp2040_flash_ioctl
+ ****************************************************************************/
+
+static int rp2040_flash_ioctl(struct mtd_dev_s *dev,
+ int cmd,
+ unsigned long arg)
+{
+ rp2040_flash_dev_t *rp_dev = (rp2040_flash_dev_t *) dev;
+ int ret = OK;
+
+ UNUSED(rp_dev);
+
+ switch (cmd)
+ {
+ case MTDIOC_GEOMETRY:
+ {
+ struct mtd_geometry_s *geo = (struct mtd_geometry_s *) arg;
+
+ if (geo != NULL)
+ {
+ geo->blocksize = FLASH_SECTOR_SIZE;
+ geo->erasesize = FLASH_BLOCK_SIZE;
+ geo->neraseblocks = FLASH_BLOCK_COUNT;
+ }
+
+ break;
+ }
+
+ case MTDIOC_BULKERASE:
+ {
+ /* Erase all the filesystem blocks for the device. Remember that
+ * we share this device with XIP memory so we cannot erase entire
+ * device.
+ */
+
+ ret = rp2040_flash_erase(dev, 0, FLASH_BLOCK_COUNT);
+
+ break;
+ }
+
+ default:
+ ret = -ENOTTY;
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rp2040_flash_initialize
+ *
+ * Description: Bind a block mode driver that uses the built-in rp2040
+ * flash programming commands for read/write access to unused flash.
+ ****************************************************************************/
+
+struct mtd_dev_s *rp2040_flash_mtd_initialize(void)
+{
+ if (initialized)
+ {
+ errno = EBUSY;
+ return NULL;
+ }
+
+ initialized = true;
+
+ nxsem_init(&(my_dev.sem), 0, 1);
+
+ if (FLASH_BLOCK_COUNT < 4)
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ rom_functions.connect_internal_flash = ROM_LOOKUP(ROM_FLASH_CONNECT);
+ rom_functions.flash_exit_xip = ROM_LOOKUP(ROM_FLASH_EXIT_XIP);
+ rom_functions.flash_range_erase = ROM_LOOKUP(ROM_FLASH_ERASE);
+ rom_functions.flash_range_program = ROM_LOOKUP(ROM_FLASH_PROGRAM);
+ rom_functions.flash_flush_cache = ROM_LOOKUP(ROM_FLASH_FLUSH_CACHE);
+
+ /* Instead of using the rom_function for flash_enable_xip, we use the one
+ * from boot stage 2 loaded at the beginning of the XIP rom. We do this
+ * because the boot_rom version can result in slower access to the the
+ * XIP memory.
+ *
+ * We need to make our own copy of this code in ram since we cannot use
+ * the rom until after this call completes.
+ */
+
+ memcpy(my_dev.boot_2, (void *) XIP_BASE, BOOT_2_SIZE);
+ rom_functions.flash_enable_xip = (flash_enable_xip_f)my_dev.boot_2 + 1;
+
+ /* Do we need to initialize the flash? */
+
+ if (memcmp(rp2040_smart_flash_start, "2040", 4) == 0)
+ {
+ uint8_t buffer[FLASH_SECTOR_SIZE];
+ irqstate_t flags = enter_critical_section();
+
+ /* OK, we found the "magic" tag... */
+
+ /* Erase all flash beyond what was loaded from NuttX binary. */
+
+ do_erase(FLASH_END_OFFSET,
+ CONFIG_RP2040_FLASH_LENGTH - FLASH_END_OFFSET);
+
+ /* Erase the "magic" flag, setting the first two bytes to zero. */
+
+ memcpy(buffer, rp2040_smart_flash_start, FLASH_SECTOR_SIZE);
+
+ buffer[0] = 0;
+ buffer[1] = 0;
+
+ do_write(FLASH_START_OFFSET, buffer, FLASH_SECTOR_SIZE);
+
+ leave_critical_section(flags);
+ }
+
+ return &(my_dev.mtd_dev);
+}
diff --git a/arch/arm/src/rp2040/rp2040_flash_mtd.h b/arch/arm/src/rp2040/rp2040_flash_mtd.h
new file mode 100644
index 0000000000..b83b451014
--- /dev/null
+++ b/arch/arm/src/rp2040/rp2040_flash_mtd.h
@@ -0,0 +1,35 @@
+/****************************************************************************
+ * arch/arm/src/rp2040/rp2040_flash_mtd.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/mtd/mtd.h>
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: rp2040_flash_mtd_initialize
+ ****************************************************************************/
+
+struct mtd_dev_s *rp2040_flash_mtd_initialize(void);
diff --git a/arch/arm/src/rp2040/rp2040_rom.h b/arch/arm/src/rp2040/rp2040_rom.h
new file mode 100644
index 0000000000..b12f85d400
--- /dev/null
+++ b/arch/arm/src/rp2040/rp2040_rom.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+ * arch/arm/src/rp2040/rp2040_rom.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define ROM_HWORD_AS_PTR(a) ((void *)(uintptr_t) (*(uint16_t *)(uintptr_t)a))
+
+#define ROM_CODE(a,b) ((b << 8) | a)
+
+#define ROM_POPCOUNT32 ROM_CODE('P', '3')
+#define ROM_REVERSE32 ROM_CODE('R', '3')
+#define ROM_CLZ32 ROM_CODE('L', '3')
+#define ROM_CTZ32 ROM_CODE('T', '3')
+#define ROM_MEMSET ROM_CODE('M', 'S')
+#define ROM_MEMSET4 ROM_CODE('S', '4')
+#define ROM_MEMCPY ROM_CODE('M', 'C')
+#define ROM_MEMCPY44 ROM_CODE('C', '4')
+#define ROM_RESET_USB_BOOT ROM_CODE('U', 'B')
+#define ROM_FLASH_CONNECT ROM_CODE('I', 'F')
+#define ROM_FLASH_EXIT_XIP ROM_CODE('E', 'X')
+#define ROM_FLASH_ERASE ROM_CODE('R', 'E')
+#define ROM_FLASH_PROGRAM ROM_CODE('R', 'P')
+#define ROM_FLASH_FLUSH_CACHE ROM_CODE('F', 'C')
+#define ROM_FLASH_ENABLE_XIP ROM_CODE('C', 'X')
+
+#define ROM_LOOKUP(x) \
+ ((rom_table_lookup_fn)ROM_HWORD_AS_PTR(0x18)) \
+ (ROM_HWORD_AS_PTR(0x14),x)
+
+#define STR(s) #s
+#define RAM_CODE_ATTR(f) __attribute__((noinline, section(".ram_code." f)))
+#define RAM_CODE(f) RAM_CODE_ATTR(STR(f)) f
+
+/****************************************************************************
+ * Public Type Definitions
+ ****************************************************************************/
+
+typedef void *(*rom_table_lookup_fn)(uint16_t *table, uint32_t code);
diff --git a/boards/arm/rp2040/adafruit-feather-rp2040/README.txt b/boards/arm/rp2040/adafruit-feather-rp2040/README.txt
index c289a627f2..80f2a72af0 100644
--- a/boards/arm/rp2040/adafruit-feather-rp2040/README.txt
+++ b/boards/arm/rp2040/adafruit-feather-rp2040/README.txt
@@ -71,6 +71,9 @@ Defconfigs
- nsh
Minimum configuration with NuttShell
+- nsh_flash
+ NuttX shell with SMART flash filesystem.
+
- nshsram
Load NuttX binary to SRAM
diff --git a/boards/arm/rp2040/adafruit-feather-rp2040/configs/nsh-flash/defconfig b/boards/arm/rp2040/adafruit-feather-rp2040/configs/nsh-flash/defconfig
new file mode 100644
index 0000000000..4ca63ed1df
--- /dev/null
+++ b/boards/arm/rp2040/adafruit-feather-rp2040/configs/nsh-flash/defconfig
@@ -0,0 +1,54 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_FS_PROCFS_EXCLUDE_ENVIRON is not set
+# CONFIG_LIBC_LONG_LONG is not set
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+# CONFIG_NSH_DISABLE_DATE is not set
+# CONFIG_STANDARD_SERIAL is not set
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="adafruit-feather-rp2040"
+CONFIG_ARCH_BOARD_ADAFRUIT_FEATHER_RP2040=y
+CONFIG_ARCH_CHIP="rp2040"
+CONFIG_ARCH_CHIP_RP2040=y
+CONFIG_ARCH_RAMVECTORS=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=10450
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DISABLE_POSIX_TIMERS=y
+CONFIG_EXAMPLES_HELLO=y
+CONFIG_FS_PROCFS=y
+CONFIG_FS_PROCFS_REGISTER=y
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_READLINE=y
+CONFIG_RAM_SIZE=270336
+CONFIG_RAM_START=0x20000000
+CONFIG_READLINE_CMD_HISTORY=y
+CONFIG_RP2040_BOARD_HAS_WS2812=y
+CONFIG_RP2040_FLASH_FILE_SYSTEM=y
+CONFIG_RP2040_FLASH_LENGTH=8388608
+CONFIG_RP2040_WS2812_GPIO_PIN=16
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_WAITPID=y
+CONFIG_SMARTFS_ALIGNED_ACCESS=y
+CONFIG_START_DAY=9
+CONFIG_START_MONTH=2
+CONFIG_START_YEAR=2021
+CONFIG_SYSLOG_CONSOLE=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_TESTING_SMART_TEST=y
+CONFIG_UART0_SERIAL_CONSOLE=y
+CONFIG_WS2812=y
diff --git a/boards/arm/rp2040/adafruit-feather-rp2040/scripts/adafruit-feather-rp2040-flash.ld b/boards/arm/rp2040/adafruit-feather-rp2040/scripts/adafruit-feather-rp2040-flash.ld
index 28c31bacc2..e7adceaf6b 100644
--- a/boards/arm/rp2040/adafruit-feather-rp2040/scripts/adafruit-feather-rp2040-flash.ld
+++ b/boards/arm/rp2040/adafruit-feather-rp2040/scripts/adafruit-feather-rp2040-flash.ld
@@ -82,11 +82,17 @@ SECTIONS
_sdata = ABSOLUTE(.);
*(.data .data.*)
*(.gnu.linkonce.d.*)
+ *(.ram_code.*)
CONSTRUCTORS
. = ALIGN(4);
_edata = ABSOLUTE(.);
} > sram AT > flash
+ .flash_section : {
+ . = ALIGN(4*1024);
+ *(.flash.*)
+ } > flash
+
.bss : {
_sbss = ABSOLUTE(.);
*(.bss .bss.*)
diff --git a/boards/arm/rp2040/adafruit-feather-rp2040/scripts/adafruit-feather-rp2040-sram.ld b/boards/arm/rp2040/adafruit-feather-rp2040/scripts/adafruit-feather-rp2040-sram.ld
index ba1b19945c..f607b392cc 100644
--- a/boards/arm/rp2040/adafruit-feather-rp2040/scripts/adafruit-feather-rp2040-sram.ld
+++ b/boards/arm/rp2040/adafruit-feather-rp2040/scripts/adafruit-feather-rp2040-sram.ld
@@ -20,6 +20,7 @@
MEMORY
{
+ flash (rx) : ORIGIN = 0x10000000, LENGTH = 8192K
sram (rwx) : ORIGIN = 0x20000000, LENGTH = 264K
}
@@ -67,11 +68,17 @@ SECTIONS
_sdata = ABSOLUTE(.);
*(.data .data.*)
*(.gnu.linkonce.d.*)
+ *(.ram_code.*)
CONSTRUCTORS
. = ALIGN(4);
_edata = ABSOLUTE(.);
} > sram
+ .flash_section : {
+ . = ALIGN(4*1024);
+ *(.flash.*)
+ } > flash
+
.bss : {
_sbss = ABSOLUTE(.);
*(.bss .bss.*)
diff --git a/boards/arm/rp2040/adafruit-kb2040/README.txt b/boards/arm/rp2040/adafruit-kb2040/README.txt
index 7451e2cfd3..4c725d2166 100644
--- a/boards/arm/rp2040/adafruit-kb2040/README.txt
+++ b/boards/arm/rp2040/adafruit-kb2040/README.txt
@@ -70,6 +70,9 @@ Defconfigs
- nsh
Minimum configuration with NuttShell
+- nsh_flash
+ NuttX shell with SMART flash filesystem.
+
- nshsram
Load NuttX binary to SRAM
diff --git a/boards/arm/rp2040/adafruit-kb2040/configs/nsh-flash/defconfig b/boards/arm/rp2040/adafruit-kb2040/configs/nsh-flash/defconfig
new file mode 100644
index 0000000000..322969f593
--- /dev/null
+++ b/boards/arm/rp2040/adafruit-kb2040/configs/nsh-flash/defconfig
@@ -0,0 +1,54 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_FS_PROCFS_EXCLUDE_ENVIRON is not set
+# CONFIG_LIBC_LONG_LONG is not set
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+# CONFIG_NSH_DISABLE_DATE is not set
+# CONFIG_STANDARD_SERIAL is not set
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="adafruit-kb2040"
+CONFIG_ARCH_BOARD_ADAFRUIT_KB2040=y
+CONFIG_ARCH_CHIP="rp2040"
+CONFIG_ARCH_CHIP_RP2040=y
+CONFIG_ARCH_RAMVECTORS=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=10450
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DISABLE_POSIX_TIMERS=y
+CONFIG_EXAMPLES_HELLO=y
+CONFIG_FS_PROCFS=y
+CONFIG_FS_PROCFS_REGISTER=y
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_READLINE=y
+CONFIG_RAM_SIZE=270336
+CONFIG_RAM_START=0x20000000
+CONFIG_READLINE_CMD_HISTORY=y
+CONFIG_RP2040_BOARD_HAS_WS2812=y
+CONFIG_RP2040_FLASH_FILE_SYSTEM=y
+CONFIG_RP2040_FLASH_LENGTH=8388608
+CONFIG_RP2040_WS2812_GPIO_PIN=17
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_WAITPID=y
+CONFIG_SMARTFS_ALIGNED_ACCESS=y
+CONFIG_START_DAY=9
+CONFIG_START_MONTH=2
+CONFIG_START_YEAR=2021
+CONFIG_SYSLOG_CONSOLE=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_TESTING_SMART_TEST=y
+CONFIG_UART0_SERIAL_CONSOLE=y
+CONFIG_WS2812=y
diff --git a/boards/arm/rp2040/adafruit-kb2040/scripts/adafruit-kb2040-flash.ld b/boards/arm/rp2040/adafruit-kb2040/scripts/adafruit-kb2040-flash.ld
index f30276ace0..1a8103198b 100644
--- a/boards/arm/rp2040/adafruit-kb2040/scripts/adafruit-kb2040-flash.ld
+++ b/boards/arm/rp2040/adafruit-kb2040/scripts/adafruit-kb2040-flash.ld
@@ -82,11 +82,17 @@ SECTIONS
_sdata = ABSOLUTE(.);
*(.data .data.*)
*(.gnu.linkonce.d.*)
+ *(.ram_code.*)
CONSTRUCTORS
. = ALIGN(4);
_edata = ABSOLUTE(.);
} > sram AT > flash
+ .flash_section : {
+ . = ALIGN(4*1024);
+ *(.flash.*)
+ } > flash
+
.bss : {
_sbss = ABSOLUTE(.);
*(.bss .bss.*)
diff --git a/boards/arm/rp2040/adafruit-kb2040/scripts/adafruit-kb2040-sram.ld b/boards/arm/rp2040/adafruit-kb2040/scripts/adafruit-kb2040-sram.ld
index b350bfb5f1..a1d8631350 100644
--- a/boards/arm/rp2040/adafruit-kb2040/scripts/adafruit-kb2040-sram.ld
+++ b/boards/arm/rp2040/adafruit-kb2040/scripts/adafruit-kb2040-sram.ld
@@ -20,6 +20,7 @@
MEMORY
{
+ flash (rx) : ORIGIN = 0x10000000, LENGTH = 8192K
sram (rwx) : ORIGIN = 0x20000000, LENGTH = 264K
}
@@ -67,11 +68,17 @@ SECTIONS
_sdata = ABSOLUTE(.);
*(.data .data.*)
*(.gnu.linkonce.d.*)
+ *(.ram_code.*)
CONSTRUCTORS
. = ALIGN(4);
_edata = ABSOLUTE(.);
} > sram
+ .flash_section : {
+ . = ALIGN(4*1024);
+ *(.flash.*)
+ } > flash
+
.bss : {
_sbss = ABSOLUTE(.);
*(.bss .bss.*)
diff --git a/boards/arm/rp2040/adafruit-qt-py-rp2040/README.txt b/boards/arm/rp2040/adafruit-qt-py-rp2040/README.txt
index d6add66f0d..039eb52964 100644
--- a/boards/arm/rp2040/adafruit-qt-py-rp2040/README.txt
+++ b/boards/arm/rp2040/adafruit-qt-py-rp2040/README.txt
@@ -65,6 +65,9 @@ Defconfigs
- nsh
Minimum configuration with NuttShell
+- nsh_flash
+ NuttX shell with SMART flash filesystem.
+
- nshsram
Load NuttX binary to SRAM
diff --git a/boards/arm/rp2040/adafruit-qt-py-rp2040/configs/nsh-flash/defconfig b/boards/arm/rp2040/adafruit-qt-py-rp2040/configs/nsh-flash/defconfig
new file mode 100644
index 0000000000..b4523bbc37
--- /dev/null
+++ b/boards/arm/rp2040/adafruit-qt-py-rp2040/configs/nsh-flash/defconfig
@@ -0,0 +1,57 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_FS_PROCFS_EXCLUDE_ENVIRON is not set
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+# CONFIG_NSH_DISABLE_DATE is not set
+# CONFIG_RP2040_UART0 is not set
+# CONFIG_STANDARD_SERIAL is not set
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="adafruit-qt-py-rp2040"
+CONFIG_ARCH_BOARD_ADAFRUIT_QT_PY_RP2040=y
+CONFIG_ARCH_CHIP="rp2040"
+CONFIG_ARCH_CHIP_RP2040=y
+CONFIG_ARCH_RAMVECTORS=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=10450
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DISABLE_POSIX_TIMERS=y
+CONFIG_EXAMPLES_HELLO=y
+CONFIG_FS_PROCFS=y
+CONFIG_FS_PROCFS_REGISTER=y
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_READLINE=y
+CONFIG_RAM_SIZE=270336
+CONFIG_RAM_START=0x20000000
+CONFIG_READLINE_CMD_HISTORY=y
+CONFIG_RP2040_BOARD_HAS_WS2812=y
+CONFIG_RP2040_FLASH_FILE_SYSTEM=y
+CONFIG_RP2040_FLASH_LENGTH=8388608
+CONFIG_RP2040_UART1=y
+CONFIG_RP2040_UART1_RX_GPIO=5
+CONFIG_RP2040_WS2812_GPIO_PIN=12
+CONFIG_RP2040_WS2812_PWR_GPIO=11
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_WAITPID=y
+CONFIG_SMARTFS_ALIGNED_ACCESS=y
+CONFIG_START_DAY=9
+CONFIG_START_MONTH=2
+CONFIG_START_YEAR=2021
+CONFIG_SYSLOG_CONSOLE=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_TESTING_SMART_TEST=y
+CONFIG_UART1_SERIAL_CONSOLE=y
+CONFIG_WS2812=y
diff --git a/boards/arm/rp2040/adafruit-qt-py-rp2040/scripts/adafruit-qt-py-rp2040-flash.ld b/boards/arm/rp2040/adafruit-qt-py-rp2040/scripts/adafruit-qt-py-rp2040-flash.ld
index 9fc8ee22a4..5c65d96751 100644
--- a/boards/arm/rp2040/adafruit-qt-py-rp2040/scripts/adafruit-qt-py-rp2040-flash.ld
+++ b/boards/arm/rp2040/adafruit-qt-py-rp2040/scripts/adafruit-qt-py-rp2040-flash.ld
@@ -82,11 +82,17 @@ SECTIONS
_sdata = ABSOLUTE(.);
*(.data .data.*)
*(.gnu.linkonce.d.*)
+ *(.ram_code.*)
CONSTRUCTORS
. = ALIGN(4);
_edata = ABSOLUTE(.);
} > sram AT > flash
+ .flash_section : {
+ . = ALIGN(4*1024);
+ *(.flash.*)
+ } > flash
+
.bss : {
_sbss = ABSOLUTE(.);
*(.bss .bss.*)
diff --git a/boards/arm/rp2040/adafruit-qt-py-rp2040/scripts/adafruit-qt-py-rp2040-sram.ld b/boards/arm/rp2040/adafruit-qt-py-rp2040/scripts/adafruit-qt-py-rp2040-sram.ld
index 7b559bf00c..b7ffd7b3c9 100644
--- a/boards/arm/rp2040/adafruit-qt-py-rp2040/scripts/adafruit-qt-py-rp2040-sram.ld
+++ b/boards/arm/rp2040/adafruit-qt-py-rp2040/scripts/adafruit-qt-py-rp2040-sram.ld
@@ -20,6 +20,7 @@
MEMORY
{
+ flash (rx) : ORIGIN = 0x10000000, LENGTH = 8192K
sram (rwx) : ORIGIN = 0x20000000, LENGTH = 264K
}
@@ -67,11 +68,17 @@ SECTIONS
_sdata = ABSOLUTE(.);
*(.data .data.*)
*(.gnu.linkonce.d.*)
+ *(.ram_code.*)
CONSTRUCTORS
. = ALIGN(4);
_edata = ABSOLUTE(.);
} > sram
+ .flash_section : {
+ . = ALIGN(4*1024);
+ *(.flash.*)
+ } > flash
+
.bss : {
_sbss = ABSOLUTE(.);
*(.bss .bss.*)
diff --git a/boards/arm/rp2040/common/Kconfig b/boards/arm/rp2040/common/Kconfig
index 0c95ae9b8f..aa69c90c1a 100644
--- a/boards/arm/rp2040/common/Kconfig
+++ b/boards/arm/rp2040/common/Kconfig
@@ -475,7 +475,6 @@ if RP2040_I2S
endif # RP2040_I2S
-
#####################################################################
# WS2812 Configuration
#####################################################################
@@ -501,3 +500,17 @@ if RP2040_BOARD_HAS_WS2812
such a pin.
endif # RP2040_BOARD_HAS_WS2812
+
+#####################################################################
+# FLASH File System Configuration
+#####################################################################
+
+if RP2040_FLASH_FILE_SYSTEM
+
+ config RP2040_FLASH_LENGTH
+ int "Size of flash memory in bytes."
+ default 2097152
+ ---help---
+ This is the overall amount of flash memory on the board.
+
+endif # RP2040_FLASH_FILE_SYSTEM
diff --git a/boards/arm/rp2040/common/src/rp2040_common_bringup.c b/boards/arm/rp2040/common/src/rp2040_common_bringup.c
index 15d40a0f78..bfdbea5256 100644
--- a/boards/arm/rp2040/common/src/rp2040_common_bringup.c
+++ b/boards/arm/rp2040/common/src/rp2040_common_bringup.c
@@ -27,6 +27,8 @@
#include <debug.h>
#include <errno.h>
#include <stddef.h>
+#include <string.h>
+#include <sys/stat.h>
#include <nuttx/fs/fs.h>
@@ -74,6 +76,14 @@
#include "rp2040_ws2812.h"
#endif
+#if defined(CONFIG_RP2040_ROMFS_ROMDISK_DEVNAME)
+# include <rp2040_romfsimg.h>
+#endif
+
+#ifdef CONFIG_RP2040_FLASH_FILE_SYSTEM
+# include "rp2040_flash_mtd.h"
+#endif
+
#ifdef CONFIG_WS2812_HAS_WHITE
#define HAS_WHITE true
#else /* CONFIG_WS2812_HAS_WHITE */
@@ -92,6 +102,10 @@ int rp2040_common_bringup(void)
{
int ret = 0;
+#ifdef CONFIG_RP2040_FLASH_FILE_SYSTEM
+ struct mtd_dev_s *mtd_dev;
+#endif
+
#ifdef CONFIG_RP2040_I2C_DRIVER
#ifdef CONFIG_RP2040_I2C0
ret = board_i2cdev_initialize(0);
@@ -570,5 +584,76 @@ int rp2040_common_bringup(void)
}
#endif
+#ifdef CONFIG_RP2040_FLASH_FILE_SYSTEM
+
+ mtd_dev = rp2040_flash_mtd_initialize();
+
+ if (mtd_dev == NULL)
+ {
+ syslog(LOG_ERR, "ERROR: flash_mtd_initialize failed: %d\n", errno);
+ }
+ else
+ {
+ ret = smart_initialize(0, mtd_dev, NULL);
+
+ if (ret < 0)
+ {
+ syslog(LOG_ERR, "ERROR: smart_initialize failed: %d\n", -ret);
+ }
+ else if (strlen(CONFIG_RP2040_FLASH_MOUNT_POINT) > 0)
+ {
+ mkdir(CONFIG_RP2040_FLASH_MOUNT_POINT, 0777);
+
+ /* Mount the file system */
+
+ ret = nx_mount("/dev/smart0",
+ CONFIG_RP2040_FLASH_MOUNT_POINT,
+ "smartfs",
+ 0,
+ NULL);
+ if (ret < 0)
+ {
+ syslog(LOG_ERR,
+ "ERROR: nx_mount(\"/dev/smart0\", \"%s\", \"smartfs\","
+ " 0, NULL) failed: %d\n",
+ CONFIG_RP2040_FLASH_MOUNT_POINT,
+ ret);
+ }
+ }
+ }
+
+#endif
+
+#if defined(CONFIG_RP2040_ROMFS_ROMDISK_DEVNAME)
+ /* Register the ROM disk */
+
+ ret = romdisk_register(CONFIG_RP2040_ROMFS_ROMDISK_MINOR,
+ rp2040_romfs_img,
+ NSECTORS(rp2040_romfs_img_len),
+ CONFIG_RP2040_ROMFS_ROMDISK_SECTSIZE);
+ if (ret < 0)
+ {
+ syslog(LOG_ERR, "ERROR: romdisk_register failed: %d\n", -ret);
+ }
+ else
+ {
+ /* Mount the file system */
+
+ ret = nx_mount(CONFIG_RP2040_ROMFS_ROMDISK_DEVNAME,
+ CONFIG_RP2040_ROMFS_MOUNT_MOUNTPOINT,
+ "romfs",
+ MS_RDONLY,
+ NULL);
+ if (ret < 0)
+ {
+ syslog(LOG_ERR,
+ "ERROR: nx_mount(%s,%s,romfs) failed: %d\n",
+ CONFIG_RP2040_ROMFS_ROMDISK_DEVNAME,
+ CONFIG_RP2040_ROMFS_MOUNT_MOUNTPOINT,
+ ret);
+ }
+ }
+
+#endif
return OK;
}
diff --git a/boards/arm/rp2040/pimoroni-tiny2040/README.txt b/boards/arm/rp2040/pimoroni-tiny2040/README.txt
index 12af598c3d..4eb1ab821c 100644
--- a/boards/arm/rp2040/pimoroni-tiny2040/README.txt
+++ b/boards/arm/rp2040/pimoroni-tiny2040/README.txt
@@ -69,6 +69,9 @@ Defconfigs
- nsh
Minimum configuration with NuttShell
+- nsh_flash
+ NuttX shell with SMART flash filesystem.
+
- nshsram
Load NuttX binary to SRAM
diff --git a/boards/arm/rp2040/pimoroni-tiny2040/configs/nsh-flash/defconfig b/boards/arm/rp2040/pimoroni-tiny2040/configs/nsh-flash/defconfig
new file mode 100644
index 0000000000..03d8ae784e
--- /dev/null
+++ b/boards/arm/rp2040/pimoroni-tiny2040/configs/nsh-flash/defconfig
@@ -0,0 +1,53 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_FS_PROCFS_EXCLUDE_ENVIRON is not set
+# CONFIG_LIBC_LONG_LONG is not set
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+# CONFIG_NSH_DISABLE_DATE is not set
+# CONFIG_STANDARD_SERIAL is not set
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="pimoroni-tiny2040"
+CONFIG_ARCH_BOARD_PIMORONI_TINY2040=y
+CONFIG_ARCH_CHIP="rp2040"
+CONFIG_ARCH_CHIP_RP2040=y
+CONFIG_ARCH_COVERAGE=y
+CONFIG_ARCH_RAMVECTORS=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=10450
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DISABLE_POSIX_TIMERS=y
+CONFIG_EXAMPLES_HELLO=y
+CONFIG_FS_PROCFS=y
+CONFIG_FS_PROCFS_REGISTER=y
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_READLINE=y
+CONFIG_RAM_SIZE=270336
+CONFIG_RAM_START=0x20000000
+CONFIG_READLINE_CMD_HISTORY=y
+CONFIG_RP2040_FLASH_FILE_SYSTEM=y
+CONFIG_RP2040_FLASH_LENGTH=8388608
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_WAITPID=y
+CONFIG_SMARTFS_ALIGNED_ACCESS=y
+CONFIG_START_DAY=11
+CONFIG_START_MONTH=12
+CONFIG_START_YEAR=2021
+CONFIG_SYSLOG_CONSOLE=y
+CONFIG_SYSTEM_GCOV=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_TESTING_SMART_TEST=y
+CONFIG_UART0_SERIAL_CONSOLE=y
diff --git a/boards/arm/rp2040/pimoroni-tiny2040/scripts/pimoroni-tiny2040-flash.ld b/boards/arm/rp2040/pimoroni-tiny2040/scripts/pimoroni-tiny2040-flash.ld
index 278777d5de..51b985467c 100644
--- a/boards/arm/rp2040/pimoroni-tiny2040/scripts/pimoroni-tiny2040-flash.ld
+++ b/boards/arm/rp2040/pimoroni-tiny2040/scripts/pimoroni-tiny2040-flash.ld
@@ -82,11 +82,17 @@ SECTIONS
_sdata = ABSOLUTE(.);
*(.data .data.*)
*(.gnu.linkonce.d.*)
+ *(.ram_code.*)
CONSTRUCTORS
. = ALIGN(4);
_edata = ABSOLUTE(.);
} > sram AT > flash
+ .flash_section : {
+ . = ALIGN(4*1024);
+ *(.flash.*)
+ } > flash
+
.bss : {
_sbss = ABSOLUTE(.);
*(.bss .bss.*)
diff --git a/boards/arm/rp2040/pimoroni-tiny2040/scripts/pimoroni-tiny2040-sram.ld b/boards/arm/rp2040/pimoroni-tiny2040/scripts/pimoroni-tiny2040-sram.ld
index bd69cdfe23..6864dee749 100644
--- a/boards/arm/rp2040/pimoroni-tiny2040/scripts/pimoroni-tiny2040-sram.ld
+++ b/boards/arm/rp2040/pimoroni-tiny2040/scripts/pimoroni-tiny2040-sram.ld
@@ -20,6 +20,7 @@
MEMORY
{
+ flash (rx) : ORIGIN = 0x10000000, LENGTH = 8192K
sram (rwx) : ORIGIN = 0x20000000, LENGTH = 264K
}
@@ -67,11 +68,17 @@ SECTIONS
_sdata = ABSOLUTE(.);
*(.data .data.*)
*(.gnu.linkonce.d.*)
+ *(.ram_code.*)
CONSTRUCTORS
. = ALIGN(4);
_edata = ABSOLUTE(.);
} > sram
+ .flash_section : {
+ . = ALIGN(4*1024);
+ *(.flash.*)
+ } > flash
+
.bss : {
_sbss = ABSOLUTE(.);
*(.bss .bss.*)
diff --git a/boards/arm/rp2040/raspberrypi-pico-w/README.txt b/boards/arm/rp2040/raspberrypi-pico-w/README.txt
index b0a96277ee..1757187c4d 100644
--- a/boards/arm/rp2040/raspberrypi-pico-w/README.txt
+++ b/boards/arm/rp2040/raspberrypi-pico-w/README.txt
@@ -72,6 +72,9 @@ Defconfigs
- nsh
Minimum configuration with NuttShell
+- nsh_flash
+ NuttX shell with SMART flash filesystem.
+
- nshsram
Load NuttX binary to SRAM
diff --git a/boards/arm/rp2040/raspberrypi-pico-w/configs/nsh-flash/defconfig b/boards/arm/rp2040/raspberrypi-pico-w/configs/nsh-flash/defconfig
new file mode 100644
index 0000000000..5441ec96cb
--- /dev/null
+++ b/boards/arm/rp2040/raspberrypi-pico-w/configs/nsh-flash/defconfig
@@ -0,0 +1,50 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_FS_PROCFS_EXCLUDE_ENVIRON is not set
+# CONFIG_LIBC_LONG_LONG is not set
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+# CONFIG_NSH_DISABLE_DATE is not set
+# CONFIG_STANDARD_SERIAL is not set
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="raspberrypi-pico-w"
+CONFIG_ARCH_BOARD_RASPBERRYPI_PICO_W=y
+CONFIG_ARCH_CHIP="rp2040"
+CONFIG_ARCH_CHIP_RP2040=y
+CONFIG_ARCH_RAMVECTORS=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=10450
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DISABLE_POSIX_TIMERS=y
+CONFIG_EXAMPLES_HELLO=y
+CONFIG_FS_PROCFS=y
+CONFIG_FS_PROCFS_REGISTER=y
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_READLINE=y
+CONFIG_RAM_SIZE=270336
+CONFIG_RAM_START=0x20000000
+CONFIG_READLINE_CMD_HISTORY=y
+CONFIG_RP2040_FLASH_FILE_SYSTEM=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_WAITPID=y
+CONFIG_SMARTFS_ALIGNED_ACCESS=y
+CONFIG_START_DAY=9
+CONFIG_START_MONTH=2
+CONFIG_START_YEAR=2021
+CONFIG_SYSLOG_CONSOLE=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_TESTING_SMART_TEST=y
+CONFIG_UART0_SERIAL_CONSOLE=y
diff --git a/boards/arm/rp2040/raspberrypi-pico-w/scripts/raspberrypi-pico-flash.ld b/boards/arm/rp2040/raspberrypi-pico-w/scripts/raspberrypi-pico-flash.ld
index f370cca326..82de4b749a 100644
--- a/boards/arm/rp2040/raspberrypi-pico-w/scripts/raspberrypi-pico-flash.ld
+++ b/boards/arm/rp2040/raspberrypi-pico-w/scripts/raspberrypi-pico-flash.ld
@@ -82,11 +82,17 @@ SECTIONS
_sdata = ABSOLUTE(.);
*(.data .data.*)
*(.gnu.linkonce.d.*)
+ *(.ram_code.*)
CONSTRUCTORS
. = ALIGN(4);
_edata = ABSOLUTE(.);
} > sram AT > flash
+ .flash_section : {
+ . = ALIGN(4*1024);
+ *(.flash.*)
+ } > flash
+
.bss : {
_sbss = ABSOLUTE(.);
*(.bss .bss.*)
diff --git a/boards/arm/rp2040/raspberrypi-pico-w/scripts/raspberrypi-pico-sram.ld b/boards/arm/rp2040/raspberrypi-pico-w/scripts/raspberrypi-pico-sram.ld
index d9278950cf..1227117022 100644
--- a/boards/arm/rp2040/raspberrypi-pico-w/scripts/raspberrypi-pico-sram.ld
+++ b/boards/arm/rp2040/raspberrypi-pico-w/scripts/raspberrypi-pico-sram.ld
@@ -20,6 +20,7 @@
MEMORY
{
+ flash (rx) : ORIGIN = 0x10000000, LENGTH = 2048K
sram (rwx) : ORIGIN = 0x20000000, LENGTH = 264K
}
@@ -67,11 +68,17 @@ SECTIONS
_sdata = ABSOLUTE(.);
*(.data .data.*)
*(.gnu.linkonce.d.*)
+ *(.ram_code.*)
CONSTRUCTORS
. = ALIGN(4);
_edata = ABSOLUTE(.);
} > sram
+ .flash_section : {
+ . = ALIGN(4*1024);
+ *(.flash.*)
+ } > flash
+
.bss : {
_sbss = ABSOLUTE(.);
*(.bss .bss.*)
diff --git a/boards/arm/rp2040/raspberrypi-pico/README.txt b/boards/arm/rp2040/raspberrypi-pico/README.txt
index 4bd892f45c..86d60167e7 100644
--- a/boards/arm/rp2040/raspberrypi-pico/README.txt
+++ b/boards/arm/rp2040/raspberrypi-pico/README.txt
@@ -71,6 +71,9 @@ Defconfigs
- nsh
Minimum configuration with NuttShell
+- nsh_flash
+ NuttX shell with SMART flash filesystem.
+
- nshsram
Load NuttX binary to SRAM
diff --git a/boards/arm/rp2040/raspberrypi-pico/configs/nsh-flash/defconfig b/boards/arm/rp2040/raspberrypi-pico/configs/nsh-flash/defconfig
new file mode 100644
index 0000000000..c07697f60f
--- /dev/null
+++ b/boards/arm/rp2040/raspberrypi-pico/configs/nsh-flash/defconfig
@@ -0,0 +1,50 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_FS_PROCFS_EXCLUDE_ENVIRON is not set
+# CONFIG_LIBC_LONG_LONG is not set
+# CONFIG_NSH_ARGCAT is not set
+# CONFIG_NSH_CMDOPT_HEXDUMP is not set
+# CONFIG_NSH_DISABLE_DATE is not set
+# CONFIG_STANDARD_SERIAL is not set
+CONFIG_ARCH="arm"
+CONFIG_ARCH_BOARD="raspberrypi-pico"
+CONFIG_ARCH_BOARD_RASPBERRYPI_PICO=y
+CONFIG_ARCH_CHIP="rp2040"
+CONFIG_ARCH_CHIP_RP2040=y
+CONFIG_ARCH_RAMVECTORS=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BOARDCTL_RESET=y
+CONFIG_BOARD_LOOPSPERMSEC=10450
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DISABLE_POSIX_TIMERS=y
+CONFIG_EXAMPLES_HELLO=y
+CONFIG_FS_PROCFS=y
+CONFIG_FS_PROCFS_REGISTER=y
+CONFIG_INIT_ENTRYPOINT="nsh_main"
+CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_READLINE=y
+CONFIG_RAM_SIZE=270336
+CONFIG_RAM_START=0x20000000
+CONFIG_READLINE_CMD_HISTORY=y
+CONFIG_RP2040_FLASH_FILE_SYSTEM=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_WAITPID=y
+CONFIG_SMARTFS_ALIGNED_ACCESS=y
+CONFIG_START_DAY=9
+CONFIG_START_MONTH=2
+CONFIG_START_YEAR=2021
+CONFIG_SYSLOG_CONSOLE=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_TESTING_SMART_TEST=y
+CONFIG_UART0_SERIAL_CONSOLE=y
diff --git a/boards/arm/rp2040/raspberrypi-pico/scripts/raspberrypi-pico-flash.ld b/boards/arm/rp2040/raspberrypi-pico/scripts/raspberrypi-pico-flash.ld
index f370cca326..82de4b749a 100644
--- a/boards/arm/rp2040/raspberrypi-pico/scripts/raspberrypi-pico-flash.ld
+++ b/boards/arm/rp2040/raspberrypi-pico/scripts/raspberrypi-pico-flash.ld
@@ -82,11 +82,17 @@ SECTIONS
_sdata = ABSOLUTE(.);
*(.data .data.*)
*(.gnu.linkonce.d.*)
+ *(.ram_code.*)
CONSTRUCTORS
. = ALIGN(4);
_edata = ABSOLUTE(.);
} > sram AT > flash
+ .flash_section : {
+ . = ALIGN(4*1024);
+ *(.flash.*)
+ } > flash
+
.bss : {
_sbss = ABSOLUTE(.);
*(.bss .bss.*)
diff --git a/boards/arm/rp2040/raspberrypi-pico/scripts/raspberrypi-pico-sram.ld b/boards/arm/rp2040/raspberrypi-pico/scripts/raspberrypi-pico-sram.ld
index d9278950cf..1227117022 100644
--- a/boards/arm/rp2040/raspberrypi-pico/scripts/raspberrypi-pico-sram.ld
+++ b/boards/arm/rp2040/raspberrypi-pico/scripts/raspberrypi-pico-sram.ld
@@ -20,6 +20,7 @@
MEMORY
{
+ flash (rx) : ORIGIN = 0x10000000, LENGTH = 2048K
sram (rwx) : ORIGIN = 0x20000000, LENGTH = 264K
}
@@ -67,11 +68,17 @@ SECTIONS
_sdata = ABSOLUTE(.);
*(.data .data.*)
*(.gnu.linkonce.d.*)
+ *(.ram_code.*)
CONSTRUCTORS
. = ALIGN(4);
_edata = ABSOLUTE(.);
} > sram
+ .flash_section : {
+ . = ALIGN(4*1024);
+ *(.flash.*)
+ } > flash
+
.bss : {
_sbss = ABSOLUTE(.);
*(.bss .bss.*)
diff --git a/drivers/mtd/smart.c b/drivers/mtd/smart.c
index 4b84e408d0..91db48d69b 100644
--- a/drivers/mtd/smart.c
+++ b/drivers/mtd/smart.c
@@ -5751,7 +5751,7 @@ static int smart_fsck_file(FAR struct smart_struct_s *dev,
/* next logical sector */
- logsector = *(uint16_t *)chain->nextsector;
+ logsector = SMARTFS_NEXTSECTOR(chain);
}
while (logsector != 0xffff);
@@ -5879,7 +5879,7 @@ static int smart_fsck_directory(FAR struct smart_struct_s *dev,
/* Check next sector recursively */
- nextsector = *(uint16_t *)chain->nextsector;
+ nextsector = SMARTFS_NEXTSECTOR(chain);
if (nextsector != 0xffff)
{
@@ -5893,7 +5893,7 @@ static int smart_fsck_directory(FAR struct smart_struct_s *dev,
ferr("Invalidate next log sector %d\n", nextsector);
- *(uint16_t *)chain->nextsector = 0xffff;
+ SMARTFS_SET_NEXTSECTOR(chain, 0xffff);
/* Set flag to relocate later */
diff --git a/fs/smartfs/smartfs.h b/fs/smartfs/smartfs.h
index 017049fd96..d00d836bf6 100644
--- a/fs/smartfs/smartfs.h
+++ b/fs/smartfs/smartfs.h
@@ -197,8 +197,18 @@
# define offsetof(type, member) ((size_t) & (((type *)0)->member))
#endif
-#define SMARTFS_NEXTSECTOR(h) (*((uint16_t *)h->nextsector))
-#define SMARTFS_USED(h) (*((uint16_t *)h->used))
+#ifdef CONFIG_SMARTFS_ALIGNED_ACCESS
+# define SMARTFS_NEXTSECTOR(h) (smartfs_rdle16(h->nextsector))
+# define SMARTFS_SET_NEXTSECTOR(h, v) smartfs_wrle16(h->nextsector, v)
+# define SMARTFS_USED(h) (smartfs_rdle16(h->used))
+# define SMARTFS_SET_USED(h, v) smartfs_wrle16(h->used, v)
+
+#else
+# define SMARTFS_NEXTSECTOR(h) (*((uint16_t *)h->nextsector))
+# define SMARTFS_SET_NEXTSECTOR(h, v) ((*((uint16_t *)h->nextsector)) = v)
+# define SMARTFS_USED(h) (*((uint16_t *)h->used))
+# define SMARTFS_SET_USED(h, v) ((*((uint16_t *)h->used)) = v)
+#endif
#ifdef CONFIG_MTD_SMART_ENABLE_CRC
#define CONFIG_SMARTFS_USE_SECTOR_BUFFER
diff --git a/fs/smartfs/smartfs_smart.c b/fs/smartfs/smartfs_smart.c
index 11b146bef5..9cebba5c99 100644
--- a/fs/smartfs/smartfs_smart.c
+++ b/fs/smartfs/smartfs_smart.c
@@ -45,6 +45,10 @@
#include "smartfs.h"
+#ifdef CONFIG_DEBUG_FS_INFO
+# include <stdio.h>
+#endif
+
/****************************************************************************
* Private Type
****************************************************************************/
@@ -528,6 +532,8 @@ static ssize_t smartfs_read(FAR struct file *filep, char *buffer,
DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
+ finfo("Reading %u bytes\n", (unsigned) buflen);
+
/* Recover our private data from the struct file instance */
sf = filep->f_priv;
@@ -578,7 +584,7 @@ static ssize_t smartfs_read(FAR struct file *filep, char *buffer,
/* Get number of used bytes in this sector */
- bytesinsector = *((uint16_t *) header->used);
+ bytesinsector = SMARTFS_USED(header);
if (bytesinsector == SMARTFS_ERASEDSTATE_16BIT)
{
/* No bytes to read from this sector */
@@ -633,6 +639,18 @@ static ssize_t smartfs_read(FAR struct file *filep, char *buffer,
/* Return the number of bytes we read */
+#ifdef CONFIG_DEBUG_FS_INFO
+ finfo("Read %lu bytes:", bytesread);
+ for (uint32_t i = 0; i < bytesread; ++i)
+ {
+ if ((i & 0x0f) == 0) printf("\n ");
+
+ printf("%02x, ", buffer[i]);
+ }
+
+ printf("\n");
+#endif
+
ret = bytesread;
errout_with_semaphore:
@@ -657,6 +675,18 @@ static ssize_t smartfs_write(FAR struct file *filep, const char *buffer,
DEBUGASSERT(filep->f_priv != NULL && filep->f_inode != NULL);
+#ifdef CONFIG_DEBUG_FS_INFO
+ finfo("Writing %lu bytes:", (uint32_t)buflen);
+ for (uint32_t i = 0; i < buflen; ++i)
+ {
+ if ((i & 0x0f) == 0) printf("\n ");
+
+ printf("%02x, ", buffer[i]);
+ }
+
+ printf("\n");
+#endif
+
/* Recover our private data from the struct file instance */
sf = filep->f_priv;
@@ -852,7 +882,7 @@ static ssize_t smartfs_write(FAR struct file *filep, const char *buffer,
/* Copy the new sector to the old one and chain it */
header = (struct smartfs_chain_header_s *) sf->buffer;
- *((uint16_t *) header->nextsector) = (uint16_t) ret;
+ SMARTFS_SET_NEXTSECTOR(header, (uint16_t) ret);
/* Now sync the file to write this sector out */
@@ -908,7 +938,7 @@ static ssize_t smartfs_write(FAR struct file *filep, const char *buffer,
/* Copy the new sector to the old one and chain it */
header = (struct smartfs_chain_header_s *) fs->fs_rwbuffer;
- *((uint16_t *) header->nextsector) = (uint16_t) ret;
+ SMARTFS_SET_NEXTSECTOR(header, (uint16_t) ret);
readwrite.offset = offsetof(struct smartfs_chain_header_s,
nextsector);
readwrite.buffer = (uint8_t *) header->nextsector;
@@ -941,6 +971,8 @@ static ssize_t smartfs_write(FAR struct file *filep, const char *buffer,
ret = byteswritten;
+ finfo("Wrote %u bytes\n", (unsigned) byteswritten);
+
errout_with_semaphore:
smartfs_semgive(fs);
return ret;
@@ -1325,6 +1357,7 @@ static int smartfs_readdir(FAR struct inode *mountpt,
entrysize = sizeof(struct smartfs_entry_header_s) +
fs->fs_llformat.namesize;
+
while (sdir->fs_currsector != SMARTFS_ERASEDSTATE_16BIT)
{
/* Read the logical sector */
@@ -1341,7 +1374,11 @@ static int smartfs_readdir(FAR struct inode *mountpt,
/* Now search for entries, starting at curroffset */
- while (sdir->fs_curroffset < ret)
+ /* Note: directories don't use the header's used field
+ * so we search all possilble directory entries.
+ */
+
+ while (sdir->fs_curroffset + entrysize < ret)
{
/* Point to next entry */
@@ -1350,24 +1387,35 @@ static int smartfs_readdir(FAR struct inode *mountpt,
/* Test if this entry is valid and active */
+#ifdef CONFIG_SMARTFS_ALIGNED_ACCESS
+ if (((smartfs_rdle16(&entry->flags)
+ & SMARTFS_DIRENT_EMPTY) ==
+ (SMARTFS_ERASEDSTATE_16BIT & SMARTFS_DIRENT_EMPTY)) ||
+ ((smartfs_rdle16(&entry->flags)
+ & SMARTFS_DIRENT_ACTIVE) !=
+ (SMARTFS_ERASEDSTATE_16BIT & SMARTFS_DIRENT_ACTIVE)))
+#else
if (((entry->flags & SMARTFS_DIRENT_EMPTY) ==
(SMARTFS_ERASEDSTATE_16BIT & SMARTFS_DIRENT_EMPTY)) ||
((entry->flags & SMARTFS_DIRENT_ACTIVE) !=
(SMARTFS_ERASEDSTATE_16BIT & SMARTFS_DIRENT_ACTIVE)))
+#endif
{
/* This entry isn't valid, skip it */
sdir->fs_curroffset += entrysize;
- entry = (struct smartfs_entry_header_s *)
- &fs->fs_rwbuffer[sdir->fs_curroffset];
-
continue;
}
/* Entry found! Report it */
+#ifdef CONFIG_SMARTFS_ALIGNED_ACCESS
+ if ((smartfs_rdle16(&entry->flags) & SMARTFS_DIRENT_TYPE) ==
+ SMARTFS_DIRENT_TYPE_DIR)
+#else
if ((entry->flags & SMARTFS_DIRENT_TYPE) ==
SMARTFS_DIRENT_TYPE_DIR)
+#endif
{
dentry->d_type = DTYPE_DIRECTORY;
}
diff --git a/fs/smartfs/smartfs_utils.c b/fs/smartfs/smartfs_utils.c
index 22d9cc1595..ef2d019c3a 100644
--- a/fs/smartfs/smartfs_utils.c
+++ b/fs/smartfs/smartfs_utils.c
@@ -714,11 +714,11 @@ int smartfs_finddirentry(struct smartfs_mountpt_s *fs,
* to next sector
*/
- if (*((FAR uint16_t *)header->used) !=
+ if (SMARTFS_USED(header) !=
SMARTFS_ERASEDSTATE_16BIT)
{
direntry->datlen +=
- *((uint16_t *)header->used);
+ SMARTFS_USED(header);
}
dirsector = SMARTFS_NEXTSECTOR(header);
@@ -1293,7 +1293,7 @@ int smartfs_deleteentry(struct smartfs_mountpt_s *fs,
{
/* We found ourselves in the chain. Update the chain. */
- SMARTFS_NEXTSECTOR(header) = nextsector;
+ SMARTFS_SET_NEXTSECTOR(header, nextsector);
readwrite.offset = offsetof(struct smartfs_chain_header_s,
nextsector);
readwrite.count = sizeof(uint16_t);
@@ -1449,13 +1449,15 @@ int smartfs_sync_internal(FAR struct smartfs_mountpt_s *fs,
/* Update the header with the number of bytes written */
header = (struct smartfs_chain_header_s *)sf->buffer;
- if (*((uint16_t *)header->used) == SMARTFS_ERASEDSTATE_16BIT)
+
+ if (SMARTFS_USED(header) == SMARTFS_ERASEDSTATE_16BIT)
{
- *((uint16_t *)header->used) = sf->byteswritten;
+ SMARTFS_SET_USED(header, sf->byteswritten);
}
else
{
- *((uint16_t *)header->used) += sf->byteswritten;
+ SMARTFS_SET_USED(header, SMARTFS_USED(header)
+ + sf->byteswritten);
}
/* Write the entire sector to FLASH */
@@ -1504,13 +1506,15 @@ int smartfs_sync_internal(FAR struct smartfs_mountpt_s *fs,
/* Add new byteswritten to existing value */
header = (struct smartfs_chain_header_s *) fs->fs_rwbuffer;
- if (*((uint16_t *) header->used) == SMARTFS_ERASEDSTATE_16BIT)
+
+ if (SMARTFS_USED(header) == SMARTFS_ERASEDSTATE_16BIT)
{
- *((uint16_t *) header->used) = sf->byteswritten;
+ SMARTFS_SET_USED(header, sf->byteswritten);
}
else
{
- *((uint16_t *) header->used) += sf->byteswritten;
+ SMARTFS_SET_USED(header, SMARTFS_USED(header)
+ + sf->byteswritten);
}
readwrite.offset = offsetof(struct smartfs_chain_header_s, used);
@@ -1813,9 +1817,8 @@ int smartfs_shrinkfile(FAR struct smartfs_mountpt_s *fs,
dest = (FAR uint8_t *)&fs->fs_rwbuffer[offset];
destsize = fs->fs_llformat.availbytes - offset;
- *((uint16_t *)header->used) = remaining;
- *((uint16_t *)header->nextsector) = SMARTFS_ERASEDSTATE_16BIT;
-
+ SMARTFS_SET_USED(header, remaining);
+ SMARTFS_SET_NEXTSECTOR(header, SMARTFS_ERASEDSTATE_16BIT);
remaining = 0;
}
@@ -1879,8 +1882,9 @@ int smartfs_shrinkfile(FAR struct smartfs_mountpt_s *fs,
destsize = fs->fs_llformat.availbytes - offset;
header = (struct smartfs_chain_header_s *)sf->buffer;
- *((uint16_t *)header->used) = length;
- *((uint16_t *)header->nextsector) = SMARTFS_ERASEDSTATE_16BIT;
+
+ SMARTFS_SET_USED(header, length);
+ SMARTFS_SET_NEXTSECTOR(header, SMARTFS_ERASEDSTATE_16BIT);
}
memset(dest, CONFIG_SMARTFS_ERASEDSTATE, destsize);
@@ -2027,7 +2031,7 @@ int smartfs_extendfile(FAR struct smartfs_mountpt_s *fs,
/* Copy the new sector to the old one and chain it */
header = (struct smartfs_chain_header_s *) sf->buffer;
- *((uint16_t *)header->nextsector) = (uint16_t)ret;
+ SMARTFS_SET_NEXTSECTOR(header, (uint16_t)ret);
/* Now sync the file to write this sector out */
@@ -2083,7 +2087,7 @@ int smartfs_extendfile(FAR struct smartfs_mountpt_s *fs,
/* Copy the new sector to the old one and chain it */
header = (struct smartfs_chain_header_s *)fs->fs_rwbuffer;
- *((FAR uint16_t *)header->nextsector) = (uint16_t)ret;
+ SMARTFS_SET_NEXTSECTOR(header, (uint16_t)ret);
readwrite.offset = offsetof(struct smartfs_chain_header_s,
nextsector);
diff --git a/tools/rp2040/make_flash_fs.c b/tools/rp2040/make_flash_fs.c
new file mode 100644
index 0000000000..3607f21397
--- /dev/null
+++ b/tools/rp2040/make_flash_fs.c
@@ -0,0 +1,480 @@
+/****************************************************************************
+ * tools/rp2040/make_flash_fs.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <stdio.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <sys/dir.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+#define MAX_NAME_LEN 16
+#define MAX_SECTOR_DATA (1024 - 10)
+#define MAX_DIR_COUNT (MAX_SECTOR_DATA / 24)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+typedef struct dir_item_s
+{
+ struct dir_item_s *prior;
+ bool is_directory;
+ int init_sector;
+ int permissions;
+ char name[0];
+} dir_item_t;
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+int max_name_len = MAX_NAME_LEN;
+int root_sector = 3;
+char path[4096];
+uint8_t *buffer;
+
+const char *preamble =
+ "\n .macro sector num, type, used=0xffff, next=0xffff"
+ "\n .balign 1024, 0xff"
+ "\n .hword \\num, 0"
+ "\n .byte 0b01101001, \\type"
+ "\n 1:"
+ "\n .hword \\next, \\used"
+ "\n .endm"
+ "\n"
+ "\n .macro dir_entry perm, addr, time, name"
+ "\n .hword \\perm | 0x7e00, \\addr"
+ "\n .word \\time"
+ "\n 0:"
+ "\n .ascii \"\\name\""
+ "\n .= 0b + name_length"
+ "\n .endm"
+ "\n"
+ "\n .macro file_entry perm, addr, time, name"
+ "\n .hword \\perm | 0x5e00, \\addr"
+ "\n .word \\time"
+ "\n 0:"
+ "\n .ascii \"\\name\""
+ "\n .= 0b + name_length"
+ "\n .endm"
+ "\n"
+ "\n .cpu cortex-m0plus"
+ "\n .thumb"
+ "\n"
+ "\n .section .flash.init, \"ax\""
+ "\n .balign 4096"
+ "\n .global rp2040_smart_flash_start"
+ "\n rp2040_smart_flash_start:"
+ "\n .ascii \"2040\""
+ "\n .byte 0b01101001"
+ "\n .ascii \"SMRT\""
+ "\n .byte 0x01, 0x10, 0"
+ "\n"
+ "\n .balign 4096, 0xff";
+
+const char *postamble =
+ "\n"
+ "\n .balign 4096, 0xff"
+ "\n .global rp2040_smart_flash_end"
+ "\n rp2040_smart_flash_end:"
+ "\n"
+ "\n .end";
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+void put_name(const char * cp)
+{
+ putchar('"');
+
+ for (; *cp != 0; ++cp)
+ {
+ switch (*cp)
+ {
+ case '\"': printf("\\\""); break;
+ case '\'': printf("\\\'"); break;
+ case '\\': printf("\\\\"); break;
+ case '\a': printf("\\a"); break;
+ case '\b': printf("\\b"); break;
+ case '\n': printf("\\n"); break;
+ case '\t': printf("\\t"); break;
+ default:
+ if (iscntrl(*cp))
+ {
+ printf("\\%03o", *cp);
+ }
+ else
+ {
+ putchar(*cp);
+ }
+ }
+ }
+
+ putchar('"');
+}
+
+/****************************************************************************
+ * Name: copy_file
+ ****************************************************************************/
+
+int copy_file(int in_sector, const char * in_name)
+{
+ FILE *data_file = fopen(path, "r");
+ struct stat file_stat;
+ int sector_len;
+ uint8_t *bp;
+
+ if (data_file == NULL) return in_sector;
+
+ lstat(path, &file_stat);
+
+ while (file_stat.st_size > 0)
+ {
+ bp = buffer;
+ sector_len = fread(buffer, 1, MAX_SECTOR_DATA, data_file);
+
+ file_stat.st_size -= sector_len;
+
+ if (file_stat.st_size > 0)
+ {
+ printf("\n sector %4d, dir, used=%d, next=%d",
+ in_sector,
+ sector_len,
+ in_sector + 1);
+ }
+ else
+ {
+ printf("\n sector %4d, file, used=%d",
+ in_sector,
+ sector_len);
+ }
+
+ in_sector += 1;
+
+ for (; sector_len > 0; sector_len -= 8)
+ {
+ printf("\n .byte ");
+
+ for (int i = 0; i < 8 && i < sector_len; ++i)
+ {
+ if (i != 0) printf(", ");
+
+ printf("0x%02x", *bp++);
+ }
+ }
+
+ printf("\n");
+ }
+
+ return in_sector;
+}
+
+/****************************************************************************
+ * Name: dir_entry
+ *
+ * On entry:
+ * The global "path" will be path to the prototype directory.
+ ****************************************************************************/
+
+int scan_dir(int in_sector)
+{
+ dir_item_t *an_item = NULL;
+ dir_item_t *prior_item = NULL;
+ int path_len = strlen(path);
+ int item_count = 0;
+ int sector = in_sector + 1;
+ DIR *input_dir;
+ struct dirent *a_dirent;
+ struct stat stat;
+ int name_len;
+
+ if (name_len > max_name_len)
+ {
+ fprintf(stderr, "directory name to big. skipped. (%s)\n", path);
+ return -1;
+ }
+
+ input_dir = opendir(path);
+
+ if (input_dir == NULL)
+ {
+ fprintf(stderr,
+ "could not open directory %s %s\n",
+ path,
+ strerror(errno));
+
+ return -1;
+ }
+
+ /* scan directory to create directory entries */
+
+ while ((a_dirent = readdir(input_dir)) != NULL)
+ {
+ if (strcmp(a_dirent->d_name, ".") == 0) continue;
+ if (strcmp(a_dirent->d_name, "..") == 0) continue;
+
+ path[path_len] = '/';
+
+ strncpy(&path[path_len + 1], a_dirent->d_name, 4094 - path_len);
+
+ if (a_dirent->d_type == DT_DIR || a_dirent->d_type == DT_REG)
+ {
+ name_len = strlen(a_dirent->d_name);
+
+ if (name_len > max_name_len)
+ {
+ fprintf(stderr, "Skipped item. Name too long: %s\n", path);
+ continue;
+ }
+
+ item_count += 1;
+
+ an_item = malloc(sizeof(dir_item_t) + name_len + 1);
+
+ an_item->prior = prior_item;
+ prior_item = an_item;
+
+ strncpy(an_item->name, a_dirent->d_name, name_len);
+
+ an_item->init_sector = sector;
+
+ if (a_dirent->d_type == DT_DIR)
+ {
+ an_item->is_directory = true;
+ an_item->permissions = 0777;
+
+ sector = scan_dir(sector);
+ }
+ else
+ {
+ an_item->is_directory = false;
+ an_item->permissions = 0666;
+
+ sector = copy_file(sector, an_item->name);
+ }
+ }
+ else
+ {
+ fprintf(stderr, "Skipped unusable item: %s\n", path);
+ }
+ }
+
+ path[path_len] = 0;
+
+ closedir(input_dir);
+
+ /* Generate the directory sector for this directory. */
+
+ if (item_count > MAX_DIR_COUNT)
+ {
+ printf("\n sector %4d, dir, next=%d", in_sector, sector);
+ }
+ else
+ {
+ printf("\n sector %4d, dir", in_sector);
+ }
+
+ while (an_item != NULL)
+ {
+ for (int i = 0; i < MAX_DIR_COUNT && an_item != NULL; ++i)
+ {
+ if (an_item->is_directory)
+ {
+ printf("\n dir_entry 0%03o, 0x%04x, 0, ",
+ an_item->permissions,
+ an_item->init_sector);
+
+ put_name(an_item->name);
+ }
+ else
+ {
+ printf("\n file_entry 0%03o, 0x%04x, 0, ",
+ an_item->permissions,
+ an_item->init_sector);
+
+ put_name(an_item->name);
+ }
+
+ prior_item = an_item->prior;
+ free(an_item);
+ an_item = prior_item;
+ item_count -= 1;
+ }
+
+ if (an_item != NULL)
+ {
+ printf("\n sector %4d, dir, used=%d",
+ sector,
+ (item_count > MAX_DIR_COUNT) ? (sector + 1) : 0xffff);
+
+ sector += 1;
+ }
+ }
+
+ printf("\n");
+
+ return sector;
+}
+
+/****************************************************************************
+ * Name: print_help
+ ****************************************************************************/
+
+void print_help(const char * name)
+{
+ fprintf(stderr, "\nusage: %s [-h][-n name-len] source-path\n\n", name);
+
+ fprintf(stderr, "-h : print this help and exit.\n\n");
+
+ fprintf(stderr, "-n : name length is the length of file names in\n");
+ fprintf(stderr, " the smart filesystem. It must match the\n");
+ fprintf(stderr, " CONFIG_SMARTFS_MAXNAMLEN with which NuttX was\n");
+ fprintf(stderr, " built. The default is %d.\n\n", max_name_len);
+
+ fprintf(stderr, "source-path is the path to a prototype directory tree\n");
+ fprintf(stderr, " that will be used to build the initial smart\n");
+ fprintf(stderr, " filesystem. Any items that are not normal\n");
+ fprintf(stderr, " files or directories will be ignored.\n\n");
+
+ fprintf(stderr, "Output is to stdout.\n\n");
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int main(int argc, char *argv[])
+{
+ FILE *output_file;
+ const char *input_path = NULL;
+
+ /* parse arguments */
+
+ for (int i = 1; i < argc; ++i)
+ {
+ if (argv[i][0] == '-')
+ {
+ if (argv[i][1] == 'h')
+ {
+ print_help(argv[0]);
+ return 0;
+ }
+
+ if (argv[i][1] == 'n')
+ {
+ if (argv[i][2] == 0 && argc > i + 1)
+ {
+ i += 1;
+
+ if (!isdigit(argv[i][0]))
+ {
+ fprintf(stderr, "invalid name length.\n");
+ print_help(argv[0]);
+ return 1;
+ }
+
+ max_name_len = atoi(argv[i]);
+ }
+ else if (isdigit(argv[i][2]))
+ {
+ max_name_len = atoi(&(argv[i][2]));
+ }
+ else
+ {
+ fprintf(stderr, "invalid name length.\n");
+ print_help(argv[0]);
+ return 1;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "unknown argument: %c\n", argv[i][1]);
+ print_help(argv[0]);
+ return 1;
+ }
+ }
+ else if (input_path == NULL)
+ {
+ input_path = argv[i];
+ }
+ }
+
+ if (input_path == NULL)
+ {
+ print_help(argv[0]);
+ return 1;
+ }
+
+ buffer = malloc(MAX_SECTOR_DATA);
+
+ if (buffer == NULL)
+ {
+ fprintf(stderr, "could not allocate file buffer.\n");
+ return 1;
+ }
+
+ strncpy(path, input_path, 4096);
+
+ /* remove any stray trailing slash characters. */
+
+ for (int c = strlen(path) - 1; c >= 0; --c)
+ {
+ if (path[c] != '/') break;
+ path[c] = 0;
+ }
+
+ /* Output the defined constants */
+
+ printf("dir= 1\n"
+ "file= 2\n"
+ "name_length= %d\n",
+ max_name_len);
+
+ /* Output the macro definitions and block zero. */
+
+ puts(preamble);
+
+ /* Scan the prototype directory tree. */
+
+ scan_dir(root_sector);
+
+ /* Wrap things up. */
+
+ puts(postamble);
+
+ return 0;
+}