From 9ad75fd95dfbe91a0f4a65dd8c0a532c04fee16b Mon Sep 17 00:00:00 2001 From: curuvar <58759586+curuvar@users.noreply.github.com> Date: Sun, 4 Sep 2022 19:02:24 -0400 Subject: [PATCH] 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 ++ .../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 + .../configs/nsh-flash/defconfig | 54 ++ .../scripts/adafruit-kb2040-flash.ld | 6 + .../scripts/adafruit-kb2040-sram.ld | 7 + .../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 +- .../rp2040/common/src/rp2040_common_bringup.c | 85 +++ .../arm/rp2040/pimoroni-tiny2040/README.txt | 3 + .../configs/nsh-flash/defconfig | 53 ++ .../scripts/pimoroni-tiny2040-flash.ld | 6 + .../scripts/pimoroni-tiny2040-sram.ld | 7 + .../arm/rp2040/raspberrypi-pico-w/README.txt | 3 + .../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 + .../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(-) create mode 100644 arch/arm/src/rp2040/rp2040_flash_initialize.S create mode 100644 arch/arm/src/rp2040/rp2040_flash_mtd.c create mode 100644 arch/arm/src/rp2040/rp2040_flash_mtd.h create mode 100644 arch/arm/src/rp2040/rp2040_rom.h create mode 100644 boards/arm/rp2040/adafruit-feather-rp2040/configs/nsh-flash/defconfig create mode 100644 boards/arm/rp2040/adafruit-kb2040/configs/nsh-flash/defconfig create mode 100644 boards/arm/rp2040/adafruit-qt-py-rp2040/configs/nsh-flash/defconfig create mode 100644 boards/arm/rp2040/pimoroni-tiny2040/configs/nsh-flash/defconfig create mode 100644 boards/arm/rp2040/raspberrypi-pico-w/configs/nsh-flash/defconfig create mode 100644 boards/arm/rp2040/raspberrypi-pico/configs/nsh-flash/defconfig create mode 100644 tools/rp2040/make_flash_fs.c 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 +#include +#include +#include + +#include "rp2040_flash_mtd.h" +#include "rp2040_rom.h" + +#include +#include +#include +#include +#include +#include +#include + +/**************************************************************************** + * 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 + +/**************************************************************************** + * 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 + +/**************************************************************************** + * 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 #include #include +#include +#include #include @@ -74,6 +76,14 @@ #include "rp2040_ws2812.h" #endif +#if defined(CONFIG_RP2040_ROMFS_ROMDISK_DEVNAME) +# include +#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 +#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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/**************************************************************************** + * 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; +}