From f0211e720bd2f892f9fd3350d8f99a0151a94858 Mon Sep 17 00:00:00 2001 From: jzlv Date: Wed, 25 Aug 2021 17:40:44 +0800 Subject: [PATCH] [feat][romfs] add romfs component --- components/romfs/CMakeLists.txt | 41 ++ components/romfs/bl_romfs.c | 600 ++++++++++++++++++++ components/romfs/bl_romfs.h | 104 ++++ components/romfs/genromfs/Makefile | 59 ++ components/romfs/genromfs/genromfs.c | 810 +++++++++++++++++++++++++++ components/romfs/readme.md | 90 +++ 6 files changed, 1704 insertions(+) create mode 100644 components/romfs/CMakeLists.txt create mode 100644 components/romfs/bl_romfs.c create mode 100644 components/romfs/bl_romfs.h create mode 100644 components/romfs/genromfs/Makefile create mode 100644 components/romfs/genromfs/genromfs.c create mode 100644 components/romfs/readme.md diff --git a/components/romfs/CMakeLists.txt b/components/romfs/CMakeLists.txt new file mode 100644 index 00000000..7f33d53f --- /dev/null +++ b/components/romfs/CMakeLists.txt @@ -0,0 +1,41 @@ +################# Add global include ################# +list(APPEND ADD_INCLUDE +"${CMAKE_CURRENT_SOURCE_DIR}" +) +####################################################### + +################# Add private include ################# +# list(APPEND ADD_PRIVATE_INCLUDE +# ) +####################################################### + +############## Add current dir source files ########### +file(GLOB_RECURSE sources "${CMAKE_CURRENT_SOURCE_DIR}/bl_romfs.c") +list(APPEND ADD_SRCS ${sources}) +# aux_source_directory(src ADD_SRCS) +# list(REMOVE_ITEM ADD_SRCS "${CMAKE_CURRENT_SOURCE_DIR}") +####################################################### + +########### Add required/dependent components ######### +list(APPEND ADD_REQUIREMENTS common) +####################################################### + +############ Add static libs ########################## +#list(APPEND ADD_STATIC_LIB "libxxx.a") +####################################################### + +############ Add dynamic libs ######################### +# list(APPEND ADD_DYNAMIC_LIB "libxxx.so") +####################################################### + +############ Add global compile option ################ +#add components denpend on this component +# list(APPEND ADD_DEFINITIONS -Dxxx) +####################################################### + +############ Add private compile option ################ +#add compile option for this component that won't affect other modules +# list(APPEND ADD_PRIVATE_DEFINITIONS -Dxxx) +####################################################### + +generate_library() diff --git a/components/romfs/bl_romfs.c b/components/romfs/bl_romfs.c new file mode 100644 index 00000000..0e7ce722 --- /dev/null +++ b/components/romfs/bl_romfs.c @@ -0,0 +1,600 @@ +/** + * @file bl_romfs.c + * @brief + * + * Copyright (c) 2021 Bouffalolab team + * + * 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. + */ + +#include +#include "drv_mmheap.h" +#include "bl_romfs.h" + +#define ROMFH_HRD 0 +#define ROMFH_DIR 1 +#define ROMFH_REG 2 +#define ROMFH_UNKNOW 3. + +static uint32_t romfs_endaddr(void); +static int dirent_type(void *addr); +static uint32_t romfs_endaddr(void); +static uint32_t dirent_hardfh(void *addr); +static uint32_t dirent_childaddr(void *addr); +static uint32_t dirent_size(void *addr); + +static char *romfs_root = NULL; /* The mount point of the physical addr */ + +static int is_path_ch(char ch) +{ + if (((ch >= 'a') && (ch <= 'z')) || + ((ch >= 'A') && (ch <= 'Z')) || + ((ch >= '0') && (ch <= '9')) || + (ch == '/') || + (ch == '.') || + (ch == '_') || + (ch == '-')) { + return 1; + } + return 0; +} + +static int filter_format(const char *path, uint32_t size) +{ + int res; + int i; + int i_old; + + /* sure mountpoint */ + res = strncmp(path, ROMFS_MOUNTPOINT, strlen(ROMFS_MOUNTPOINT)); + if (res) { + ROMFS_ERROR("ERROR: format is error.\r\n"); + return -1; + } + + /* sure '/' format, sure every ch */ + for (i = 0; i < size; i++) { + /* sure every ch */ + if (0 == is_path_ch(path[i])) { + ROMFS_ERROR("ERROR: is_path_ch. i = %d\r\n", i); + return -2; + } + + /* sure '/' */ + if ('/' != path[i]) { + continue; + } + if (i != 0) { + if (i == i_old) { + ROMFS_ERROR("ERROR: format error.\r\n"); + return -3; + } else { + i_old = i; + } + } else { + i_old = i; + } + } + + return 0; +} + +int romfs_mount(void) +{ + /* get romfs infomation */ + + romfs_root = (void *)ROMFS_ROOT_ADDRESS; + + ROMFS_DEBUG("romfs: set romfs_addr:%8X\r\n", romfs_root); + + if (strncmp(romfs_root, "-rom1fs-", 8)) { + ROMFS_ERROR("ERROR: no find romfs\r\n"); + return -1; + } else { + ROMFS_DEBUG("romfs: found romfs\r\n"); + } + + ROMFS_DEBUG("romfs: romfs size:%d*1024Byte\r\n", dirent_size(romfs_root) >> 10); + + return 0; +} + +static int dirent_type(void *addr) +{ + if (0 == ((U32HTONL(*((uint32_t *)addr))) & 0x00000007)) { + return ROMFH_HRD; + } else if (2 == ((U32HTONL(*((uint32_t *)addr))) & 0x00000007)) { + return ROMFH_REG; + } else if (1 == ((U32HTONL(*((uint32_t *)addr))) & 0x00000007)) { + return ROMFH_DIR; + } + + return ROMFH_UNKNOW; +} + +static uint32_t romfs_endaddr(void) +{ + return ((uint32_t)romfs_root + U32HTONL(*((uint32_t *)romfs_root + 2))); +} + +static uint32_t dirent_hardfh(void *addr) +{ + return U32HTONL(*((uint32_t *)addr)) & 0xFFFFFFF0; +} + +static uint32_t dirent_childaddr(void *addr) +{ + return U32HTONL(*((uint32_t *)addr + 1)) & 0xFFFFFFF0; +} + +static uint32_t dirent_size(void *addr) +{ + return U32HTONL(*((uint32_t *)addr + 2)); +} + +static int file_info(char *path, char **p_addr_start_input, char **p_addr_end_input) +{ + char *addr_start = *p_addr_start_input; + char *addr_end = *p_addr_end_input; + ROMFS_ASSERT(path && addr_start_input && addr_end_input); + + ROMFS_DEBUG("romfs: file info path = %s\r\n", path); + + /* check arg */ + if (ROMFS_MAX_NAME_LEN < strlen(path)) { + return -1; + } + + /* /romfs */ + ROMFS_DEBUG("romfs: addr_start = %p\r\n", addr_start); + if (addr_start == romfs_root) { + addr_start = (char *)(romfs_root + ALIGNUP16(strlen(romfs_root + 16) + 1) + 16 + 64); + } + + ROMFS_DEBUG("romfs: addr_start = %p, addr_end = %p, path = %s\r\n", addr_start, addr_end, path); + while (1) { + if (ROMFH_DIR == dirent_type(addr_start)) { + if (0 == memcmp(path, addr_start + 16, strlen(path))) { + if (addr_start[16 + strlen(path)] == 0) { + if (0 == dirent_hardfh(addr_start)) { + break; // the dir is the last dirent + } + addr_end = romfs_root + dirent_hardfh(addr_start); + ROMFS_DEBUG("romfs: update addr_end = %p\r\n", addr_end); + break; + } + } + } else if (ROMFH_REG == dirent_type(addr_start)) { + if (0 == memcmp(path, addr_start + 16, strlen(path))) { + if (addr_start[16 + strlen(path)] == 0) { + addr_end = romfs_root + dirent_hardfh(addr_start); + break; + } + } + } else if (ROMFH_HRD != dirent_type(addr_start)) { + ROMFS_ERROR("ERROR: addr_start = %p, dirent_type(addr_start) = %d\r\n", addr_start, dirent_type(addr_start)); + // log_buf(addr_start, 8); + ROMFS_ERROR("ERROR: unknow the dirent_type.\r\n"); + return -1; + } + + ROMFS_DEBUG("romfs: addr_start = %p, off = 0x%08lx\r\n", addr_start, dirent_hardfh(addr_start)); + addr_start = romfs_root + dirent_hardfh(addr_start); + if (addr_start >= addr_end) { + ROMFS_WARN("WARN: start >= end, not found path = %s, addr_start = %p, addr_end = %p\r\n", path, addr_start, addr_end); + return -1; + } + } + + ROMFS_DEBUG("romfs: update addr_start = %p, addr_end = %p\r\n", addr_start, addr_end); + /* update out */ + *p_addr_start_input = addr_start; + *p_addr_end_input = addr_end; + return 0; +} + +/* + * input : path + * output: p_addr_start_input, p_addr_end_input + * return: 0 success, other error + */ +uint32_t dirent_file(char *path, void **p_addr_start_input, void **p_addr_end_input) +{ + char *addr_start; + char *addr_end; + + char *p_name = NULL; + char name[ROMFS_MAX_NAME_LEN + 1]; + char *p_ret = NULL; + char need_enter_child = 0; + + ROMFS_ASSERT(path && addr_start_input && addr_end_input); + + /* check arg */ + if (strlen(path) < strlen(ROMFS_MOUNTPOINT)) { + return -1; + } + + ROMFS_DEBUG("romfs: dirent_file path = %s\r\n", path); + + /* rm root_mountpoint and'/', /romfs/ */ + if (0 != memcmp(path, ROMFS_MOUNTPOINT, strlen(ROMFS_MOUNTPOINT))) { + ROMFS_ERROR("ERROR: not support path.\r\n"); + return -1; + } + p_name = path + strlen(ROMFS_MOUNTPOINT); + if ((*p_name != '/') && (*p_name != '\0')) { + ROMFS_ERROR("ERROR: not support path.\r\n"); + return -1; + } + if (*p_name == '/') { + p_name += 1; + } + + /* search every one */ + addr_start = romfs_root; + addr_end = (char *)romfs_endaddr(); + ROMFS_DEBUG("romfs: romfs start_addr:%p, end_addr:%p, p_name = %s\r\n", addr_start, addr_end, p_name); + + while (1) { + if (0 == *p_name) { + break; + } + p_ret = strchr(p_name, '/'); + + if (1 == need_enter_child) { + if (addr_start == (romfs_root + dirent_childaddr(addr_start))) { + return -2; + } + addr_start = romfs_root + dirent_childaddr(addr_start); + need_enter_child = 0; + } + + if (NULL == p_ret) { + /* last name, use it find, update addr_start_end and return */ + ROMFS_DEBUG("romfs: last name.\r\n"); + if (strlen(p_name) > ROMFS_MAX_NAME_LEN) { + ROMFS_ERROR("ERROR: name too long!\r\n"); + return -1; + } + if (0 != file_info(p_name, (char **)&addr_start, (char **)&addr_end)) { + ROMFS_WARN("WARN: file info error, p_name = %s, addr_start = %p, addr_end = %p\r\n", p_name, addr_start, addr_end); + return -1; + } + + break; + } else { + memset(name, 0, sizeof(name)); + memcpy(name, p_name, (p_ret - p_name)); + ROMFS_DEBUG("romfs: mid name.\r\n"); + /* mid name, use it find, update addr_start_end and continue */ + if (0 != file_info(name, (char **)&addr_start, (char **)&addr_end)) { + ROMFS_ERROR("ERROR: file info error.\r\n"); + return -1; + } + + need_enter_child = 1; + p_name = p_ret + 1; + continue; + } + } + + ROMFS_DEBUG("romfs: dirent_file start = %p, end = %p\r\n", addr_start, addr_end); + /* update out arg, and return */ + *p_addr_start_input = addr_start; + *p_addr_end_input = addr_end; + + return 0; +} + +int romfs_open(romfs_file_t *fp, const char *path, int flags) +{ + char *start_addr; + char *end_addr; + + ROMFS_DEBUG("romfs: romfs open.\r\n"); + + /* sure romfs_root is valid */ + if (romfs_root == NULL) { + ROMFS_ERROR("ERROR: romfs_root is null.\r\n"); + return -1; + } + + /* sure format is valid */ + if (0 != filter_format(path, strlen(path))) { + ROMFS_ERROR("ERROR: path format is error.\r\n"); + return -1; + } + + /* jump to the back of volume name, get addr_max */ + if (0 != dirent_file((char *)path, (void **)&start_addr, (void **)&end_addr)) { + return -2; + } + + fp->f_arg = start_addr; + fp->offset = 0; + + return 0; +} + +int romfs_close(romfs_file_t *fp) +{ + ROMFS_DEBUG("romfs: romfs close.\r\n"); + /* update romfs_file_t *fp */ + fp->f_arg = NULL; + fp->offset = 0; + return -1; +} + +size_t romfs_read(romfs_file_t *fp, char *buf, size_t length) +{ + char *payload_buf; + uint32_t payload_size; + int len; + + /* init payload_buf and payload_size */ + payload_buf = ((char *)fp->f_arg) + ALIGNUP16(strlen(((char *)fp->f_arg) + 16) + 1) + 16; + payload_size = dirent_size(fp->f_arg); + + /* check arg */ + if (fp->offset >= payload_size) { + //ROMFS_WARN("WARN: offset >= payload_size\r\n"); + return 0; + } + + /* memcpy data */ + if ((fp->offset + length) < payload_size) { + len = length; + memcpy(buf, payload_buf + fp->offset, len); + fp->offset += len; + } else { + len = payload_size - fp->offset; + memcpy(buf, payload_buf + fp->offset, len); + fp->offset = payload_size; + } + + return len; +} + +// int romfs_ioctl(romfs_file_t *fp, int cmd, unsigned long arg) +// { +// int ret = -1; +// romfs_filebuf_t *file_buf = (romfs_filebuf_t *)arg; + +// if ((NULL == fp) || (NULL == file_buf)) { +// return -2; +// } +// switch (cmd) { +// case (IOCTL_ROMFS_GET_FILEBUF): { +// ROMFS_DEBUG("romfs: IOCTL_ROMFS_GET_FILEBUF.\r\n"); +// file_buf->buf = ((char *)fp->f_arg) + ALIGNUP16(strlen(((char *)fp->f_arg) + 16) + 1) + 16; +// file_buf->bufsize = dirent_size(fp->f_arg); +// return 0; +// } break; +// default: { +// ret = -3; +// } +// } + +// return ret; +// } + +size_t romfs_lseek(romfs_file_t *fp, int off, romfs_whence_t whence) +{ + uint32_t payload_size; + size_t tmp; + + if (NULL == fp) { + return -1; + } + + payload_size = dirent_size(fp->f_arg); + + if (whence == ROMFS_SEEK_SET) { + if (off < 0) { + ROMFS_ERROR("ERROR: not support whence.\r\n"); + return -2; + } + tmp = off; + } else if (whence == ROMFS_SEEK_END) { + if (off > 0) { + ROMFS_ERROR("ERROR: not support whence.\r\n"); + return -3; + } + tmp = off + payload_size; + } else if (whence == ROMFS_SEEK_CUR) { + tmp = off + fp->offset; + } else { + ROMFS_ERROR("ERROR: not support whence.\r\n"); + return -4; + } + + if ((tmp < 0) || (tmp > payload_size)) { + ROMFS_ERROR("ERROR: not support whence.\r\n"); + return -5; + } + + fp->offset = tmp; + + return fp->offset; +} + +int romfs_stat(const char *path, romfs_stat_t *st) +{ + char *start_addr = 0; + char *end_addr = 0; + int res; + + ROMFS_DEBUG("romfs: romfs_stat path = %s\r\n", path); + res = dirent_file((char *)path, (void **)&start_addr, (void **)&end_addr); + + if (res != 0) { + ROMFS_WARN("WARN: dirent_file res = %d\r\n", res); + return -1; + } + + if (start_addr == romfs_root) { + st->st_size = 0; + } else { + if (ROMFH_DIR == dirent_type(start_addr)) { + st->st_size = 0; + st->st_mode = ROMFS_S_IFDIR; + ROMFS_DEBUG("romfs: st_size set 0"); + } else if (ROMFH_REG == dirent_type(start_addr)) { + st->st_size = dirent_size(start_addr); + ROMFS_DEBUG("romfs: st_size set %ld\r\n", st->st_size); + st->st_mode = ROMFS_S_IFREG; + } else { + ROMFS_WARN("WARN: dirent_type err.\r\n"); + return -2; + } + } + + return 0; +} + +romfs_dir_t *romfs_opendir(const char *path) +{ + romfs_dir_t *dp = NULL; + char *start_addr; + char *end_addr; + int res; + + ROMFS_DEBUG("romfs: path = %s\r\n", path); + + /* sure romfs_root is valid */ + if (romfs_root == NULL) { + ROMFS_ERROR("ERROR: romfs_root is null.\r\n"); + return NULL; + } + + dp = (romfs_dir_t *)mmheap_alloc(sizeof(romfs_dir_t) + ROMFS_MAX_NAME_LEN + 1); + if (NULL == dp) { + return NULL; + } + memset(dp, 0, sizeof(romfs_dir_t) + ROMFS_MAX_NAME_LEN + 1); + + res = dirent_file((char *)path, (void **)&start_addr, (void **)&end_addr); + ROMFS_DEBUG("romfs: open dir path = %s, start = %p, end = %p\r\n", path, start_addr, end_addr); + if (0 == res) { + /* need add update dir_addr and current_addr */ + if (start_addr == romfs_root) { + dp->dir_start_addr = (char *)(romfs_root + ALIGNUP16(strlen(romfs_root + 16) + 1) + 16 + 64); + } else { + if (0 == dirent_childaddr(start_addr)) { + return NULL; + } else { + dp->dir_start_addr = (char *)(romfs_root + dirent_childaddr(start_addr)); + } + } + dp->dir_end_addr = end_addr; + dp->dir_cur_addr = NULL; + return dp; + } + + /* open err */ + mmheap_free(dp); + return NULL; +} + +romfs_dirent_t *romfs_readdir(romfs_dir_t *dir) +{ + if (!dir) { + return NULL; + } + + while (1) { + /* current is NULL */ + if (NULL == dir->dir_cur_addr) { + dir->dir_cur_addr = dir->dir_start_addr; + } else { + if (dir->dir_cur_addr >= dir->dir_end_addr) { + return NULL; + } else { + while (1) { + if ((dir->dir_cur_addr >= dir->dir_end_addr) || (dir->dir_cur_addr < dir->dir_start_addr)) { + ROMFS_DEBUG("romfs: cur_addr = %p\r\n", dir->dir_cur_addr); + return NULL; + } + //ROMFS_ERROR("ERROR: cur_addr = %p\r\n", dir->dir_cur_addr); + if (0 == dirent_hardfh(dir->dir_cur_addr)) { + ROMFS_DEBUG("romfs: cur_addr = %p\r\n", dir->dir_cur_addr); + break; + } + ROMFS_DEBUG("romfs: cur_addr = %p\r\n", dir->dir_cur_addr); + if (NULL == dir->dir_cur_addr) { + return NULL; + } + if ((ROMFH_DIR == dirent_type(dir->dir_cur_addr)) || + (ROMFH_REG == dirent_type(dir->dir_cur_addr))) { + ROMFS_DEBUG("romfs: cur_addr = %p\r\n", dir->dir_cur_addr); + break; + } + dir->dir_cur_addr = romfs_root + dirent_hardfh(dir->dir_cur_addr); + } + } + } + + ROMFS_DEBUG("romfs: name = %s\r\n", (char *)(dir->dir_cur_addr + 16)); + strncpy(dir->cur_dirent.d_name, dir->dir_cur_addr + 16, ROMFS_MAX_NAME_LEN); + dir->cur_dirent.d_name[ROMFS_MAX_NAME_LEN] = '\0'; + ROMFS_DEBUG("romfs: name = %s\r\n", dir->cur_dirent.d_name); + + if (0 == dirent_hardfh(dir->dir_cur_addr)) { + dir->dir_cur_addr = dir->dir_end_addr; + } else { + dir->dir_cur_addr = romfs_root + dirent_hardfh(dir->dir_cur_addr); + } + + /* rm . and .. dir */ + if (((dir->cur_dirent.d_name[0] == '.') && (dir->cur_dirent.d_name[1] == '.') && (dir->cur_dirent.d_name[2] == '\0')) || + ((dir->cur_dirent.d_name[0] == '.') && (dir->cur_dirent.d_name[1] == '\0'))) { + ROMFS_DEBUG("romfs: ......name = %s\r\n", dir->cur_dirent.d_name); + continue; + } else { + break; + } + } + + return &(dir->cur_dirent); +} + +int romfs_closedir(romfs_dir_t *dir) +{ + if (!dir) { + return -1; + } + + mmheap_free(dir); + return 0; +} + +// static const fs_ops_t romfs_ops = { +// .open = &romfs_open, +// .close = &romfs_close, +// .read = &romfs_read, +// .write = NULL, +// .access = NULL, +// .lseek = &romfs_lseek, +// .stat = &romfs_stat, +// .unlink = NULL, +// .opendir = &romfs_opendir, +// .readdir = &romfs_readdir, +// .closedir = &romfs_closedir, +// .telldir = NULL, +// .seekdir = NULL, +// .ioctl = &romfs_ioctl +// }; diff --git a/components/romfs/bl_romfs.h b/components/romfs/bl_romfs.h new file mode 100644 index 00000000..991d7211 --- /dev/null +++ b/components/romfs/bl_romfs.h @@ -0,0 +1,104 @@ +/** + * @file bl_romfs.h + * @brief + * + * Copyright (c) 2021 Bouffalolab team + * + * 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. + */ + +#ifndef __BL_ROMFS_H__ +#define __BL_ROMFS_H__ + +#include "bflb_platform.h" + +#define ROMFS_DEBUG(a, ...) //bflb_platform_printf(a, ##__VA_ARGS__) +#define ROMFS_WARN(a, ...) bflb_platform_printf(a, ##__VA_ARGS__) +#define ROMFS_ERROR(a, ...) bflb_platform_printf(a, ##__VA_ARGS__) +#define ROMFS_ASSERT(EXPR) + +#define ALIGNUP16(x) (((x) + 15) & ~15) + +#define U32MK_HL(a, b, c, d) (((uint32_t)((a)&0xff) << 24) | \ + ((uint32_t)((b)&0xff) << 16) | \ + ((uint32_t)((c)&0xff) << 8) | \ + (uint32_t)((d)&0xff)) +#define U32HTONL(x) ((((x) & (uint32_t)0x000000ffUL) << 24) | \ + (((x) & (uint32_t)0x0000ff00UL) << 8) | \ + (((x) & (uint32_t)0x00ff0000UL) >> 8) | \ + (((x) & (uint32_t)0xff000000UL) >> 24)) +#define U32NTOHL(x) U32HTONL(x) + +#define ROMFS_MOUNTPOINT "/romfs" /* must '/' */ +#define ROMFS_MAX_NAME_LEN (64) + +#define ROMFS_S_IFDIR 0x0040000 +#define ROMFS_S_IFREG 0x0100000 + +/* romfs address,plase Change the address for your romfs-image programming*/ +#define ROMFS_ROOT_ADDRESS (0x23000000 - 0x2000 + 0x80000) + +struct bl_mtd_handle_t { + char name[16]; + int id; + unsigned int offset; + unsigned int size; + void *xip_addr; +}; + +typedef enum { + ROMFS_SEEK_SET, + ROMFS_SEEK_CUR, + ROMFS_SEEK_END, +} romfs_whence_t; + +typedef struct { + uint32_t st_mode; + uint32_t st_size; +} romfs_stat_t; + +typedef struct { + void *f_arg; /* f_arg for file */ + size_t offset; /* offset for file */ + int fd; /* file fd */ +} romfs_file_t; + +/* readdir 返回的路径结构体,被包含在 romfs_dir_t 中*/ +typedef struct { + int d_ino; /* file number */ + uint8_t d_type; /* type of file */ + char d_name[]; /* file name */ +} romfs_dirent_t; + +/* opendir 得到的目录结构体 */ +typedef struct { + char *dir_start_addr; + char *dir_end_addr; + char *dir_cur_addr; + romfs_dirent_t cur_dirent; +} romfs_dir_t; + +int romfs_mount(void); +int romfs_open(romfs_file_t *fp, const char *path, int flags); +int romfs_close(romfs_file_t *fp); +size_t romfs_read(romfs_file_t *fp, char *buf, size_t length); +size_t romfs_lseek(romfs_file_t *fp, int off, romfs_whence_t whence); +int romfs_stat(const char *path, romfs_stat_t *st); +romfs_dir_t *romfs_opendir(const char *path); +romfs_dirent_t *romfs_readdir(romfs_dir_t *dir); +int romfs_closedir(romfs_dir_t *dir); + +#endif diff --git a/components/romfs/genromfs/Makefile b/components/romfs/genromfs/Makefile new file mode 100644 index 00000000..d278efc5 --- /dev/null +++ b/components/romfs/genromfs/Makefile @@ -0,0 +1,59 @@ + +# Makefile for the genromfs program. + +all: genromfs + +PACKAGE = genromfs +VERSION = 0.5.2 +CC = gcc +CFLAGS = -O2 -Wall -DVERSION=\"$(VERSION)\"#-g# +LDFLAGS = -s#-g + +DISTDIR = $(PACKAGE)-$(VERSION) + +FILES = COPYING NEWS ChangeLog Makefile \ + genromfs.8 genromfs.c genromfs.lsm \ + readme-kernel-patch genrommkdev romfs.txt \ + checkdist + +prefix = /usr +bindir = $(prefix)/bin +mandir = $(prefix)/man + +genromfs: genromfs.o + $(CC) $(LDFLAGS) genromfs.o -o genromfs + +.c.o: + $(CC) $(CFLAGS) $< -c -o $@ + +clean: + rm -f genromfs *.o + +distclean: clean + rm -rf $(DISTDIR) $(DISTDIR).tar.gz + +dist: + ./checkdist $(VERSION) + rm -rf $(DISTDIR).tar.gz $(DISTDIR) + mkdir $(DISTDIR); + for i in $(FILES); do \ + cp $$i $(DISTDIR)/; \ + done; \ + tar --owner=root --group=root -zcf $(DISTDIR).tar.gz $(DISTDIR); + rm -rf $(DISTDIR) + +install: all install-bin install-man + +install-bin: + mkdir -p $(PREFIX)$(bindir) + install -m 755 genromfs $(PREFIX)$(bindir)/ + +install-man: + # genromfs 0.5 installed the man page in this file, + # remove it before someone notices :) + if [ -f $(PREFIX)$(bindir)/man8 ]; then \ + rm -f $(PREFIX)$(bindir)/man8; \ + fi + mkdir -p $(PREFIX)$(mandir)/man8 + install -m 644 genromfs.8 $(PREFIX)$(mandir)/man8/ + diff --git a/components/romfs/genromfs/genromfs.c b/components/romfs/genromfs/genromfs.c new file mode 100644 index 00000000..9d05fdcc --- /dev/null +++ b/components/romfs/genromfs/genromfs.c @@ -0,0 +1,810 @@ + +/* Generate a ROMFS file system + * + * Copyright (C) 1997,1998 Janos Farkas + * Copyright (C) 1998 Jakub Jelinek + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Changes: + * 2 Jan 1997 Initial release + * 6 Aug 1997 Second release + * 11 Sep 1998 Alignment support + * 11 Jan 2001 special files of name @name,[cpub],major,minor + */ + +/* + * Some sparse words about how to use the program + * + * `genromfs' is the `mkfs' equivalent of the other filesystems, but + * you must tell it from which directory you want to build the + * filesystem. I.e. all files (and directories) in that directory + * will be part of the newly created filesystem. Imagine it like + * building a cd image, or creating an archive (tar, zip) file. + * + * Basic usage: + * + * # genromfs -d rescue/ -f /dev/fd0 + * + * All files in the rescue directory will be written to /dev/fd0 as a + * new romfs filesystem image. You can mount it (if you have the + * romfs module loaded, or compiled into the kernel) via: + * + * # mount -t romfs /dev/fd0 /mnt + * + * You can also set the volume name of the filesystem (which is not + * currently used by the kernel) with the -V option. If you don't + * specify one, genromfs will create a volume name of the form: 'rom + * xxxxxxxx', where the x's represent the current time in a cryptic + * form. + * + * All in all, it's as simple as: + * + * # genromfs -d rescue -f testimg.rom -V "Install disk" + * + * Other options: + * -a N force all regular file data to be aligned on N bytes boundary + * -A N,/name force named file(s) (shell globbing applied against the filenames) + * to be aligned on N bytes boundary + * In both cases, N must be a power of two. + */ + +/* + * Warning! Quite spaghetti code, it was born in a few hours. + * Sorry about that. Feel free to contact me if you have problems. + */ + +#include /* Userland pieces of the ANSI C standard I/O package */ +#include /* Userland prototypes of the ANSI C std lib functions */ +#include /* Userland prototypes of the string handling funcs */ +#include /* Userland prototypes of the Unix std system calls */ +#include /* Flag value for file handling functions */ +#include +#include +#include +#include +#include + +#include /* Consts & structs defined by the internet system */ + +/* good old times without autoconf... */ +#if defined(__linux__) || defined(__sun__) || defined(__CYGWIN__) +#include +#endif + + +struct romfh { + int32_t nextfh; + int32_t spec; + int32_t size; + int32_t checksum; +}; + +#define ROMFS_MAXFN 128 +#define ROMFH_HRD 0 +#define ROMFH_DIR 1 +#define ROMFH_REG 2 +#define ROMFH_LNK 3 +#define ROMFH_BLK 4 +#define ROMFH_CHR 5 +#define ROMFH_SCK 6 +#define ROMFH_FIF 7 +#define ROMFH_EXEC 8 + +struct filenode; + +struct filehdr { + /* leave h, t, tp at front, this is a linked list header */ + struct filenode *head; + struct filenode *tail; + struct filenode *tailpred; + /* end fragile header */ + struct filenode *owner; +}; + +struct filenode { + /* leave n, p at front, this is a linked list item */ + struct filenode *next; + struct filenode *prev; + /* end fragile header */ + struct filenode *parent; + struct filehdr dirlist; + struct filenode *orig_link; + char *name; + char *realname; + dev_t ondev; + dev_t devnode; + ino_t onino; + mode_t modes; + unsigned int offset; + unsigned int size; + unsigned int pad; +}; + +struct aligns { + struct aligns *next; + int align; + char pattern[0]; +}; + +struct excludes { + struct excludes *next; + char pattern[0]; +}; + +void initlist(struct filehdr *fh, struct filenode *owner) +{ + fh->head = (struct filenode *)&fh->tail; + fh->tail = NULL; + fh->tailpred = (struct filenode *)&fh->head; + fh->owner = owner; +} + +int listisempty(struct filehdr *fh) +{ + return fh->head == (struct filenode *)&fh->tail; +} + +void append(struct filehdr *fh, struct filenode *n) +{ + struct filenode *tail = (struct filenode *)&fh->tail; + + n->next = tail; n->prev = tail->prev; + tail->prev = n; n->prev->next =n; + n->parent = fh->owner; +} + +void shownode(int level, struct filenode *node, FILE *f) +{ + struct filenode *p; + fprintf(f, "%-4d %-20s [0x%-8x, 0x%-8x] %07o, sz %5u, at 0x%-6x", + level, node->name, + (int)node->ondev, (int)node->onino, node->modes, node->size, + node->offset); + + if (node->orig_link) + fprintf(f, " [link to 0x%-6x]", node->orig_link->offset); + fprintf(f, "\n"); + + p = node->dirlist.head; + while (p->next) { + shownode(level+1, p, f); + p = p->next; + } +} + +/* Dumping functions */ + +static char bigbuf[4096]; +static char fixbuf[512]; +static int atoffs = 0; +static int align = 16; +struct aligns *alignlist = NULL; +struct excludes *excludelist = NULL; +int realbase; + +/* helper function to match an exclusion or align pattern */ + +int nodematch(char *pattern, struct filenode *node) +{ + char *start = node->name; + /* XXX: ugly realbase is global */ + if (pattern[0] == '/') start = node->realname + realbase; + return fnmatch(pattern,start,FNM_PATHNAME|FNM_PERIOD); +} + +int findalign(struct filenode *node) +{ + struct aligns *pa; + int i; + + if (S_ISREG(node->modes)) i = align; + else i = 16; + + for (pa = alignlist; pa; pa = pa->next) { + if (pa->align > i) { + if (!nodematch(pa->pattern,node)) i = pa->align; + } + } + return i; +} + +int romfs_checksum(void *data, int size) +{ + int32_t sum, word, *ptr; + + sum = 0; ptr = data; + size>>=2; + while (size>0) { + word = *ptr++; + sum += ntohl(word); + size--; + } + return sum; +} + +void fixsum(struct romfh *ri, int size) +{ + ri->checksum = 0; + ri->checksum = htonl(-romfs_checksum(ri, size)); +} + +void dumpdata(void *addr, int len, FILE *f) +{ + int tocopy; + struct romfh *ri; + + if (!len) + return; + if (atoffs >= 512) { + fwrite(addr, len, 1, f); + atoffs+=len; + return; + } + + tocopy = len < 512-atoffs ? len : 512-atoffs; + memcpy(fixbuf+atoffs, addr, tocopy); + atoffs+=tocopy; + addr=(char*)addr+tocopy; + len-=tocopy; + + if (atoffs==512) { + ri = (struct romfh *)&fixbuf; + fixsum(ri, atoffssize)?atoffs:ntohl(ri->size)); + fwrite(fixbuf, atoffs, 1, f); + } + if (len) { + fwrite(addr, len, 1, f); + atoffs+=len; + } +} + +void dumpzero(int len, FILE *f) +{ + memset(bigbuf, 0, len); + dumpdata(bigbuf, len, f); +} + +void dumpdataa(void *addr, int len, FILE *f) +{ + dumpdata(addr, len, f); + if ((len & 15) != 0) + dumpzero(16-(len&15), f); +} + +void dumpstring(char *str, FILE *f) +{ + dumpdataa(str, strlen(str)+1, f); +} + +void dumpri(struct romfh *ri, struct filenode *n, FILE *f) +{ + int len; + + len = strlen(n->name)+1; + memcpy(bigbuf, ri, sizeof(*ri)); + memcpy(bigbuf+16, n->name, len); + if (len&15) { + memset(bigbuf+16+len, 0, 16-(len&15)); + len += 16-(len&15); + } + len+=16; + ri=(struct romfh *)bigbuf; + if (n->offset) + fixsum(ri, len); + dumpdata(bigbuf, len, f); +#if 0 + fprintf(stderr, "RI: [at %06x] %08lx, %08lx, %08lx, %08lx [%s]\n", + n->offset, + ntohl(ri->nextfh), ntohl(ri->spec), + ntohl(ri->size), ntohl(ri->checksum), + n->name); +#endif +} + +void dumpnode(struct filenode *node, FILE *f) +{ + struct romfh ri; + struct filenode *p; + + ri.nextfh = 0; + ri.spec = 0; + ri.size = htonl(node->size); + ri.checksum = htonl(0x55555555); + if (node->pad) + dumpzero(node->pad, f); + if (node->next && node->next->next) + ri.nextfh = htonl(node->next->offset); + if ((node->modes & 0111) && + (S_ISDIR(node->modes) || S_ISREG(node->modes))) + ri.nextfh |= htonl(ROMFH_EXEC); + + if (node->orig_link) { + ri.nextfh |= htonl(ROMFH_HRD); + /* Don't allow hardlinks to convey attributes */ + ri.nextfh &= ~htonl(ROMFH_EXEC); + ri.spec = htonl(node->orig_link->offset); + dumpri(&ri, node, f); + } else if (S_ISDIR(node->modes)) { + ri.nextfh |= htonl(ROMFH_DIR); + if (listisempty(&node->dirlist)) { + ri.spec = htonl(node->offset); + } else { + ri.spec = htonl(node->dirlist.head->offset); + } + dumpri(&ri, node, f); + } else if (S_ISLNK(node->modes)) { + ri.nextfh |= htonl(ROMFH_LNK); + dumpri(&ri, node, f); + memset(bigbuf, 0, sizeof(bigbuf)); + readlink(node->realname, bigbuf, node->size); + dumpdataa(bigbuf, node->size, f); + } else if (S_ISREG(node->modes)) { + int offset, len, fd, max, avail; + ri.nextfh |= htonl(ROMFH_REG); + dumpri(&ri, node, f); + offset = 0; + max = node->size; + /* XXX warn about size mismatch */ + fd = open(node->realname, O_RDONLY +#ifdef O_BINARY +| O_BINARY +#endif +); + if (fd) { + while(offset < max) { + avail = max-offset < sizeof(bigbuf) ? max-offset : sizeof(bigbuf); + len = read(fd, bigbuf, avail); + if (len <= 0) + break; + dumpdata(bigbuf, len, f); + offset+=len; + } + close(fd); + } + max = (max+15)&~15; + while (offset < max) { + avail = max-offset < sizeof(bigbuf) ? max-offset : sizeof(bigbuf); + memset(bigbuf, 0, avail); + dumpdata(bigbuf, avail, f); + offset+=avail; + } + } else if (S_ISCHR(node->modes)) { + ri.nextfh |= htonl(ROMFH_CHR); + ri.spec = htonl(major(node->devnode)<<16|minor(node->devnode)); + dumpri(&ri, node, f); + } else if (S_ISBLK(node->modes)) { + ri.nextfh |= htonl(ROMFH_BLK); + ri.spec = htonl(major(node->devnode)<<16|minor(node->devnode)); + dumpri(&ri, node, f); + } else if (S_ISFIFO(node->modes)) { + ri.nextfh |= htonl(ROMFH_FIF); + dumpri(&ri, node, f); + } else if (S_ISSOCK(node->modes)) { + ri.nextfh |= htonl(ROMFH_SCK); + dumpri(&ri, node, f); + } + + p = node->dirlist.head; + while (p->next) { + dumpnode(p, f); + p = p->next; + } +} + +void dumpall(struct filenode *node, int lastoff, FILE *f) +{ + struct romfh ri; + struct filenode *p; + + ri.nextfh = htonl(0x2d726f6d); + ri.spec = htonl(0x3166732d); + ri.size = htonl(lastoff); + ri.checksum = htonl(0x55555555); + dumpri(&ri, node, f); + p = node->dirlist.head; + while (p->next) { + dumpnode(p, f); + p = p->next; + } + /* Align the whole bunch to ROMBSIZE boundary */ + if (lastoff&1023) + dumpzero(1024-(lastoff&1023), f); +} + +/* Node manipulating functions */ + +void freenode(struct filenode *n) +{ + /* Rare, not yet */ +} + +void setnode(struct filenode *n, dev_t dev, ino_t ino, mode_t um) +{ + n->ondev = dev; + n->onino = ino; + n->modes = um; +} + +struct filenode *newnode(const char *base, const char *name, int curroffset) +{ + struct filenode *node; + int len; + char *str; + + node = malloc(sizeof (*node)); + if (!node) { + fprintf(stderr,"out of memory\n"); + exit(1); + } + + len = strlen(name); + str = malloc(len+1); + if (!str) { + fprintf(stderr,"out of memory\n"); + exit(1); + } + strcpy(str, name); + node->name = str; + + if (!curroffset) { + len = 1; + name = "."; + } + if (strlen(base)) + len++; + str = malloc(strlen(base)+len+1); + if (!str) { + fprintf(stderr,"out of memory\n"); + exit(1); + } + if (strlen(base)) { + sprintf(str, "%s/%s", base, name); + } else { + strcpy(str, name); + } + + node->realname = str; + node->next = node->prev = NULL; + node->parent = NULL; + initlist(&node->dirlist, node); + + node->ondev = -1; + node->onino = -1; + node->modes = -1; + node->size = 0; + node->devnode = 0; + node->orig_link = NULL; + node->offset = curroffset; + node->pad = 0; + + return node; +} + +struct filenode *findnode(struct filenode *node, dev_t dev, ino_t ino) +{ + struct filenode *found, *p; + + /* scan the whole tree */ + if (node->ondev == dev && node->onino == ino) + return node; + p = node->dirlist.head; + while (p->next) { + found = findnode(p, dev, ino); + if (found) + return found; + p = p->next; + } + return NULL; +} + +#define ALIGNUP16(x) (((x)+15)&~15) + +int spaceneeded(struct filenode *node) +{ + return 16 + ALIGNUP16(strlen(node->name)+1) + ALIGNUP16(node->size); +} + +int alignnode(struct filenode *node, int curroffset, int extraspace) +{ + int align = findalign(node), d; + + d = ((curroffset + extraspace) & (align - 1)); + if (d) { + align -= d; + curroffset += align; + node->offset += align; + node->pad = align; + } + return curroffset; +} + +int processdir(int level, const char *base, const char *dirname, struct stat *sb, + struct filenode *dir, struct filenode *root, int curroffset) +{ + DIR *dirfd; + struct dirent *dp; + struct filenode *n, *link; + struct excludes *pe; + + if (level <= 1) { + /* Ok, to make sure . and .. are handled correctly + * we add them first. Note also that we alloc them + * first to get to know the real name + */ + link = newnode(base, ".", curroffset); + if (!lstat(link->realname, sb)) { + setnode(link, sb->st_dev, sb->st_ino, sb->st_mode); + append(&dir->dirlist, link); + + /* special case for root node - '..'s in subdirs should link to + * '.' of root node, not root node itself. + */ + dir->dirlist.owner = link; + + curroffset = alignnode(link, curroffset, 0) + spaceneeded(link); + n = newnode(base, "..", curroffset); + + if (!lstat(n->realname, sb)) { + setnode(n, sb->st_dev, sb->st_ino, sb->st_mode); + append(&dir->dirlist, n); + n->orig_link = link; + curroffset = alignnode(n, curroffset, 0) + spaceneeded(n); + } + } + } + + dirfd = opendir(dir->realname); + if (dirfd == NULL) { + perror(dir->realname); + } + while(dirfd && (dp = readdir(dirfd))) { + /* don't process main . and .. twice */ + if (level <= 1 && + (strcmp(dp->d_name, ".") == 0 + || strcmp(dp->d_name, "..") == 0)) + continue; + n = newnode(base, dp->d_name, curroffset); + + /* Process exclude list. */ + for (pe = excludelist; pe; pe = pe->next) { + if (!nodematch(pe->pattern, n)) { freenode(n); break; } + } + if (pe) continue; + + if (lstat(n->realname, sb)) { + fprintf(stderr, "ignoring '%s' (lstat failed)\n", n->realname); + freenode(n); continue; + } + + /* Handle special names */ + if ( n->name[0] == '@' ) { + if (S_ISLNK(sb->st_mode)) { + /* this is a link to follow at build time */ + n->name = n->name + 1; /* strip off the leading @ */ + memset(bigbuf, 0, sizeof(bigbuf)); + readlink(n->realname, bigbuf, sizeof(bigbuf)); + n->realname = strdup(bigbuf); + + if (lstat(n->realname, sb)) { + fprintf(stderr, "ignoring '%s' (lstat failed)\n", + n->realname); + freenode(n); continue; + } + } else if (S_ISREG(sb->st_mode) && sb->st_size == 0) { + /* + * special file @name,[bcp..],major,minor + */ + char devname[32]; + char type; + int major; + int minor; + + if (sscanf(n->name, "@%[a-zA-Z0-9_+-],%c,%d,%d", + devname, &type, &major, &minor) == 4 ) { + strcpy(n->name, devname); + sb->st_rdev = makedev(major, minor); + sb->st_mode &= ~S_IFMT; + switch (type) { + case 'c': + case 'u': + sb->st_mode |= S_IFCHR; + break; + case 'b': + sb->st_mode |= S_IFBLK; + break; + case 'p': + sb->st_mode |= S_IFIFO; + break; + default: + fprintf(stderr, "Invalid special device type '%c' " + "for file %s\n", type, n->realname); + freenode(n); + continue; + } + } + } + } + + setnode(n, sb->st_dev, sb->st_ino, sb->st_mode); + /* Skip unreadable files/dirs */ + if (!S_ISLNK(n->modes) && access(n->realname, R_OK)) { + fprintf(stderr, "ignoring '%s' (access failed)\n", n->realname); + freenode(n); continue; + } + + /* Look up old links */ + if ( strcmp(n->name, ".") == 0 ) { + append(&dir->dirlist, n); + link = n->parent; + } else if (strcmp(n->name, "..") == 0) { + append(&dir->dirlist, n); + link = n->parent->parent; + } else { + link = findnode(root, n->ondev, n->onino); + append(&dir->dirlist, n); + } + + if (link) { + n->orig_link = link; + curroffset = alignnode(n, curroffset, 0) + spaceneeded(n); + continue; + } + if (S_ISREG(sb->st_mode)) { + curroffset = alignnode(n, curroffset, spaceneeded(n)); + n->size = sb->st_size; + } else + curroffset = alignnode(n, curroffset, 0); + if (S_ISLNK(sb->st_mode)) { + n->size = sb->st_size; + } + curroffset += spaceneeded(n); + if (S_ISCHR(sb->st_mode) || S_ISBLK(sb->st_mode)) { + n->devnode = sb->st_rdev; + } + + if (S_ISDIR(sb->st_mode)) { + if (!strcmp(n->name, "..")) { + curroffset = processdir(level+1, dir->realname, dp->d_name, + sb, dir, root, curroffset); + } else { + curroffset = processdir(level+1, n->realname, dp->d_name, + sb, n, root, curroffset); + } + } + } + if (dirfd) closedir(dirfd); + return curroffset; +} + +void showhelp(const char *argv0) +{ + printf("genromfs %s\n",VERSION); + printf("Usage: %s [OPTIONS] -f IMAGE\n",argv0); + printf("Create a romfs filesystem image from a directory\n"); + printf("\n"); + printf(" -f IMAGE Output the image into this file\n"); + printf(" -d DIRECTORY Use this directory as source\n"); + printf(" -v (Too) verbose operation\n"); + printf(" -V VOLUME Use the specified volume name\n"); + printf(" -a ALIGN Align regular file data to ALIGN bytes\n"); + printf(" -A ALIGN,PATTERN Align all objects matching pattern to at least ALIGN bytes\n"); + printf(" -x PATTERN Exclude all objects matching pattern\n"); + printf(" -h Show this help\n"); + printf("\n"); + printf("Report bugs to chexum@shadow.banki.hu\n"); +} + +int main(int argc, char *argv[]) +{ + int c; + char *dir = "."; + char *outf = NULL; + char *volname = NULL; + int verbose=0; + char buf[256]; + struct filenode *root; + struct stat sb; + int lastoff; + int i; + char *p; + struct aligns *pa, *pa2; + struct excludes *pe, *pe2; + FILE *f; + + while ((c = getopt(argc, argv, "V:vd:f:ha:A:x:")) != EOF) { + switch(c) { + case 'd': + dir = optarg; + break; + case 'f': + outf = optarg; + break; + case 'V': + volname = optarg; + break; + case 'v': + verbose = 1; + break; + case 'h': + showhelp(argv[0]); + exit(0); + case 'a': + align = strtoul(optarg, NULL, 0); + if (align < 16 || (align & (align - 1))) { + fprintf(stderr, "Align has to be at least 16 bytes and a power of two\n"); + exit(1); + } + break; + case 'A': + i = strtoul(optarg, &p, 0); + if (i < 16 || (i & (i - 1))) { + fprintf(stderr, "Align has to be at least 16 bytes and a power of two\n"); + exit(1); + } + if (*p != ',' || !p[1]) { + fprintf(stderr, "-A takes N,PATTERN format of argument, where N is a number\n"); + exit(1); + } + /* strlen(p+1) + 1 eq strlen(p) */ + pa = (struct aligns *)malloc(sizeof(*pa) + strlen(p)); + pa->align = i; + pa->next = NULL; + strcpy(pa->pattern, p + 1); + if (!alignlist) + alignlist = pa; + else { + for (pa2 = alignlist; pa2->next; pa2 = pa2->next) + ; + pa2->next = pa; + } + break; + case 'x': + pe = (struct excludes *)malloc(sizeof(*pe) + strlen(optarg) + 1); + pe->next = NULL; + strcpy(pe->pattern, optarg); + if (!excludelist) + excludelist = pe; + else { + for (pe2 = excludelist; pe2->next; pe2 = pe2->next) + ; + pe2->next = pe; + } + break; + default: + exit(1); + } + } + + if (!volname) { + sprintf(buf, "rom %08lx", time(NULL)); + volname = buf; + } + if (!outf) { + fprintf(stderr, "%s: you must specify the destination file\n", argv[0]); + fprintf(stderr, "Try `%s -h' for more information\n",argv[0]); + exit(1); + } + if (strcmp(outf, "-") == 0) { + f = fdopen(1,"wb"); + } else + f = fopen(outf, "wb"); + + if (!f) { + perror(outf); + exit(1); + } + + realbase = strlen(dir); + root = newnode(dir, volname, 0); + root->parent = root; + lastoff = processdir (1, dir, dir, &sb, root, root, spaceneeded(root)); + if (verbose) + shownode(0, root, stderr); + dumpall(root, lastoff, f); + + exit(0); +} diff --git a/components/romfs/readme.md b/components/romfs/readme.md new file mode 100644 index 00000000..a3151c65 --- /dev/null +++ b/components/romfs/readme.md @@ -0,0 +1,90 @@ +## 1.romfs 介绍 + +romfs 是一种简单的只读文件系统,通常用来当做初始文件系统来使用的, 在嵌入式 linux 通常使用它作为引导系统的文件系统,作为过渡。 + +这里使用 romfs 来构建一个小型文件系统,方便将文件烧录到 flash 里使用,如音频、图片等,无需转化为 hex 数组加入程序中、编译下载,并且能形成一个文件层次结构,,可用使用 open、read 等文件读操作函数。 + +## 2 romfs 文件系统的制作 + +romfs 除了需要相关 代码提供的 api 来读取操作外,还需要使用工具制作一个 romfs 文件系统的镜像,这里使用genromfs 工具来实现镜像制作: + +#### 2.1 编译 genromfs 工具 + +SDK 库这里 提供了 genromfs 源码与 makefile 文件,需要在 linux 环境下编译出可执行文件,以当前路径在bl_mcu_sdk 为例: + +``` +# 进入文件夹路径 +$ cd components/romfs/genromfs +# 编译 +$ make +``` + +之后在 components/romfs/genromfs 下面会出现一个 genromfs 可执行文件,查看使用帮助: + +``` +$ ./genromfs -h +``` + + + +#### 2.2. 放入需要的文件 + +建立一个文件夹,将需要的文件与文件夹放入到其中,注意所有文件与文件夹名只能支持:小写字符 “a~z”、大写字符 “A-Z”、数字 “0~9”、下划线 “_”、横线 “-”、点 “.” 。其他字符不支持,并且长度不能超过 14 字节。 + + + +#### 2.3 使用 genromfs 制作出镜像 + +使用以下命令 从选中的文件夹生成镜像文件: + +``` +$ ./genromfs -d -f +``` + +其中 是需要打包的文件夹路径, 是要生成的 romfs 文件系统镜像,例如在就在当前目录 genromfs 下有一个文件夹 picture,那么执行以下命令就能生成它的 romfs 文件系统镜像文件 picture.bin : + +``` +$ ./genromfs -d picture -f picture.bin +``` + +此时就会生成一个文件 picture.bin ,这就是我们生成的 romfs 文件系统镜像,里面包含了 picture 文件夹的所有文件与层次结构 + + + +## 3. 将 romfs 烧录到 flash + +​ 生成的 romfs 文件系统镜像还需要烧录到 MCU 的 flash 中,用 BouffaloLabDevCube 工具烧录: + +1. 打开 BouffaloLabDevCube 工具,选择 MCU 型号,进入主页面 +2. 在左上角 View 菜单下选择 IOT 模式 +3. 勾选 Single Download Config 下方的 Enable 框,点击 Browse 选择之前生成的 镜像文件 +4. 在 Enable 框 右边填入 要烧录的 flash 地址,注意位置要大于用户程序的大小,避免覆盖了用户代码,如烧录在512K位置:0x80000 +5. 选择正确的串口号,点击 Create&Download 按键下载。 + + + +## 4. romfs 使用 + +经过以上步骤,你需要的文件已经通过 romfs 镜像文件系统烧录进入 flash 中了,即可通过 romfs 代码使用了,但在使用前你需要指定 flash 中 romfs 文件系统的位置。 + +打开 components/romfs/genromfs/bl_romfs.h 文件,找到宏: + +```c +/* romfs address,plase Change the address for your romfs-image programming*/ +#define ROMFS_ROOT_ADDRESS (0x23000000 - 0x2000 + 0x80000) +``` + +其中最后的 0x80000 就是我们在上面烧录步骤中设置的烧录位置,根据自己实际修改。关于 0x23000000 - 0x2000 是与实际地址映射设置的,需要了解请参考其他文档 + +最后,调用 romfs_mount() 函数,即可使用 romfs文件系统了,如: + +```c +romfs_file_t img_file; +char buff[512]; + +romfs_mount(); +romfs_open(&img_file, "/romfs/img_1.jpg", 0); +romfs_read(&img_file, buff, 512); +romfs_close(&img_file); +``` +