Browse Source

add ubootenv api

Signed-off-by: surenyi <surenyi82@163.com>
master
surenyi 2 weeks ago
parent
commit
9fc5f44689
  1. 4
      Makefile
  2. 5
      bspApi.h
  3. 161
      bspEnv.c
  4. 27
      bspStubs.c
  5. 5
      config.h
  6. 2
      hwconf.c
  7. 5
      sysLib.c
  8. 113
      ubootenv/crc32.c
  9. 145
      ubootenv/libuboot.h
  10. 699
      ubootenv/uboot_env.c
  11. 190
      ubootenv/uboot_private.h
  12. 6
      vxbLfsLib.c

4
Makefile

@ -20,8 +20,8 @@ RELEASE += bootrom_uncmp.hex
MACH_EXTRA += vxbArmGenIntCtlrV3.o vxbArmv7GenTimer.o vxbArmv7AuxTimer.o \
vxbFtPcie.o vxbAhciStorage.o vxbFtGmacEnd.o vxbFtcan.o vxbPci.o \
vxbFtSdCtrl.o vxbFtI2c.o vxbYt8521Phy.o genericPhy.o vxbFtQspi.o\
vxbSp25SpiFlash.o vxbFtGpio.o vxbFtSpi.o vxbSm2130SpiDev.o \
bspStubs.o vxbLfsLib.o
vxbSp25SpiFlash.o vxbFtGpio.o vxbFtSpi.o vxbSm2130SpiDev.o vxbLfsLib.o \
bspStubs.o bspEnv.o \
ifneq ($(findstring bootrom,$(MAKECMDGOALS)),bootrom)
LIB_EXTRA = lib/libFtX100dcdrv.a

5
bspApi.h

@ -31,6 +31,11 @@ struct sm2130_xfer_mem {
typedef struct sm2130_xfer_mem SM2130_MEM_XFER;
/* }}} */
/* functions */
int envInit();
int bspLoadUserApp();
int updateVxWorks(const char *file, int pos);
#ifdef __cplusplus
}
#endif

161
bspEnv.c

@ -0,0 +1,161 @@
#include <vxWorks.h>
#include <vsbConfig.h>
#include <semLib.h>
#include <stdlib.h>
#include "ubootenv/crc32.c"
#include "ubootenv/uboot_env.c"
#include "config.h"
extern int lfsLowRawWrite(unsigned long offset, const char *buffer, int size);
static int env_read(unsigned int offset, void *buf, size_t len)
{
memcpy(buf, (void *)(offset), len);
return 0;
}
static int env_write(unsigned int offset, const void *buf, size_t size)
{
lfsLowRawWrite(offset, buf, size);
return 0;
}
/* clang-format off */
static struct uboot_env_device __bsp_uenv = {
"qspiflash",
QSPI_ENV_OFFSET,
0x10000,
0x1000,
0x10,
env_read,
env_write,
};
/* clang-format on */
static struct uboot_ctx *__ctx = NULL;
static SEM_ID __ctx_lock = NULL;
int uenvInit()
{
int err = 0;
if (__ctx == NULL) {
if (!__ctx_lock) {
__ctx_lock = semBCreate(SEM_Q_FIFO, SEM_FULL);
}
semTake(__ctx_lock, WAIT_FOREVER);
if (__ctx == NULL) {
err = libuboot_initialize(&__ctx, &__bsp_uenv, 1);
if (err) {
semGive(__ctx_lock);
goto skip;
}
if (libuboot_open(__ctx)) {
libuboot_exit(__ctx);
err = -101;
__ctx = NULL;
}
}
semGive(__ctx_lock);
}
skip:
return (err);
}
int uenvget(const char *varname, char *buf, size_t len)
{
const char *val = NULL;
int r = -1;
if (__ctx) {
semTake(__ctx_lock, WAIT_FOREVER);
val = libuboot_get_env(__ctx, varname);
if (val) {
strncpy(buf, val, len);
r = 0;
}
semGive(__ctx_lock);
}
return r;
}
unsigned int uenvGetUint(const char *varname)
{
char value[64] = {0};
if (uenvget(varname, value, sizeof value) == 0) {
return strtoul(value, NULL, 16);
}
return (unsigned int)(-1);
}
int setenv(const char *varname, const char *value)
{
int err = -1;
if (__ctx) {
semTake(__ctx_lock, WAIT_FOREVER);
err = libuboot_set_env(__ctx, varname, value);
semGive(__ctx_lock);
}
return (err);
}
int saveenv()
{
int err = -1;
if (__ctx) {
semTake(__ctx_lock, WAIT_FOREVER);
err = libuboot_env_store(__ctx);
semGive(__ctx_lock);
}
return (err);
}
static void *envNext(void *next)
{
if (__ctx) {
return libuboot_iterator(__ctx, next);
}
return NULL;
}
static const char *envGetName(void *entry)
{
return libuboot_getname(entry);
}
static const char *envGetValue(void *entry)
{
return libuboot_getvalue(entry);
}
int printenv(const char *name)
{
void *entry;
if (!__ctx) {
return -1;
}
semTake(__ctx_lock, WAIT_FOREVER);
if (name) {
const char *val;
val = libuboot_get_env(__ctx, name);
if (val) {
printf("%s\r\n", val);
} else {
printf("%s: not found\r\n", name);
}
semGive(__ctx_lock);
return 0;
}
entry = envNext(NULL);
while (entry) {
printf("%18s: %s\n", envGetName(entry), envGetValue(entry));
entry = envNext(entry);
}
semGive(__ctx_lock);
return 0;
}

27
bspStubs.c

@ -1,14 +1,17 @@
#include <vxWorks.h>
#include <vsbConfig.h>
#include <stdio.h>
#include <string.h>
#include <moduleLib.h>
#include <usrLib.h>
#include <cacheLib.h>
#include <ioLib.h>
#include <sysSymTbl.h>
#include <fcntl.h>
#include <hwif/vxbus/vxBus.h>
#include <hwif/util/vxbParamSys.h>
#include "config.h"
#include "ubootenv/libuboot.h"
#include "vxbFtGpio.h"
#if defined(INCLUDE_IPFTPS)
#include <ipcom_sysvar.h>
@ -21,7 +24,9 @@
/* externs */
extern int lfsLowRawWrite(unsigned long offset, const char *buffer, int size);
extern void gpioIsrSetTest (UINT32 gpio, UINT32 pin);
extern unsigned int uenvGetUint(const char *varname);
extern int uenvInit();
int bspLoadUserApp()
{
SEGMENT_ID seg;
@ -62,6 +67,7 @@ int bspLoadUserApp()
#if defined(__DCC__)
void usrAppInit(void)
{
uenvInit();
bspLoadUserApp();
}
#endif
@ -77,7 +83,13 @@ int updateVxWorks(const char *file, int pos)
printf("Can't stat %s\r\n", file);
return ERROR;
}
if (pos <= 0) {
pos = (int)uenvGetUint("krnaddr");
}
if (pos <= QSPI_PROTECT_SIZE) {
printf("Unknown flash offset (0x%x)\r\n", pos);
return -1;
}
size = (stbuf.st_size + 0x10000 - 1) / 0x10000;
size *= 0x10000;
ptr = malloc(size);
@ -95,7 +107,7 @@ int updateVxWorks(const char *file, int pos)
return ERROR;
}
printf("Reading: %d bytes\r\n", stbuf.st_size);
size = read(fd, ptr, stbuf.st_size);
size = read(fd, (void *)ptr, stbuf.st_size);
close(fd);
if (size != stbuf.st_size) {
@ -105,11 +117,8 @@ int updateVxWorks(const char *file, int pos)
}
size = (stbuf.st_size + 0x100 - 1) / 0x100;
size *= 0x100;
printf("Write to flash\r\n");
if (pos <= 0) {
pos = VXWORKS_POS;
}
status = lfsLowRawWrite(pos, ptr, size);
printf("Write to flash offset: 0x%x, len: %d\r\n", pos, stbuf.st_size);
status = lfsLowRawWrite(pos, (void *)ptr, size);
free(ptr);
printf("%s\r\n", status == OK ? "Success" : "Failed");
return status;

5
config.h

@ -191,7 +191,8 @@ extern "C" {
#define SPI_FLASH_SECTOR_NUM ((SPI_FLASH_SIZE) / (SPI_FLASH_SECTOR_SIZE))
#define SPI_BOOTROM_SIZE (0x400000)
#define SPI_KERNEL_SIZE (0x600000)
#define QSPI_PROTECT_SIZE (0x2A0000)
#define QSPI_ENV_OFFSET (0x2f0000)
#if defined(INCLUDE_TFFS)
#define INCLUDE_TFFS_MOUNT
#define INCLUDE_TFFS_SHOW
@ -292,8 +293,6 @@ extern "C" {
#define INCLUDE_ISR_OBJECTS
#define USER_APPL_INIT (loadUserApp())
#ifdef __cplusplus
}
#endif

2
hwconf.c

@ -592,7 +592,7 @@ const struct hcfDevice hcfDeviceList[] = {
{ "ftGpio", 1, VXB_BUSID_PLB, 0, gpioDev1Num, gpioDev1Resources },
#endif
#ifdef DRV_FS_LITTLEFS
{ "lfs", 0, VXB_BUSID_PLB, 0, lfsResNum, lfsResources},
{ "littlefs", 0, VXB_BUSID_PLB, 0, lfsResNum, lfsResources},
#endif
{ "SM2130", 0, VXB_BUSID_SPI, 0, sm2130ResNum, sm2130Resources},
};

5
sysLib.c

@ -205,12 +205,12 @@ PHYS_MEM_DESC sysPhysMemDesc[] = {
#ifdef DRV_FTQSPI
{ /* Qspi BootRom */
SPI_FLASH_BASE_ADRS, SPI_FLASH_BASE_ADRS, SPI_BOOTROM_SIZE,
SPI_FLASH_BASE_ADRS, SPI_FLASH_BASE_ADRS, QSPI_PROTECT_SIZE,
MMU_ATTR_VALID_MSK | MMU_ATTR_PROT_MSK | MMU_ATTR_DEVICE_SHARED_MSK,
MMU_ATTR_VALID | MMU_ATTR_SUP_RO | MMU_ATTR_DEVICE_SHARED },
{ /* Qspi Flash */
SPI_FLASH_BASE_ADRS + SPI_BOOTROM_SIZE, SPI_FLASH_BASE_ADRS + SPI_BOOTROM_SIZE, SPI_FLASH_SIZE - SPI_BOOTROM_SIZE,
SPI_FLASH_BASE_ADRS + QSPI_PROTECT_SIZE, SPI_FLASH_BASE_ADRS + QSPI_PROTECT_SIZE, SPI_FLASH_SIZE - QSPI_PROTECT_SIZE,
MMU_ATTR_VALID_MSK | MMU_ATTR_PROT_MSK | MMU_ATTR_DEVICE_SHARED_MSK,
MMU_ATTR_VALID | MMU_ATTR_SUP_RW | MMU_ATTR_DEVICE_SHARED },
#endif
@ -580,7 +580,6 @@ void sysHwInit(void)
reg &= ~((0x3 << 12) | (0x3 << 8) | 0x3);
reg |= (1 << 12) | ( 1 << 8) | 1;
writel(reg, PIN_DEMUX_BASE + REG200);
#ifdef DRV_X100DC
ftX100DcDevicePciRegister();
#endif

113
ubootenv/crc32.c

@ -0,0 +1,113 @@
#include <stdint.h>
#include <stddef.h>
static const uint32_t crc_table[256] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL,
0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L,
0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L,
0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL,
0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L,
0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L,
0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L,
0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L,
0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL,
0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL,
0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL,
0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L,
0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L,
0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL,
0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL,
0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L,
0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL,
0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L,
0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L,
0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L,
0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL,
0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL,
0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL,
0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L,
0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L,
0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L,
0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL,
0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L,
0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL,
0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL,
0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L,
0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL,
0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L,
0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L,
0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L,
0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL,
0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L,
0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L,
0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L,
0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
};
#define DO_CRC(x) crc = tab[(crc ^ (x)) & 255] ^ (crc >> 8)
static uint32_t crc32_no_comp(uint32_t crc, const uint8_t *buf, size_t len)
{
const uint32_t *tab = crc_table;
const uint32_t *b =(const uint32_t *)buf;
size_t rem_len;
/* Align it */
if (((long)b) & 3 && len) {
uint8_t *p = (uint8_t *)b;
do {
DO_CRC(*p++);
} while ((--len) && ((long)p)&3);
b = (uint32_t *)p;
}
rem_len = len & 3;
len = len >> 2;
for (--b; len; --len) {
/* load data 32 bits wide, xor data 32 bits wide. */
crc ^= *++b; /* use pre increment for speed */
DO_CRC(0);
DO_CRC(0);
DO_CRC(0);
DO_CRC(0);
}
len = rem_len;
/* And the last few bytes */
if (len) {
uint8_t *p = (uint8_t *)(b + 1) - 1;
do {
DO_CRC(*++p); /* use pre increment for speed */
} while (--len);
}
return crc;
}
#undef DO_CRC
uint32_t crc32 (uint32_t crc, const uint8_t *p, size_t len)
{
return crc32_no_comp(crc ^ 0xffffffffL, p, len) ^ 0xffffffffL;
}

145
ubootenv/libuboot.h

@ -0,0 +1,145 @@
#ifndef __LIBUBOOT_H___
#define __LIBUBOOT_H___
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
struct uboot_ctx;
#define DEVNAME_MAX_LENGTH 256
/**
* Configuration passed in initialization
*
*/
struct uboot_env_device {
/** path to device or file where env is stored */
char *devname;
/** Start offset inside device path */
long long int offset;
/** size of environment */
size_t envsize;
/** Size of sector */
size_t sectorsize;
/** Number of sectors for each environment */
unsigned long envsectors;
/* operators */
int (*read)(unsigned int offset, void *buf, size_t len);
int (*write)(unsigned int offset, const void *buf, size_t len);
int (*erase)(unsigned int offset, size_t len);
};
/** @brief Read U-Boot environment configuration from structure
*
* @param[in] ctx libuboot context
* @param[in] envdevs array of two uboot_env_device
* @return 0 in case of success, else negative value
*/
int libuboot_configure(struct uboot_ctx *ctx,
struct uboot_env_device *envdevs, int copies);
/** @brief Flush environment to the storage
*
* Write the environment back to the storage and handle
* redundant devices.
*
* @param[in] ctx libuboot context
* @return 0 in case of success, else negative value
*/
int libuboot_env_store(struct uboot_ctx *ctx);
/** @brief Initialize the library
*
* Initialize the library and get the context structure
*
* @param[out] *ctx struct uboot_ctx **out allocated structure
* @param[in] struct uboot_env_device *envdevs
* @return 0 in case of success, else negative value
*/
int libuboot_initialize(struct uboot_ctx **out,
struct uboot_env_device *envdevs, int copies);
/** @brief Release all resources and exit the library
*
* @param[in] ctx libuboot context
*/
void libuboot_exit(struct uboot_ctx *ctx);
/** @brief Load an environment
*
* @param[in] ctx libuboot context
* @return 0 in case of success
*/
int libuboot_open(struct uboot_ctx *ctx);
/** @brief Release an environment
*
* Release allocated recource for the environment, but
* maintain the context. This allows to call
* libuboot_open() again.
*
* @param[in] ctx libuboot context
* @return 0 in case of success
*/
void libuboot_close(struct uboot_ctx *ctx);
/** @brief Set a variable
*
* Set a variable. It creates a new variable if not present in
* the database, changes it or drops if value is NULL
*
* @param[in] ctx libuboot context
* @param[in] variable name
* @param[in] value. In case this is NULL, the variable is dropped
* @return 0 in case of success
*/
int libuboot_set_env(struct uboot_ctx *ctx, const char *varname, const char *value);
/** @brief Get a variable
*
* Return value of a variable as string or NULL if
* variable is not present in the database.
* The returned string must be freed by the caller when not
* used anymore.
*
* @param[in] ctx libuboot context
* @param[in] variable name
* @return value in case of success, NULL in case of error
*/
char *libuboot_get_env(struct uboot_ctx *ctx, const char *varname);
/** @brief Iterator
*
* Return a pointer to an entry in the database
* Used to iterate all variables in the database.
*
* @param[in] ctx libuboot context
* @param[in] next
* @return pointer to next entry or NULL
*/
void *libuboot_iterator(struct uboot_ctx *ctx, void *next);
/** @brief Accessor to get variable name from DB entry
*
* @param[in] entry element in the database
* @return pointer to name or NULL
*/
const char *libuboot_getname(void *entry);
/** @brief Accessor to get variable value from DB entry
*
* @param[in] entry element in the database
* @return pointer to name or NULL
*/
const char *libuboot_getvalue(void *entry);
#ifdef __cplusplus
}
#endif
#endif

699
ubootenv/uboot_env.c

@ -0,0 +1,699 @@
/* vim: set ts=4 sw=4 et ci: */
/**
* @file uboot_env.c
*
* @brief This is the implementation of libubootenv library
*
* Changes:
*
* 2021/12/28: port to P7 use spiFlash API by surenyi926
* 2024/10/23: port to KM02 project
*/
#define _GNU_SOURCE
#include "uboot_private.h"
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST((head)); (var) != NULL && ((tvar) = LIST_NEXT((var), field), 1); (var) = (tvar))
static char attr_tostring(type_attribute a)
{
switch (a) {
case TYPE_ATTR_STRING:
return 's';
case TYPE_ATTR_DECIMAL:
return 'd';
case TYPE_ATTR_HEX:
return 'h';
case TYPE_ATTR_BOOL:
return 'b';
case TYPE_ATTR_IP:
return 'i';
case TYPE_ATTR_MAC:
return 'm';
}
return 's';
}
static char access_tostring(access_attribute a)
{
switch (a) {
case ACCESS_ATTR_ANY:
return 'a';
case ACCESS_ATTR_READ_ONLY:
return 'r';
case ACCESS_ATTR_WRITE_ONCE:
return 'o';
case ACCESS_ATTR_CHANGE_DEFAULT:
return 'c';
}
return 'a';
}
static struct var_entry *__libuboot_get_env(struct vars *envs, const char *varname)
{
struct var_entry *entry;
LIST_FOREACH(entry, envs, next)
{
if (strcmp(varname, entry->name) == 0)
return entry;
}
return NULL;
}
static void free_var_entry(struct vars *envs, struct var_entry *entry)
{
if (entry) {
LIST_REMOVE(entry, next);
free(entry->name);
free(entry->value);
free(entry);
}
}
static bool check_compatible_devices(struct uboot_ctx *ctx)
{
if (!ctx->redundant)
return true;
if (ctx->envdevs[0].flagstype != ctx->envdevs[1].flagstype)
return false;
if (ctx->envdevs[0].envsize != ctx->envdevs[1].envsize)
return false;
return true;
}
static int inline spiFlashRead(struct uboot_flash_env *dev, unsigned int offset, void *data, size_t len)
{
if (dev->read) {
return dev->read(offset, data, len);
}
return -128;
}
static int inline spiFlashWrite(struct uboot_flash_env *dev, unsigned int offset, void *data, size_t len)
{
if (dev->write) {
return dev->write(offset, data, len);
}
return -128;
}
static int inline spiFlashErase(struct uboot_flash_env *dev, unsigned int offset, size_t len)
{
if (dev->erase) {
return dev->erase(offset, len);
}
return 0;
}
static int devread(struct uboot_ctx *ctx, unsigned int copy, void *data)
{
int ret;
struct uboot_flash_env *dev;
if (copy > 1)
return -1;
dev = &ctx->envdevs[copy];
/* read data from dev->offset with dev->envsize */
ret = spiFlashRead(dev, dev->offset, data, dev->envsize);
if (ret) {
return -2;
}
return dev->envsize;
}
static int devwrite(struct uboot_ctx *ctx, unsigned int copy, void *data)
{
int ret = 0;
struct uboot_flash_env *dev;
if (copy > 1)
return -1;
dev = &ctx->envdevs[copy];
ret = spiFlashErase(dev, dev->offset, dev->envsize);
if (ret) {
printf("Erase environment area failed.\r\n");
return ret;
}
/* write dev->offset with dev->envsize to flash */
ret = spiFlashWrite(dev, dev->offset, data, dev->envsize);
return ret;
}
static int set_obsolete_flag(struct uboot_flash_env *dev)
{
#if 0
uint8_t offsetflags = offsetof(struct uboot_env_redund, flags);
unsigned char flag = 0;
return spiFlashWrite(dev, dev->offset + offsetflags, &flag, sizeof flag);
#else
return 0;
#endif
}
int libuboot_env_store(struct uboot_ctx *ctx)
{
struct var_entry *entry;
void *image;
char *data;
char *buf;
bool saveflags = false;
size_t size;
uint8_t offsetdata;
int ret;
int copy;
/*
* Allocate the bigger of the case
*/
image = malloc(sizeof(struct uboot_env_redund) + ctx->size);
if (!image)
return -1;
if (ctx->redundant)
offsetdata = offsetof(struct uboot_env_redund, data);
else
offsetdata = offsetof(struct uboot_env_noredund, data);
data = (char *)((uint8_t *)image + offsetdata);
buf = data;
LIST_FOREACH(entry, &ctx->varlist, next)
{
size = (ctx->size - offsetdata) - (buf - data);
if ((strlen(entry->name) + strlen(entry->value) + 2) > size)
return -1;
if (entry->type || entry->access)
saveflags = true;
buf += snprintf(buf, size, "%s=%s", entry->name, entry->value);
buf++;
}
/*
* Now save the .flags
*/
if (saveflags) {
bool first = true;
size = (ctx->size - offsetdata) - (buf - data);
buf += snprintf(buf, size, ".flags=");
LIST_FOREACH(entry, &ctx->varlist, next)
{
size = (ctx->size - offsetdata) - (buf - data);
if (entry->type || entry->access) {
buf += snprintf(buf, size, "%s%s:%c%c", first ? "" : ",", entry->name, attr_tostring(entry->type),
access_tostring(entry->access));
first = false;
}
}
buf++;
}
*buf++ = '\0';
if (ctx->redundant) {
unsigned char flags = ctx->envdevs[ctx->current].flags;
switch (ctx->envdevs[ctx->current].flagstype) {
case FLAGS_INCREMENTAL:
flags++;
break;
case FLAGS_BOOLEAN:
flags = 1;
break;
default:
break;
}
((struct uboot_env_redund *)image)->flags = flags;
}
*(uint32_t *)image = crc32(0, (uint8_t *)data, ctx->size - offsetdata);
copy = ctx->redundant ? (ctx->current ? 0 : 1) : 0;
ret = devwrite(ctx, copy, image);
free(image);
if (ret == ctx->size)
ret = 0;
if (ctx->redundant && !ret) {
if (ctx->envdevs[ctx->current].flagstype == FLAGS_BOOLEAN)
ret = set_obsolete_flag(&ctx->envdevs[ctx->current]);
}
if (!ret)
ctx->current = ctx->current ? 0 : 1;
return ret;
}
static int libuboot_load(struct uboot_ctx *ctx)
{
int ret, i;
int copies = 1;
uint8_t *buf[2];
size_t bufsize, usable_envsize;
struct uboot_flash_env *dev;
bool crcenv[2];
// unsigned char flags[2];
char *line, *next;
uint8_t offsetdata = offsetof(struct uboot_env_noredund, data);
uint8_t offsetcrc = offsetof(struct uboot_env_noredund, crc);
uint8_t offsetflags = offsetof(struct uboot_env_redund, flags);
uint8_t *data;
struct var_entry *entry;
ctx->valid = false;
bufsize = ctx->size;
if (ctx->redundant) {
copies++;
bufsize += ctx->size;
offsetdata = offsetof(struct uboot_env_redund, data);
offsetcrc = offsetof(struct uboot_env_redund, crc);
}
usable_envsize = ctx->size - offsetdata;
buf[0] = malloc(bufsize);
if (!buf[0])
return -1;
if (copies > 1)
buf[1] = buf[0] + ctx->envdevs[0].envsize;
for (i = 0; i < copies; i++) {
data = (uint8_t *)(buf[i] + offsetdata);
uint32_t crc;
dev = &ctx->envdevs[i];
ret = devread(ctx, i, buf[i]);
if (ret != ctx->size) {
free(buf[0]);
return -2;
}
crc = *(uint32_t *)(buf[i] + offsetcrc);
dev->crc = crc32(0, data, usable_envsize);
crcenv[i] = dev->crc == crc;
if (ctx->redundant)
dev->flags = *(buf[i] + offsetflags);
}
if (!ctx->redundant) {
ctx->current = 0;
ctx->valid = crcenv[0];
} else {
if (crcenv[0] && !crcenv[1]) {
ctx->valid = true;
ctx->current = 0;
} else if (!crcenv[0] && crcenv[1]) {
ctx->valid = true;
ctx->current = 1;
} else if (!crcenv[0] && !crcenv[1]) {
ctx->valid = false;
ctx->current = 0;
} else { /* both valid, check flags */
ctx->valid = true;
if (ctx->envdevs[1].flags > ctx->envdevs[0].flags)
ctx->current = 1;
else
ctx->current = 0;
switch (ctx->envdevs[0].flagstype) {
case FLAGS_BOOLEAN:
if (ctx->envdevs[1].flags == 0xFF)
ctx->current = 1;
else if (ctx->envdevs[0].flags == 0xFF)
ctx->current = 0;
break;
case FLAGS_INCREMENTAL:
/* check overflow */
if (ctx->envdevs[0].flags == 0xFF && ctx->envdevs[1].flags == 0)
ctx->current = 1;
else if (ctx->envdevs[1].flags == 0xFF && ctx->envdevs[0].flags == 0)
ctx->current = 0;
break;
default:
break;
}
}
}
#if !defined(NDEBUG)
fprintf(stdout, "Environment %s, copy %d\r\n", ctx->valid ? "OK" : "WRONG", ctx->current);
#endif
data = buf[ctx->current] + offsetdata;
char *flagsvar = NULL;
if (ctx->valid) {
for (line = (char *)data; *line; line = next + 1) {
char *value;
/*
* Search the end of the string pointed by line
*/
for (next = line; *next; ++next) {
if ((next - (char *)data) > usable_envsize) {
free(buf[0]);
return -2;
}
}
value = strchr(line, '=');
if (!value)
continue;
*value++ = '\0';
if (!strcmp(line, ".flags"))
flagsvar = strdup(value);
else
libuboot_set_env(ctx, line, value);
}
}
/*
* Parse .flags and set the attributes for a variable
*/
char *pvar;
char *pval;
if (flagsvar) {
#if !defined(NDEBUG)
fprintf(stdout, "Environment FLAGS %s\n", flagsvar);
#endif
pvar = flagsvar;
while (*pvar && (pvar - flagsvar) < strlen(flagsvar)) {
char *pnext;
pval = strchr(pvar, ':');
if (!pval)
break;
*pval++ = '\0';
pnext = strchr(pval, ',');
if (!pnext)
pnext = flagsvar + strlen(flagsvar);
else
*pnext++ = '\0';
entry = __libuboot_get_env(&ctx->varlist, pvar);
if (entry) {
int i;
for (i = 0; i < strlen(pval); i++) {
switch (pval[i]) {
case 's':
entry->type = TYPE_ATTR_STRING;
break;
case 'd':
entry->type = TYPE_ATTR_DECIMAL;
break;
case 'x':
entry->type = TYPE_ATTR_HEX;
break;
case 'b':
entry->type = TYPE_ATTR_BOOL;
break;
case 'i':
entry->type = TYPE_ATTR_IP;
break;
case 'm':
entry->type = TYPE_ATTR_MAC;
break;
case 'a':
entry->access = ACCESS_ATTR_ANY;
break;
case 'r':
entry->access = ACCESS_ATTR_READ_ONLY;
break;
case 'o':
entry->access = ACCESS_ATTR_WRITE_ONCE;
break;
case 'c':
entry->access = ACCESS_ATTR_CHANGE_DEFAULT;
break;
default: /* ignore it */
break;
}
}
}
pvar = pnext;
}
}
free(flagsvar);
free(buf[0]);
return ctx->valid ? 0 : -4;
}
static bool libuboot_validate_flags(struct var_entry *entry, const char *value)
{
bool ok_type = true, ok_access = true;
unsigned long long test;
switch (entry->access) {
case ACCESS_ATTR_ANY:
ok_access = true;
break;
case ACCESS_ATTR_READ_ONLY:
case ACCESS_ATTR_WRITE_ONCE:
ok_access = false;
break;
case ACCESS_ATTR_CHANGE_DEFAULT:
break;
}
if (!ok_access)
return false;
if (!value)
return true;
switch (entry->type) {
case TYPE_ATTR_STRING:
ok_type = true;
break;
case TYPE_ATTR_DECIMAL:
case TYPE_ATTR_HEX:
errno = 0;
ok_type = strlen(value) > 2 && (value[0] == 0) && (value[1] == 'x' || value[1] == 'X');
if (ok_type) {
test = strtoul(value, NULL, 16);
if (errno)
ok_type = false;
}
break;
case TYPE_ATTR_BOOL:
ok_access = (value[0] == '1' || value[0] == 'y' || value[0] == 't' || value[0] == 'Y' || value[0] == 'T' ||
value[0] == '0' || value[0] == 'n' || value[0] == 'f' || value[0] == 'N' || value[0] == 'F') &&
(strlen(value) != 1);
break;
case TYPE_ATTR_IP:
case TYPE_ATTR_MAC:
break;
}
(void)test; /* suppressing warning */
return ok_type;
}
int libuboot_set_env(struct uboot_ctx *ctx, const char *varname, const char *value)
{
struct var_entry *entry, *elm, *lastentry;
struct vars *envs = &ctx->varlist;
/* U-Boot setenv treats '=' as an illegal character for variable names */
if (strchr(varname, '='))
return -1;
entry = __libuboot_get_env(envs, varname);
if (entry) {
if (libuboot_validate_flags(entry, value)) {
if (!value) {
free_var_entry(envs, entry);
} else {
free(entry->value);
entry->value = strdup(value);
}
return 0;
} else {
return -3;
}
}
if (!value)
return 0;
entry = (struct var_entry *)calloc(1, sizeof(*entry));
if (!entry)
return -1;
entry->name = strdup(varname);
if (!entry->name) {
free(entry);
return -1;
}
entry->value = strdup(value);
if (!entry->value) {
free(entry->name);
free(entry);
return -1;
}
lastentry = NULL;
LIST_FOREACH(elm, envs, next)
{
if (strcmp(elm->name, varname) > 0) {
LIST_INSERT_BEFORE(elm, entry, next);
return 0;
}
lastentry = elm;
}
if (lastentry)
LIST_INSERT_AFTER(lastentry, entry, next);
else
LIST_INSERT_HEAD(envs, entry, next);
return 0;
}
char *libuboot_get_env(struct uboot_ctx *ctx, const char *varname)
{
struct var_entry *entry;
struct vars *envs = &ctx->varlist;
entry = __libuboot_get_env(envs, varname);
if (!entry)
return NULL;
return entry->value;
/* return strdup(entry->value); */
}
const char *libuboot_getname(void *entry)
{
struct var_entry *e = entry;
return e ? e->name : NULL;
}
const char *libuboot_getvalue(void *entry)
{
struct var_entry *e = entry;
return e ? e->value : NULL;
}
void *libuboot_iterator(struct uboot_ctx *ctx, void *next)
{
if (!next)
return ctx->varlist.lh_first;
else
return ((struct var_entry *)next)->next.le_next;
}
int libuboot_configure(struct uboot_ctx *ctx, struct uboot_env_device *envdevs, int copies)
{
if (envdevs) {
struct uboot_flash_env *dev;
int i, n = copies;
dev = &ctx->envdevs[0];
if (n > 2)
n = 2;
for (i = 0; i < n; i++, envdevs++, dev++) {
if (!envdevs)
break;
memset(dev->devname, 0, sizeof(dev->devname));
strncpy(dev->devname, envdevs->devname, sizeof(dev->devname) - 1);
dev->offset = envdevs->offset;
dev->envsize = envdevs->envsize;
dev->sectorsize = envdevs->sectorsize;
dev->envsectors = envdevs->envsectors;
dev->read = envdevs->read;
dev->erase = envdevs->erase;
dev->write = envdevs->write;
if (!ctx->size)
ctx->size = dev->envsize;
if (i > 0) {
ctx->redundant = true;
if (!check_compatible_devices(ctx))
return -2;
}
}
}
return 0;
}
int libuboot_initialize(struct uboot_ctx **out, struct uboot_env_device *envdevs, int copies)
{
struct uboot_ctx *ctx;
int ret;
*out = NULL;
ctx = calloc(1, sizeof(*ctx));
if (!ctx)
return -1;
ctx->valid = false;
ret = libuboot_configure(ctx, envdevs, copies);
if (ret < 0) {
free(ctx);
return ret;
}
*out = ctx;
return 0;
}
int libuboot_open(struct uboot_ctx *ctx)
{
if (!ctx)
return -1;
return libuboot_load(ctx);
}
void libuboot_close(struct uboot_ctx *ctx)
{
struct var_entry *e, *tmp;
if (!ctx)
return;
ctx->valid = false;
LIST_FOREACH_SAFE(e, &ctx->varlist, next, tmp)
{
if (e->name)
free(e->name);
if (e->value)
free(e->value);
LIST_REMOVE(e, next);
free(e);
}
}
void libuboot_exit(struct uboot_ctx *ctx)
{
free(ctx);
}

190
ubootenv/uboot_private.h

@ -0,0 +1,190 @@
#ifndef __LIBUBOOT_PRIVATE_H__
#define __LIBUBOOT_PRIVATE_H__
#if defined(__DCC__)
#define bool int
#define true 1
#define false 0
#else
#include <stdbool.h>
#endif
#include <stdint.h>
#include <stddef.h>
#include "libuboot.h"
/*
* List definitions.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List functions.
*/
#define LIST_INIT(head) do { \
(head)->lh_first = NULL; \
} while (/*CONSTCOND*/0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
(listelm)->field.le_next->field.le_prev = \
&(elm)->field.le_next; \
(listelm)->field.le_next = (elm); \
(elm)->field.le_prev = &(listelm)->field.le_next; \
} while (/*CONSTCOND*/0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.le_prev = (listelm)->field.le_prev; \
(elm)->field.le_next = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &(elm)->field.le_next; \
} while (/*CONSTCOND*/0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
(head)->lh_first = (elm); \
(elm)->field.le_prev = &(head)->lh_first; \
} while (/*CONSTCOND*/0)
#define LIST_REMOVE(elm, field) do { \
if ((elm)->field.le_next != NULL) \
(elm)->field.le_next->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = (elm)->field.le_next; \
} while (/*CONSTCOND*/0)
#define LIST_FOREACH(var, head, field) \
for ((var) = ((head)->lh_first); \
(var); \
(var) = ((var)->field.le_next))
/*
* List access methods.
*/
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
typedef enum {
TYPE_ATTR_STRING, /* default */
TYPE_ATTR_DECIMAL,
TYPE_ATTR_HEX,
TYPE_ATTR_BOOL,
TYPE_ATTR_IP,
TYPE_ATTR_MAC
} type_attribute;
typedef enum {
ACCESS_ATTR_ANY, /* default */
ACCESS_ATTR_READ_ONLY,
ACCESS_ATTR_WRITE_ONCE,
ACCESS_ATTR_CHANGE_DEFAULT,
} access_attribute;
enum flags_type {
FLAGS_NONE,
FLAGS_BOOLEAN,
FLAGS_INCREMENTAL
};
/**
* U-Boot environment should always be redundant, but
* for compatibility reasons a single copy must
* be also supported. Structure is different because
* there is no flags in the single copy
*/
struct uboot_env_noredund {
/** computed crc32 value */
uint32_t crc;
/** placeholder to point to the env in flash */
char data[];
};
struct uboot_env_redund {
/** computed crc32 value */
uint32_t crc;
/** flags, see flags_type */
unsigned char flags;
/** placeholder to point to the env in flash */
char data[];
};
struct uboot_flash_env {
/** path to device or file where env is stored */
char devname[DEVNAME_MAX_LENGTH];
/** Start offset inside device path */
long long int offset;
/** size of environment */
size_t envsize;
/** Size of sector (for MTD) */
size_t sectorsize;
/** Number of sectors for each environment */
long unsigned int envsectors;
/** MTD structure as returned by ioctl() call */
//struct mtd_info_user mtdinfo;
/** Computed CRC on the stored environment */
uint32_t crc;
/** file descriptor used to access the device */
int fd;
/** flags (see flags_type) are one byte in the stored environment */
unsigned char flags;
/** flags according to device type */
enum flags_type flagstype;
/* operators */
int (*read)(unsigned int offset, void *buf, size_t len);
int (*erase)(unsigned int offset, size_t len);
int (*write)(unsigned int offset, const void *buf, size_t len);
};
/** Internal structure for an environment variable
*/
struct var_entry {
/** Variable's name */
char *name;
/** Variable's value */
char *value;
/** Type of the variable, see access_attribute */
type_attribute type;
/** Permissions for the variable */
access_attribute access;
/** Pointer to next element in the list */
LIST_ENTRY(var_entry) next;
};
LIST_HEAD(vars, var_entry);
/** libubootenv context
*/
struct uboot_ctx {
/** true if the environment is redundant */
bool redundant;
/** set to valid after a successful load */
bool valid;
/** size of the environment */
size_t size;
/** devices where environment is stored */
struct uboot_flash_env envdevs[2];
/** Set which device contains the current(last valid) environment */
int current;
/** semaphore on the environment */
int lock;
/** pointer to the internal db */
struct vars varlist;
};
uint32_t crc32 (uint32_t crc, const uint8_t *p, size_t len);
#endif

6
vxbLfsLib.c

@ -26,6 +26,8 @@
#include "lfs/lfs.c"
#include "lfs/lfs_util.c"
#define LFS_NAME "littlefs"
typedef struct __lfs_drv_ctrl lfsDrvCtrl;
typedef struct lfs_ios_drv lfsIosDrv;
@ -549,7 +551,7 @@ LOCAL struct vxbSpiRegister lfsDevDriver = {
VXB_DEVID_DEVICE, /* devID */
VXB_BUSID_PLB, /* busID */
VXBUS_VERSION_5, /* vxbVersion */
"lfs", /* drvName */
LFS_NAME, /* drvName */
&lfsDevFuncs, /* pDrvBusFuncs */
lfsDevMethods, /* pMethods */
NULL, /* devProbe */
@ -568,7 +570,7 @@ LOCAL lfsDrvCtrl * getLfsLowHandle(int unit)
VXB_DEVICE_ID pDev;
lfsDrvCtrl *pDrvCtrl = NULL;
pDev = vxbInstByNameFind("lfs", unit);
pDev = vxbInstByNameFind(LFS_NAME, unit);
if (pDev == NULL) {
printf("Can't find lfs%d\n", unit);
return NULL;

Loading…
Cancel
Save