GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
CROSS_COMPILE_PREFIX ?= $(CONFIG_XMEDIA_USR_ARM_TOOLCHAINS)
|
||||
CC := $(CROSS_COMPILE_PREFIX)-gcc
|
||||
CROSS_STRIP := $(CROSS_COMPILE_PREFIX)-strip
|
||||
|
||||
|
||||
UBOOT_ENV_TOOL := fw_printenv
|
||||
UBOOTENV_BUILD := $(ROOTFS_BUILDDIR)/uboot_env
|
||||
|
||||
UBOOTENV_INCDIR := $(ROOTFS_SRCDIR)/uboot_env/include
|
||||
UBOOTENV_SRCDIR := $(ROOTFS_SRCDIR)/uboot_env/source
|
||||
|
||||
UBOOTENV_SRC_OBJ_DIR := $(ROOTFS_SRCDIR)/uboot_env
|
||||
|
||||
CFLAGS := -Wall -O2 -I$(UBOOTENV_INCDIR)
|
||||
|
||||
|
||||
|
||||
SRCS := \
|
||||
$(UBOOTENV_SRCDIR)/crc32.c \
|
||||
$(UBOOTENV_SRCDIR)/fw_env.c \
|
||||
$(UBOOTENV_SRCDIR)/fw_env_main.c
|
||||
OBJS := $(patsubst $(UBOOTENV_SRCDIR)/%.c, $(UBOOTENV_BUILD)/%.o, $(SRCS))
|
||||
|
||||
rootfs_unstrip: $(ROOTFS_PREFIX)/bin/$(UBOOT_ENV_TOOL)
|
||||
|
||||
|
||||
$(ROOTFS_PREFIX)/bin/$(UBOOT_ENV_TOOL): $(UBOOTENV_BUILD)/.built
|
||||
@mkdir -p $(@D)
|
||||
cp -f $(UBOOTENV_BUILD)/$(UBOOT_ENV_TOOL) $(ROOTFS_PREFIX)/bin/
|
||||
cd $(@D) && ln -sf $(UBOOT_ENV_TOOL) fw_setenv
|
||||
touch $@
|
||||
|
||||
$(UBOOTENV_BUILD)/.built: $(OBJS) uboot_env_prepare
|
||||
$(CC) $(OBJS) -o $(UBOOTENV_BUILD)/$(UBOOT_ENV_TOOL)
|
||||
$(CROSS_STRIP) $(UBOOTENV_BUILD)/$(UBOOT_ENV_TOOL)
|
||||
@echo "Link and strip $(UBOOT_ENV_TOOL) to $(UBOOTENV_BUILD)"
|
||||
touch $@
|
||||
|
||||
uboot_env_prepare:
|
||||
mkdir -p $(UBOOTENV_BUILD) >/dev/null 2>&1
|
||||
if [ -e $(UBOOTENV_SRC_OBJ_DIR)/*.o ]; then \
|
||||
cp -af $(UBOOTENV_SRC_OBJ_DIR)/*.o $(UBOOTENV_BUILD)/; \
|
||||
fi
|
||||
@echo "Prepare uboot_env build dir: $(UBOOTENV_BUILD)"
|
||||
|
||||
$(UBOOTENV_BUILD)/%.o: $(UBOOTENV_SRCDIR)/%.c
|
||||
@mkdir -p $(@D)
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
@echo "Compiled: $< -> $@"
|
||||
|
||||
.PHONY: rootfs_unstrip uboot_env_prepare
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef __CRC32_H__
|
||||
#define __CRC32_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// U-Boot标准CRC32计算函数
|
||||
uint32_t crc32(uint32_t crc, const unsigned char *buf, unsigned int len);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,83 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
#ifndef __FW_ENV_H__
|
||||
#define __FW_ENV_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h> // 引入标准类型头文件
|
||||
|
||||
// 基础类型定义
|
||||
typedef uint32_t u32;
|
||||
typedef uint8_t u8;
|
||||
typedef int32_t s32;
|
||||
typedef unsigned long ulong; // 关键:显式定义ulong类型
|
||||
|
||||
// 环境变量核心宏
|
||||
#define MAX_REDUND 2
|
||||
#define ENV_CRC_SIZE sizeof(uint32_t)
|
||||
#define ENV_HEADER_SIZE ENV_CRC_SIZE
|
||||
#define CONFIG_ENV_SIZE 0x10000
|
||||
|
||||
// 环境变量操作选项
|
||||
struct env_opts {
|
||||
#ifdef CONFIG_FILE
|
||||
char *config_file;
|
||||
#endif
|
||||
char *lockname;
|
||||
char *part;
|
||||
ulong offset;
|
||||
ulong size;
|
||||
ulong esize;
|
||||
};
|
||||
|
||||
// 环境变量设备配置
|
||||
struct env_device {
|
||||
char *devname; // /dev/mtdX
|
||||
ulong offset; // 偏移
|
||||
ulong size; // 环境变量总大小
|
||||
ulong erasesize; // 擦除块大小
|
||||
int type; // 设备类型(MTD)
|
||||
int ubi_volume; // UBI卷标识
|
||||
};
|
||||
|
||||
// 环境变量上下文
|
||||
struct environment {
|
||||
void *image; // 环境变量缓冲区
|
||||
uint32_t *crc; // CRC指针(前4字节)
|
||||
uint8_t *flags; // 冗余标志
|
||||
char *data; // 数据区指针
|
||||
ulong usable_envsize; // 数据区有效长度
|
||||
int dirty; // 是否需要刷写
|
||||
int dev_current; // 当前激活设备
|
||||
int flag_scheme; // 标志方案
|
||||
};
|
||||
|
||||
// 快捷宏
|
||||
#define DEVNAME(idx) envdevices[idx].devname
|
||||
#define DEVOFFSET(idx) envdevices[idx].offset
|
||||
#define ENVSIZE(idx) envdevices[idx].size
|
||||
#define DEVESIZE(idx) envdevices[idx].erasesize
|
||||
#define DEVTYPE(idx) envdevices[idx].type
|
||||
#define IS_UBI(idx) envdevices[idx].ubi_volume
|
||||
#define CUR_DEVNAME DEVNAME(environment.dev_current)
|
||||
#define CUR_DEVOFFSET DEVOFFSET(environment.dev_current)
|
||||
#define CUR_ENVSIZE ENVSIZE(environment.dev_current)
|
||||
#define CUR_DEVESIZE DEVESIZE(environment.dev_current)
|
||||
|
||||
// 全局变量声明
|
||||
extern struct env_device envdevices[MAX_REDUND];
|
||||
extern struct environment environment;
|
||||
extern int have_redund_env;
|
||||
|
||||
// 函数声明
|
||||
int fw_printenv(int argc, char *argv[], int value_only, struct env_opts *opts);
|
||||
int fw_env_set(int argc, char *argv[], struct env_opts *opts);
|
||||
int fw_parse_script(char *fname, struct env_opts *opts);
|
||||
int fw_env_open(struct env_opts *opts);
|
||||
char *fw_getenv(char *name);
|
||||
int fw_env_write(char *name, char *value);
|
||||
int fw_env_flush(struct env_opts *opts);
|
||||
int fw_env_close(struct env_opts *opts);
|
||||
char *fw_env_version(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,82 @@
|
||||
#include "crc32.h"
|
||||
|
||||
#define tole(x) (x)
|
||||
|
||||
static const uint32_t crc_table[256] = {
|
||||
tole(0x00000000L), tole(0x77073096L), tole(0xee0e612cL), tole(0x990951baL),
|
||||
tole(0x076dc419L), tole(0x706af48fL), tole(0xe963a535L), tole(0x9e6495a3L),
|
||||
tole(0x0edb8832L), tole(0x79dcb8a4L), tole(0xe0d5e91eL), tole(0x97d2d988L),
|
||||
tole(0x09b64c2bL), tole(0x7eb17cbdL), tole(0xe7b82d07L), tole(0x90bf1d91L),
|
||||
tole(0x1db71064L), tole(0x6ab020f2L), tole(0xf3b97148L), tole(0x84be41deL),
|
||||
tole(0x1adad47dL), tole(0x6ddde4ebL), tole(0xf4d4b551L), tole(0x83d385c7L),
|
||||
tole(0x136c9856L), tole(0x646ba8c0L), tole(0xfd62f97aL), tole(0x8a65c9ecL),
|
||||
tole(0x14015c4fL), tole(0x63066cd9L), tole(0xfa0f3d63L), tole(0x8d080df5L),
|
||||
tole(0x3b6e20c8L), tole(0x4c69105eL), tole(0xd56041e4L), tole(0xa2677172L),
|
||||
tole(0x3c03e4d1L), tole(0x4b04d447L), tole(0xd20d85fdL), tole(0xa50ab56bL),
|
||||
tole(0x35b5a8faL), tole(0x42b2986cL), tole(0xdbbbc9d6L), tole(0xacbcf940L),
|
||||
tole(0x32d86ce3L), tole(0x45df5c75L), tole(0xdcd60dcfL), tole(0xabd13d59L),
|
||||
tole(0x26d930acL), tole(0x51de003aL), tole(0xc8d75180L), tole(0xbfd06116L),
|
||||
tole(0x21b4f4b5L), tole(0x56b3c423L), tole(0xcfba9599L), tole(0xb8bda50fL),
|
||||
tole(0x2802b89eL), tole(0x5f058808L), tole(0xc60cd9b2L), tole(0xb10be924L),
|
||||
tole(0x2f6f7c87L), tole(0x58684c11L), tole(0xc1611dabL), tole(0xb6662d3dL),
|
||||
tole(0x76dc4190L), tole(0x01db7106L), tole(0x98d220bcL), tole(0xefd5102aL),
|
||||
tole(0x71b18589L), tole(0x06b6b51fL), tole(0x9fbfe4a5L), tole(0xe8b8d433L),
|
||||
tole(0x7807c9a2L), tole(0x0f00f934L), tole(0x9609a88eL), tole(0xe10e9818L),
|
||||
tole(0x7f6a0dbbL), tole(0x086d3d2dL), tole(0x91646c97L), tole(0xe6635c01L),
|
||||
tole(0x6b6b51f4L), tole(0x1c6c6162L), tole(0x856530d8L), tole(0xf262004eL),
|
||||
tole(0x6c0695edL), tole(0x1b01a57bL), tole(0x8208f4c1L), tole(0xf50fc457L),
|
||||
tole(0x65b0d9c6L), tole(0x12b7e950L), tole(0x8bbeb8eaL), tole(0xfcb9887cL),
|
||||
tole(0x62dd1ddfL), tole(0x15da2d49L), tole(0x8cd37cf3L), tole(0xfbd44c65L),
|
||||
tole(0x4db26158L), tole(0x3ab551ceL), tole(0xa3bc0074L), tole(0xd4bb30e2L),
|
||||
tole(0x4adfa541L), tole(0x3dd895d7L), tole(0xa4d1c46dL), tole(0xd3d6f4fbL),
|
||||
tole(0x4369e96aL), tole(0x346ed9fcL), tole(0xad678846L), tole(0xda60b8d0L),
|
||||
tole(0x44042d73L), tole(0x33031de5L), tole(0xaa0a4c5fL), tole(0xdd0d7cc9L),
|
||||
tole(0x5005713cL), tole(0x270241aaL), tole(0xbe0b1010L), tole(0xc90c2086L),
|
||||
tole(0x5768b525L), tole(0x206f85b3L), tole(0xb966d409L), tole(0xce61e49fL),
|
||||
tole(0x5edef90eL), tole(0x29d9c998L), tole(0xb0d09822L), tole(0xc7d7a8b4L),
|
||||
tole(0x59b33d17L), tole(0x2eb40d81L), tole(0xb7bd5c3bL), tole(0xc0ba6cadL),
|
||||
tole(0xedb88320L), tole(0x9abfb3b6L), tole(0x03b6e20cL), tole(0x74b1d29aL),
|
||||
tole(0xead54739L), tole(0x9dd277afL), tole(0x04db2615L), tole(0x73dc1683L),
|
||||
tole(0xe3630b12L), tole(0x94643b84L), tole(0x0d6d6a3eL), tole(0x7a6a5aa8L),
|
||||
tole(0xe40ecf0bL), tole(0x9309ff9dL), tole(0x0a00ae27L), tole(0x7d079eb1L),
|
||||
tole(0xf00f9344L), tole(0x8708a3d2L), tole(0x1e01f268L), tole(0x6906c2feL),
|
||||
tole(0xf762575dL), tole(0x806567cbL), tole(0x196c3671L), tole(0x6e6b06e7L),
|
||||
tole(0xfed41b76L), tole(0x89d32be0L), tole(0x10da7a5aL), tole(0x67dd4accL),
|
||||
tole(0xf9b9df6fL), tole(0x8ebeeff9L), tole(0x17b7be43L), tole(0x60b08ed5L),
|
||||
tole(0xd6d6a3e8L), tole(0xa1d1937eL), tole(0x38d8c2c4L), tole(0x4fdff252L),
|
||||
tole(0xd1bb67f1L), tole(0xa6bc5767L), tole(0x3fb506ddL), tole(0x48b2364bL),
|
||||
tole(0xd80d2bdaL), tole(0xaf0a1b4cL), tole(0x36034af6L), tole(0x41047a60L),
|
||||
tole(0xdf60efc3L), tole(0xa867df55L), tole(0x316e8eefL), tole(0x4669be79L),
|
||||
tole(0xcb61b38cL), tole(0xbc66831aL), tole(0x256fd2a0L), tole(0x5268e236L),
|
||||
tole(0xcc0c7795L), tole(0xbb0b4703L), tole(0x220216b9L), tole(0x5505262fL),
|
||||
tole(0xc5ba3bbeL), tole(0xb2bd0b28L), tole(0x2bb45a92L), tole(0x5cb36a04L),
|
||||
tole(0xc2d7ffa7L), tole(0xb5d0cf31L), tole(0x2cd99e8bL), tole(0x5bdeae1dL),
|
||||
tole(0x9b64c2b0L), tole(0xec63f226L), tole(0x756aa39cL), tole(0x026d930aL),
|
||||
tole(0x9c0906a9L), tole(0xeb0e363fL), tole(0x72076785L), tole(0x05005713L),
|
||||
tole(0x95bf4a82L), tole(0xe2b87a14L), tole(0x7bb12baeL), tole(0x0cb61b38L),
|
||||
tole(0x92d28e9bL), tole(0xe5d5be0dL), tole(0x7cdcefb7L), tole(0x0bdbdf21L),
|
||||
tole(0x86d3d2d4L), tole(0xf1d4e242L), tole(0x68ddb3f8L), tole(0x1fda836eL),
|
||||
tole(0x81be16cdL), tole(0xf6b9265bL), tole(0x6fb077e1L), tole(0x18b74777L),
|
||||
tole(0x88085ae6L), tole(0xff0f6a70L), tole(0x66063bcaL), tole(0x11010b5cL),
|
||||
tole(0x8f659effL), tole(0xf862ae69L), tole(0x616bffd3L), tole(0x166ccf45L),
|
||||
tole(0xa00ae278L), tole(0xd70dd2eeL), tole(0x4e048354L), tole(0x3903b3c2L),
|
||||
tole(0xa7672661L), tole(0xd06016f7L), tole(0x4969474dL), tole(0x3e6e77dbL),
|
||||
tole(0xaed16a4aL), tole(0xd9d65adcL), tole(0x40df0b66L), tole(0x37d83bf0L),
|
||||
tole(0xa9bcae53L), tole(0xdebb9ec5L), tole(0x47b2cf7fL), tole(0x30b5ffe9L),
|
||||
tole(0xbdbdf21cL), tole(0xcabac28aL), tole(0x53b39330L), tole(0x24b4a3a6L),
|
||||
tole(0xbad03605L), tole(0xcdd70693L), tole(0x54de5729L), tole(0x23d967bfL),
|
||||
tole(0xb3667a2eL), tole(0xc4614ab8L), tole(0x5d681b02L), tole(0x2a6f2b94L),
|
||||
tole(0xb40bbe37L), tole(0xc30c8ea1L), tole(0x5a05df1bL), tole(0x2d02ef8dL)
|
||||
};
|
||||
|
||||
uint32_t crc32(uint32_t crc, const unsigned char *buf, unsigned int len)
|
||||
{
|
||||
if (crc == 0)
|
||||
crc = 0xFFFFFFFF;
|
||||
|
||||
while (len--) {
|
||||
crc = crc_table[(crc ^ *buf++) & 0xFF] ^ (crc >> 8);
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
@@ -0,0 +1,466 @@
|
||||
#include "fw_env.h"
|
||||
#include "crc32.h"
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <mtd/mtd-user.h>
|
||||
#include <errno.h>
|
||||
|
||||
// 全局变量定义
|
||||
struct env_device envdevices[MAX_REDUND] = {0};
|
||||
struct environment environment = {0};
|
||||
int have_redund_env;
|
||||
|
||||
// 默认参数
|
||||
static struct env_opts default_opts = {
|
||||
#ifdef CONFIG_FILE
|
||||
.config_file = NULL,
|
||||
#endif
|
||||
.lockname = NULL,
|
||||
.part = "bootargs",
|
||||
.offset = 0x0,
|
||||
.size = 0x0,
|
||||
.esize = 0x0,
|
||||
};
|
||||
|
||||
// 解析/proc/mtd获取分区信息
|
||||
static int find_mtd_by_name(const char *name, char *devpath, unsigned long *size, unsigned long *erase)
|
||||
{
|
||||
FILE *fp;
|
||||
char line[128];
|
||||
int mtdnum;
|
||||
char mtdname[64];
|
||||
|
||||
fp = fopen("/proc/mtd", "r");
|
||||
if (!fp)
|
||||
return -1;
|
||||
|
||||
fgets(line, sizeof(line), fp);
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
if (sscanf(line, "mtd%d: %lx %lx \"%63[^\"]\"", &mtdnum, size, erase, mtdname) == 4) {
|
||||
if (!strcmp(mtdname, name)) {
|
||||
sprintf(devpath, "/dev/mtd%d", mtdnum);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int check_device_config(int index)
|
||||
{
|
||||
if (CUR_DEVOFFSET + CUR_ENVSIZE > (1ULL << 32)) {
|
||||
fprintf(stderr, "Error: ENV range exceeds 32-bit address space\n");
|
||||
return -1;
|
||||
}
|
||||
if (CUR_ENVSIZE == 0 || CUR_DEVESIZE == 0) {
|
||||
fprintf(stderr, "Error: ENV size or erase size is zero\n");
|
||||
return -1;
|
||||
}
|
||||
if (environment.usable_envsize < 8) {
|
||||
fprintf(stderr, "Error: Usable ENV size too small (%lu bytes)\n", environment.usable_envsize);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_config(struct env_opts *opts)
|
||||
{
|
||||
int rc;
|
||||
char devname[32];
|
||||
unsigned long part_size = 0, part_erase = 0;
|
||||
|
||||
if (!opts) {
|
||||
fprintf(stderr, "env_opts is NULL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *part_name = opts->part ? opts->part : "bootargs";
|
||||
if (find_mtd_by_name(part_name, devname, &part_size, &part_erase) < 0) {
|
||||
fprintf(stderr, "Cannot find mtd partition '%s'\n", part_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEVNAME(0) = strdup(devname);
|
||||
if (!DEVNAME(0)) {
|
||||
fprintf(stderr, "No memory for DEVNAME\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEVOFFSET(0) = (opts->offset != 0) ? opts->offset : 0x0;
|
||||
ENVSIZE(0) = (opts->size != 0) ? opts->size : part_erase;
|
||||
DEVESIZE(0) = (opts->esize != 0) ? opts->esize : part_erase;
|
||||
environment.usable_envsize = CUR_ENVSIZE - ENV_CRC_SIZE;
|
||||
|
||||
have_redund_env = 0;
|
||||
rc = check_device_config(0);
|
||||
if (rc < 0) {
|
||||
free(DEVNAME(0));
|
||||
DEVNAME(0) = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int env_check_crc(void)
|
||||
{
|
||||
uint32_t stored_crc, calc_crc;
|
||||
|
||||
if (!environment.image || environment.usable_envsize == 0)
|
||||
return -1;
|
||||
|
||||
memcpy(&stored_crc, environment.image, ENV_CRC_SIZE);
|
||||
calc_crc = crc32(0, (unsigned char *)environment.data, environment.usable_envsize);
|
||||
|
||||
if (stored_crc != calc_crc) {
|
||||
fprintf(stderr, "U-Boot CRC Check Failed: stored=0x%08x, calc=0x%08x\n", stored_crc, calc_crc);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_mtd_info(int fd, struct mtd_info_user *info)
|
||||
{
|
||||
if (ioctl(fd, MEMGETINFO, info) < 0) {
|
||||
perror("MEMGETINFO");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Flash读写封装
|
||||
static int flash_io(int mode)
|
||||
{
|
||||
int fd;
|
||||
ssize_t ret;
|
||||
struct mtd_info_user mtd;
|
||||
size_t rw_len = CUR_ENVSIZE;
|
||||
off_t offset = CUR_DEVOFFSET;
|
||||
|
||||
fd = open(CUR_DEVNAME, (mode == O_RDONLY) ? O_RDONLY : O_RDWR);
|
||||
if (fd < 0) {
|
||||
perror(CUR_DEVNAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (get_mtd_info(fd, &mtd)) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (offset + rw_len > mtd.size) {
|
||||
fprintf(stderr, "ENV exceeds MTD size (off=0x%lx size=0x%lx mtd=0x%x)\n", offset, rw_len, mtd.size);
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (offset) {
|
||||
char dummy[4096];
|
||||
size_t skip = offset;
|
||||
while (skip) {
|
||||
size_t n = skip > sizeof(dummy) ? sizeof(dummy) : skip;
|
||||
ret = read(fd, dummy, n);
|
||||
if (ret <= 0)
|
||||
goto err;
|
||||
skip -= ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == O_RDONLY) {
|
||||
ret = read(fd, environment.image, rw_len);
|
||||
} else {
|
||||
ret = write(fd, environment.image, rw_len);
|
||||
fsync(fd);
|
||||
}
|
||||
|
||||
if (ret != (ssize_t)rw_len)
|
||||
goto err;
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
perror("flash_io");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 擦除Flash
|
||||
static int flash_erase(void)
|
||||
{
|
||||
int fd;
|
||||
struct erase_info_user ei;
|
||||
struct mtd_info_user mtd;
|
||||
|
||||
fd = open(CUR_DEVNAME, O_RDWR);
|
||||
if (fd < 0) {
|
||||
perror(CUR_DEVNAME);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (get_mtd_info(fd, &mtd)) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (ulong off = CUR_DEVOFFSET; off < CUR_DEVOFFSET + CUR_ENVSIZE; off += mtd.erasesize) {
|
||||
ei.start = off;
|
||||
ei.length = mtd.erasesize;
|
||||
if (ioctl(fd, MEMERASE, &ei) < 0) {
|
||||
perror("MEMERASE");
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 打开环境变量
|
||||
int fw_env_open(struct env_opts *opts)
|
||||
{
|
||||
int ret;
|
||||
void *addr = NULL;
|
||||
|
||||
if (!opts) {
|
||||
printf("==== Error no opts ==== \n");
|
||||
opts = &default_opts;
|
||||
}
|
||||
|
||||
if (parse_config(opts))
|
||||
return -1;
|
||||
|
||||
addr = calloc(1, CUR_ENVSIZE);
|
||||
if (!addr) {
|
||||
fprintf(stderr, "Not enough memory for environment (%lu bytes)\n", CUR_ENVSIZE);
|
||||
free(CUR_DEVNAME);
|
||||
CUR_DEVNAME = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
environment.image = addr;
|
||||
environment.crc = (uint32_t *)addr;
|
||||
environment.data = (char *)addr + ENV_HEADER_SIZE;
|
||||
environment.dev_current = 0;
|
||||
environment.dirty = 0;
|
||||
|
||||
if (flash_io(O_RDONLY)) {
|
||||
free(addr);
|
||||
free(CUR_DEVNAME);
|
||||
CUR_DEVNAME = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = env_check_crc();
|
||||
if (ret < 0) {
|
||||
free(addr);
|
||||
free(CUR_DEVNAME);
|
||||
CUR_DEVNAME = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 获取环境变量
|
||||
char *fw_getenv(char *name)
|
||||
{
|
||||
char *ptr = environment.data;
|
||||
char *end = environment.data + environment.usable_envsize;
|
||||
int name_len = strlen(name);
|
||||
|
||||
if (!environment.image || environment.usable_envsize == 0)
|
||||
return NULL;
|
||||
|
||||
while (ptr < end && *ptr) {
|
||||
if (strncmp(ptr, name, name_len) == 0 && ptr[name_len] == '=') {
|
||||
return ptr + name_len + 1;
|
||||
}
|
||||
ptr += strlen(ptr) + 1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 打印环境变量
|
||||
int fw_printenv(int argc, char *argv[], int value_only, struct env_opts *opts)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (fw_env_open(opts))
|
||||
return -1;
|
||||
|
||||
if (argc == 0) {
|
||||
// 打印所有变量
|
||||
char *ptr = environment.data;
|
||||
char *end = environment.data + environment.usable_envsize;
|
||||
while (ptr < end && *ptr) {
|
||||
printf("%s\n", ptr);
|
||||
ptr += strlen(ptr) + 1;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < argc; i++) {
|
||||
char *val = fw_getenv(argv[i]);
|
||||
if (val) {
|
||||
if (value_only) {
|
||||
printf("%s\n", val);
|
||||
} else {
|
||||
printf("%s=%s\n", argv[i], val);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "%s: Not found\n", argv[i]);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fw_env_close(opts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 拼接环境变量值
|
||||
static char *concat_env_value(int argc, char *argv[])
|
||||
{
|
||||
int total_len = 0;
|
||||
char *val, *ptr;
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
total_len += strlen(argv[i]) + 1;
|
||||
}
|
||||
if (total_len == 0)
|
||||
return NULL;
|
||||
|
||||
val = malloc(total_len);
|
||||
if (!val)
|
||||
return NULL;
|
||||
|
||||
ptr = val;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
strcpy(ptr, argv[i]);
|
||||
ptr += strlen(argv[i]);
|
||||
if (i < argc - 1) {
|
||||
*ptr++ = ' ';
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
// 写入环境变量
|
||||
int fw_env_write(char *name, char *value)
|
||||
{
|
||||
char *new_env, *ptr, *old_ptr;
|
||||
int name_len = strlen(name);
|
||||
uint32_t new_crc;
|
||||
|
||||
if (!environment.image || environment.usable_envsize == 0)
|
||||
return -1;
|
||||
|
||||
new_env = calloc(1, CUR_ENVSIZE);
|
||||
if (!new_env)
|
||||
return -1;
|
||||
|
||||
ptr = new_env + ENV_HEADER_SIZE;
|
||||
old_ptr = environment.data;
|
||||
char *end = environment.data + environment.usable_envsize;
|
||||
|
||||
while (old_ptr < end && *old_ptr) {
|
||||
if (strncmp(old_ptr, name, name_len) != 0 || old_ptr[name_len] != '=') {
|
||||
int len = strlen(old_ptr) + 1;
|
||||
if (ptr + len > new_env + ENV_HEADER_SIZE + environment.usable_envsize) {
|
||||
fprintf(stderr, "Error: ENV data overflow\n");
|
||||
free(new_env);
|
||||
return -1;
|
||||
}
|
||||
memcpy(ptr, old_ptr, len);
|
||||
ptr += len;
|
||||
}
|
||||
old_ptr += strlen(old_ptr) + 1;
|
||||
}
|
||||
|
||||
if (value) {
|
||||
int entry_len = snprintf(ptr, new_env + ENV_HEADER_SIZE + environment.usable_envsize - ptr, "%s=%s", name, value) + 1;
|
||||
if (ptr + entry_len > new_env + ENV_HEADER_SIZE + environment.usable_envsize) {
|
||||
fprintf(stderr, "Error: New variable exceeds usable ENV size\n");
|
||||
free(new_env);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
new_crc = crc32(0, (unsigned char *)new_env + ENV_HEADER_SIZE, environment.usable_envsize);
|
||||
memcpy(new_env, &new_crc, ENV_CRC_SIZE);
|
||||
|
||||
memcpy(environment.image, new_env, CUR_ENVSIZE);
|
||||
free(new_env);
|
||||
|
||||
environment.dirty = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 设置环境变量
|
||||
int fw_env_set(int argc, char *argv[], struct env_opts *opts)
|
||||
{
|
||||
char *name, *value;
|
||||
int ret = 0;
|
||||
|
||||
if (argc < 1) {
|
||||
fprintf(stderr, "Error: No variable name specified\n");
|
||||
return -1;
|
||||
}
|
||||
name = argv[0];
|
||||
|
||||
if (fw_env_open(opts))
|
||||
return -1;
|
||||
|
||||
value = concat_env_value(argc, argv);
|
||||
if (fw_env_write(name, value)) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (flash_erase() || flash_io(O_WRONLY)) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Success: set %s=%s (ENV size: %lu bytes, usable: %lu bytes)\n",
|
||||
name, value ? value : "", CUR_ENVSIZE, environment.usable_envsize);
|
||||
|
||||
out:
|
||||
free(value);
|
||||
fw_env_close(opts);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 关闭环境变量
|
||||
int fw_env_close(struct env_opts *opts)
|
||||
{
|
||||
(void)opts;
|
||||
|
||||
if (environment.image) {
|
||||
free(environment.image);
|
||||
environment.image = NULL;
|
||||
}
|
||||
if (CUR_DEVNAME) {
|
||||
free(CUR_DEVNAME);
|
||||
CUR_DEVNAME = NULL;
|
||||
}
|
||||
|
||||
memset(&environment, 0, sizeof(environment));
|
||||
memset(envdevices, 0, sizeof(envdevices));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 版本信息
|
||||
char *fw_env_version(void)
|
||||
{
|
||||
static char version[] = "fw_env v1.0 (U-Boot compatible, no mmap, dynamic ENV size)";
|
||||
return version;
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
#include "fw_env.h"
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/file.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define CMD_PRINTENV "fw_printenv"
|
||||
#define CMD_SETENV "fw_setenv"
|
||||
|
||||
static int do_printenv = 0;
|
||||
static char *script_file = NULL;
|
||||
static int noheader = 0;
|
||||
static struct env_opts env_opts = {
|
||||
#ifdef CONFIG_FILE
|
||||
.config_file = NULL,
|
||||
#endif
|
||||
.lockname = NULL,
|
||||
.part = NULL,
|
||||
.offset = 0x0,
|
||||
.size = 0x0,
|
||||
.esize = 0x0,
|
||||
};
|
||||
|
||||
static const struct option long_options[] = {
|
||||
{"config", required_argument, NULL, 'c'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{"script", required_argument, NULL, 'S'},
|
||||
{"noheader", no_argument, NULL, 'n'},
|
||||
{"lock", required_argument, NULL, 'l'},
|
||||
{"version", no_argument, NULL, 'v'},
|
||||
{"part", required_argument, NULL, 'p'},
|
||||
{"offset", required_argument, NULL, 'o'},
|
||||
{"size", required_argument, NULL, 's'},
|
||||
{"esize", required_argument, NULL, 'e'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
static void usage(int is_printenv)
|
||||
{
|
||||
if (is_printenv) {
|
||||
fprintf(stderr,
|
||||
"Usage: %s [OPTIONS]... [VARIABLE]...\n"
|
||||
"Print variables from U-Boot environment\n\n"
|
||||
"Options:\n"
|
||||
" -h, --help Print this help message\n"
|
||||
" -v, --version Display version information\n"
|
||||
#ifdef CONFIG_FILE
|
||||
" -c, --config FILE Use specified configuration file\n"
|
||||
#endif
|
||||
" -n, --noheader Only print variable values\n"
|
||||
" -l, --lock FILE Use specified lock file\n"
|
||||
" -p, --part NAME Specify partition name\n"
|
||||
" -o, --offset NUM Specify environment offset\n"
|
||||
" -s, --size NUM Specify environment size\n"
|
||||
" -e, --esize NUM Specify environment effective size\n\n",
|
||||
CMD_PRINTENV);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Usage: %s [OPTIONS]... [VARIABLE]... [VALUE]...\n"
|
||||
"Modify variables in U-Boot environment\n\n"
|
||||
"Options:\n"
|
||||
" -h, --help Print this help message\n"
|
||||
" -v, --version Display version information\n"
|
||||
#ifdef CONFIG_FILE
|
||||
" -c, --config FILE Use specified configuration file\n"
|
||||
#endif
|
||||
" -l, --lock FILE Use specified lock file\n"
|
||||
" -S, --script FILE Batch modify variables via script\n"
|
||||
" -p, --part NAME Specify partition name\n"
|
||||
" -o, --offset NUM Specify environment offset\n"
|
||||
" -s, --size NUM Specify environment size\n"
|
||||
" -e, --esize NUM Specify environment effective size\n\n"
|
||||
"Examples:\n"
|
||||
" %s foo bar Set variable 'foo' to 'bar'\n"
|
||||
" %s foo Delete variable 'foo'\n\n",
|
||||
CMD_SETENV, CMD_SETENV, CMD_SETENV);
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_env_args(int argc, char *argv[], int is_printenv)
|
||||
{
|
||||
int c;
|
||||
opterr = 0;
|
||||
|
||||
#ifdef CONFIG_FILE
|
||||
env_opts.config_file = CONFIG_FILE;
|
||||
#endif
|
||||
|
||||
while ((c = getopt_long(argc, argv, "a:c:nl:h:vS:p:o:s:e:", long_options, NULL)) != EOF) {
|
||||
switch (c) {
|
||||
case 'c':
|
||||
#ifdef CONFIG_FILE
|
||||
env_opts.config_file = optarg;
|
||||
#endif
|
||||
break;
|
||||
case 'l':
|
||||
env_opts.lockname = optarg;
|
||||
break;
|
||||
case 'n':
|
||||
noheader = 1;
|
||||
break;
|
||||
case 'S':
|
||||
script_file = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
env_opts.part = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
env_opts.offset = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 's':
|
||||
env_opts.size = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'e':
|
||||
env_opts.esize = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'h':
|
||||
usage(is_printenv);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'v':
|
||||
fprintf(stderr, "fw_env v2020.01-standalone\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'a':
|
||||
break;
|
||||
case '?':
|
||||
fprintf(stderr, "Unknown option: -%c\n", optopt);
|
||||
usage(is_printenv);
|
||||
return -1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int retval = EXIT_SUCCESS;
|
||||
char *cmdname = *argv;
|
||||
|
||||
if (strrchr(cmdname, '/')) {
|
||||
cmdname = strrchr(cmdname, '/') + 1;
|
||||
}
|
||||
|
||||
if (strcmp(cmdname, CMD_PRINTENV) == 0) {
|
||||
do_printenv = 1;
|
||||
} else if (strcmp(cmdname, CMD_SETENV) == 0) {
|
||||
do_printenv = 0;
|
||||
} else {
|
||||
fprintf(stderr, "Error: Must be called as '%s' or '%s' (not '%s')\n", CMD_PRINTENV, CMD_SETENV, cmdname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (parse_env_args(argc, argv, do_printenv) != 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (do_printenv) {
|
||||
if (fw_printenv(argc, argv, noheader, &env_opts) != 0)
|
||||
retval = EXIT_FAILURE;
|
||||
} else {
|
||||
if (script_file) {
|
||||
fprintf(stderr, "Script mode not implemented\n");
|
||||
retval = EXIT_FAILURE;
|
||||
} else {
|
||||
if (argc < 1) {
|
||||
fprintf(stderr, "Error: No variable name specified\n");
|
||||
usage(0);
|
||||
retval = EXIT_FAILURE;
|
||||
} else if (fw_env_set(argc, argv, &env_opts) != 0) {
|
||||
retval = EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
Reference in New Issue
Block a user