GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
+51
View File
@@ -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
+9
View File
@@ -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
+83
View File
@@ -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
+82
View File
@@ -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;
}
+466
View File
@@ -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;
}