MS-FLASHFS 文件系统

更新时间:
2023-08-09
下载文档

MS-FLASHFS 文件系统

本章将介绍 MS-FLASHFS 文件系统相关的知识。

MS-FLASHFS 文件系统介绍

MS-FLASHFS 是翼辉信息自主研发的针对 MCU 内部 FLASH 的掉电安全文件系统,主要用于存放 APP 镜像和启动参数文件,支持 APP XIP(片内执行),和一般的片内执行文件系统(如 ROMFS)不同,MS-FLASHFS 支持文件的增、删、改和磁盘空间碎片整理功能,并且做到了掉电安全,可有效保障智能设备的 OTA 升级安全。

MS-FLASHFS 利用了外部文件系统备份功能,不需要在 MCU 内部 FLASH 划分两个 slot 这里参考了 mcuboot 的 slot 概念open in new window,可有效降低 OTA 升级功能对 MCU 内部 FLASH 容量的需求,大大降低智能设备的 MCU 成本(片外 FLASH 的成本要比片内 FLASH 的成本低得多)。

MS-FLASHFS 文件系统结构

MS-FLASHFS 为了掉电安全能力,MS-FLASHFS 需要使用 MCU 内部 FLASH 的两个扇区分别作为主文件系统表和从文件系统表,MS-FLASHFS DATA 区用于存放文件,MS-FLASHFS 设计时考虑到 MCU 内部 FLASH 扇区大小可能不相同的情况和为了提升内部 FLASH 的利用率,分配单元可以不是扇区,默认扇区最大可以有 16 个分配单元,每个扇区可以拥有不相同的分配单元数。

+-----------+--------------+---+------------+---+------------+---+-------------------+
|           |              |   |            |   |            |   |                   |
|           |              |   | MS-FLASHFS |   | MS-FLASHFS |   |                   |
|  MS-BOOT  |   MS-RTOS    | ~ |            | ~ |            | ~ |  MS-FLASHFS DATA  |
|           |              |   |  MAIN TBL  |   |  SEC TBL   |   |                   |
|           |              |   |            |   |            |   |                   |
+-----------+--------------+---+------------+---+------------+---+-------------------+

制作 MS-FLASHFS 镜像

可以使用 MS-RTOS ImagePackager 将 APP 镜像、启动参数文件等储存到 MS-FLASHFS 文件系统中并合并成为一个统一的 MCU FLASH 烧录镜像。

MS-RTOS ImagePackager 的使用方法见 MS-RTOS ImagePackager 解压缩目录下的《MS-RTOS ImagePackager.pdf》。

MS-FLASHFS 维护

MS-FLASHFS 维护指的是对 MS-FLASHFS 内的文件进行增、删、改和磁盘空间碎片整理。

在设备开发阶段,可以使用 MS-FLASHFS 相关的命令对 MS-FLASHFS 进行维护。

在设备正式运行阶段,可以通过 launcher 的 ms_apps_update 函数对 MS-FLASHFS 进行维护。

ms_err_t ms_apps_update(const char *update_req_path, const char *log_path);

ms_apps_update 函数需要升级请求文件和升级日志文件作为参数。

升级请求文件存储了升级动作文件的路径,而升级动作文件存储了需要对 MS-FLASHFS 进行的维护动作数组(以紧排方式存储)。

MS_STRUCT_PACK_BEGIN
struct ms_flashfs_action {
    // 动作 id
#define MS_FLASHFS_ACTION_CREATE_FILE       0U // 创建文件
#define MS_FLASHFS_ACTION_UPDATE_FILE       1U // 升级文件
#define MS_FLASHFS_ACTION_REMOVE_FILE       2U // 删除文件
#define MS_FLASHFS_ACTION_DEFRAG            3U // 磁盘碎片整理
#define MS_FLASHFS_ACTION_UPDATE_OS         4U // 升级 OS 镜像(该类型动作由 MS-BOOT 执行) 
    MS_STRUCT_PACK_FIELD(ms_uint32_t  id);           // 动作 id
    MS_STRUCT_PACK_FIELD(ms_uint32_t  reserve_size); // 预留给未来升级的大小
    MS_STRUCT_PACK_FIELD(ms_uint32_t  crc32);        // 文件的 CRC32
    MS_STRUCT_PACK_FIELD(ms_err_t     err);          // 动作执行的错误码
    MS_STRUCT_PACK_FIELD(char         name[MS_FLASHFS_NAME_BUF_SIZE]);   // 文件名
    MS_STRUCT_PACK_FIELD(char         source[MS_FLASHFS_PATH_BUF_SIZE]); // 外部文件系统中的源文件
} MS_STRUCT_PACK_STRUCT;
MS_STRUCT_PACK_END
typedef struct ms_flashfs_action ms_flashfs_action_t;

与 OTA 升级的对接

上层的 OTA 升级服务下载新版本 OS 镜像、APP 镜像、启动参数文件(这些文件可以是差分文件,也允许只升级部分文件)到外部文件系统后,在外部文件系统中生成升级动作文件和升级请求文件,然后调用 ms_rtos_update 函数,MS-RTOS 将文件系统 CACHE 回写到磁盘后进行重启。

MS-RTOS 重启后,在 BSP 中,一般由启动线程 boot_thread 来调用 ms_apps_update 函数:

static void boot_thread(ms_ptr_t arg)
{
    // do something

    ms_launcher_init(rsa_pub_key, rsa_pub_key_len);

    ms_apps_update("/nor/update/firmware/update_req", "/nor/update/firmware/update_log");

    // do something
}

ms_apps_update 函数按顺序执行升级动作文件中的每个动作,执行出错时会将错误码写到升级动作文件,并将升级日志记录到指定的日志文件中。

相关命令

命令介绍参数
flashc拷贝外文件系统的文件进 MS-FLASHFS 中flashc name source_path [reserve_size(decimal)]
flashr删除 MS-FLASHFS 中的一个文件flashr name
flashu使用外文件系统的文件升级 MS-FLASHFS 中的一个文件flashu name
flashd执行 MS-FLASHFS 磁盘碎片整理
flashl查看 MS-FLASHFS 中的文件信息

相关 API

// 注册 MS-FLASHFS 文件系统
ms_err_t ms_flashfs_register(void);

移植方法

// 分区的扇区大小表(扇区大小可以不同)
static const ms_uint32_t flash_sectors_size[] = {
        128U * 1024U,     /* FLASH_SECTOR_6  */
        128U * 1024U,     /* FLASH_SECTOR_7  */
        128U * 1024U,     /* FLASH_SECTOR_8  */
        128U * 1024U,     /* FLASH_SECTOR_9  */
};

// 分区信息
static ms_flashfs_partition_t flash_partition = {
        .flash_base   = ADDR_FLASH_SECTOR_6,               // 分区的第一个扇区的地址
        .n_sector     = MS_ARRAY_SIZE(flash_sectors_size), // 分区有多少个扇区
        .sectors_size = flash_sectors_size,                // 提供扇区大小表
};

// 获得分区信息
static ms_err_t __stm32_flash_get_part_info(ms_ptr_t priv, const ms_flashfs_partition_t **part)
{
    *part = &flash_partition;

    return MS_ERR_NONE;
}

// 擦除指定的扇区
static ms_err_t __stm32_flash_erase_sector(ms_ptr_t priv, ms_uint32_t sector_id)
{
    // sector_id 0 -> FLASH_SECTOR_6
    // sector_id 1 -> FLASH_SECTOR_7
    // sector_id 2 -> FLASH_SECTOR_8
    // sector_id 3 -> FLASH_SECTOR_9
    
    // do something 
}

// 对指定地址进行编程
static ms_err_t __stm32_flash_program(ms_ptr_t priv, ms_addr_t addr, ms_const_ptr_t buf, ms_uint32_t len)
{
    // do something 
}

// 擦除指定的文件系统表并编程
static ms_err_t __stm32_flash_erase_program_tbl(ms_ptr_t priv, ms_addr_t tbl_addr, ms_const_ptr_t buf, ms_uint32_t len)
{
    // do something 
}

// 无效指定的文件系统表
static ms_err_t __stm32_flash_invalid_tbl(ms_ptr_t priv, ms_addr_t tbl_addr)
{
    // 文件系统表第一个字写为 0 则可以无效文件系统表
    ms_uint32_t data = 0;

    return __stm32_flash_program(priv, tbl_addr, &data, sizeof(data));
}

// 定义 MS-FLASHFS 驱动
static ms_flashfs_drv_t stm32_flash_drv = {
        .get_part_info      = __stm32_flash_get_part_info,
        .erase_sector       = __stm32_flash_erase_sector,
        .program            = __stm32_flash_program,
        .erase_program_tbl  = __stm32_flash_erase_program_tbl,
        .invalid_tbl        = __stm32_flash_invalid_tbl,
};

// 挂载 MS-FLASHFS
ms_err_t stm32_flash_mount(const char *mnt_path)
{
    // 挂载参数
    ms_flashfs_mount_param_t mount_param;

    mount_param.main_tbl_addr        = BSP_CFG_FLASHFS_MAIN_TBL_ADDR;  // 主文件系统表扇区地址
    mount_param.sec_tbl_addr         = BSP_CFG_FLASHFS_SEC_TBL_ADDR;   // 从文件系统表扇区地址
    mount_param.drv                  = &stm32_flash_drv;               // MS-FLASHFS 驱动
    mount_param.priv                 = MS_NULL;                        // 私有信息
    mount_param.readonly             = MS_FALSE;                       // 是否只读
    mount_param.calc_crc32           = ms_crc32;                       // 提供 CRC32 函数
    mount_param.mkfs_param.max_file  = BSP_CFG_FLASHFS_MAX_FILE;       // 如果没有格式化,则用这参数进行格式化,最大存放多少个文件
    mount_param.mkfs_param.unit_size = BSP_CFG_FLASHFS_UNIT_SIZE;      // 如果没有格式化,则用这参数进行格式化,分配单元的大小(字节单位)
    mount_param.update_req_path      = MS_NULL;

    return ms_io_mount(mnt_path, MS_NULL, MS_FLASHFS_NAME, &mount_param);
}

static void boot_thread(ms_ptr_t arg)
{
    // do something 

    // 注册 MS-FLASHFS 文件系统
    ms_flashfs_register();

    // 挂载到 /flash 目录
    stm32_flash_mount("/flash");

    // do something 
}
文档内容是否对您有所帮助?
有帮助
没帮助