[feat][romfs] add romfs component
This commit is contained in:
parent
dfe0516d59
commit
f0211e720b
41
components/romfs/CMakeLists.txt
Normal file
41
components/romfs/CMakeLists.txt
Normal file
@ -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()
|
600
components/romfs/bl_romfs.c
Normal file
600
components/romfs/bl_romfs.c
Normal file
@ -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 <string.h>
|
||||
#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
|
||||
// };
|
104
components/romfs/bl_romfs.h
Normal file
104
components/romfs/bl_romfs.h
Normal file
@ -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
|
59
components/romfs/genromfs/Makefile
Normal file
59
components/romfs/genromfs/Makefile
Normal file
@ -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/
|
||||
|
810
components/romfs/genromfs/genromfs.c
Normal file
810
components/romfs/genromfs/genromfs.c
Normal file
@ -0,0 +1,810 @@
|
||||
|
||||
/* Generate a ROMFS file system
|
||||
*
|
||||
* Copyright (C) 1997,1998 Janos Farkas <chexum@shadow.banki.hu>
|
||||
* Copyright (C) 1998 Jakub Jelinek <jj@ultra.linux.cz>
|
||||
*
|
||||
* 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 <stdio.h> /* Userland pieces of the ANSI C standard I/O package */
|
||||
#include <stdlib.h> /* Userland prototypes of the ANSI C std lib functions */
|
||||
#include <string.h> /* Userland prototypes of the string handling funcs */
|
||||
#include <unistd.h> /* Userland prototypes of the Unix std system calls */
|
||||
#include <fcntl.h> /* Flag value for file handling functions */
|
||||
#include <time.h>
|
||||
#include <fnmatch.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <netinet/in.h> /* Consts & structs defined by the internet system */
|
||||
|
||||
/* good old times without autoconf... */
|
||||
#if defined(__linux__) || defined(__sun__) || defined(__CYGWIN__)
|
||||
#include <sys/sysmacros.h>
|
||||
#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, atoffs<ntohl(ri->size)?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);
|
||||
}
|
90
components/romfs/readme.md
Normal file
90
components/romfs/readme.md
Normal file
@ -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 <source_> -f <image.bin>
|
||||
```
|
||||
|
||||
其中 <source_> 是需要打包的文件夹路径,<image.bin> 是要生成的 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);
|
||||
```
|
||||
|
Reference in New Issue
Block a user