[PATCH 1/2] add boot_config command support
Jean-Christophe PLAGNIOL-VILLARD
plagnioj at jcrosoft.com
Fri Oct 28 05:37:39 EDT 2011
this just contain the bootmenu and dtb parsing can not yet boot for real
this will allow to create a boot config from a dtb file that can be provided
by the OS to show a list a boot option
an example a file is in Documentation/bootsec.cfg
you can test using sandbox
# ./barebox -i Documentation/bootsec.dtb
add file Documentation/bootsec.dtb()
barebox 2011.10.0-00119-gad62fdb-dirty (Oct 15 2011 - 11:38:46)
Board: sandbox
Malloc space: 0x7f679f24b010 -> 0x7f679fa4b010 (size 8 MB)
Open /dev/env0 No such file or directory
no valid environment found on /dev/env0. Using default environment
running /env/bin/init...
barebox:/ boot_config -f /dev/fd0 -d
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
---
Documentation/bootsec.dtb | Bin 0 -> 2198 bytes
Documentation/bootsec/bootsec.cfg | 104 +++++++++
commands/Kconfig | 11 +
commands/Makefile | 1 +
commands/boot_config.c | 262 ++++++++++++++++++++++
common/Kconfig | 5 +
common/Makefile | 1 +
common/boot_config.c | 438 +++++++++++++++++++++++++++++++++++++
common/boot_config_dts.c | 256 ++++++++++++++++++++++
include/boot_config.h | 158 +++++++++++++
10 files changed, 1236 insertions(+), 0 deletions(-)
create mode 100644 Documentation/bootsec.dtb
create mode 100644 Documentation/bootsec/bootsec.cfg
create mode 100644 Documentation/bootsec/splash_installer.bmp
create mode 100644 Documentation/bootsec/splash_menu.bmp
create mode 100644 commands/boot_config.c
create mode 100644 common/boot_config.c
create mode 100644 common/boot_config_dts.c
create mode 100644 include/boot_config.h
diff --git a/Documentation/bootsec.dtb b/Documentation/bootsec.dtb
new file mode 100644
index 0000000000000000000000000000000000000000..762a8965485df4c349bba1a0bef80c3ea8375456
GIT binary patch
literal 2198
zcmdT^-HOvd6rTFGuItKb#k<7_f?l|7n%3fi#j=awg5t%3f;VB>nRJ8s=_V6x_d$Fv
zU&L1s&zYH|C&2}4 at xp<VnVd|{`M&e_efQ at N#%_LNjJ<&UCG1Z@?t<)r;Q9pmYvx#c
zw(MI=aK+2>XPG538u#q`RoJ)iT!b;7Nv%cQb&#!GaC#4QJ944=`W9n&?>@+#?j%iB
zw>Uuy2VQ5`=@0SB6_8e#gens?e}7 at ySZUg}Ts(9JtKxF8F_#O%<q&OCF4W(KTvoO%
z7aH45^3n#(^}O^uZpTF`H7?ZOpK`gkvJH93#KFq6u^k9CwuaZKC5_pXQa<td;mmV8
zLQPhfZHxw5L-Kt|?NV;r at Xt<uUhw=Z$jSfvaIVKGOmfAeNM at 8)EoRhz8M8Hg*?PX*
zm#(*Ingrpj$hZpA#DK<lJ_2cfl+iSerIRMk5zpi#T{uV3h0duwFJv;6=DO~Q+i-pu
zg-NmS`@ZYzB0xL0K%P_(%nzu?S<(eTZupK13$<lzc>d5g4Guc|z6;WRi}syW^V at H)
zVIRjb9t{WY9N?3uksK+tJawP-de1%AbuvIb>I(U#3**Lfvaebb<Z3yWqsJ!Yel2I1
z%Qv<b=zK!``^LP{aU{5P!&z)i-1OV4&2U#!65~Vh(%C`rmU at C$=gOaO0Vb+E+BjDo
zhxY#!)@DtYv8DPO;Qs^myKRal{{I5IC8V+crXL;viS|i3793OQRR&CMj^WN4bv}S1
zr*&SNOqf$#SdY#6p|gk9PpL-^rECXj7IVd*w-_|goU1c9=hG~l>wzL<z>7#R9x0r<
d3?D*9e97{81cQ=IV*#xrndvoVT8lxp*)MJ)fYks1
literal 0
HcmV?d00001
diff --git a/Documentation/bootsec/bootsec.cfg b/Documentation/bootsec/bootsec.cfg
new file mode 100644
index 0000000..75160ee
--- /dev/null
+++ b/Documentation/bootsec/bootsec.cfg
@@ -0,0 +1,104 @@
+/dts-v1/;
+
+/ {
+ data {
+ kernel at 1 {
+ format = "uimage";
+ dev = "sda1";
+ fs = "ext3";
+ path = "/boot/uImage-2.6.36";
+ };
+ initrd at 1 {
+ dev = "sda1";
+ fs = "ext3";
+ path = "/boot/initrd-2.6.36";
+ };
+
+ kernel at 2 {
+ format = "zimage";
+ dev = "sda1";
+ fs = "ext3";
+ path = "/boot/zImage-2.6.39";
+ };
+ initrd at 2 {
+ dev = "sda1";
+ fs = "ext3";
+ path = "/boot/initrd-2.6.39";
+ };
+
+ kernel at 3 {
+ format = "uimage";
+ dev = "sda1";
+ fs = "ext3";
+ path = "/boot/uImage-3.0.0";
+ };
+ initrd at 3 {
+ dev = "sda1";
+ fs = "ext3";
+ path = "/boot/inird-3.0.0";
+ };
+ fdt at 3 {
+ dev = "sda1";
+ fs = "ext3";
+ path = "boot/usb_a9g20.dtb";
+ };
+
+ kernel at 4 {
+ format = "uimage";
+ dev = "sda3";
+ fs = "squashfs";
+ path = "/boot/uImage-installer-3.0.0";
+ };
+ initrd at 4 {
+ dev = "sda3";
+ fs = "squashfs";
+ path = "/boot/initrd-installer-3.0.0";
+ };
+ };
+
+ configuration {
+ description = "Welcome on Barebox Boot Sequence";
+ default = "linux_3_0_0";
+ altboot = "installer";
+ bootdelay = <5>;
+ splash = /incbin/("splash_menu.bmp");
+
+ linux_2_6_36 {
+ description = "Linux 2.6.36";
+ cmdline = "mem=64M console=ttyS0,115200 root=/dev/sda2 rw rootfstype=ext3";
+ kernel = "kernel at 1";
+ initrd = "initrd at 1";
+ };
+
+ linux_2_6_39 {
+ description = "Linux 2.6.39";
+ cmdline = "mem=64M console=ttyS0,115200 root=/dev/sda2 rw rootfstype=ext3";
+ kernel = "kernel at 2";
+ initrd = "initrd at 2";
+ };
+
+ linux_3_0_0_bad {
+ description = "Linux 3.0.0";
+ cmdline = "mem=64M console=ttyS0,115200 root=/dev/sda2 rw rootfstype=ext3";
+ kernel = "kernel at 3";
+ initrd = "initrd at 3";
+ fdt = "fdt at 4";
+ };
+
+ linux_3_0_0 {
+ description = "Linux 3.0.0";
+ cmdline = "mem=64M console=ttyS0,115200 root=/dev/sda2 rw rootfstype=ext3";
+ kernel = "kernel at 3";
+ initrd = "initrd at 3";
+ fdt = "fdt at 3";
+ };
+
+ installer {
+ description = "Installer Linux 3.0.0";
+ cmdline = "mem=64M console=ttyS0,115200 root=/dev/sda4 ro rootfstype=squashfs";
+ splash = /incbin/("splash_installer.bmp");
+ kernel = "kernel at 4";
+ initrd = "initrd at 4";
+ };
+ };
+};
diff --git a/Documentation/bootsec/splash_installer.bmp b/Documentation/bootsec/splash_installer.bmp
new file mode 100644
index 0000000..e69de29
diff --git a/Documentation/bootsec/splash_menu.bmp b/Documentation/bootsec/splash_menu.bmp
new file mode 100644
index 0000000..e69de29
diff --git a/commands/Kconfig b/commands/Kconfig
index 18ab840..7980ab7 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -69,6 +69,17 @@ config CMD_MENU_MANAGEMENT
depends on CMD_MENU
prompt "menu scripts management"
+config CMD_BOOT_CONFIG
+ tristate
+ depends on BOOT_CONFIG
+ select FDT
+ prompt "boot config"
+
+config CMD_BOOT_CONFIG_MANAGEMENT
+ bool
+ depends on CMD_BOOT_CONFIG
+ prompt "boot config management"
+
config CMD_LOGIN
tristate
select PASSWORD
diff --git a/commands/Makefile b/commands/Makefile
index 5c51916..a832302 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -58,3 +58,4 @@ obj-$(CONFIG_CMD_LED_TRIGGER) += trigger.o
obj-$(CONFIG_CMD_USB) += usb.o
obj-$(CONFIG_CMD_TIME) += time.o
obj-$(CONFIG_CMD_OFTREE) += oftree.o
+obj-$(CONFIG_CMD_BOOT_CONFIG) += boot_config.o
diff --git a/commands/boot_config.c b/commands/boot_config.c
new file mode 100644
index 0000000..4aa9844
--- /dev/null
+++ b/commands/boot_config.c
@@ -0,0 +1,262 @@
+/*
+ * (C) Copyright 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.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; version 2 of
+ * the License.
+ *
+ * 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 <command.h>
+#include <getopt.h>
+#include <boot_config.h>
+#include <malloc.h>
+
+typedef enum {
+ action_load,
+ action_boot,
+ action_list,
+} bc_action;
+
+struct cmd_bood_config {
+ char *filename;
+ bc_action action;
+ char *config;
+};
+
+#define OPTS "f:dlc:b:"
+
+static void print_entries(void)
+{
+ struct boot_config_data *bed;
+
+ printf("[Kernel]\n");
+
+ list_for_each_entry(bed, boot_config_get_kernels(), list)
+ printf("%s\n", bed->name);
+ printf("[Initrd]\n");
+
+ list_for_each_entry(bed, boot_config_get_initrds(), list)
+ printf("%s\n", bed->name);
+
+ printf("[FDT]\n");
+
+ list_for_each_entry(bed, boot_config_get_fdts(), list)
+ printf("%s\n", bed->name);
+
+}
+
+static void print_boot_config_data(struct boot_config_data *bed)
+{
+ printf("name = '%s'\n", bed->name);
+ printf("dev = '%s'\n", bed->dev);
+ printf("fs = '%s'\n", bed->fs);
+ printf("path = '%s'\n", bed->path);
+}
+
+static void print_boot_config(struct boot_config *e)
+{
+ struct boot_config_var *v;
+
+ printf("Config '%s'\n\n", e->name);
+
+ v = boot_config_var_get_by_name(e, "description");
+ printf("description = %s\n", v->value);
+ v = boot_config_var_get_by_name(e, "cmdline");
+ printf("cmdline = '%s'\n", v->value);
+ v = boot_config_var_get_by_name(e, "splash");
+ if (v)
+ printf("splash = '%s'\n", v->value);
+
+ printf("[Kernel]\n");
+ print_boot_config_data(e->kernel);
+
+ if (e->initrd) {
+ printf("[Initrd]\n");
+ print_boot_config_data(e->initrd);
+ }
+
+ if (e->fdt) {
+ printf("[fdt]\n");
+ print_boot_config_data(e->fdt);
+ }
+}
+
+/*
+ * boot_config -l [-c config]
+ */
+static int do_boot_config_list(struct cmd_bood_config *cbc)
+{
+ struct boot_config* bc;
+ char * description = boot_config_get_description();
+ uint32_t bootdelay = boot_config_get_bootdelay();
+ int i = 0;
+
+ if (!description)
+ return 0;
+
+ bc = boot_config_get_by_name(cbc->config);
+
+ if (bc) {
+ print_boot_config(bc);
+ return 0;
+ }
+
+ if (is_entry(cbc)) {
+ if (cbc->config) {
+ struct boot_config_data *bed;
+
+ bed = boot_config_kernel_get_by_name(cbc->config);
+ if (bed)
+ goto bed_print;
+
+ bed = boot_config_initrd_get_by_name(cbc->config);
+ if (bed)
+ goto bed_print;
+
+ bed = boot_config_fdt_get_by_name(cbc->config);
+
+ bed_print:
+ if (bed) {
+ print_boot_config_data(bed);
+ return 0;
+ }
+ }
+
+ print_entries();
+ return 0;
+ }
+
+ printf("description = %s\n", description);
+ printf("default_boot = %s\n", boot_config_get_default_boot()->name);
+ if (bootdelay != -1)
+ printf("bootdelay = %ds\n", bootdelay);
+
+ printf("[Configurations]\n");
+ list_for_each_entry(bc, boot_config_get_configs(), list) {
+ printf("%d: %s\n", i, bc->name);
+ i++;
+ }
+
+ return 0;
+}
+
+static int do_boot_config_load(struct cmd_bood_config *cbc)
+{
+ int ret;
+
+ boot_config_unload();
+ ret = boot_config_load(cbc->filename);
+ if (ret) {
+ eprintf("impossible to load the config");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int do_boot_config_boot(struct cmd_bood_config *cbc)
+{
+ struct boot_config *bc;
+
+ if (strcmp(cbc->config, "default") == 0)
+ bc = boot_config_get_default_boot();
+ else
+ bc = boot_config_get_by_name(cbc->config);
+
+ if (!bc)
+ eprintf("Config '%s' not found\n", cbc->config);
+
+ return boot_config_set_env(bc);
+}
+
+static int do_boot_config(struct command *cmdtp, int argc, char *argv[])
+{
+ struct cmd_bood_config cbc;
+ int opt;
+ int ret = COMMAND_ERROR_USAGE;
+
+ memset(&cbc, 0, sizeof(struct cmd_bood_config));
+
+ while((opt = getopt(argc, argv, OPTS)) > 0) {
+ switch(opt) {
+ case 'f':
+ cbc.action = action_load;
+ cbc.filename = optarg;
+ break;
+ case 'd':
+ boot_config_unload();
+ break;
+ case 'l':
+ cbc.action = action_list;
+ break;
+ case 'b':
+ cbc.action = action_boot;
+ case 'c':
+ cbc.config = optarg;
+ break;
+ }
+ }
+
+ switch(cbc.action) {
+ case action_list:
+ ret = do_boot_config_list(&cbc);
+ break;
+ case action_load:
+ ret = do_boot_config_load(&cbc);
+ break;
+ case action_boot:
+ ret = do_boot_config_boot(&cbc);
+ break;
+
+ };
+
+ if (ret)
+ return COMMAND_ERROR_USAGE;
+
+ return 0;
+}
+
+static const __maybe_unused char cmd_boot_config_help[] =
+"Usage: boot_config [OPTION]... \n"
+"Boot Config\n"
+" -c config\n"
+" -d unload\n"
+" -f load config\n"
+" -l list\n"
+" -b boot\n"
+"\n"
+"How to\n"
+"\n"
+"Load config\n"
+" boot_config -f <file>\n"
+"\n"
+"Unoad config\n"
+" boot_config -d\n"
+"\n"
+"Boot"
+" (default or none for default boot config)\n"
+" boot_config -b [-c <config>]\n"
+"\n"
+"List configs\n"
+" boot_cofnfig -l\n";
+
+BAREBOX_CMD_START(boot_config)
+ .cmd = do_boot_config,
+ .usage = "Boot Menu",
+ BAREBOX_CMD_HELP(cmd_boot_config_help)
+BAREBOX_CMD_END
diff --git a/common/Kconfig b/common/Kconfig
index 8e96920..fd06213 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -306,6 +306,11 @@ config AUTO_COMPLETE
depends on CMDLINE_EDITING
prompt "Enable auto completion"
+config BOOT_CONFIG
+ bool
+ prompt "Boot Configuration Framework"
+ help
+
config MENU
bool
prompt "Menu Framework"
diff --git a/common/Makefile b/common/Makefile
index 7bb8ea4..dd30686 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -26,6 +26,7 @@ obj-y += misc.o
obj-y += memsize.o
obj-$(CONFIG_MENU) += menu.o
obj-$(CONFIG_PASSWORD) += password.o
+obj-$(CONFIG_BOOT_CONFIG) += boot_config.o boot_config_dts.o
obj-$(CONFIG_MODULES) += module.o
extra-$(CONFIG_MODULES) += module.lds
diff --git a/common/boot_config.c b/common/boot_config.c
new file mode 100644
index 0000000..b60ce26
--- /dev/null
+++ b/common/boot_config.c
@@ -0,0 +1,438 @@
+/*
+ * (C) Copyright 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.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; version 2 of
+ * the License.
+ *
+ * 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 <command.h>
+#include <readkey.h>
+#include <errno.h>
+#include <linux/err.h>
+#include <boot_config.h>
+#include <environment.h>
+
+int boot_config_debug;
+static char *description;
+static struct boot_config *default_boot;
+static uint32_t bootdelay = -1;
+
+static LIST_HEAD(kernels);
+static LIST_HEAD(initrds);
+static LIST_HEAD(fdts);
+static LIST_HEAD(configs);
+
+char* boot_config_get_description(void)
+{
+ return description;
+}
+
+struct boot_config* boot_config_get_default_boot(void)
+{
+ return default_boot;
+}
+
+uint32_t boot_config_get_bootdelay(void)
+{
+ return bootdelay;
+}
+
+int boot_config_set_description(const char *s)
+{
+ if (!s)
+ return -EINVAL;
+ free(description);
+ description = strdup(s);
+
+ if (!description)
+ return -ENOMEM;
+
+ return 0;
+}
+
+int boot_config_set_default_boot(struct boot_config *b)
+{
+ default_boot = b;
+
+ return 0;
+}
+
+int boot_config_set_default_boot_by_name(const char *s)
+{
+ struct boot_config *b;
+
+ b = boot_config_get_by_name(s);
+
+ if (!b)
+ return -EINVAL;
+
+ return boot_config_set_default_boot(b);
+}
+
+int boot_config_set_bootdelay(uint32_t v)
+{
+ bootdelay = v;
+
+ return 0;
+}
+
+struct list_head* boot_config_get_configs(void)
+{
+ return &configs;
+}
+
+struct list_head* boot_config_get_kernels(void)
+{
+ return &kernels;
+}
+
+struct list_head* boot_config_get_initrds(void)
+{
+ return &initrds;
+}
+
+struct list_head* boot_config_get_fdts(void)
+{
+ return &fdts;
+}
+
+struct boot_config_data* bed_list_get_by_name(struct list_head *l, const char *name)
+{
+ struct boot_config_data* bed;
+
+ if (!name)
+ return NULL;
+
+ list_for_each_entry(bed, l, list) {
+ if (strcmp(bed->name, name) == 0)
+ return bed;
+ }
+
+ return NULL;
+}
+
+int bed_list_add(struct list_head *l, struct boot_config_data *bed)
+{
+ if (!bed || !bed->name)
+ return -EINVAL;
+
+ if (bed_list_get_by_name(l, bed->name))
+ return -EEXIST;
+
+ list_add_tail(&bed->list, l);
+
+ return 0;
+}
+
+void bed_list_free(struct list_head *l)
+{
+ struct boot_config_data *bed, *tmp;
+
+ list_for_each_entry_safe(bed, tmp, l, list) {
+ list_del(&bed->list);
+ boot_config_data_free(bed);
+ }
+}
+
+void boot_config_data_free(struct boot_config_data *bed)
+{
+ if (!bed)
+ return;
+
+ free(bed->name);
+ free(bed->format);
+ free(bed->dev);
+ free(bed->fs);
+ free(bed->path);
+
+ free(bed);
+}
+
+struct boot_config* boot_config_get_by_name(const char *name)
+{
+ struct boot_config* bc;
+
+ if (!name)
+ return NULL;
+
+ list_for_each_entry(bc, &configs, list) {
+ if (strcmp(bc->name, name) == 0)
+ return bc;
+ }
+
+ return NULL;
+}
+
+int boot_config_add(struct boot_config *bc)
+{
+ if (!bc || !bc->name)
+ return -EINVAL;
+
+ if (boot_config_get_by_name(bc->name))
+ return -EEXIST;
+
+ list_add_tail(&bc->list, &configs);
+
+ return 0;
+}
+
+void boot_config_free(void)
+{
+ struct boot_config *bc, *tmp;
+
+ list_for_each_entry_safe(bc, tmp, &configs, list) {
+ list_del(&bc->list);
+ boot_config_item_free(bc);
+ }
+}
+
+void boot_config_item_free(struct boot_config *bc)
+{
+ struct boot_config_var *v, *tmp;
+ if (!bc)
+ return;
+
+ free(bc->name);
+
+ list_for_each_entry_safe(v, tmp, &bc->vars, list) {
+ list_del(&v->list);
+ boot_config_var_free(v);
+ }
+
+ free(bc);
+}
+
+int boot_config_item_init(struct boot_config *e)
+{
+ struct boot_config_var *v;
+ int ret;
+
+ if (!e)
+ return -EINVAL;
+
+ v = boot_config_var_get_by_name(e, "kernel");
+ if (!v) {
+ ret = -EINVAL;
+ eprintf("Config %s: Missing kernel\n", e->name);
+ goto err;
+ }
+ e->kernel = bed_list_get_by_name(&kernels, v->value);
+ if (!e->kernel) {
+ ret = -EINVAL;
+ eprintf("Config %s: kernel '%s' not found\n", e->name, v->value);
+ goto err;
+ }
+
+ v = boot_config_var_get_by_name(e, "initrd");
+ if (v) {
+ e->initrd = bed_list_get_by_name(&initrds, v->value);
+ if (!e->initrd) {
+ ret = -EINVAL;
+ eprintf("Config %s: initrd '%s' not found\n", e->name, v->value);
+ goto err;
+ }
+ }
+
+ v = boot_config_var_get_by_name(e, "fdt");
+ if (v) {
+ e->fdt = bed_list_get_by_name(&fdts, v->value);
+ if (!e->fdt) {
+ ret = -EINVAL;
+ eprintf("Config %s: fdt '%s' not found\n", e->name, v->value);
+ goto err;
+ }
+ }
+
+ return 0;
+err:
+ return ret;
+}
+
+int boot_config_add_by_name(const char *name, const char *desc,
+ const char *kernel, const char *cmdline,
+ const char *initrd, const char *fdt)
+{
+ struct boot_config *e = boot_config_alloc();
+ int ret;
+
+ if (!e)
+ return -ENOMEM;
+
+ if (boot_config_debug)
+ printf("Boot '%s'\n", name);
+
+ if (boot_config_get_by_name(name))
+ return -EEXIST;
+
+ e->name = strdup(name);
+ if (!e->name) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ ret = boot_config_var_add(e, "description", desc);
+ if (ret)
+ goto err_free;
+ ret = boot_config_var_add(e, "cmdline", cmdline);
+ if (ret)
+ goto err_free;
+
+ ret = boot_config_var_add(e, "kernel", kernel);
+ if (ret)
+ goto err_free;
+
+ if (initrd) {
+ ret = boot_config_var_add(e, "initrd", initrd);
+ if (ret)
+ goto err_free;
+ }
+
+ if (fdt) {
+ ret = boot_config_var_add(e, "fdt", fdt);
+ if (ret)
+ goto err_free;
+ }
+
+ ret = boot_config_item_init(e);
+ if (ret)
+ goto err_free;
+
+ ret = boot_config_add(e);
+
+ if (ret)
+ goto err_free;
+
+ return 0;
+err_free:
+ boot_config_item_free(e);
+ return 0;
+}
+
+int boot_config_remove_by_name(const char *name)
+{
+ struct boot_config *e;
+
+ e = boot_config_get_by_name(name);
+
+ if (!e)
+ return -EINVAL;
+
+ if (default_boot == e)
+ default_boot = NULL;
+
+ boot_config_item_free(e);
+
+ return 0;
+}
+
+void boot_config_var_free(struct boot_config_var *v)
+{
+ if (!v)
+ return;
+
+ free(v->name);
+ free(v->value);
+ free(v);
+}
+
+struct boot_config_var* boot_config_var_get_by_name(struct boot_config *bc, const char *name)
+{
+ struct boot_config_var *v;
+
+ if (!bc || !name)
+ return NULL;
+
+ list_for_each_entry(v, &bc->vars, list) {
+ if (strcmp(v->name, name) == 0)
+ return v;
+ }
+
+ return NULL;
+}
+
+int boot_config_var_add(struct boot_config *bc, const char *name, const char* value)
+{
+ struct boot_config_var *v;
+ int ret;
+
+ if (!bc || !name || !value)
+ return -EINVAL;
+
+ v = calloc(1, sizeof(struct boot_config_var));
+ if (!v)
+ return -ENOMEM;
+
+ v->name = strdup(name);
+ if (!v->name) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ v->value = strdup(value);
+ if (!v->name) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ list_add_tail(&v->list, &bc->vars);
+
+ return 0;
+err:
+ boot_config_var_free(v);
+
+ return ret;
+}
+
+int boot_config_set_env(struct boot_config *bc)
+{
+ struct boot_config_var *v;
+
+ if (!bc)
+ return -EINVAL;
+
+ list_for_each_entry(v, &bc->vars, list) {
+ setenv(v->name, v->value);
+ export(v->name);
+ }
+
+ setenv("kernel_dev", bc->kernel->dev);
+ setenv("kernel_name", bc->kernel->name);
+ setenv("kernel_fs", bc->kernel->fs);
+ setenv("kernel_path", bc->kernel->path);
+ setenv("kernel_format", bc->kernel->format);
+ export("kernel_dev");
+ export("kernel_name");
+ export("kernel_fs");
+ export("kernel_path");
+ export("kernel_format");
+
+ return 0;
+}
+
+int boot_config_unload(void)
+{
+ free(description);
+ description = NULL;
+
+ boot_config_free();
+ bed_list_free(&kernels);
+ bed_list_free(&initrds);
+ bed_list_free(&fdts);
+
+ return 0;
+}
diff --git a/common/boot_config_dts.c b/common/boot_config_dts.c
new file mode 100644
index 0000000..1ce9aa5
--- /dev/null
+++ b/common/boot_config_dts.c
@@ -0,0 +1,256 @@
+/*
+ * (C) Copyright 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.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; version 2 of
+ * the License.
+ *
+ * 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 <errno.h>
+#include <malloc.h>
+#include <fs.h>
+#include <asm/byteorder.h>
+#include <libfdt.h>
+#include <boot_config.h>
+
+static void *data;
+
+#define DATA_PATH "/data"
+#define CONFIGURATION_PATH "/configuration"
+
+static int fdt_add_for_each_subnode(int offset, int (*add)(int offset))
+{
+ int depth;
+ int ret;
+
+ for (depth = 0, offset = fdt_next_node(data, offset, &depth);
+ (offset >= 0) && (depth > 0);
+ offset = fdt_next_node(data, offset, &depth)) {
+ if (depth == 1) {
+ ret = add(offset);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int do_add_boot_config(int offset)
+{
+ const char* name = fdt_get_name(data, offset, NULL);
+ struct boot_config *bc = boot_config_alloc();
+ int ret;
+ int noffset;
+
+ if (!bc)
+ return -ENOMEM;
+
+ if (boot_config_get_by_name(name))
+ return -EEXIST;
+
+ bc->name = strdup(name);
+ if (!bc->name) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (noffset = fdt_first_property_offset(data, offset);
+ (noffset >= 0);
+ (noffset = fdt_next_property_offset(data, noffset))) {
+ const struct fdt_property *prop;
+ const char * var_name;
+ const char * var_value;
+
+ if (!(prop = fdt_get_property_by_offset(data, noffset, NULL))) {
+ offset = -FDT_ERR_INTERNAL;
+ break;
+ }
+
+ var_name = fdt_string(data, fdt32_to_cpu(prop->nameoff));
+ var_value = fdt_getprop(data, offset, var_name, NULL);
+
+ ret = boot_config_var_add(bc, var_name, var_value);
+ if (ret)
+ goto err;
+ }
+
+ ret = boot_config_item_init(bc);
+ if (ret)
+ goto err;
+
+ ret = boot_config_add(bc);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ boot_config_item_free(bc);
+
+ return 0;
+}
+
+static int do_add_data_config(int offset)
+{
+ struct boot_config_data *bed = calloc(1, sizeof(*bed));
+ const char* name = fdt_get_name(data, offset, NULL);
+ const char* prop;
+ int ret = 0;
+
+ if (!bed)
+ return -ENOMEM;
+
+ bed->name = strdup(name);
+ if (!bed->name) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ prop = fdt_getprop(data, offset, "dev", NULL);
+ if (!prop) {
+ eprintf("%s: Missing dev\n", name);
+ ret = -EIO;
+ goto err;
+ }
+
+ bed->dev = strdup(prop);
+ if (!bed->dev) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ prop = fdt_getprop(data, offset, "path", NULL);
+ if (!prop) {
+ eprintf("%s: Missing path\n", name);
+ ret = -EIO;
+ goto err;
+ }
+
+ bed->path = strdup(prop);
+ if (!bed->path) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ prop = fdt_getprop(data, offset, "fs", NULL);
+ if (!prop) {
+ eprintf("%s: Missing fs\n", name);
+ ret = -EIO;
+ goto err;
+ }
+ bed->fs = strdup(prop);
+ if (!bed->fs) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ if (boot_config_debug)
+ printf("add %s\n", name);
+
+ if (strncmp(name, "kernel@", 7) == 0) {
+ prop = fdt_getprop(data, offset, "format", NULL);
+ if (!prop) {
+ eprintf("%s: Missing format\n", name);
+ ret = -EIO;
+ goto err;
+ }
+ bed->format = strdup(prop);
+ if (!bed->format) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ ret = boot_config_kernel_add(bed);
+ } else if (strncmp(name, "initrd@", 7) == 0) {
+ ret = boot_config_initrd_add(bed);
+ } else if (strncmp(name, "fdt@", 4) == 0) {
+ ret = boot_config_fdt_add(bed);
+ } else {
+ eprintf("Unknown data format %s\n", name);
+ ret = -EIO;
+ }
+
+ if (ret)
+ goto err;
+
+ return 0;
+
+err:
+ boot_config_data_free(bed);
+ return 0;
+}
+
+
+int boot_config_load(char *filename)
+{
+ int offset;
+ const char* prop;
+ const uint32_t *prop_u32;
+ int ret = -1;
+
+ if (!filename)
+ return -EINVAL;
+
+ data = read_file(filename, NULL);
+ if (!data) {
+ perror("read_file");
+ goto exit;
+ }
+
+ offset = fdt_path_offset(data, DATA_PATH);
+
+ if (offset < 0) {
+ printf("Can't find '%s' node (%s)\n", DATA_PATH, fdt_strerror(offset));
+ goto exit_add;
+ }
+
+ fdt_add_for_each_subnode(offset, do_add_data_config);
+
+ offset = fdt_path_offset(data, CONFIGURATION_PATH);
+
+ fdt_add_for_each_subnode(offset, do_add_boot_config);
+
+ prop = fdt_getprop(data, offset, "description", NULL);
+ if (!prop)
+ prop = "boot";
+ boot_config_set_description(prop);
+
+ prop = fdt_getprop(data, offset, "default", NULL);
+ if (prop) {
+ if (boot_config_debug)
+ printf("default config %s\n", prop);
+
+ if (boot_config_set_default_boot_by_name(prop))
+ eprintf("Can not set config '%s' as default (not found)\n", prop);
+ }
+ prop_u32 = fdt_getprop(data, offset, "bootdelay", NULL);
+ if (prop_u32) {
+ boot_config_set_bootdelay(be32_to_cpu(*prop_u32));
+
+ if (boot_config_debug)
+ printf("auto boot in %ds\n", boot_config_get_bootdelay());
+ } else {
+ boot_config_set_bootdelay(-1);
+ }
+
+ ret = 0;
+
+exit_add:
+exit:
+ free(data);
+ return ret;
+}
diff --git a/include/boot_config.h b/include/boot_config.h
new file mode 100644
index 0000000..778ac4e
--- /dev/null
+++ b/include/boot_config.h
@@ -0,0 +1,158 @@
+/*
+ * (C) Copyright 2011 Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.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; version 2 of
+ * the License.
+ *
+ * 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 __BOOT_CONFIG_H__
+#define __BOOT_CONFIG_H__
+
+#include <malloc.h>
+#include <linux/list.h>
+
+extern int boot_config_debug;
+
+struct boot_config_data {
+ char *name;
+ char *format;
+ char *dev;
+ char *fs;
+ char *path;
+
+ struct list_head list;
+};
+
+struct boot_config_var {
+ char* name;
+ char* value;
+
+ struct list_head list;
+};
+
+struct boot_config {
+ char *name;
+ struct boot_config_data *kernel;
+ struct boot_config_data *initrd;
+ struct boot_config_data *fdt;
+
+ struct list_head list;
+ struct list_head vars;
+};
+
+/*
+ * boot_conig functions
+ */
+static inline struct boot_config* boot_config_alloc(void)
+{
+ struct boot_config *bc;
+
+ bc = calloc(1, sizeof(struct boot_config));
+ if (bc) {
+ INIT_LIST_HEAD(&bc->vars);
+ }
+ return bc;
+}
+
+char* boot_config_get_description(void);
+struct boot_config* boot_config_get_default_boot(void);
+uint32_t boot_config_get_bootdelay(void);
+
+int boot_config_set_description(const char *);
+int boot_config_set_default_boot(struct boot_config *b);
+int boot_config_set_default_boot_by_name(const char *s);
+int boot_config_set_bootdelay(uint32_t);
+
+struct list_head* boot_config_get_configs(void);
+struct list_head* boot_config_get_kernels(void);
+struct list_head* boot_config_get_initrds(void);
+struct list_head* boot_config_get_fdts(void);
+
+struct boot_config_data* bed_list_get_by_name(struct list_head *l, const char *name);
+
+static inline struct boot_config_data* boot_config_kernel_get_by_name(const char *name)
+{
+ return bed_list_get_by_name(boot_config_get_kernels(), name);
+}
+
+static inline struct boot_config_data* boot_config_initrd_get_by_name(const char *name)
+{
+ return bed_list_get_by_name(boot_config_get_initrds(), name);
+}
+
+static inline struct boot_config_data* boot_config_fdt_get_by_name(const char *name)
+{
+ return bed_list_get_by_name(boot_config_get_fdts(), name);
+}
+
+int bed_list_add(struct list_head *l, struct boot_config_data *bed);
+
+static inline int boot_config_kernel_add(struct boot_config_data *bed)
+{
+ return bed_list_add(boot_config_get_kernels(), bed);
+}
+
+static inline int boot_config_initrd_add(struct boot_config_data *bed)
+{
+ return bed_list_add(boot_config_get_initrds(), bed);
+}
+
+static inline int boot_config_fdt_add(struct boot_config_data *bed)
+{
+ return bed_list_add(boot_config_get_fdts(), bed);
+}
+
+void bed_list_free(struct list_head *l);
+
+static inline void boot_config_kernel_free(void)
+{
+ return bed_list_free(boot_config_get_kernels());
+}
+
+static inline void boot_config_initrd_free(void)
+{
+ return bed_list_free(boot_config_get_initrds());
+}
+
+static inline void boot_config_fdt_free(void)
+{
+ return bed_list_free(boot_config_get_fdts());
+}
+
+struct boot_config* boot_config_get_by_name(const char *name);
+int boot_config_add(struct boot_config *bc);
+int boot_config_add_by_name(const char *name, const char *desc,
+ const char *kernel, const char *cmdline,
+ const char *initrd, const char *fdt);
+int boot_config_item_init(struct boot_config *e);
+
+int boot_config_var_add(struct boot_config *bc, const char *name, const char* value);
+struct boot_config_var* boot_config_var_get_by_name(struct boot_config *bc,
+ const char *name);
+void boot_config_var_free(struct boot_config_var *v);
+
+int boot_config_remove_by_name(const char *name);
+void boot_config_free(void);
+void boot_config_item_free(struct boot_config *bc);
+void boot_config_data_free(struct boot_config_data *bed);
+int boot_config_set_env(struct boot_config *bc);
+
+int boot_config_load(char *filename);
+int boot_config_unload(void);
+
+#endif /* __BOOT_CONFIG_H__ */
--
1.7.7
More information about the barebox
mailing list