Add hnvram for grabbing env variables during boot
cmd_hnvram.c modifed from uboot/armada
hnvram must be loaded into dram during boot since the uboot heap
uses sram, which is too small. Currently hnvram is stored at
0x87800000 or 120-122 of dram's 128 MB.
Change-Id: I24a6f8ebed08beb3b1026c9765143a1b9d3400d8
diff --git a/board/ruby/ruby.c b/board/ruby/ruby.c
index a4ecd69..c1e0c5c 100644
--- a/board/ruby/ruby.c
+++ b/board/ruby/ruby.c
@@ -198,6 +198,9 @@
spi_protect_mode_off();
}
}
+#ifdef CONFIG_CMD_HNVRAM
+ RUN("hnvram");
+#endif
return 0;
}
diff --git a/common/Makefile b/common/Makefile
index 8a875ac..1d0cbd2 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -96,6 +96,7 @@
ifdef CONFIG_FPGA
COBJS-$(CONFIG_CMD_FPGA) += cmd_fpga.o
endif
+COBJS-$(CONFIG_CMD_HNVRAM) += cmd_hnvram.o
COBJS-$(CONFIG_CMD_I2C) += cmd_i2c.o
COBJS-$(CONFIG_CMD_IDE) += cmd_ide.o
COBJS-$(CONFIG_CMD_IMMAP) += cmd_immap.o
diff --git a/common/cmd_hnvram.c b/common/cmd_hnvram.c
new file mode 100644
index 0000000..52f0ae1
--- /dev/null
+++ b/common/cmd_hnvram.c
@@ -0,0 +1,266 @@
+/*
+ * cmd_hnvram.c -- makes hnvram contents available in u-boot.
+ * Loads contents of hnvram from spi flash and saves it
+ * to environment variables named HNV_<name>.
+ *
+ * Copyright (C) 2015 Google Inc.
+ * Author: Chris Gibson <cgibson@google.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <command.h>
+#include <common.h>
+#include <malloc.h>
+#include <spi_flash.h>
+
+/* local debug macro */
+#undef HNVRAM_DEBUG
+
+#ifdef HNVRAM_DEBUG
+#define DEBUG(fmt, args...) printf(fmt, ##args)
+#else
+#define DEBUG(fmt, args...)
+#endif /* HNVRAM_DEBUG */
+
+#define CONFIG_SF_DEFAULT_MODE SPI_MODE_3
+
+
+// Flash erase block size
+#define HNVRAM_BLOCKSIZE 0x00010000
+
+// Location in DRAM where hnvram variables are stored during boot
+// DRAM is 128 MB [0x80000000 - 0x88000000]
+// Store hnvram at 120 - 122 MB
+#define HNVRAM_DRAM_OFFSET 0x87800000
+
+// Where in flash does hnvram partition start
+#define HNVRAM_MTD_OFFSET 0x00200000
+
+// Total hnvram is 2MB with 4 partitions
+#define MAX_HNVRAM_SIZE 0x00200000
+
+#define HNVRAM_RO_SIZE 0x00100000
+#define HNVRAM_RW_SIZE 0x00040000
+#define HNVRAM_RWB_SIZE 0x00020000
+#define HNVRAM_RAW_FS_SIZE 0x00020000
+
+// B1 and B2 corresponding to RW_OFFSET and RWB_OFFSET
+#define HNVRAM_B1_OFFSET (HNVRAM_RO_SIZE)
+#define HNVRAM_B2_OFFSET (HNVRAM_RO_SIZE + HNVRAM_RW_SIZE)
+
+#define CMD_RET_SUCCESS 0
+#define CMD_RET_FAILURE 1
+#define CMD_RET_USAGE -1
+
+// These keys are stored in binary format for historical reasons
+const char *hnvram_binary_keys[] = {
+ "LOADER_VERSION",
+ "HDCP_KEY",
+ "DTCP_KEY",
+};
+
+static void *xmalloc(size_t size)
+{
+ void *p = NULL;
+ if (!(p = malloc(size))) {
+ printf("error: memory not allocated\n");
+ return 0;
+ }
+ memset(p, 0, size);
+ return p;
+}
+
+int read_u8(const char **p)
+{
+ int v = *(const unsigned char *)(*p);
+ *p += 1;
+ return v;
+}
+
+int read_s32_be(const char **p)
+{
+ const unsigned char *vp = (const unsigned char *)*p;
+ *p += 4;
+ return (vp[0]<<24) + (vp[1]<<16) + (vp[2]<<8) + vp[3];
+}
+
+int read_u16_le(const char **p)
+{
+ const unsigned char *up = (const unsigned char *)(*p);
+ *p += 2;
+ return up[0] + (up[1] << 8);
+}
+
+int is_hnvram_binary(const char *name, int namelen)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(hnvram_binary_keys); i++) {
+ const char *k = hnvram_binary_keys[i];
+ if ((int)strlen(k) == namelen && strncmp(k, name, namelen) == 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+char *encode_hex(const char *s, int len)
+{
+ char *optr, *out = xmalloc(len * 2 + 1);
+ for (optr = out; len > 0; len--) {
+ sprintf(optr, "%02x", read_u8(&s));
+ optr += 2;
+ }
+ return out;
+}
+
+char *encode_macaddr(const char *mac)
+{
+ int i;
+ char *out = xmalloc(6 * 2 + 5 + 2);
+ for (i = 0; i < 6; i++) {
+ sprintf(out + i * 3, "%02X:", read_u8(&mac));
+ }
+ out[6*2 + 5] = '\0';
+ return out;
+}
+
+static void _copy_setenv(const char *name, int namelen,
+ const char *val, int vallen)
+{
+ char *n, *v;
+ if (namelen + vallen < 128) {
+ n = xmalloc(4 + namelen + 1);
+ v = xmalloc(vallen + 1);
+ memcpy(n, "HNV_", 4);
+ memcpy(n + 4, name, namelen);
+ memcpy(v, val, vallen);
+ n[namelen+4] = 0;
+ v[vallen] = 0;
+ setenv(n, v);
+ free(n);
+ free(v);
+ } else {
+ DEBUG("ignoring oversized val: %.15s, vallen: %d\n", val, vallen);
+ }
+}
+
+static int _parse_hnvram(const char *buf, int len)
+{
+ // An hnvram structure. Format is a tag-length-value sequence of:
+ // [1 byte] type (1 for notdone, 0 for done)
+ // [4 bytes] record length
+ // [1 byte] key length
+ // [x bytes] key
+ // [4 bytes] value length
+ // [y bytes] value
+ int rectype, reclen, namelen, vallen;
+ int done = 0;
+ const char *name, *val, *p = buf;
+ while (p - buf <= len + 11) {
+ rectype = read_u8(&p);
+ if (rectype == 0x00) {
+ printf("done processing hnvram block!\n");
+ done = 1;
+ break;
+ }
+ if (rectype != 0x01) {
+ printf("error: hnvram invalid rectype %x\n", rectype);
+ return -1;
+ }
+
+ reclen = read_s32_be(&p);
+ if (reclen <= 6 || (p - buf) + reclen >= len) {
+ printf("error: hnvram invalid reclen %d\n", reclen);
+ return -1;
+ }
+ namelen = read_u8(&p);
+ if (namelen < 1 || (p - buf) + namelen >= len) {
+ printf("error: hnvram invalid namelen %d\n", namelen);
+ return -1;
+ }
+ name = p;
+ p += namelen;
+ vallen = read_s32_be(&p);
+ if (vallen < 0 || (p - buf) + vallen >= len) {
+ printf("error: hnvram invalid vallen %d\n", vallen);
+ return -1;
+ }
+ val = p;
+ p += vallen;
+ if (vallen == 6 && namelen >= 8 &&
+ strncmp("MAC_ADDR", name, 8) == 0) {
+ char *macstr = encode_macaddr(val);
+ _copy_setenv(name, namelen, macstr, strlen(macstr));
+ free(macstr);
+ } else if (is_hnvram_binary(name, namelen)) {
+ char *hexstr = encode_hex(val, vallen);
+ _copy_setenv(name, namelen, hexstr, strlen(hexstr));
+ free(hexstr);
+ } else {
+ _copy_setenv(name, namelen, val, vallen);
+ }
+ }
+ if (!done) {
+ printf("error: failed to find final hnvram record?\n");
+ return -1;
+ }
+ return 0;
+}
+
+#if defined(CONFIG_CMD_HNVRAM)
+int do_hnvram(void) {
+ char command[60];
+ sprintf(command, "spi_flash read 0x%x 0x%x 0x%x", HNVRAM_MTD_OFFSET, HNVRAM_DRAM_OFFSET, MAX_HNVRAM_SIZE);
+ int ret = run_command(command, 0);
+
+ if (ret) {
+ printf("failed reading from spi-flash at addr: %d\n", HNVRAM_MTD_OFFSET);
+ return ret;
+ }
+
+ char *buf = HNVRAM_DRAM_OFFSET;
+
+ // Next step: Seek to different parts of the buffer that contain the
+ // first, second, and third sections of hnvram.
+ if (_parse_hnvram(buf, HNVRAM_BLOCKSIZE) != 0) {
+ printf("failed parsing hnvram at offset: 0x%p\n", buf);
+ return -1;
+ }
+ if (_parse_hnvram(buf+HNVRAM_B1_OFFSET, HNVRAM_BLOCKSIZE) != 0) {
+ printf("failed parsing hnvram at offset: 0x%p\n", buf+HNVRAM_B1_OFFSET);
+ return -1;
+ }
+ if (_parse_hnvram(buf+HNVRAM_B2_OFFSET, HNVRAM_BLOCKSIZE) != 0) {
+ printf("failed parsing hnvram at offset: 0x%p\n", buf+HNVRAM_B2_OFFSET);
+ return -1;
+ }
+
+ free(buf);
+ return CMD_RET_SUCCESS;
+}
+
+static int do_hnvram_cmd(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[]) {
+ return do_hnvram();
+}
+
+U_BOOT_CMD(
+ hnvram, 1, 0, do_hnvram_cmd,
+ "load hnvram from flash",
+ "\n"
+ "load hnvram from flash into environment vars named HNV_<name>\n"
+ );
+#endif /* CONFIG_CMD_HNVRAM */
diff --git a/include/configs/ruby.h b/include/configs/ruby.h
index 4d0c629..ffda11b 100644
--- a/include/configs/ruby.h
+++ b/include/configs/ruby.h
@@ -33,6 +33,7 @@
/* Commands */
#define CONFIG_CMD_CONSOLE
#define CONFIG_CMD_ECHO
+#define CONFIG_CMD_HNVRAM
#define CONFIG_CMD_MEMORY
#define CONFIG_CMD_MISC
#define CONFIG_CMD_RUN
diff --git a/include/configs/ruby_mini.h b/include/configs/ruby_mini.h
index d14332d..2071c40 100644
--- a/include/configs/ruby_mini.h
+++ b/include/configs/ruby_mini.h
@@ -36,6 +36,7 @@
#ifndef TOPAZ_EP_MINI_UBOOT
/* Commands */
+#define CONFIG_CMD_HNVRAM
#define CONFIG_CMD_NET
#define CONFIG_CMD_PING
#define CONFIG_CMD_INTR