[U-Boot-Users] [PATCH 3/5] Adds support for RedBoot
Pantelis Antoniou
pantelis at embeddedalley.com
Wed Nov 29 18:25:59 CET 2006
CHANGELOG entry:
Provide support for RedBoot's FIS & config variables.
For PPC provide also a way to boot a redboot compiled Linux kernel.
The bd_t is different in that case.
---
Signed-off-by: Pantelis Antoniou <pantelis at embeddedalley.com>
---
README | 70 ++++
common/Makefile | 1
common/cmd_bootm.c | 19 +
common/redboot.c | 941 ++++++++++++++++++++++++++++++++++++++++++++++++++++
include/redboot.h | 91 +++++
5 files changed, 1121 insertions(+), 1 deletions(-)
diff --git a/README b/README
index 0aab04c..502f8ec 100644
--- a/README
+++ b/README
@@ -2265,6 +2265,76 @@ Low Level (hardware related) configuration options:
some other boot loader or by a debugger which
performs these intializations itself.
+- CONFIG_REDBOOT
+ Add support for read-only parsing of the FIS & config areas.
+ For PPC also add an option to boot a kernel compiled for RedBoot.
+
+ The redboot command is also enabled conditional on CFG_CMD_FLASH.
+
+ - Select a different FIS
+ > redboot fis select ([bank] [sector] | reset)
+
+ - Display FIS
+ > redboot fis list
+
+ - Set an environment variable from a member variable of a FIS entry
+
+ > redboot fis setenv var type name
+
+ Where type: flash_base, mem_base, size, entry_point, data_length.
+
+ An example given a FIS entry of
+
+ Name FLASH addr Mem addr Datalen Length Entry point
+ Linux 0xF0470000 0x00100000 0x000FA000 0x00100000 0x00100000
+
+ > redboot fis setenv linux_base flash_base Linux
+
+ Would set the environment variable linux_base to 0xf0470000
+
+ - Print either all the RedBoot config variables or a specific one
+
+ > redboot config printenv [config-var] [member]
+
+ member is one of value, type, enable-sense, enable-key with value
+ being the default one.
+
+ - Set an environment variable from a RedBoot config variable
+
+ > redboot config setenv var config-var [member]
+
+ For example when given a config variable of
+
+ tsec1_esa=00:08:e5:11:32:33
+ type=esa enable-sense=true
+
+ > redboot config setenv ethaddr tsec1_esa
+
+ would set the ethaddr environment variable to 00:08:e5:11:32:33
+
+ - Boot a RedBoot kernel [PPC specific]
+
+ > redboot exec address
+
+ The PPC bd_t differs for kernels compiled for redboot; this command
+ lets you boot such a kernel.
+
+ RedBoot config defaults (can be overriden on board config):
+
+ - Sector containing the FIS area (negative values for counting from the end)
+ CONFIG_REDBOOT_FIS_DIRECTORY_BLOCK -1
+
+ - FIS directory entry size
+ CONFIG_REDBOOT_DIRECTORY_ENTRY_SIZE 0x100
+
+ - Size of the config area
+ CONFIG_REDBOOT_FLASH_CONFIG_SIZE 4096
+
+ - Size of the script config variables
+ CONFIG_REDBOOT_FLASH_SCRIPT_SIZE 256
+
+ - Size of the string config variables
+ CONFIG_REDBOOT_FLASH_STRING_SIZE 128
Building the Software:
======================
diff --git a/common/Makefile b/common/Makefile
index 8baeab3..b6db7f4 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -49,6 +49,7 @@ COBJS = main.o ACEX1K.o altera.o bedbug.o circbuf.o \
flash.o fpga.o ft_build.o \
hush.o kgdb.o lattice.o lattice_ivm_core.o lcd.o lists.o lynxkdi.o \
memsize.o miiphybb.o miiphyutil.o \
+ redboot.o \
s_record.o serial.o soft_i2c.o soft_spi.o spartan2.o spartan3.o \
usb.o usb_kbd.o usb_storage.o \
virtex2.o xilinx.o crc16.o xyzModem.o cmd_mac.o
diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c
index 7aae8a6..fd02257 100644
--- a/common/cmd_bootm.c
+++ b/common/cmd_bootm.c
@@ -146,6 +146,12 @@ extern void lynxkdi_boot( image_header_t * );
#define CFG_BOOTM_LEN 0x800000 /* use 8MByte as default max gunzip size */
#endif
+#ifdef CONFIG_REDBOOT_BD_T_SIZE
+extern void board_redboot_bd_t_adapt(void *kbd,
+ ulong cmd_start, ulong cmd_end,
+ ulong initrd_start, ulong initrd_end);
+#endif
+
image_header_t header;
ulong load_addr = CFG_LOAD_ADDR; /* Default Load Address */
@@ -533,6 +539,11 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag,
char *of_flat_tree = NULL;
ulong of_data = 0;
#endif
+#ifdef CONFIG_REDBOOT_BD_T_SIZE
+#define BD_T_SIZE max(sizeof(bd_t), CONFIG_REDBOOT_BD_T_SIZE)
+#else
+#define BD_T_SIZE sizeof(bd_t)
+#endif
if ((s = getenv ("initrd_high")) != NULL) {
/* a value of "no" or a similar string will act like 0,
@@ -575,7 +586,7 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag,
debug ("=> set upper limit to 0x%08lX\n", sp);
cmdline = (char *)((sp - CFG_BARGSIZE) & ~0xF);
- kbd = (bd_t *)(((ulong)cmdline - sizeof(bd_t)) & ~0xF);
+ kbd = (bd_t *)(((ulong)cmdline - BD_T_SIZE) & ~0xF);
if ((s = getenv("bootargs")) == NULL)
s = "";
@@ -904,6 +915,12 @@ do_bootm_linux (cmd_tbl_t *cmdtp, int flag,
initrd_end = 0;
}
+ /* redboot bd_t modify */
+#ifdef CONFIG_REDBOOT_BD_T_SIZE
+ if ((s = getenv ("redboot_bd_t")) != NULL)
+ board_redboot_bd_t_adapt(kbd, cmd_start, cmd_end, initrd_start, initrd_end);
+#endif
+
debug ("## Transferring control to Linux (at address %08lx) ...\n",
(ulong)kernel);
diff --git a/common/redboot.c b/common/redboot.c
new file mode 100644
index 0000000..eb19a58
--- /dev/null
+++ b/common/redboot.c
@@ -0,0 +1,941 @@
+/*
+ * (C) Copyright 2006 - Embedded Alley Solutions Inc.
+ * by Pantelis Antoniou, pantelis at embeddedalley.com
+ *
+ * Based on Linux & RedBoot code fragments
+ * by David Woodhouse, dwmw2 at infradead.org
+ * by Mark Sattler, msalter at redhat.com
+ * by Gary Thomas, gthomas at redhat.com
+ *
+ * RedBoot flash images/configuration & kernel startup
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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 <common.h>
+#include <malloc.h>
+#include <flash.h>
+#include <command.h>
+
+#include <redboot.h>
+
+#ifdef CONFIG_SHOW_BOOT_PROGRESS
+# include <status_led.h>
+# define SHOW_BOOT_PROGRESS(arg) show_boot_progress(arg)
+#else
+# define SHOW_BOOT_PROGRESS(arg)
+#endif
+
+#ifdef CFG_INIT_RAM_LOCK
+#include <asm/cache.h>
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_FLASH) && defined(CONFIG_REDBOOT)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+extern void board_redboot_bd_t_adapt(void *kbd,
+ ulong cmd_start, ulong cmd_end,
+ ulong initrd_start, ulong initrd_end);
+
+extern flash_info_t flash_info[]; /* info for FLASH chips */
+
+static inline int redboot_checksum(struct fis_image_desc *img)
+{
+ /* RedBoot doesn't actually write the desc_cksum field yet AFAICT */
+ return 1;
+}
+
+static int get_sector_size(flash_info_t *info, int sector)
+{
+ ulong s, e;
+
+ if (info->flash_id == FLASH_UNKNOWN)
+ return 0;
+
+ if ((unsigned int)sector >= info->sector_count)
+ return 0;
+
+ s = info->start[sector];
+ if (sector < info->sector_count - 1)
+ e = info->start[sector + 1];
+ else
+ e = info->start[0] + info->size;
+
+ return e - s;
+}
+
+/* get the sector which corresponds to this address */
+static int get_sector(flash_info_t *info, void *ptr)
+{
+ int i;
+ ulong s, e;
+
+ if (info->flash_id == FLASH_UNKNOWN)
+ return -1;
+
+ if (info->start[0] > (ulong)ptr ||
+ info->start[info->sector_count - 1] < (ulong)ptr)
+ return -1;
+
+ for (i = 0; i < info->sector_count; i++) {
+ s = info->start[i];
+ if (i < info->sector_count - 1)
+ e = info->start[i + 1];
+ else
+ e = info->start[0] + info->size;
+
+ if (s <= (ulong)ptr && e > (ulong)ptr)
+ return i;
+ }
+
+ /* should not happen */
+ return -1;
+}
+
+static void *get_fis(flash_info_t *info, void *fis)
+{
+ int dir_block, sector;
+
+ if (info->flash_id == FLASH_UNKNOWN)
+ return NULL;
+
+ /* already given a fis address (verify it) */
+ if (fis != NULL) {
+ if (info->start[0] > (ulong)fis ||
+ info->start[info->sector_count - 1] < (ulong)fis)
+ return NULL;
+ return fis;
+ }
+
+ /* go with defaults */
+ dir_block = CONFIG_REDBOOT_FIS_DIRECTORY_BLOCK;
+ if (dir_block < 0)
+ sector = info->sector_count + dir_block;
+ else
+ sector = dir_block;
+
+ if ((unsigned int)sector >= info->sector_count)
+ return NULL;
+
+ return (void *)info->start[sector];
+}
+
+static int get_fis_slots(flash_info_t *info, void *fis, int *swapped)
+{
+ int i, sector, sector_size, slots;
+ struct fis_image_desc *ptr;
+
+ *swapped = -1;
+
+ fis = get_fis(info, fis);
+ if (fis == NULL)
+ return -1;
+
+ sector = get_sector(info, fis);
+ sector_size = get_sector_size(info, sector);
+
+ slots = sector_size / sizeof(struct fis_image_desc);
+
+ /* first pass; detect swap status */
+ for (i = 0, ptr = fis; i < slots; i++, ptr++) {
+ if (ptr->name[0] == 0xFF)
+ break;
+
+ if (!memcmp(ptr->name, "FIS directory", 14))
+ *swapped = swab32(ptr->size) == sector_size;
+ }
+
+ if (*swapped == -1)
+ return -1;
+
+ return i;
+}
+
+void *redboot_fis_get(int bank, int dir_block, flash_info_t **infop)
+{
+ flash_info_t *info;
+ int block;
+
+ if (bank < 1 || bank > CFG_MAX_FLASH_BANKS) {
+ printf ("Only FLASH Banks # 1 ... # %d supported\n",
+ CFG_MAX_FLASH_BANKS);
+ return NULL;
+ }
+ info = &flash_info[bank-1];
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("FLASH Bank #%d, not present\n", bank);
+ return NULL;
+ }
+
+ if (dir_block < 0)
+ block = info->sector_count + dir_block;
+ else
+ block = dir_block;
+
+ if ((unsigned int)block >= info->sector_count) {
+ printf ("FLASH dir_block %d out of range in Bank #%d\n", dir_block, bank);
+ return NULL;
+ }
+
+ if (infop)
+ *infop = info;
+ return (void *)info->start[block];
+}
+
+
+int redboot_fis_entry_lookup(flash_info_t *info, void *fis, struct fis_image_desc *fis_buf, const char *name)
+{
+ int i, slots, swapped, name_len;
+ struct fis_image_desc *ptr;
+
+ fis = get_fis(info, fis);
+ if (fis == NULL)
+ return -1;
+
+ slots = get_fis_slots(info, fis, &swapped);
+ if (slots == -1) {
+ printf("fis list: FIS not found\n");
+ return -1;
+ }
+
+ name_len = strlen(name);
+
+ /* now do the proper read (with swapping if needed */
+ for (i = 0, ptr = fis; i < slots; i++, ptr++) {
+
+ if (ptr->name[0] == 0xFF)
+ break;
+
+ /* copy to buffer */
+ memcpy(fis_buf, ptr, sizeof(struct fis_image_desc));
+ if (swapped) {
+ /* The unsigned long fields were written with the
+ * wrong byte sex, name and pad have no byte sex.
+ */
+ swab32s(&fis_buf->flash_base);
+ swab32s(&fis_buf->mem_base);
+ swab32s(&fis_buf->size);
+ swab32s(&fis_buf->entry_point);
+ swab32s(&fis_buf->data_length);
+ swab32s(&fis_buf->desc_cksum);
+ swab32s(&fis_buf->file_cksum);
+ }
+
+ /* found */
+ if (strcmp(name, fis_buf->name) == 0)
+ return 0;
+ }
+
+ return -1;
+}
+
+int redboot_fis_list(flash_info_t *info, void *fis)
+{
+ int i, slots, swapped, found;
+ static struct fis_image_desc fis_buf; /* static; to save stack space */
+ struct fis_image_desc *ptr;
+ u32 last, lowest, flash_base;
+
+ fis = get_fis(info, fis);
+ if (fis == NULL) {
+ printf("fis list: could not get FIS\n");
+ return -1;
+ }
+
+ slots = get_fis_slots(info, fis, &swapped);
+ if (slots == -1) {
+ printf("fis list: FIS not found\n");
+ return -1;
+ }
+
+ printf("%-16s %-10s %-10s %-10s %-10s %-s\n",
+ "Name", "FLASH addr", "Mem addr",
+ "Datalen", "Length", "Entry point" );
+
+ last = 0;
+ do {
+ found = -1;
+ lowest = 0xFFFFFFFF;
+
+ /* now do the proper read (with swapping if needed */
+ for (i = 0, ptr = fis; i < slots; i++, ptr++) {
+
+ if (ptr->name[0] == 0xFF)
+ break;
+
+ if (swapped)
+ flash_base = swab32(ptr->flash_base);
+ else
+ flash_base = ptr->flash_base;
+
+ if (flash_base > last && flash_base < lowest) {
+ lowest = flash_base;
+ found = i;
+ }
+ }
+
+ if (found >= 0) {
+ ptr = fis;
+ memcpy(&fis_buf, &ptr[found], sizeof(struct fis_image_desc));
+ if (swapped) {
+ /* The unsigned long fields were written with the
+ * wrong byte sex, name and pad have no byte sex.
+ */
+ swab32s(&fis_buf.flash_base);
+ swab32s(&fis_buf.mem_base);
+ swab32s(&fis_buf.size);
+ swab32s(&fis_buf.entry_point);
+ swab32s(&fis_buf.data_length);
+ swab32s(&fis_buf.desc_cksum);
+ swab32s(&fis_buf.file_cksum);
+ }
+
+ printf("%-16s 0x%08lX 0x%08lX 0x%08lX 0x%08lX 0x%08lX\n",
+ fis_buf.name,
+ (unsigned long)fis_buf.flash_base, fis_buf.mem_base,
+ fis_buf.data_length, fis_buf.size,
+ (unsigned long)fis_buf.entry_point);
+ }
+ last = lowest;
+ } while (found >= 0);
+
+ return 0;
+}
+
+int redboot_fis_setenv(flash_info_t *info, void *fis, const char *name, const char *what, char *var)
+{
+ static struct fis_image_desc fis_buf; /* static; to save stack space */
+ static char varbuf[12];
+ int i;
+
+ i = redboot_fis_entry_lookup(info, fis, &fis_buf, name);
+ if (i != 0)
+ return -1;
+
+ if (strcmp(what, "flash_base") == 0)
+ sprintf(varbuf, "0x%x", fis_buf.flash_base);
+ else if (strcmp(what, "mem_base") == 0)
+ sprintf(varbuf, "0x%x", fis_buf.mem_base);
+ else if (strcmp(what, "size") == 0)
+ sprintf(varbuf, "0x%x", fis_buf.size);
+ else if (strcmp(what, "entry_point") == 0)
+ sprintf(varbuf, "0x%x", fis_buf.entry_point);
+ else if (strcmp(what, "data_length") == 0)
+ sprintf(varbuf, "0x%x", fis_buf.data_length);
+ else
+ return -1;
+
+ setenv(var, varbuf);
+
+ return 0;
+}
+
+/*************************************************************************/
+
+#define CONFIG_KEY1 0x0badface
+#define CONFIG_KEY2 0xdeaddead
+
+//
+// Layout of config data
+// Each data item is variable length, with the name, type and dependencies
+// encoded into the object.
+// offset contents
+// 0 data type
+// 1 length of name (N)
+// 2 enable sense
+// 3 length of enable key (M)
+// 4 key name
+// N+4 enable key
+// M+N+4 data value
+//
+
+#define TYPE(dp) ((dp)[0])
+#define KEYLEN(dp) ((dp)[1])
+#define ENABLE_SENSE(dp) ((dp)[2])
+#define ENABLE_KEYLEN(dp) ((dp)[3])
+#define KEY(dp) ((dp)+4)
+#define ENABLE_KEY(dp) ((dp)+4+KEYLEN(dp))
+#define VALUE(dp) ((dp)+4+KEYLEN(dp)+ENABLE_KEYLEN(dp))
+
+void *get_config(flash_info_t *info, void *fis, int *sizep, int *swappedp)
+{
+ static struct fis_image_desc fis_buf; /* static; to save stack space */
+ int i;
+ ulong base, size;
+ void *config;
+ u32 *ps, *pe;
+
+ /* lookup the RedBoot config */
+ i = redboot_fis_entry_lookup(info, fis, &fis_buf, "RedBoot config");
+ if (i != 0)
+ return NULL;
+
+ base = fis_buf.flash_base;
+ size = fis_buf.data_length;
+
+ config = (void *)base;
+
+ /* verify */
+ ps = (u32 *)base;
+ if (ps[1] != CONFIG_KEY1 && ps[1] != swab32(CONFIG_KEY1))
+ return NULL;
+
+ if (ps[1] == CONFIG_KEY1) {
+ *swappedp = 0;
+ if (ps[0] != size)
+ return NULL;
+ pe = (u32 *)(base + ps[0]);
+ if (pe[-2] != CONFIG_KEY2)
+ return NULL;
+ } else {
+ *swappedp = 1;
+ if (swab32(ps[0]) != size)
+ return NULL;
+ pe = (u32 *)(base + swab32(ps[0]));
+ if (pe[-2] != swab32(CONFIG_KEY2))
+ return NULL;
+ }
+
+ *sizep = size;
+ return config;
+}
+
+#define CONFIG_EMPTY 0
+#define CONFIG_BOOL 1
+#define CONFIG_INT 2
+#define CONFIG_STRING 3
+#define CONFIG_SCRIPT 4
+#define CONFIG_IP 5
+#define CONFIG_ESA 6
+#define CONFIG_NETPORT 7
+
+static const int config_len_tab[] = {
+ [CONFIG_EMPTY] = 0,
+ [CONFIG_BOOL] = 4,
+ [CONFIG_INT] = 4,
+ [CONFIG_STRING] = CONFIG_REDBOOT_FLASH_STRING_SIZE,
+ [CONFIG_SCRIPT] = CONFIG_REDBOOT_FLASH_SCRIPT_SIZE,
+ [CONFIG_IP] = 4,
+ [CONFIG_ESA] = 8,
+ [CONFIG_NETPORT]= CONFIG_REDBOOT_FLASH_STRING_SIZE,
+};
+
+static const char *config_txt_tab[] = {
+ [CONFIG_EMPTY] = "",
+ [CONFIG_BOOL] = "bool",
+ [CONFIG_INT] = "int",
+ [CONFIG_STRING] = "string",
+ [CONFIG_SCRIPT] = "script",
+ [CONFIG_IP] = "ip",
+ [CONFIG_ESA] = "esa",
+ [CONFIG_NETPORT]= "netport",
+};
+
+static inline int config_length(int type)
+{
+ if ((unsigned int)type >= sizeof(config_len_tab)/sizeof(config_len_tab[0]))
+ return -1;
+ return config_len_tab[type];
+}
+
+static const char *config_format_value(int type, const char *value, char *small_buf, int swapped)
+{
+ int val;
+ unsigned int uval;
+ const char *fmt;
+
+ switch (type) {
+ case CONFIG_BOOL:
+ val = *(int *)value;
+ if (swapped)
+ val = swab32(val);
+ fmt = val ? "true" : "false";
+ break;
+ case CONFIG_INT:
+ val = *(int *)value;
+ if (swapped)
+ val = swab32(val);
+ sprintf(small_buf, "%d", val);
+ fmt = small_buf;
+ break;
+ case CONFIG_STRING:
+ fmt = value;
+ break;
+ case CONFIG_SCRIPT:
+ fmt = value;
+ break;
+ case CONFIG_IP:
+ uval = *(unsigned int *)value;
+ if (swapped)
+ uval = swab32(uval);
+ sprintf(small_buf, "%u.%u.%u.%u",
+ (uval >> 24) & 0xff, (uval >> 16) & 0xff,
+ (uval >> 8) & 0xff, uval & 0xff);
+ fmt = small_buf;
+ break;
+ case CONFIG_ESA:
+ sprintf(small_buf, "%02x:%02x:%02x:%02x:%02x:%02x",
+ value[0] & 0xff, value[1] & 0xff,
+ value[2] & 0xff, value[3] & 0xff,
+ value[4] & 0xff, value[5] & 0xff);
+ fmt = small_buf;
+ break;
+ case CONFIG_NETPORT:
+ fmt = value;
+ break;
+
+ default:
+ fmt = ""; /* empty */
+ break;
+ }
+
+ return fmt;
+}
+
+int redboot_config_printenv(flash_info_t *info, void *fis, char *small_buf, const char *what)
+{
+ int size, cfglen, len, printit, swapped;
+ void *config;
+ char *dp, *dpe;
+
+ if (small_buf == NULL)
+ return -1;
+
+ config = get_config(info, fis, &size, &swapped);
+ if (config == NULL)
+ return -1;
+
+ /* point to the config data */
+ dp = config + 8;
+ dpe = config + size - 8;
+
+ for (; dp < dpe; dp += len) {
+
+ cfglen = config_length(TYPE(dp));
+ if (cfglen < 0) /* illegal type */
+ return -1;
+
+ len = 4 + KEYLEN(dp) + ENABLE_KEYLEN(dp) + cfglen;
+
+ /* don't bother with the empty */
+ if (TYPE(dp) == CONFIG_EMPTY)
+ continue;
+
+ /* printf("%p: %02x %02x %02x %02x\n",
+ dp, (int)dp[0] & 0xff, (int)dp[1] & 0xff,
+ (int)dp[2] & 0xff, (int)dp[3] & 0xff); */
+
+ printit = what == NULL || (what != NULL && strcmp(what, KEY(dp)) == 0);
+
+ if (printit) {
+ printf("%s=%s\n", KEY(dp), config_format_value(TYPE(dp), VALUE(dp), small_buf, swapped));
+ printf("\ttype=%s", config_txt_tab[(int)TYPE(dp)]);
+ printf(" enable-sense=%s", ENABLE_SENSE(dp) ? "true" : "false");
+ if (ENABLE_KEYLEN(dp) > 0)
+ printf(" enable-key=%s", ENABLE_KEY(dp));
+ printf("\n");
+
+ if (what)
+ break;
+ }
+ }
+
+ return 0;
+}
+
+const char *redboot_config_getenv(flash_info_t *info, void *fis, char *small_buf, const char *what, const char *special)
+{
+ int size, cfglen, len, swapped;
+ void *config;
+ char *dp, *dpe;
+
+ /* this time we need that */
+ if (what == NULL || small_buf == NULL)
+ return NULL;
+
+ config = get_config(info, fis, &size, &swapped);
+ if (config == NULL)
+ return NULL;
+
+ /* point to the config data */
+ dp = config + 8;
+ dpe = config + size - 8;
+
+ for (; dp < dpe; dp += len) {
+
+ cfglen = config_length(TYPE(dp));
+ if (cfglen < 0) /* illegal type */
+ return NULL;
+
+ len = 4 + KEYLEN(dp) + ENABLE_KEYLEN(dp) + cfglen;
+
+ /* don't bother with the empty */
+ if (TYPE(dp) == CONFIG_EMPTY)
+ continue;
+
+ if (strcmp(what, KEY(dp)) == 0) {
+
+ /* return value */
+ if (special == NULL || strcmp(special, "value") == 0)
+ return config_format_value(TYPE(dp), VALUE(dp), small_buf, swapped);
+
+ if (strcmp(special, "type") == 0)
+ return config_txt_tab[(int)TYPE(dp)];
+
+ if (strcmp(special, "enable-sense") == 0)
+ return ENABLE_SENSE(dp) ? "true" : "false";
+
+ if (strcmp(special, "enable-key") == 0)
+ return ENABLE_KEY(dp);
+ }
+ }
+
+ return NULL;
+}
+
+int redboot_config_setenv(flash_info_t *info, void *fis,
+ const char *var, const char *what, const char *special)
+{
+ static char small_buf[18];
+ const char *value;
+
+ value = redboot_config_getenv(info, fis, small_buf, what, special);
+ if (!value)
+ return -1;
+
+ setenv((char *)var, (char *)value);
+
+ return 0;
+}
+
+/*************************************************************/
+
+#ifdef CONFIG_PPC
+
+/* Note: Only tested on a PPC board - other arches
+ * should be made to work with not much trouble
+ *
+ * The way this works is: we do pretty much what
+ * we do for a bootm case of a uImage (even creating
+ * the u-boot's idea of bd_t). And then we call
+ * board specific code to fix the mess.
+ */
+
+static void __attribute__((noinline))
+redboot_linux_exec(ulong addr, ulong ramdisk_address, ulong ramdisk_length)
+{
+ ulong sp;
+ ulong initrd_start, initrd_end;
+ ulong cmd_start, cmd_end;
+ char *cmdline;
+ char *s;
+ bd_t *kbd;
+
+ initrd_start = ramdisk_address;
+ initrd_end = ramdisk_address + ramdisk_length;
+
+ /*
+ * Booting a (Linux) kernel image
+ *
+ * Allocate space for command line and board info - the
+ * address should be as high as possible within the reach of
+ * the kernel (see CFG_BOOTMAPSZ settings), but in unused
+ * memory, which means far enough below the current stack
+ * pointer.
+ */
+
+ /* point stack at the end of memory */
+ /* redboot is different that u-boot in that regard */
+ sp = (gd->bd->bi_memstart + gd->bd->bi_memsize) - 16;
+ sp &= ~0x0f;
+
+ debug ("## Current stack ends at 0x%08lX ", sp);
+
+ sp -= 2048; /* just to be sure */
+
+ debug ("=> set upper limit to 0x%08lX\n", sp);
+
+ cmdline = (char *)((sp - CFG_BARGSIZE) & ~0xF);
+ kbd = (bd_t *)(((ulong)cmdline - CONFIG_REDBOOT_BD_T_SIZE) & ~0xF);
+
+ if ((s = getenv("bootargs")) != NULL) {
+
+ strcpy (cmdline, s);
+
+ cmd_start = (ulong)&cmdline[0];
+ cmd_end = cmd_start + strlen(cmdline);
+ } else {
+ cmd_start = 0;
+ cmd_end = 0;
+ }
+
+ *kbd = *(gd->bd);
+
+ if ((s = getenv("clocks_in_mhz")) != NULL) {
+ /* convert all clock information to MHz */
+ kbd->bi_intfreq /= 1000000L;
+ kbd->bi_busfreq /= 1000000L;
+#if defined(CONFIG_MPC8220)
+ kbd->bi_inpfreq /= 1000000L;
+ kbd->bi_pcifreq /= 1000000L;
+ kbd->bi_pevfreq /= 1000000L;
+ kbd->bi_flbfreq /= 1000000L;
+ kbd->bi_vcofreq /= 1000000L;
+#endif
+#if defined(CONFIG_CPM2)
+ kbd->bi_cpmfreq /= 1000000L;
+ kbd->bi_brgfreq /= 1000000L;
+ kbd->bi_sccfreq /= 1000000L;
+ kbd->bi_vco /= 1000000L;
+#endif
+#if defined(CONFIG_MPC5xxx)
+ kbd->bi_ipbfreq /= 1000000L;
+ kbd->bi_pcifreq /= 1000000L;
+#endif /* CONFIG_MPC5xxx */
+ }
+
+ /* convert u-boot bd_t to redboot_bd_t in place */
+ board_redboot_bd_t_adapt(kbd, cmd_start, cmd_end, initrd_start, initrd_end);
+
+ debug ("## Transferring control to Linux (at address %08lx) ...\n",
+ (ulong)kernel);
+
+ SHOW_BOOT_PROGRESS (15);
+
+#if defined(CFG_INIT_RAM_LOCK) && !defined(CONFIG_E500)
+ unlock_ram_in_cache();
+#endif
+ dcache_disable();
+ icache_disable();
+ disable_interrupts();
+
+ /* Call into Linux */
+ __asm__ volatile (
+ /* Start by disabling MMU - the mappings are */
+ /* 1-1 so this should not cause any problems */
+ "mfmsr 3\n"
+ "li 4,0xFFFFFFCF\n"
+ "and 3,3,4\n"
+ "sync\n"
+ "mtmsr 3\n"
+ "sync\n"
+
+ /* Now set up parameters to jump into linux */
+
+ "mtlr %0\n" /* set entry address in LR */
+ "mr 1,%1\n" /* set stack pointer */
+ "mr 3,%2\n" /* set board info in R3 */
+ "mr 4,%3\n" /* set command line in R4 */
+ "blr \n" /* jump into linux */
+ :
+ : "r"(addr), "r"(sp), "r"(kbd), "r"(cmd_start)
+ : "r3", "r4");
+
+ /* never reached */
+}
+#endif /* CONFIG_PPC */
+
+extern flash_info_t flash_info[]; /* info for FLASH chips */
+
+int do_redboot (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+ int i, j;
+ char *name, *var;
+ static int bank = 1;
+ static int dir_block = -1; /* defaults */
+ void *fis;
+ static char small_buf[18];
+ const char *value;
+
+ if (argc < 2)
+ goto usage;
+
+ if (strcmp(argv[1], "fis") == 0) {
+
+ if (argc < 3)
+ goto usage;
+
+ if (strcmp(argv[2], "select") == 0) {
+
+ i = bank;
+ j = dir_block;
+
+ if (argc == 3 || strcmp(argv[3], "show") == 0) {
+ ; /* nothing */
+ } else if (argc >= 4 && strcmp(argv[3], "reset") == 0) {
+ i = 1;
+ j = -1;
+ } else {
+ if (argc >= 4)
+ i = simple_strtoul(argv[3], NULL, 16);
+ if (argc >= 5)
+ j = simple_strtol(argv[4], NULL, 16);
+ }
+
+ fis = redboot_fis_get(i, j, NULL);
+ if (fis == NULL) {
+ printf ("Illegal selection: bank %ld, dir_block # %ld\n", i, j);
+ return 1;
+ }
+
+ printf ("bank #%ld, dir-block #%ld: RedBoot FIS @%p\n", bank, dir_block, fis);
+ bank = i;
+ dir_block = j;
+ return 0;
+ }
+
+ if (strcmp(argv[2], "list") == 0) {
+
+ fis = redboot_fis_get(bank, dir_block, NULL);
+ if (fis == NULL) {
+ printf ("Illegal selection: bank %ld, dir_block # %ld\n", bank, dir_block);
+ return 1;
+ }
+
+ printf ("\nbank #%ld, dir-block #%ld: RedBoot FIS @%p\n", bank, dir_block, fis);
+
+ redboot_fis_list(&flash_info[bank-1], fis);
+
+ return 0;
+ }
+
+ if (strcmp(argv[2], "setenv") == 0) {
+
+ if (argc < 6)
+ goto usage;
+
+ var = argv[3];
+ name = argv[5];
+
+ fis = redboot_fis_get(bank, dir_block, NULL);
+ if (fis == NULL) {
+ printf ("Illegal selection: bank %ld, dir_block # %ld\n", bank, dir_block);
+ return 1;
+ }
+
+ i = redboot_fis_setenv(&flash_info[bank-1], fis, name, argv[4], var);
+ if (i != 0) {
+ printf ("Unable to set var '%s' from '%s'\n", argv[4], name);
+ return 1;
+ }
+
+ return 0;
+ }
+ }
+
+ if (strcmp(argv[1], "config") == 0) {
+
+ if (argc < 3)
+ goto usage;
+
+ fis = redboot_fis_get(bank, dir_block, NULL);
+ if (fis == NULL) {
+ printf ("Illegal selection: bank %ld, dir_block # %ld\n", bank, dir_block);
+ return 1;
+ }
+
+ if (strcmp(argv[2], "printenv") == 0) {
+
+ if (argc >= 5) {
+ value = redboot_config_getenv(&flash_info[bank-1], fis, small_buf, argv[3], argv[4]);
+ if (value)
+ printf("%s=%s\n", argv[3], value);
+ } else
+ redboot_config_printenv(&flash_info[bank-1], fis, small_buf, argc >= 4 ? argv[3] : NULL);
+
+ return 0;
+ }
+
+ if (strcmp(argv[2], "setenv") == 0) {
+
+ if (argc < 5)
+ goto usage;
+
+ i = redboot_config_setenv(&flash_info[bank-1], fis,
+ argv[3], argv[4], argc >= 6 ? argv[5] : NULL);
+ if (i != 0) {
+ printf("Failed to set variable\n");
+ return 1;
+ }
+
+ return 0;
+ }
+ }
+
+#ifdef CONFIG_PPC
+ if (strcmp(argv[1], "exec") == 0) {
+ ulong addr, ramdisk_start, ramdisk_length;
+
+ addr = 0;
+ ramdisk_start = 0;
+ ramdisk_length = 0;
+
+ if (argc >= 3)
+ addr = simple_strtoul(argv[2], NULL, 16);
+ else if ((value = getenv("loadaddr")) != NULL)
+ addr = simple_strtoul(value, NULL, 16);
+ else if ((value = getenv("redboot_kernel_address")) != NULL)
+ addr = simple_strtoul(value, NULL, 16);
+ else {
+ printf("Kernel address not found\n");
+ goto usage;
+ }
+
+ if ((value = getenv("redboot_ramdisk_address")) != NULL)
+ ramdisk_start = simple_strtoul(value, NULL, 16);
+
+ if ((value = getenv("redboot_ramdisk_length")) != NULL)
+ ramdisk_length = simple_strtoul(value, NULL, 16);
+
+ redboot_linux_exec(addr, ramdisk_start, ramdisk_length);
+ }
+
+#endif
+
+usage:
+ printf ("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+}
+
+
+U_BOOT_CMD(
+ redboot, 6, 1, do_redboot,
+ "redboot - redboot support commands\n",
+ "select ([bank] [sector] | reset)\n"
+ " - Select FIS\n"
+ "redboot fis list\n"
+ " - List FIS\n"
+ "redboot fis setenv var type name\n"
+ " - Set variable var to the type variable of the image\n"
+ " type: flash_base, mem_base, size, entry_point, data_length\n"
+ "redboot config printenv [cfgvar] [member]\n"
+ " - Print Redboot config key(s) of [member] of [cfgvar]\n"
+ "redboot config setenv var cfgvar [member]\n"
+ " - Print Redboot config key(s) of [member] of cfgvar\n"
+#ifdef CONFIG_PPC
+ "redboot exec [address]\n"
+ " - Boot a Linux kernel compiled for redboot\n"
+#endif
+ "" /* last empty string */
+);
+
+#endif
+
diff --git a/include/redboot.h b/include/redboot.h
new file mode 100644
index 0000000..4fc6315
--- /dev/null
+++ b/include/redboot.h
@@ -0,0 +1,91 @@
+/*
+ * (C) Copyright 2006 - Embedded Alley Solutions Inc.
+ * by Pantelis Antoniou, pantelis at embeddedalley.com
+ *
+ * Based on Linux & RedBoot code fragments
+ * by David Woodhouse, dwmw2 at infradead.org
+ * by Mark Sattler, msalter at redhat.com
+ * by Gary Thomas, gthomas at redhat.com
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ *
+ */
+
+#ifndef REDBOOT_H
+#define REDBOOT_H
+
+#include <common.h>
+#include <flash.h>
+
+struct fis_image_desc {
+ u8 name[16]; /* Null terminated name */
+ u32 flash_base; /* Address within FLASH of image */
+ u32 mem_base; /* Address in memory where it executes */
+ u32 size; /* Length of image */
+ u32 entry_point; /* Execution entry point */
+ u32 data_length; /* Length of actual data */
+ u8 _pad[256-(16+7*sizeof(unsigned long))];
+ u32 desc_cksum; /* Checksum over image descriptor */
+ u32 file_cksum; /* Checksum over image data */
+};
+
+/* redboot config is stored like this
+ note that we don't define it, since we can work
+ without having a fixed size config
+
+struct redboot_config {
+ u32 len;
+ u32 key1;
+ char config_data[MAX_CONFIG_DATA-(4*4)];
+ u32 key2;
+ u32 long cksum;
+};
+*/
+
+/* defaults */
+#ifndef CONFIG_REDBOOT_FIS_DIRECTORY_BLOCK
+#define CONFIG_REDBOOT_FIS_DIRECTORY_BLOCK -1 /* last block of flash */
+#endif
+
+#ifndef CONFIG_REDBOOT_DIRECTORY_ENTRY_SIZE
+#define CONFIG_REDBOOT_DIRECTORY_ENTRY_SIZE 0x100 /* default */
+#endif
+
+#ifndef CONFIG_REDBOOT_FLASH_SCRIPT_SIZE
+#define CONFIG_REDBOOT_FLASH_SCRIPT_SIZE 256
+#endif
+
+#ifndef CONFIG_REDBOOT_FLASH_STRING_SIZE
+#define CONFIG_REDBOOT_FLASH_STRING_SIZE 128
+#endif
+
+#ifndef CONFIG_REDBOOT_FLASH_CONFIG_SIZE
+#define CONFIG_REDBOOT_FLASH_CONFIG_SIZE 4096
+#endif
+
+void *redboot_fis_get(int bank, int dir_block, flash_info_t **infop);
+int redboot_fis_list(flash_info_t *info, void *fis);
+int redboot_fis_entry_lookup(flash_info_t *info, void *fis, struct fis_image_desc *fis_buf, const char *name);
+int redboot_fis_setenv(flash_info_t *info, void *fis, const char *name, const char *what, char *var);
+
+int redboot_config_printenv(flash_info_t *info, void *fis, char *small_buf, const char *what);
+const char *redboot_config_getenv(flash_info_t *info, void *fis, char *small_buf, const char *what, const char *special);
+int redboot_config_setenv(flash_info_t *info, void *fis, const char *var, const char *what, const char *special);
+
+#endif
More information about the U-Boot
mailing list