Add system variable management in u-boot
Change-Id: I862eec11795940fc3e516eb63654708ab333fb1f
diff --git a/common/cmd_sysvar.c b/common/cmd_sysvar.c
new file mode 100755
index 0000000..a5dac7f
--- /dev/null
+++ b/common/cmd_sysvar.c
@@ -0,0 +1,711 @@
+/* Copyright 2012 Google Inc. All Rights Reserved.
+ * Author: weixiaofeng@google.com (Xiaofeng Wei)
+ */
+
+#include <common.h>
+#include <spi_flash.h>
+#include <asm/io.h>
+
+#include "sysvar.h"
+
+#define PAGE_SIZE 256
+#define SYSVAR_VALUE 256
+
+#define SYSVAR_RO_MEM 0x00000100
+#define SYSVAR_RW_MEM SYSVAR_RO_MEM + SYSVAR_BLOCK_SIZE
+
+struct spi_flash *sf_dev = NULL;
+struct sysvar_buf ro_buf;
+struct sysvar_buf rw_buf;
+static const long sysvar_offset[SYSVAR_SPI_BLOCK] = {
+ SYSVAR_RW_OFFSET0, SYSVAR_RW_OFFSET1, SYSVAR_RO_OFFSET0, SYSVAR_RO_OFFSET1
+};
+
+static int data_recovery(struct sysvar_buf *buf, int idx);
+static int data_load(struct sysvar_buf *buf, int idx);
+static int data_save(struct sysvar_buf *buf, int *idx);
+
+static int open_sf(bool load);
+static void close_sf(void);
+
+static int loadvar(void);
+static int savevar(struct sysvar_buf *buf, int idx);
+static int getvar(char *name, char *value, int len);
+static int setvar(struct sysvar_buf *buf, int idx, char *name, char *value);
+
+/*
+ * print_msg - print the message string
+ */
+static void print_msg(char *msg, int idx) {
+ if (idx < 0) {
+ printf("SV: %s\n", msg);
+ } else {
+ printf("SV: System variables(%s) has been %s\n",
+ (idx < SYSVAR_RO_BUF) ? "RW" : "RO", msg);
+ }
+}
+
+/*
+ * print_err - print the error message
+ */
+static void print_err(char *err, int idx) {
+ if (idx < 0) {
+ printf("## Error: %s\n", err);
+ } else {
+ printf("## Error: failed to %s system variables(%s)\n",
+ err, (idx < SYSVAR_RO_BUF) ? "RW" : "RO");
+ }
+}
+
+/*
+ * data_recovery - system variables recovering routine
+ */
+static int data_recovery(struct sysvar_buf *buf, int idx) {
+ int i, j, ret;
+
+ /* load the system variables */
+ printf("SV: Recovering data");
+ for (i = idx, j = idx + 1; i < idx + 2; i++, j--) {
+ /* read the data from SPI flash */
+ if (spi_flash_read(sf_dev, sysvar_offset[i], buf->data_len, buf->data))
+ continue;
+
+ /* check crc32 and wc32 (write count) */
+ if (check_var(buf, SYSVAR_LOAD_MODE) == SYSVAR_SUCCESS) {
+ /* erase SPI flash */
+ ret = spi_flash_erase(sf_dev, sysvar_offset[j], buf->data_len);
+ if (ret) {
+ print_err("erase", j);
+ goto recovery_err;
+ }
+
+ /* check crc32 and wc32 (write count) */
+ if (check_var(buf, SYSVAR_SAVE_MODE))
+ goto recovery_err;
+
+ /* write system variables(RW) to SPI flash */
+ ret = spi_flash_write(sf_dev, sysvar_offset[j],
+ buf->data_len, buf->data);
+ printf("\n");
+ if (ret) {
+ print_err("write", j);
+ goto recovery_err;
+ }
+
+ buf->loaded = true;
+ print_msg("Data recovery was completed", SYSVAR_MESSAGE);
+ return 0;
+ }
+ }
+
+recovery_err:
+ clear_buf(buf);
+
+ printf("\n");
+ print_err("recovery", idx);
+ return 0;
+}
+
+/*
+ * data_load - load the data from SPI flash to data buffer
+ */
+static int data_load(struct sysvar_buf *buf, int idx) {
+ int i, j;
+
+ /* load the system variables */
+ for (i = idx, j = 0; i < idx + 2; i++, j++) {
+ buf->failed[j] = false;
+
+ /* read the data from SPI flash */
+ if (spi_flash_read(sf_dev, sysvar_offset[i], buf->data_len, buf->data))
+ buf->failed[j] = true;
+
+ /* check crc32 and wc32 (write count) */
+ if (check_var(buf, SYSVAR_LOAD_MODE))
+ buf->failed[j] = true;
+ }
+
+load_err:
+ if (buf->failed[0] || buf->failed[1])
+ return data_recovery(buf, idx);
+ return 0;
+}
+
+/*
+ * data_save - save the data from data buffer to SPI flash
+ */
+static int data_save(struct sysvar_buf *buf, int *idx) {
+ int i, j, ret;
+
+ /* save the system variables */
+ for (j = 0; j < 2; j++) {
+ i = idx[j];
+ printf("SV: Erasing SPI flash 0x%08lx - 0x%08lx\n",
+ sysvar_offset[i], sysvar_offset[i] + buf->data_len);
+ ret = spi_flash_erase(sf_dev, sysvar_offset[i], buf->data_len);
+ if (ret) {
+ print_err("erase", i);
+ return 1;
+ }
+
+ /* check crc32 and wc32 (write count) */
+ if (check_var(buf, SYSVAR_SAVE_MODE)) {
+ print_err("save", SYSVAR_RO_BUF);
+ return 1;
+ }
+
+ /* write system variables to SPI flash */
+ printf("SV: Writing to SPI flash");
+ ret = spi_flash_write(sf_dev, sysvar_offset[i], buf->data_len, buf->data);
+ printf("\n");
+ if (ret) {
+ print_err("write", i);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * open_sf - open SPI flash and read the data to buffer
+ */
+static int open_sf(bool load) {
+ /* check SPI flash */
+ if (sf_dev != NULL)
+ return 0;
+
+ memset(&rw_buf, 0, sizeof(rw_buf));
+ memset(&ro_buf, 0, sizeof(ro_buf));
+
+ /* probe SPI flash */
+ sf_dev = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
+ CONFIG_ENV_SPI_MAX_HZ, SPI_MODE_3);
+ if (sf_dev == NULL) {
+ print_err("failed to initialize SPI flash", SYSVAR_MESSAGE);
+ return 1;
+ }
+
+ /* allocate data buffers */
+ rw_buf.data = (uchar *)map_physmem(SYSVAR_RW_MEM,
+ SYSVAR_BLOCK_SIZE, MAP_WRBACK);
+ ro_buf.data = (uchar *)map_physmem(SYSVAR_RO_MEM,
+ SYSVAR_BLOCK_SIZE, MAP_WRBACK);
+ if (!rw_buf.data || !ro_buf.data) {
+ print_err("failed to map physical memory", SYSVAR_MESSAGE);
+ goto open_err;
+ }
+
+ /* allocate data lists */
+ rw_buf.list = (struct sysvar_list *)malloc(sizeof(struct sysvar_list));
+ ro_buf.list = (struct sysvar_list *)malloc(sizeof(struct sysvar_list));
+ if (!rw_buf.list || !ro_buf.list) {
+ print_err("failed to allocate data list", SYSVAR_MESSAGE);
+ goto open_err;
+ }
+
+ rw_buf.data_len = SYSVAR_BLOCK_SIZE;
+ rw_buf.total_len = SYSVAR_BLOCK_SIZE - SYSVAR_HEAD;
+ rw_buf.free_len = rw_buf.total_len;
+ rw_buf.readonly = false;
+
+ strncpy(rw_buf.list->name, "rw", SYSVAR_NAME);
+ rw_buf.list->value = NULL;
+ rw_buf.list->len = SYSVAR_NAME + 2;
+ rw_buf.list->next = NULL;
+
+ ro_buf.data_len = SYSVAR_BLOCK_SIZE;
+ ro_buf.total_len = SYSVAR_BLOCK_SIZE - SYSVAR_HEAD;
+ ro_buf.free_len = ro_buf.total_len;
+ ro_buf.readonly = true;
+
+ strncpy(rw_buf.list->name, "ro", SYSVAR_NAME);
+ ro_buf.list->value = NULL;
+ ro_buf.list->len = SYSVAR_NAME + 2;
+ ro_buf.list->next = NULL;
+
+ /* load data from SPI flash to data buffer */
+ if (load) {
+ if (loadvar())
+ goto open_err;
+ }
+ return 0;
+
+open_err:
+ close_sf();
+ return 1;
+}
+
+/*
+ * close_sf - close SPI flash and release the data buffer
+ */
+static void close_sf(void) {
+ /* release data lists */
+ if (rw_buf.list != NULL) {
+ clear_var(&rw_buf);
+ free(rw_buf.list);
+ }
+ if (ro_buf.list != NULL) {
+ clear_var(&ro_buf);
+ free(ro_buf.list);
+ }
+
+ /* release data buffers */
+ if (rw_buf.data != NULL)
+ unmap_physmem(rw_buf.data, rw_buf.data_len);
+ if (ro_buf.data != NULL)
+ unmap_physmem(ro_buf.data, ro_buf.data_len);
+
+ sf_dev = NULL;
+}
+
+/*
+ * loadvar - load the data from SPI flash to data buffer
+ */
+static int loadvar(void) {
+ if (data_load(&rw_buf, SYSVAR_RW_BUF))
+ return 1;
+
+ /* move the data from data buffer to data list */
+ if (load_var(&rw_buf))
+ return 1;
+
+ rw_buf.loaded = true;
+ print_msg("loaded", SYSVAR_RW_BUF);
+
+ if (data_load(&ro_buf, SYSVAR_RO_BUF))
+ return 1;
+
+ /* move the data from data buffer to data list */
+ if (load_var(&ro_buf))
+ return 1;
+
+ ro_buf.loaded = true;
+ print_msg("loaded", SYSVAR_RO_BUF);
+ return 0;
+}
+
+/*
+ * savevar - save the data from data buffer to SPI flash
+ */
+static int savevar(struct sysvar_buf *buf, int idx) {
+ int save_idx[2];
+
+ if (open_sf(true))
+ return 1;
+
+ /* move the data from data list to data buffer */
+ if (save_var(buf))
+ return 1;
+
+ /* erase failed partition first
+ * part0 part1 erase
+ * ----- ----- -----
+ * ok ok 0, 1
+ * failed ok 0, 1
+ * ok failed 1, 0
+ * failed failed 0, 1
+ */
+ if (buf->failed[1]) {
+ save_idx[0] = idx + 1;
+ save_idx[1] = idx;
+ } else {
+ save_idx[0] = idx;
+ save_idx[1] = idx + 1;
+ }
+
+ /* save the data from data buffer to SPI flash */
+ if (data_save(buf, save_idx))
+ return 1;
+
+ printf("\n");
+ print_msg("saved", idx);
+ return 0;
+}
+
+/*
+ * getvar - get or print the system variable from data list
+ */
+static int getvar(char *name, char *value, int len) {
+ struct sysvar_list *var = NULL;
+
+ if (open_sf(true))
+ return 1;
+
+ if (name == NULL) {
+ /* print all system variables(RO) */
+ print_var(&ro_buf);
+ /* print all system variables(RW) */
+ print_var(&rw_buf);
+ return 0;
+ }
+
+ /* find the system variable(RO) */
+ var = find_var(&ro_buf, name);
+ if (var != NULL)
+ goto get_data;
+
+ /* find the system variable(RW) */
+ var = find_var(&rw_buf, name);
+ if (var != NULL)
+ goto get_data;
+
+ /* system variable not found */
+ printf("## Error: '%s' not found\n", name);
+ return 1;
+
+get_data:
+ return get_var(var, name, value, len);
+}
+
+/*
+ * setvar - add or delete the system variable in data list
+ */
+static int setvar(struct sysvar_buf *buf, int idx, char *name, char *value) {
+ struct sysvar_list *var = NULL;
+ int ret = 0;
+
+ if (open_sf(true))
+ return 1;
+
+ if (name != NULL) {
+ if (idx < SYSVAR_RO_BUF) {
+ /* read only variable? */
+ var = find_var(&ro_buf, name);
+ } else {
+ /* variable existed? */
+ var = find_var(&rw_buf, name);
+ }
+
+ if (var != NULL) {
+ if (idx < SYSVAR_RO_BUF) {
+ printf("## Error: '%s' is read only variable\n", name);
+ return 1;
+ } else {
+ printf("## Error: '%s' is not read only variable\n", name);
+ return 1;
+ }
+ }
+
+ var = find_var(buf, name);
+ if (var != NULL) {
+ /* delete system variable */
+ ret = delete_var(buf, var);
+ if (ret != SYSVAR_SUCCESS) {
+ printf("## Error: failed to delete '%s'\n", name);
+ return 1;
+ }
+
+ /* add system variable */
+ if (value != NULL) {
+ ret = set_var(buf, name, value);
+ if (ret == 0)
+ print_msg("added", idx);
+ } else {
+ print_msg("deleted", idx);
+ }
+ } else {
+ /* add system variable */
+ if (value != NULL) {
+ ret = set_var(buf, name, value);
+ if (ret == 0)
+ print_msg("added", idx);
+ } else {
+ printf("## Error: '%s' not found\n", name);
+ ret = 1;
+ }
+ }
+ } else {
+ /* delete all of system variables */
+ ret = clear_var(buf);
+ if (ret == 0)
+ print_msg("deleted", idx);
+ }
+ return ret;
+}
+
+/*
+ * do_loadvar - load system variables from SPI flash
+ *
+ * loadvar command:
+ * loadvar - load system variables from persistent storage
+ */
+static int do_loadvar(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) {
+ if (open_sf(false))
+ return 1;
+
+ /* load system variables from SPI flash */
+ return loadvar();
+}
+
+U_BOOT_CMD(
+ loadvar, 1, 0, do_loadvar,
+ "load system variables",
+ "\n - load system variables from SPI flash\n"
+);
+
+/*
+ * do_savevar - save system variables(RW) to SPI flash
+ *
+ * savevar command:
+ * savevar - save system variables(RW) to SPI flash
+ */
+static int do_savevar(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ /* save system variables(RW) */
+ return savevar(&rw_buf, SYSVAR_RW_BUF);
+}
+
+U_BOOT_CMD(
+ savevar, 1, 0, do_savevar,
+ "save system variables(RW)",
+ "\n - save system variables(RW) to SPI flash\n"
+);
+
+/*
+ * do_printvar - print system variables
+ *
+ * printvar command:
+ * printvar name - print system variable with name
+ * printvar - print all system variables
+ */
+static int do_printvar(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) {
+ char value[SYSVAR_VALUE];
+
+ if (open_sf(true))
+ return 1;
+
+ if (argv[1] == NULL) {
+ /* print all system variables */
+ getvar(NULL, NULL, 0);
+
+ printf("\nSV: System Variables(RO): %d/%d bytes\n",
+ ro_buf.used_len, ro_buf.total_len);
+ printf("SV: System Variables(RW): %d/%d bytes\n",
+ rw_buf.used_len, rw_buf.total_len);
+ } else {
+ /* get a system variable */
+ if (getvar(argv[1], value, SYSVAR_VALUE) == 0) {
+ printf("%s=%s\n", argv[1], value);
+ printf("\nSV: System Variable: %d bytes\n",
+ (int)(SYSVAR_NAME + 2 + strlen(value)));
+ }
+ }
+ return 0;
+}
+
+U_BOOT_CMD(
+ printvar, 2, 0, do_printvar,
+ "print system variables",
+ "\n - print values of all system variables\n"
+ "printvar name ...\n"
+ " - print value of system variable 'name'\n"
+);
+
+/*
+ * do_setvar - add or delete system variables(RW)
+ *
+ * setvar command:
+ * setvar name value - add system variable with name:value
+ * setvar name - delete system variable with name
+ * setvar - delete all system variables
+ */
+static int do_setvar(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) {
+ int ret = 0;
+
+ if (argc == 3) {
+ /* add a system variable(RW) */
+ ret = setvar(&rw_buf, SYSVAR_RW_BUF, argv[1], argv[2]);
+ } else if (argc == 2) {
+ /* delete a system variable(RW) */
+ ret = setvar(&rw_buf, SYSVAR_RW_BUF, argv[1], NULL);
+ } else {
+ /* delete all system variables(RW) */
+ ret = setvar(&rw_buf, SYSVAR_RW_BUF, NULL, NULL);
+ }
+ return ret;
+}
+
+U_BOOT_CMD(
+ setvar, 3, 0, do_setvar,
+ "set system variables(RW)",
+ "name value ...\n"
+ " - set system variable(RW) 'name' to 'value ...'\n"
+ "setvar name\n"
+ " - delete system variable(RW) 'name'\n"
+ "setvar\n"
+ " - delete all system variables(RW)\n"
+);
+
+/*
+ * sysvar_dump - dump the data buffer in binary/ascii format
+ */
+static void sysvar_dump(struct sysvar_buf *buf, int idx, bool load) {
+ extern char console_buffer[];
+ int start = 0;
+
+ if (open_sf(load))
+ return 1;
+
+ printf("System Variables(%s):\n", (idx < SYSVAR_RO_BUF) ? "RW" : "RO");
+ printf("offset : 0x%08lx\n", sysvar_offset[idx]);
+ printf("size : %d bytes\n", buf->data_len);
+ printf("total : %d bytes\n", buf->total_len);
+ printf("used : %d bytes\n", buf->used_len);
+ printf("wc32 : 0x%08lx\n", get_wc32(buf));
+ printf("crc32 : 0x%08lx\n", get_crc32(buf));
+
+ while (1) {
+ /* dump one page data in data buffer */
+ dump_buf(buf, start, PAGE_SIZE);
+ /* continue to dump...? */
+ readline("(n)ext, (p)rev, (f)irst, (l)ast ? >> ");
+ if (strcmp(console_buffer, "n") == 0) {
+ start += PAGE_SIZE; /* go to next page */
+ if (start >= buf->data_len)
+ return;
+ } else if (strcmp(console_buffer, "p") == 0) {
+ start -= PAGE_SIZE; /* go to previous page */
+ if (start < 0)
+ return;
+ } else if (strcmp(console_buffer, "f") == 0) {
+ if (start == 0)
+ return;
+ start = 0; /* go to first page */
+ } else if (strcmp(console_buffer, "l") == 0) {
+ if (start == buf->data_len - PAGE_SIZE)
+ return;
+ start = buf->data_len - PAGE_SIZE; /* go to last page */
+ } else {
+ return;
+ }
+ }
+}
+
+/*
+ * sysvar_io - SPI flash IO operations
+ */
+static int sysvar_io(int argc, char *argv[]) {
+ struct sysvar_buf *buf;
+ int i, idx, ret = 0;
+
+ if (open_sf(false))
+ return 1;
+
+ if (strcmp(argv[1], "0") == 0) {
+ idx = 0;
+ buf = &rw_buf;
+ } else if (strcmp(argv[1], "1") == 0) {
+ idx = 1;
+ buf = &rw_buf;
+ } else if (strcmp(argv[1], "2") == 0) {
+ idx = 2;
+ buf = &ro_buf;
+ } else if (strcmp(argv[1], "3") == 0) {
+ idx = 3;
+ buf = &ro_buf;
+ } else {
+ print_err("invalid SPI flash device", SYSVAR_MESSAGE);
+ return 1;
+ }
+
+ if (strcmp(argv[0], "write") == 0) {
+ /* fill data to data buffer */
+ for (i = 0; i < buf->data_len; i++)
+ buf->data[i] = i;
+
+ /* write the data buffer to spi_flash */
+ ret = spi_flash_write(sf_dev, sysvar_offset[idx],
+ buf->data_len, buf->data);
+ printf("\n");
+ } else if (strcmp(argv[0], "erase") == 0) {
+ /* erase spi_flash */
+ ret = spi_flash_erase(sf_dev, sysvar_offset[idx], buf->data_len);
+ }
+
+ if (ret == 0) {
+ ret = spi_flash_read(sf_dev, sysvar_offset[idx],
+ buf->data_len, buf->data);
+ if (ret == 0)
+ sysvar_dump(buf, idx, false);
+ }
+
+ if (ret != 0)
+ printf("## Error: SPI flash %s failed at 0x%08lx\n",
+ argv[0], sysvar_offset[idx]);
+
+ rw_buf.loaded = false;
+ ro_buf.loaded = false;
+ return ret;
+}
+
+/*
+ * do_sysvar - system variable debug functions
+ */
+static int do_sysvar(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) {
+ if (argc < 2)
+ goto usage;
+
+ if (strcmp(argv[1], "set") == 0) {
+ if (argc == 4) {
+ /* add a system variable(RO) */
+ return setvar(&ro_buf, SYSVAR_RO_BUF, argv[2], argv[3]);
+ } else if (argc == 3) {
+ /* delete a system variable(RO) */
+ return setvar(&ro_buf, SYSVAR_RO_BUF, argv[2], NULL);
+ } else if (argc == 2) {
+ /* delete all system variables(RO) */
+ return setvar(&ro_buf, SYSVAR_RO_BUF, NULL, NULL);
+ } else {
+ goto usage;
+ }
+ }
+
+ if (strcmp(argv[1], "save") == 0 && argc == 2) {
+ /* save system variables(RO) */
+ return savevar(&ro_buf, SYSVAR_RO_BUF);
+ }
+
+ if (strcmp(argv[1], "dump") == 0 && argc == 3) {
+ if (strcmp(argv[2], "rw") == 0) {
+ /* dump data in data buffer(RW) */
+ sysvar_dump(&rw_buf, SYSVAR_RW_BUF, true);
+ } else if (strcmp(argv[2], "ro") == 0) {
+ /* dump data in data buffer(RO) */
+ sysvar_dump(&ro_buf, SYSVAR_RO_BUF, true);
+ } else {
+ goto usage;
+ }
+ return 0;
+ }
+
+ if ((strcmp(argv[1], "read") == 0 && argc == 3) ||
+ (strcmp(argv[1], "write") == 0 && argc == 3) ||
+ (strcmp(argv[1], "erase") == 0 && argc == 3))
+ return sysvar_io(argc - 1, argv + 1);
+
+usage:
+ cmd_usage(cmdtp);
+ return 1;
+}
+
+U_BOOT_CMD(
+ sysvar, 4, 0, do_sysvar,
+ "system variable debug functions",
+ "set name value\n"
+ " - set system variable(RO) 'name' to 'value ...'\n"
+ "sysvar set name\n"
+ " - delete system variable(RO) 'name'\n"
+ "sysvar set\n"
+ " - delete all system variables(RO)\n"
+ "sysvar save\n"
+ " - save system variables(RO) to SPI flash\n"
+ "sysvar dump rw|ro\n"
+ " - dump data in data buffer\n"
+ "sysvar read 0|1|2|3\n"
+ " - read data from SPI flash 0|1|2|3 to data buffer\n"
+ "sysvar write 0|1|2|3\n"
+ " - write data from data buffer to SPI flash 0|1|2|3\n"
+ "sysvar erase 0|1|2|3\n"
+ " - erase data on SPI flash 0|1|2|3\n"
+);
+
diff --git a/common/sysvar.c b/common/sysvar.c
new file mode 100755
index 0000000..55cd162
--- /dev/null
+++ b/common/sysvar.c
@@ -0,0 +1,475 @@
+/* Copyright 2012 Google Inc. All Rights Reserved.
+ * Author: weixiaofeng@google.com (Xiaofeng Wei)
+ */
+
+#include "sysvar.h"
+
+static const unsigned long 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 INIT_CRC 0xffffffffL
+
+#define DO1(buf) do {crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);} while(0);
+#define DO2(buf) do {DO1(buf); DO1(buf);} while(0);
+#define DO4(buf) do {DO2(buf); DO2(buf);} while(0);
+#define DO8(buf) do {DO4(buf); DO4(buf);} while(0);
+
+/*
+ * sysvar_crc - calculate the checksum of data buffer
+ */
+static unsigned long sysvar_crc(unsigned char *buf, int len) {
+ unsigned long crc = 0;
+
+ crc = crc ^ INIT_CRC;
+ while (len >= 8) {
+ DO8(buf);
+ len -= 8;
+ }
+ if (len) {
+ do {
+ DO1(buf);
+ } while (--len);
+ }
+ return crc ^ INIT_CRC;
+}
+
+/*
+ * sysvar_len - calculate the used bytes in data buffer
+ */
+static void sysvar_len(struct sysvar_buf *buf, int len) {
+ buf->used_len += len;
+
+ if (buf->used_len < 0)
+ buf->used_len = 0;
+
+ if (buf->used_len > buf->total_len)
+ buf->used_len = buf->total_len;
+
+ buf->free_len = buf->total_len - buf->used_len;
+}
+
+/*
+ * sysvar_copy - copy data from/to the data buffer
+ */
+static void sysvar_copy(char *dst, char *src, int len, char end) {
+ int i;
+
+ if (end == SYSVAR_STR_TO_BUF) {
+ /* copy a string to data buffer */
+ memset(dst, 0xff, len);
+ } else if (end == SYSVAR_BUF_TO_STR) {
+ /* copy data buffer to a string */
+ memset(dst, 0, len + 1);
+ } else {
+ return;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (src[i] == end)
+ break;
+ dst[i] = src[i];
+ }
+}
+
+/*
+ * get_wc32 - return the write counter of data buffer
+ */
+unsigned long get_wc32(struct sysvar_buf *buf) {
+ int len = buf->total_len;
+ unsigned long x = buf->data[len + 3];
+
+ x = (x << 8) + buf->data[len + 2];
+ x = (x << 8) + buf->data[len + 1];
+ x = (x << 8) + buf->data[len];
+ return x;
+}
+
+/*
+ * set_wc32 - update the write counter of data buffer
+ */
+void set_wc32(struct sysvar_buf *buf) {
+ int len = buf->total_len;
+ unsigned long wc = get_wc32(buf) + 1;
+
+ buf->data[len + 3] = (unsigned char)(wc >> 24);
+ buf->data[len + 2] = (unsigned char)(wc >> 16);
+ buf->data[len + 1] = (unsigned char)(wc >> 8);
+ buf->data[len] = (unsigned char)(wc);
+}
+
+/*
+ * get_crc32 - check and return checksum of data buffer
+ */
+unsigned long get_crc32(struct sysvar_buf *buf) {
+ int len = buf->total_len + SYSVAR_WC32;
+ unsigned long x = buf->data[len + 3];
+
+ x = (x << 8) + buf->data[len + 2];
+ x = (x << 8) + buf->data[len + 1];
+ x = (x << 8) + buf->data[len];
+ return x;
+}
+
+/*
+ * set_crc32 - update checksum of data buffer
+ */
+void set_crc32(struct sysvar_buf *buf) {
+ int len = buf->total_len + SYSVAR_WC32;
+ unsigned long crc = sysvar_crc(buf->data, buf->total_len);
+
+ buf->data[len + 3] = (unsigned char)(crc >> 24);
+ buf->data[len + 2] = (unsigned char)(crc >> 16);
+ buf->data[len + 1] = (unsigned char)(crc >> 8);
+ buf->data[len] = (unsigned char)(crc);
+}
+
+/*
+ * load_var - move data from data buffer to data list
+ */
+int load_var(struct sysvar_buf *buf) {
+ int i, len, ret;
+ char name[SYSVAR_NAME + 1];
+ char *value;
+
+ /* clear system variables in data list */
+ ret = clear_var(buf);
+
+ /* system variable: name(32) + len(2) + value ... */
+ for (i = 0; i < buf->total_len && ret == SYSVAR_SUCCESS; i += len) {
+ if (buf->data[i] == 0xff)
+ break;
+
+ /* name of system variable */
+ sysvar_copy(name, (char *)&buf->data[i], SYSVAR_NAME, SYSVAR_BUF_TO_STR);
+ i += SYSVAR_NAME;
+
+ /* length of system variable */
+ len = (buf->data[i] << 8) + buf->data[i + 1];
+ if (len < 0 || len > buf->free_len)
+ return SYSVAR_PARAM_ERR;
+
+ value = (char *)malloc(len + 1);
+ if (value == NULL)
+ return SYSVAR_MEMORY_ERR;
+
+ i += 2;
+ /* copy system variable */
+ sysvar_copy(value, (char *)&buf->data[i], len, SYSVAR_BUF_TO_STR);
+
+ /* add system variable to data list */
+ ret = set_var(buf, name, value);
+
+ free(value);
+ }
+ return ret;
+}
+
+/*
+ * save_var - move data from data list to data buffer
+ */
+int save_var(struct sysvar_buf *buf) {
+ int i, len;
+ struct sysvar_list *curr = buf->list->next;
+
+ /* clear data buffer */
+ memset(buf->data, 0xff, buf->data_len);
+
+ for (i = 0; i < buf->total_len && curr != NULL; i += len) {
+ /* name of system variable */
+ sysvar_copy((char *)&buf->data[i], curr->name,
+ SYSVAR_NAME, SYSVAR_STR_TO_BUF);
+ i += SYSVAR_NAME;
+
+ /* length of system variable */
+ len = strlen(curr->value);
+ if (len < 0 || len > buf->used_len)
+ return SYSVAR_PARAM_ERR;
+
+ buf->data[i] = (unsigned char)(len >> 8);
+ buf->data[i + 1] = (unsigned char)len;
+ i += 2;
+
+ /* copy system variable */
+ sysvar_copy((char *)&buf->data[i], curr->value, len, SYSVAR_STR_TO_BUF);
+
+ curr = curr->next;
+ }
+
+ return check_var(buf, SYSVAR_SET_MODE);
+}
+
+/*
+ * get_var - return the system variable from data list
+ */
+int get_var(struct sysvar_list *var, char *name, char *value, int len) {
+ if (len <= 0)
+ goto get_err;
+
+ /* copy variable name */
+ strncpy(name, var->name, SYSVAR_NAME);
+
+ /* copy variable value */
+ if (var->value == NULL)
+ goto get_err;
+
+ strncpy(value, var->value, len);
+ return SYSVAR_SUCCESS;
+
+get_err:
+ value[0] = '\0';
+ return SYSVAR_GET_ERR;
+}
+
+/*
+ * set_var - add the system variable from data buffer
+ */
+int set_var(struct sysvar_buf *buf, char *name, char *value) {
+ struct sysvar_list *curr = buf->list;
+ struct sysvar_list *var = NULL;
+ int name_len = strlen(name);
+ int value_len = strlen(value);
+
+ /* system variable: name(32) + len(2) + value ... */
+ if (name_len > SYSVAR_NAME)
+ return SYSVAR_PARAM_ERR;
+
+ var = (struct sysvar_list *)malloc(sizeof(struct sysvar_list));
+ if (var == NULL)
+ return SYSVAR_MEMORY_ERR;
+
+ var->value = (char *)malloc(value_len + 1);
+ if (var->value == NULL) {
+ free(var);
+ return SYSVAR_MEMORY_ERR;
+ }
+
+ strncpy(var->name, name, SYSVAR_NAME);
+ strncpy(var->value, value, value_len);
+ var->value[value_len] = '\0';
+ var->len = SYSVAR_NAME + 2 + value_len;
+ var->next = NULL;
+
+ /* add system variable */
+ while (curr->next != NULL)
+ curr = curr->next;
+ curr->next = var;
+
+ /* update the used bytes in data buffer */
+ sysvar_len(buf, var->len);
+ return SYSVAR_SUCCESS;
+}
+
+/*
+ * delete_var - delete system variable from data list
+ */
+int delete_var(struct sysvar_buf *buf, struct sysvar_list *var) {
+ struct sysvar_list *curr = buf->list->next;
+
+ /* last system variable? */
+ if (curr == var) {
+ buf->list->next = var->next;
+ } else {
+ /* go to next system variable */
+ while (curr != NULL) {
+ if (curr->next == var) {
+ curr->next = var->next;
+ goto delete_ok;
+ }
+ curr = curr->next;
+ }
+ return SYSVAR_DELETE_ERR;
+ }
+
+delete_ok:
+ /* update the used bytes in data buffer */
+ sysvar_len(buf, -var->len);
+
+ if (var->value != NULL)
+ free(var->value);
+ free(var);
+
+ return SYSVAR_SUCCESS;
+}
+
+/*
+ * clear_var - delete all system variables in data list
+ */
+int clear_var(struct sysvar_buf *buf) {
+ struct sysvar_list *curr = buf->list->next;
+ struct sysvar_list *var;
+ int ret = SYSVAR_SUCCESS;
+
+ while (curr != NULL && ret == SYSVAR_SUCCESS) {
+ /* store next position of variable */
+ var = curr->next;
+ /* delete last variable */
+ ret = delete_var(buf, curr);
+ /* restore next position of variable */
+ curr = var;
+ }
+ return ret;
+}
+
+/*
+ * find_var - find the system variable in data list
+ */
+struct sysvar_list *find_var(struct sysvar_buf *buf, char *name) {
+ struct sysvar_list *curr = buf->list->next;
+
+ if (name == NULL)
+ return NULL;
+
+ /* search the data list */
+ while (curr != NULL) {
+ if (strncmp(curr->name, name, SYSVAR_NAME) == 0)
+ break;
+ curr = curr->next;
+ }
+ return curr;
+}
+
+/*
+ * check_var - check/update checksum and write counter in data buffer
+ */
+int check_var(struct sysvar_buf *buf, int mode) {
+ unsigned long crc[2];
+ int ret = SYSVAR_SUCCESS;
+
+ switch (mode) {
+ case SYSVAR_LOAD_MODE:
+ crc[0] = get_crc32(buf);
+ crc[1] = sysvar_crc(buf->data, buf->total_len);
+ if (crc[0] == crc[1])
+ buf->modified = false;
+ else
+ ret = SYSVAR_CRC_ERR;
+ break;
+ case SYSVAR_SAVE_MODE:
+ set_wc32(buf);
+ buf->modified = false;
+ break;
+ case SYSVAR_SET_MODE:
+ set_crc32(buf);
+ buf->modified = true;
+ break;
+ default:
+ ret = SYSVAR_PARAM_ERR;
+ break;
+ }
+ return ret;
+}
+
+/*
+ * print_var - print the system variables
+ */
+void print_var(struct sysvar_buf *buf) {
+ struct sysvar_list *curr = buf->list->next;
+
+ while (curr != NULL) {
+ /* print variable name */
+ printf("%s(%s)=%s\n", curr->name,
+ buf->readonly ? "RO" : "RW", curr->value);
+ curr = curr->next;
+ }
+}
+
+/*
+ * clear_buf - clear the data buffer
+ */
+void clear_buf(struct sysvar_buf *buf) {
+ if (buf->data != NULL) {
+ memset(buf->data, 0xff, buf->data_len);
+ buf->loaded = true;
+
+ set_wc32(buf);
+ set_crc32(buf);
+ }
+}
+
+/*
+ * dump_buf - dump the data buffer in binary/ascii format
+ */
+void dump_buf(struct sysvar_buf *buf, int start, int len) {
+ char c;
+ int i, j;
+
+ for (i = start; i < start + len; i += 16) {
+ printf("[%08x] ", start + i);
+
+ /* binary format */
+ for (j = 0; j < 16; j++) {
+ if (i + j < buf->data_len)
+ printf("%02x ", buf->data[i + j]);
+ else
+ printf(" ");
+ }
+
+ /* ascii format */
+ for (j = 0; j < 16; j++) {
+ if (i + j < buf->data_len) {
+ c = buf->data[i + j];
+ if (c >= 32 && c < 127) {
+ printf("%c", c);
+ } else {
+ printf(".");
+ }
+ } else {
+ printf(" ");
+ }
+ }
+ printf("\n");
+ }
+}
+
diff --git a/include/sysvar.h b/include/sysvar.h
new file mode 100755
index 0000000..4e73b1f
--- /dev/null
+++ b/include/sysvar.h
@@ -0,0 +1,114 @@
+/* Copyright 2012 Google Inc. All Rights Reserved.
+ * Author: weixiaofeng@google.com (Xiaofeng Wei)
+ */
+
+#ifndef _SYSVAR_H_
+#define _SYSVAR_H_
+
+#define SYSVAR_UBOOT
+
+#ifndef SYSVAR_UBOOT
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#else
+typedef enum _bool{false, true} bool;
+#endif
+#include <malloc.h>
+
+#define SYSVAR_WC32 4
+#define SYSVAR_CRC32 4
+#define SYSVAR_HEAD (SYSVAR_WC32 + SYSVAR_CRC32)
+#define SYSVAR_NAME 32
+#define SYSVAR_MESSAGE -1
+
+#define SYSVAR_STR_TO_BUF 0x00
+#define SYSVAR_BUF_TO_STR 0xff
+
+#define SYSVAR_BLOCK_SIZE 0x00010000 /* size of system variables (64K) */
+
+#define SYSVAR_SPI_BLOCK 4 /* number of SPI flash blocks */
+#define SYSVAR_RW_OFFSET0 0x00100000 /* location of system variables(RW) */
+#define SYSVAR_RW_OFFSET1 0x00120000 /* location of system variables(RW backup) */
+#define SYSVAR_RO_OFFSET0 0x00140000 /* location of system variables(RO) */
+#define SYSVAR_RO_OFFSET1 0x00160000 /* location of system variables(RO backup) */
+
+#define SYSVAR_MTD_DEVICE 4 /* number of MTD devices */
+#define SYSVAR_RW_NAME0 "/dev/mtd2" /* MTD device of system variables(RW) */
+#define SYSVAR_RW_NAME1 "/dev/mtd3" /* MTD device of system variables(RW backup) */
+#define SYSVAR_RO_NAME0 "/dev/mtd4" /* MTD device of system variables(RO) */
+#define SYSVAR_RO_NAME1 "/dev/mtd5" /* MTD device of system variables(RO backup) */
+
+#define SYSVAR_RW_DATA0 0
+#define SYSVAR_RW_DATA1 1
+#define SYSVAR_RO_DATA0 2
+#define SYSVAR_RO_DATA1 3
+
+#define SYSVAR_RW_BUF 0
+#define SYSVAR_RO_BUF 2
+
+#define SYSVAR_GET_MODE 0
+#define SYSVAR_SET_MODE 1
+#define SYSVAR_LOAD_MODE 2
+#define SYSVAR_SAVE_MODE 3
+
+#define SYSVAR_SUCCESS 0
+#define SYSVAR_MEMORY_ERR -1
+#define SYSVAR_OPEN_ERR -2
+#define SYSVAR_READ_ERR -3
+#define SYSVAR_WRITE_ERR -4
+#define SYSVAR_ERASE_ERR -5
+#define SYSVAR_LOAD_ERR -6
+#define SYSVAR_SAVE_ERR -7
+#define SYSVAR_GET_ERR -8
+#define SYSVAR_SET_ERR -9
+#define SYSVAR_DELETE_ERR -10
+#define SYSVAR_PARAM_ERR -11
+#define SYSVAR_CRC_ERR -12
+#define SYSVAR_READONLY_ERR -13
+#define SYSVAR_EXISTED_ERR -14
+
+struct sysvar_list {
+ char name[SYSVAR_NAME + 1]; /* name of system variable */
+ char *value; /* value of system variable */
+ int len; /* length of system variable */
+
+ struct sysvar_list *next;
+};
+
+struct sysvar_buf {
+ unsigned char *data; /* data buffer to store system variables */
+ int data_len; /* buffer size */
+
+ int total_len; /* total space = buffer size - buffer header */
+ int free_len; /* free space in data buffer */
+ int used_len; /* total bytes of variables */
+
+ bool loaded; /* data buffer has been loaded from SPI flash */
+ bool modified; /* data modified in the data buffer */
+ bool readonly; /* read only system variables */
+ bool failed[2]; /* failed to read data from SPI flash */
+
+ struct sysvar_list *list;
+};
+
+extern unsigned long get_wc32(struct sysvar_buf *buf);
+extern void set_wc32(struct sysvar_buf *buf);
+extern unsigned long get_crc32(struct sysvar_buf *buf);
+extern void set_crc32(struct sysvar_buf *buf);
+
+extern int load_var(struct sysvar_buf *buf);
+extern int save_var(struct sysvar_buf *buf);
+extern int get_var(struct sysvar_list *var, char *name, char *value, int len);
+extern int set_var(struct sysvar_buf *buf, char *name, char *value);
+extern int delete_var(struct sysvar_buf *buf, struct sysvar_list *var);
+extern int clear_var(struct sysvar_buf *buf);
+extern struct sysvar_list *find_var(struct sysvar_buf *buf, char *name);
+extern int check_var(struct sysvar_buf *buf, int mode);
+extern void print_var(struct sysvar_buf *buf);
+
+extern void clear_buf(struct sysvar_buf *buf);
+extern void dump_buf(struct sysvar_buf *buf, int start, int len);
+
+#endif /* _SYSVAR_H_ */