[U-Boot] [PATCH 1/3] init_func: Add fundamental framework

Graeme Russ
2012-04-22T15:23:06Z

Signed-off-by: Graeme Russ <graeme.russ@gmail.com>
---
Makefile | 34 ++-
common/Makefile | 2 +
config.mk | 2 +
doc/README.INIT_FUNC | 65 +++
include/init_func.h | 37 ++
tools/Makefile | 6 +
tools/mkinitseq.c | 1512 ++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 1657 insertions(+), 1 deletions(-)
create mode 100644 doc/README.INIT_FUNC
create mode 100644 include/init_func.h
create mode 100644 tools/mkinitseq.c

diff --git a/Makefile b/Makefile
index cdd4294..62d9f81 100644
--- a/Makefile
+++ b/Makefile
@@ -467,8 +467,40 @@ GEN_UBOOT = \
-Map u-boot.map -o u-boot
endif

+ifeq ($(CONFIG_INIT_FUNC),y)
+INIT_SEQ = $(obj)init_seq.o
+
+GEN_UBOOT_INIT = \
+ UNDEF_SYM=`$(OBJDUMP) -x $(LIBBOARD) $(LIBS) | \
+ sed -n -e 's/.*\($(SYM_PREFIX)__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
+ cd $(LNDIR) && $(LD) $(LDFLAGS) $(LDFLAGS_$(@F)) $$UNDEF_SYM $(__OBJS) \
+ --start-group $(__LIBS) --end-group \
+ -Map u-boot-init.map -o u-boot-init
+
+$(obj)u-boot-init.lds: $(LDSCRIPT)
+ $(CPP) $(CPPFLAGS) $(LDPPFLAGS) -ansi -D__ASSEMBLY__ -DMAKE_INIT_LDS -P - <$^ >$@
+
+$(obj)u-boot-init: depend \
+ $(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) $(obj)u-boot-init.lds
+ $(GEN_UBOOT_INIT)
+
+$(obj)u-boot-init.bin: $(obj)u-boot-init
+ $(OBJCOPY) -j .initfuncs -O binary $< $@
+
+$(obj)init_seq.c: depend \
+ $(obj)u-boot-init.bin
+ $(obj)tools/mkinitseq $(obj)u-boot-init.bin $(obj)common/init_seq.c
+
+$(obj)init_seq.o: depend \
+ $(obj)init_seq.c
+ $(MAKE) BUILD_INIT_SEQ=y -C common all
+else
+INIT_SEQ =
+endif
+
$(obj)u-boot: depend \
- $(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds
+ $(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) \
+ $(INIT_SEQ) $(obj)u-boot.lds
$(GEN_UBOOT)
ifeq ($(CONFIG_KALLSYMS),y)
smap=`$(call SYSTEM_MAP,u-boot) | \
diff --git a/common/Makefile b/common/Makefile
index d9f10f3..02a4485 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -195,6 +195,8 @@ COBJS-y += dlmalloc.o
COBJS-y += memsize.o
COBJS-y += stdio.o

+# initialisation sequence (second build stage)
+COBJS-$(BUILD_INIT_SEQ) += init_seq.o

COBJS := $(sort $(COBJS-y))
XCOBJS := $(sort $(XCOBJS-y))
diff --git a/config.mk b/config.mk
index fa33e62..2124b84 100644
--- a/config.mk
+++ b/config.mk
@@ -257,6 +257,8 @@ ifneq ($(CONFIG_SYS_TEXT_BASE),)
LDFLAGS_u-boot += -Ttext $(CONFIG_SYS_TEXT_BASE)
endif

+LDFLAGS_u-boot-init += -T $(obj)u-boot-init.lds $(LDFLAGS_FINAL)
+
LDFLAGS_u-boot-spl += -T $(obj)u-boot-spl.lds $(LDFLAGS_FINAL)
ifneq ($(CONFIG_SPL_TEXT_BASE),)
LDFLAGS_u-boot-spl += -Ttext $(CONFIG_SPL_TEXT_BASE)
diff --git a/doc/README.INIT_FUNC b/doc/README.INIT_FUNC
new file mode 100644
index 0000000..f9a0b18
--- /dev/null
+++ b/doc/README.INIT_FUNC
@@ -0,0 +1,65 @@
+The INIT_FUNC macro allows initialisation functions (i.e. functions which are
+executed before the main loop) to be easily added to the init sequence
+
+
+Specifying an Initialisation Function and is Dependencies
+---------------------------------------------------------
+The format of the INIT_FUNC macro is:
+
+INIT_FUNC(fn, grp, man_reqs, pre_reqs, pst_reqs)
+
+fn is the name of the init function to call. This function must have the
+following prototype:
+
+int foo(void);
+
+Each init function must return 0 to indicate success - any other return value
+indicates failure and the init sequence will stop
+
+grp is the name of the group that the init function belongs to. grp may be
+the same as fn for any individual init function, but between init functions,
+fn and grp must be unique.
+
+The purpose of groups is to allow functions to be grouped together so other
+functions can specify the group as a whole as a dependency rather than having
+to list every function in the group in the dependency list
+
+man_reqs is a space seperated list of functions or groups that MUST exist and
+MUST run BEFORE fn
+
+pre_reqs is a space seperated list of functions or groups that MAY exist and
+(if they do) MUST run BEFORE fn
+
+pst_reqs is a space seperated list of functions or groups that MAY exist and
+(if they do) MUST run AFTER fn
+
+Skipping or Replacing a Function or Group
+-----------------------------------------
+Occassionally, a board may provide a completely seperate implementation for
+an initialisation function that is provided in the common arch, SoC or
+common code.
+
+SKIP_INIT(fn_or_group)
+
+After the initialisation function dependencies are calculated, all functions
+and groups listed in any SKIP_INITs are removed - This may result in
+dependent functions being removed - It is up to the board code developer
+to ensure suitable replacements are in place
+
+REPLACE_INIT(old_fn_or_group, new_fn_or_group)
+
+Like SKIP_INIT but replaces on function with another (or one group with
+another)
+
+Example: In the SoC code yoy may have
+
+INIT_FUNC(init_cpu_f, RESET, , , );
+
+In the board code, you may want a slightly tweaked version, so you might
+have:
+
+int my_new_init_cpu_f(void)
+{
+ ...
+}
+REPLACE_INIT(init_cpu_f, my_new_init_cpu_f);
diff --git a/include/init_func.h b/include/init_func.h
new file mode 100644
index 0000000..e4366b8
--- /dev/null
+++ b/include/init_func.h
@@ -0,0 +1,37 @@
+#ifndef __INIT_FUNC_H__
+#define __INIT_FUNC_H__
+
+/*
+ * The requirements for any new initalization function is simple: it is
+ * a function with no parameters which returns an integer return code,
+ * where 0 means "continue" and != 0 means "fatal error, hang the system"
+ */
+typedef int (init_fnc_t) (void);
+
+extern init_fnc_t *init_sequence_f[];
+extern init_fnc_t *init_sequence_f_r[];
+extern init_fnc_t *init_sequence_r[];
+
+#ifdef CONFIG_INIT_FUNC
+#include <linux/compiler.h>
+
+#define INIT_FUNC(fn, grp, man_reqs, pre_reqs, pst_reqs) \
+ static const char __init_func_ ## fn[] __used \
+ __attribute__((__section__(".initfuncs"))) = \
+ "(f:" #fn ":" #grp ":" #man_reqs " | " #pre_reqs " | " #pst_reqs ")\n";
+
+#define SKIP_INIT(fn_or_group) \
+ static const char __skip_init_ ## fn_or_group[] __used \
+ __attribute__((__section__(".initfuncs"))) = \
+ "(s:" #fn_or_group ")\n";
+
+#define REPLACE_INIT(old_fn_or_group, new_fn_or_group) \
+ static const char __replace_init_ ## old_fn_or_group[] __used \
+ __attribute__((__section__(".initfuncs"))) = \
+ "(r:" #old_fn_or_group ":" #new_fn_or_group ")\n";
+#else
+#define INIT_FUNC(fn, group, man_reqs, pre_reqs, post_reqs)
+#define SKIP_INIT(fn_or_group)
+#define REPLACE_INIT(old_fn_or_group, new_fn_or_group)
+#endif
+#endif /* !__INIT_FUNC_H__ */
diff --git a/tools/Makefile b/tools/Makefile
index 8993fdd..e6ba6ef 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -68,6 +68,7 @@ BIN_FILES-$(CONFIG_CMD_LOADS) += img2srec$(SFX)
BIN_FILES-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes$(SFX)
BIN_FILES-y += mkenvimage$(SFX)
BIN_FILES-y += mkimage$(SFX)
+BIN_FILES-$(CONFIG_INIT_FUNC) += mkinitseq$(SFX)
BIN_FILES-$(CONFIG_SMDK5250) += mksmdk5250spl$(SFX)
BIN_FILES-$(CONFIG_MX28) += mxsboot$(SFX)
BIN_FILES-$(CONFIG_NETCONSOLE) += ncb$(SFX)
@@ -95,6 +96,7 @@ NOPED_OBJ_FILES-y += imximage.o
NOPED_OBJ_FILES-y += omapimage.o
NOPED_OBJ_FILES-y += mkenvimage.o
NOPED_OBJ_FILES-y += mkimage.o
+NOPED_OBJ_FILES-$(CONFIG_INIT_FUNC) += mkinitseq.o
OBJ_FILES-$(CONFIG_SMDK5250) += mkexynosspl.o
OBJ_FILES-$(CONFIG_MX28) += mxsboot.o
OBJ_FILES-$(CONFIG_NETCONSOLE) += ncb.o
@@ -215,6 +217,10 @@ $(obj)mkimage$(SFX): $(obj)aisimage.o \
$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
$(HOSTSTRIP) $@

+$(obj)mkinitseq$(SFX): $(obj)mkinitseq.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ $(HOSTSTRIP) $@
+
$(obj)mk$(BOARD)spl$(SFX): $(obj)mkexynosspl.o
$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
$(HOSTSTRIP) $@
diff --git a/tools/mkinitseq.c b/tools/mkinitseq.c
new file mode 100644
index 0000000..b150de4
--- /dev/null
+++ b/tools/mkinitseq.c
@@ -0,0 +1,1512 @@
+/*
+ * (C) Copyright 2012
+ * Graeme Russ <graeme.russ@gmail.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
+ */
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+#include "os_support.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <linux/list.h>
+#include <malloc.h>
+
+#include <version.h>
+
+struct func_def {
+ struct list_head list;
+ char *name;
+};
+
+struct init_def {
+ struct list_head list;
+
+ char *function;
+ char *group;
+
+ int cyclic_checked;
+
+ struct list_head mandatory_deps;
+ struct list_head pre_deps;
+ struct list_head post_deps;
+};
+
+struct skip_def {
+ struct list_head list;
+ char *name;
+};
+
+struct replace_def {
+ struct list_head list;
+ char *old_name;
+ char *new_name;
+};
+
+
+struct init_group {
+ struct list_head list;
+
+ char *name;
+
+ struct list_head functions;
+};
+
+struct list_head init_defs;
+struct list_head skip_defs;
+struct list_head replace_defs;
+
+struct list_head mandatory_functions;
+struct list_head init_groups;
+
+struct list_head init_sequence;
+
+/* These are the initialisation sequence placeholders */
+static const char default_init_reset[] = "f:RESET:RESET: | | SDRAM";
+static const char default_init_sdram[] = "f:SDRAM:SDRAM: RESET | | RELOC";
+static const char default_init_reloc[] = "f:RELOC:RELOC: SDRAM | | ";
+
+static void free_function_list(struct list_head *function_list)
+{
+ struct func_def *tmp;
+
+ while (!list_empty(function_list)) {
+
+ tmp = list_first_entry(function_list, struct func_def, list);
+
+ free(tmp->name);
+ list_del(&tmp->list);
+ }
+}
+
+static int function_exists(const char *function)
+{
+ struct list_head *init_def_pos;
+ struct init_def *init_def;
+
+ list_for_each(init_def_pos , &init_defs) {
+ init_def = list_entry(init_def_pos, struct init_def, list);
+
+ if (!strcmp(init_def->function, function))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int check_for_empty_groups(void)
+{
+ int err = 0;
+ struct list_head *group_pos;
+ struct init_group *init_group;
+
+ /* Look for an existing group */
+ list_for_each(group_pos, &init_groups)
+ {
+ init_group = list_entry(group_pos, struct init_group, list);
+
+ if (list_empty(&init_group->functions)) {
+ fprintf(stderr,
+ "Empty init group '%s'\n",
+ init_group->name);
+ err = 1;
+ }
+ }
+
+ return err;
+}
+
+static struct init_def *pop_first_independent_function(void)
+{
+ struct list_head *init_def_pos;
+ struct init_def *init_def;
+
+ list_for_each(init_def_pos , &init_defs)
+ {
+ init_def = list_entry(init_def_pos, struct init_def, list);
+
+ if (list_empty(&init_def->pre_deps)) {
+ list_del(init_def_pos);
+ return init_def;
+ }
+ }
+
+ return NULL;
+}
+
+static int find_or_create_group(const char *group,
+ struct init_group **init_group)
+{
+ struct list_head *group_pos;
+
+ /* Look for an existing group */
+ list_for_each(group_pos, &init_groups)
+ {
+ *init_group = list_entry(group_pos, struct init_group, list);
+
+ if (!strcmp((*init_group)->name, group))
+ return 0;
+ }
+
+ /* No existing group found - Create a new group */
+ *init_group = malloc(sizeof(struct init_group));
+
+ if (!(*init_group))
+ return -ENOMEM;
+
+ (*init_group)->name = strdup(group);
+
+ if (!(*init_group)->name) {
+ free(*init_group);
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&(*init_group)->functions);
+ list_add(&(*init_group)->list, &init_groups);
+
+ return 0;
+}
+
+static int add_function_to_group(const char *function,
+ const char *group)
+{
+ int err;
+ struct init_group *init_group;
+ struct func_def *func_def;
+
+ if (!strcmp(group, ""))
+ return 0;
+
+ err = find_or_create_group(group, &init_group);
+ if (err)
+ return err;
+
+ /* Add the function to the group */
+ func_def = malloc(sizeof(struct func_def));
+
+ if (!func_def)
+ return -ENOMEM;
+
+ func_def->name = strdup(function);
+
+ if (!func_def->name) {
+ free(func_def);
+ return -ENOMEM;
+ }
+
+ list_add(&func_def->list, &init_group->functions);
+
+ return 0;
+}
+
+static void delete_group(const char *group)
+{
+ struct list_head *init_group_pos;
+ struct list_head *q;
+ struct init_group *init_group;
+
+
+ list_for_each_safe(init_group_pos, q, &init_groups) {
+ init_group = list_entry(init_group_pos,
+ struct init_group,
+ list);
+
+ if (!strcmp(init_group->name, group)) {
+ free(init_group->name);
+ free_function_list(&init_group->functions);
+
+ list_del(init_group_pos);
+
+ free(init_group);
+ }
+ }
+
+}
+
+static void delete_dep_from_init_defs(const char *dep)
+{
+ struct list_head *init_def_pos;
+ struct list_head *func_def_pos;
+ struct init_def *init_def;
+ struct func_def *func_def;
+
+ list_for_each(init_def_pos , &init_defs)
+ {
+ init_def = list_entry(init_def_pos,
+ struct init_def,
+ list);
+
+ list_for_each(func_def_pos , &init_def->pre_deps)
+ {
+ func_def = list_entry(func_def_pos,
+ struct func_def,
+ list);
+
+ if (!strcmp(func_def->name, dep)) {
+ free(func_def->name);
+ list_del(func_def_pos);
+ free(func_def);
+ break;
+ }
+ }
+
+ }
+}
+
+
+static int add_mandatory_function(const char *name)
+{
+ struct list_head *position;
+ struct func_def *func_def;
+
+ list_for_each(position, &mandatory_functions)
+ {
+ func_def = list_entry(position, struct func_def, list);
+
+ if (!strcmp(func_def->name, name))
+ return 0;
+ }
+
+ func_def = malloc(sizeof(struct func_def));
+
+ if (!func_def)
+ return -ENOMEM;
+
+ func_def->name = strdup(name);
+
+ if (!func_def->name) {
+ free(func_def);
+ return -ENOMEM;
+ }
+
+ list_add(&func_def->list, &mandatory_functions);
+
+ return 0;
+}
+
+static int process_dep_list(struct list_head *dep_list,
+ char *deps,
+ int mandatory)
+{
+ int err = 0;
+ struct func_def *func_def;
+ char *save_ptr;
+
+ char *dep_function;
+
+ dep_function = strtok_r(deps, " \t", &save_ptr);
+
+ while (dep_function) {
+ func_def = malloc(sizeof(struct func_def));
+
+ if (!func_def)
+ return -ENOMEM;
+
+ func_def->name = strdup(dep_function);
+
+ if (!func_def->name) {
+ free(func_def);
+ return -ENOMEM;
+ }
+
+ list_add(&func_def->list, dep_list);
+
+ if (mandatory)
+ if (add_mandatory_function(dep_function))
+ err = 1;
+
+ dep_function = strtok_r(NULL, " ", &save_ptr);
+ };
+
+ return err;
+}
+
+static int process_init_info(struct init_def *init_def,
+ char *deps)
+{
+ char *mandatory_deps;
+ char *pre_deps;
+ char *post_deps;
+ char *save_ptr;
+
+ INIT_LIST_HEAD(&init_def->mandatory_deps);
+ INIT_LIST_HEAD(&init_def->pre_deps);
+ INIT_LIST_HEAD(&init_def->post_deps);
+
+ mandatory_deps = strtok_r(deps, "|", &save_ptr);
+ pre_deps = strtok_r(NULL, "|", &save_ptr);
+ post_deps = strtok_r(NULL, "|", &save_ptr);
+
+ process_dep_list(&init_def->mandatory_deps, mandatory_deps, 1);
+ process_dep_list(&init_def->pre_deps, pre_deps, 0);
+ process_dep_list(&init_def->post_deps, post_deps, 0);
+
+ return 0;
+}
+
+static int check_for_duplicates(const char *function,
+ const char *group)
+{
+ struct list_head *position;
+ struct init_def *init_def;
+
+ list_for_each(position , &init_defs)
+ {
+ init_def = list_entry(position, struct init_def, list);
+
+ if (!strcmp(function, init_def->function)) {
+ fprintf(stderr,
+ "Duplicate function name '%s'\n",
+ function);
+
+ return -EEXIST;
+ }
+
+ if (!strcmp(function, init_def->group)) {
+ fprintf(stderr,
+ "Function '%s' matches an existing group\n",
+ function);
+
+ return -EEXIST;
+ }
+
+ if (!strcmp(group, init_def->function)) {
+ fprintf(stderr,
+ "Group '%s' matches an existing function\n",
+ function);
+
+ return -EEXIST;
+ }
+ }
+
+ return 0;
+}
+
+static int add_to_init_list(const char *function,
+ const char *group,
+ char *deps)
+{
+ int err;
+ struct init_def *init_def;
+
+ /* Check that the function is not already included */
+ err = check_for_duplicates(function, group);
+
+ if (err)
+ return err;
+
+ /* Create a list node for the new init function */
+ init_def = malloc(sizeof(struct init_def));
+
+ if (!init_def)
+ return -ENOMEM;
+
+ init_def->function = strdup(function);
+ init_def->group = strdup(group);
+ init_def->cyclic_checked = 0;
+
+ if ((!init_def->function) ||
+ (!init_def->group)) {
+ free(init_def->function);
+ free(init_def->group);
+ free(init_def);
+ return -ENOMEM;
+ }
+
+ /* Add the new function to the init function list */
+ list_add(&init_def->list, &init_defs);
+
+ /* Process the new functions dependencies */
+ err = process_init_info(init_def, deps);
+
+ if (err)
+ return err;
+
+ return add_function_to_group(function, group);
+}
+
+static int add_to_skip_list(const char *function_name)
+{
+ struct list_head *skip_pos;
+ struct list_head *replace_pos;
+
+ struct skip_def *skip_def = NULL;
+ struct replace_def *rdef;
+
+ /* Duplicate skip definitions are OK, but we only need the fist one */
+ list_for_each(skip_pos, &skip_defs)
+ {
+ skip_def = list_entry(skip_pos, struct skip_def, list);
+
+ if (!strcmp(function_name, skip_def->name))
+ return 0;
+ }
+
+ /* Skip definitions matching a replace definition are not OK */
+ list_for_each(replace_pos, &replace_defs)
+ {
+ rdef = list_entry(replace_pos,
+ struct replace_def,
+ list);
+
+ if (!strcmp(skip_def->name, rdef->old_name) ||
+ !strcmp(skip_def->name, rdef->new_name)) {
+ fprintf(stderr,
+ "Skip '%s' is in a replace definition\n",
+ skip_def->name);
+ return -EEXIST;
+ }
+ }
+
+ skip_def = malloc(sizeof(struct skip_def));
+
+ if (!skip_def)
+ return -ENOMEM;
+
+ skip_def->name = strdup(function_name);
+
+ if (!skip_def->name) {
+ free(skip_def);
+ return -ENOMEM;
+ }
+
+ list_add(&skip_def->list, &skip_defs);
+
+ return 0;
+}
+
+static int add_to_replace_list(const char *old_name, const char *new_name)
+{
+ struct list_head *skip_pos;
+ struct list_head *replace_pos;
+
+ struct skip_def *skip_def;
+ struct replace_def *rdef;
+
+ /* Duplicate replace definitions are not OK */
+ list_for_each(replace_pos , &replace_defs)
+ {
+ rdef = list_entry(replace_pos,
+ struct replace_def,
+ list);
+
+ if (!strcmp(old_name, rdef->old_name) ||
+ !strcmp(old_name, rdef->new_name)) {
+ fprintf(stderr,
+ "Multiple replace defs for function '%s'\n",
+ old_name);
+
+ return -EEXIST;
+ }
+
+ if (!strcmp(new_name, rdef->old_name) ||
+ !strcmp(new_name, rdef->new_name)) {
+ fprintf(stderr,
+ "Multiple replace defs for function '%s'\n",
+ new_name);
+
+ return -EEXIST;
+ }
+ }
+
+ /* Replace definitions matching a skip definition are not OK */
+ list_for_each(skip_pos, &skip_defs)
+ {
+ skip_def = list_entry(skip_pos, struct skip_def, list);
+
+ if (!strcmp(skip_def->name, old_name)) {
+ fprintf(stderr,
+ "Replace '%s' is in a skip definition\n",
+ old_name);
+ return -EEXIST;
+ }
+
+ if (!strcmp(skip_def->name, new_name)) {
+ fprintf(stderr,
+ "Replace '%s' is in a skip definition\n",
+ new_name);
+ return -EEXIST;
+ }
+ }
+
+ rdef = malloc(sizeof(struct replace_def));
+
+ if (!rdef)
+ return -ENOMEM;
+
+ rdef->old_name = strdup(old_name);
+ rdef->new_name = strdup(new_name);
+
+ if ((!rdef->old_name) || (!rdef->new_name)) {
+ free(rdef->old_name);
+ free(rdef->new_name);
+ free(rdef);
+ return -ENOMEM;
+ }
+
+ list_add(&rdef->list, &replace_defs);
+
+ return 0;
+}
+
+static int process_initcall_string(const char *string)
+{
+ char *save_ptr;
+ char *def_type;
+ char *function;
+ char *group;
+ char *old_name;
+ char *new_name;
+ char *deps;
+ int err;
+
+ char *local_string = strdup(string);
+
+ if (!local_string)
+ return -ENOMEM;
+
+ def_type = strtok_r(local_string, ":", &save_ptr);
+
+ switch (def_type[0]) {
+ case 'f':
+ /* An init function definition - Get the function name */
+ function = strtok_r(NULL, ":", &save_ptr);
+ group = strtok_r(NULL, ":", &save_ptr);
+ deps = strtok_r(NULL, ":", &save_ptr);
+
+ err = add_to_init_list(function, group, deps);
+ break;
+
+ case 's':
+ function = strtok_r(NULL, ":", &save_ptr);
+
+ err = add_to_skip_list(function);
+ break;
+
+ case 'r':
+ old_name = strtok_r(NULL, ":", &save_ptr);
+ new_name = strtok_r(NULL, ":", &save_ptr);
+
+ err = add_to_replace_list(old_name, new_name);
+ break;
+
+ default:
+ fprintf(stderr, "Unknown Init Type: %s", def_type);
+ err = -ENOENT;
+ break;
+ }
+
+ free(local_string);
+ return err;
+}
+
+static int process_marker_strings(void)
+{
+ int err = 0;
+
+ err = process_initcall_string(default_init_reset);
+ if (err)
+ return err;
+
+ err = process_initcall_string(default_init_sdram);
+ if (err)
+ return err;
+
+ err = process_initcall_string(default_init_reloc);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int build_function_list(char *buffer)
+{
+ int err = 0;
+
+ char *save_ptr;
+
+ char *init_call_string;
+
+ err = process_marker_strings();
+ if (err)
+ return err;
+
+ init_call_string = strtok_r(buffer, "()", &save_ptr);
+
+ while (init_call_string) {
+ if (process_initcall_string(init_call_string))
+ err = 1;
+
+ /* Skip the garbage between init definitions */
+ init_call_string = strtok_r(NULL, "(", &save_ptr);
+
+ /* Get the next init definition */
+ init_call_string = strtok_r(NULL, ")", &save_ptr);
+ };
+
+ return err;
+}
+
+static int open_file(const char *file, char **buffer, int *buf_size)
+{
+ struct stat sbuf;
+ int file_ptr;
+
+ char *ptr;
+
+ file_ptr = open(file, O_RDONLY|O_BINARY);
+
+ if (file_ptr < 0) {
+ fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno));
+ return errno;
+ }
+
+ if (fstat(file_ptr, &sbuf) < 0) {
+ fprintf(stderr, "Can't stat %s: %s\n", file, strerror(errno));
+ return errno;
+ }
+
+ ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, file_ptr, 0);
+ if (ptr == MAP_FAILED) {
+ fprintf(stderr, "Can't read %s: %s\n", file, strerror(errno));
+ return errno;
+ }
+
+ *buffer = malloc(sbuf.st_size + 1);
+
+ if (!*buffer)
+ return -ENOMEM;
+
+ *buf_size = sbuf.st_size;
+ memcpy(*buffer, ptr, sbuf.st_size);
+ (*buffer)[sbuf.st_size] = 0x00;
+
+ munmap((void *)ptr, sbuf.st_size);
+ close(file_ptr);
+
+ return 0;
+}
+
+static int check_mandatory_list(void)
+{
+ int err = 0;
+ struct list_head *position;
+ struct list_head *q;
+ struct list_head *sub_position;
+ struct init_def *init_def;
+ struct func_def *func_def;
+
+
+ /* Remove functions that exist from the mandatory functions list */
+ list_for_each_safe(position, q, &mandatory_functions) {
+ func_def = list_entry(position, struct func_def, list);
+
+ list_for_each(sub_position , &init_defs) {
+ init_def = list_entry(sub_position,
+ struct init_def,
+ list);
+
+ if (!strcmp(func_def->name, init_def->function) ||
+ !strcmp(func_def->name, init_def->group)) {
+ free(func_def->name);
+
+ list_del(position);
+ free(func_def);
+ }
+ }
+
+ }
+
+ list_for_each(position , &mandatory_functions) {
+ func_def = list_entry(position, struct func_def, list);
+
+ fprintf(stderr,
+ "Missing mandatory function: %s\n",
+ func_def->name);
+ err = 1;
+ }
+
+ return err;
+}
+
+static int process_skip_list(void)
+{
+ int err = 0;
+ int group_skip = 0;
+
+ /*
+ * The same function cannot appear in both the skip list and the
+ * replace list (either as the new or old function name)
+ */
+ struct list_head *skip_pos;
+ struct skip_def *skip_def;
+
+ struct list_head *init_def_pos;
+ struct init_def *init_def;
+
+ struct list_head *q;
+
+ list_for_each(skip_pos, &skip_defs)
+ {
+ skip_def = list_entry(skip_pos, struct skip_def, list);
+
+ /* Remove the named skip from init entries */
+ list_for_each_safe(init_def_pos, q, &init_defs) {
+ init_def = list_entry(init_def_pos,
+ struct init_def,
+ list);
+ /*
+ * We already know that function and group names
+ * are unique across both namespaces so we can
+ * delete any init definitions whose function or
+ * group name matches the skip name
+ */
+ if (!strcmp(init_def->group, skip_def->name))
+ group_skip = 1;
+
+ if (!strcmp(init_def->function, skip_def->name) ||
+ group_skip) {
+ free(init_def->function);
+ free(init_def->group);
+
+ free_function_list(&init_def->mandatory_deps);
+ free_function_list(&init_def->post_deps);
+ free_function_list(&init_def->pre_deps);
+
+ list_del(init_def_pos);
+
+ free(init_def);
+ }
+ }
+
+ if (group_skip)
+ /* Remove the named skip group */
+ delete_group(skip_def->name);
+ }
+
+ return err;
+}
+
+static int process_replace_list(void)
+{
+ int err = 0;
+
+ struct list_head *init_def_pos;
+ struct list_head *replace_pos;
+
+ struct init_def *init_def;
+ struct replace_def *rdef;
+
+ struct init_group *dummy;
+
+ int group_replace;
+ int function_replace;
+
+ list_for_each(replace_pos, &replace_defs)
+ {
+ rdef = list_entry(replace_pos, struct replace_def, list);
+
+ group_replace = 0;
+ function_replace = 0;
+
+ list_for_each(init_def_pos , &init_defs)
+ {
+ init_def = list_entry(init_def_pos,
+ struct init_def,
+ list);
+
+ if (!strcmp(init_def->function,
+ rdef->old_name)) {
+ /* Function replacements are easy */
+ function_replace = 1;
+
+ free(init_def->function);
+ init_def->function = strdup(rdef->new_name);
+
+ if (!init_def->function)
+ return -ENOMEM;
+
+ } else if (!strcmp(init_def->group,
+ rdef->old_name)) {
+ /* Hmm, a group replacement */
+ group_replace = 1;
+
+ free(init_def->group);
+ init_def->group = strdup(rdef->new_name);
+
+ if (!init_def->group)
+ return -ENOMEM;
+ }
+ }
+
+ if (group_replace) {
+ /* Delete 'old name' group */
+ delete_group(rdef->old_name);
+
+ /*
+ * Create a 'new group' (if it does not already
+ * exist. It will be tested later and if it is
+ * empty, an error will be reported
+ */
+ err = find_or_create_group(rdef->new_name, &dummy);
+ if (!err)
+ return err;
+ }
+
+ if (!group_replace && !function_replace) {
+ fprintf(stderr,
+ "Replace function %s not in init list\n",
+ rdef->old_name);
+ err = ENOENT;
+ }
+ }
+
+ return err;
+}
+
+static int add_dep(const char *function, const char *dep)
+{
+ int found = 0;
+
+ struct list_head *init_def_pos;
+ struct list_head *pre_dep_pos;
+
+ struct init_def *init_def;
+ struct func_def *func_def;
+ struct func_def *pre_dep_id;
+
+ list_for_each(init_def_pos , &init_defs)
+ {
+ init_def = list_entry(init_def_pos, struct init_def, list);
+
+ if (!strcmp(init_def->function, function)) {
+
+ list_for_each(pre_dep_pos, &init_def->pre_deps) {
+ pre_dep_id = list_entry(pre_dep_pos,
+ struct func_def,
+ list);
+ if (!strcmp(pre_dep_id->name, dep)) {
+ found = 1;
+ break;
+ }
+
+ }
+
+ if (!found) {
+ func_def = malloc(sizeof(struct func_def));
+
+ if (!func_def)
+ return -ENOMEM;
+
+ func_def->name = strdup(dep);
+
+ if (!func_def->name) {
+ free(func_def);
+ return -ENOMEM;
+ }
+
+ list_add(&func_def->list, &init_def->pre_deps);
+ }
+
+ return 0;
+ }
+ }
+
+ fprintf(stderr, "Function '%s' not found\n", function);
+ return -ENOENT;
+}
+
+
+static int insert_into_dep_list(struct list_head *dep_list,
+ struct init_group *init_group)
+{
+ struct list_head *position;
+ struct func_def *func_def;
+ struct func_def *new_func_def;
+
+ list_for_each(position, &init_group->functions)
+ {
+ func_def = list_entry(position, struct func_def, list);
+
+ new_func_def = malloc(sizeof(struct func_def));
+
+ if (!new_func_def)
+ return -ENOMEM;
+
+ new_func_def->name = strdup(func_def->name);
+
+ if (!new_func_def->name) {
+ free(new_func_def);
+ return -ENOMEM;
+ }
+
+ list_add(&new_func_def->list, dep_list);
+ }
+
+ return 0;
+}
+
+static int expand_dep_list(struct list_head *dep_list)
+{
+ int err = 0;
+
+ struct list_head *position;
+ struct func_def *func_def;
+ struct list_head *q;
+
+ struct list_head *step_pos;
+ struct init_group *init_group;
+
+
+ list_for_each_safe(position, q, dep_list) {
+ func_def = list_entry(position, struct func_def, list);
+
+ /* Is this a 'step' rather than a 'function' */
+ list_for_each(step_pos, &init_groups)
+ {
+ init_group = list_entry(step_pos,
+ struct init_group,
+ list);
+
+ if (!strcmp(init_group->name, func_def->name)) {
+ /*
+ * Replace this init id (which is a 'step'
+ * with the list of step functions
+ */
+ free(func_def->name);
+
+ list_del(position);
+ free(func_def);
+
+ err = insert_into_dep_list(dep_list,
+ init_group);
+
+ if (err)
+ return err;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int expand_dep_lists(void)
+{
+ int err = 0;
+
+ struct list_head *position;
+ struct init_def *init_def;
+
+ list_for_each(position , &init_defs)
+ {
+ init_def = list_entry(position, struct init_def, list);
+
+ err = expand_dep_list(&init_def->mandatory_deps);
+
+ if (err)
+ return err;
+
+ err = expand_dep_list(&init_def->pre_deps);
+
+ if (err)
+ return err;
+
+ err = expand_dep_list(&init_def->post_deps);
+
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+
+static void remove_unused_deps(struct list_head *list,
+ const char *function,
+ const char *dep_type)
+{
+ struct list_head *dep_pos;
+ struct func_def *func_def;
+ struct list_head *q;
+
+ list_for_each_safe(dep_pos, q, list)
+ {
+ func_def = list_entry(dep_pos,
+ struct func_def,
+ list);
+
+ if (!function_exists(func_def->name)) {
+ fprintf(stderr,
+ "Removing unmet %s dep '%s' from '%s'\n",
+ dep_type,
+ func_def->name,
+ function);
+ free(func_def->name);
+ list_del(dep_pos);
+ free(func_def);
+ }
+ }
+
+}
+
+static int strip_unmet_deps(void)
+{
+ /*
+ * Any entry in the pre-dep and post-dep lists that do not have a
+ * matching entry in the init_defs list can be removed
+ */
+ struct list_head *init_def_pos;
+ struct init_def *init_def;
+
+ list_for_each(init_def_pos , &init_defs)
+ {
+ init_def = list_entry(init_def_pos, struct init_def, list);
+
+ remove_unused_deps(&init_def->pre_deps,
+ init_def->function,
+ "pre");
+ remove_unused_deps(&init_def->post_deps,
+ init_def->function,
+ "post");
+ }
+
+ return 0;
+}
+
+static int cleanup_dep_lists(void)
+{
+ int err = 0;
+ int found;
+
+ struct list_head *init_def_pos;
+ struct list_head *dep_pos;
+ struct list_head *pre_dep_pos;
+
+ struct list_head *q;
+
+ struct init_def *init_def;
+ struct func_def *func_def;
+ struct func_def *pre_dep_id;
+
+ list_for_each(init_def_pos , &init_defs)
+ {
+ init_def = list_entry(init_def_pos, struct init_def, list);
+
+ /* Convert post-deps into pre-deps */
+ list_for_each_safe(dep_pos, q, &init_def->post_deps)
+ {
+ func_def = list_entry(dep_pos,
+ struct func_def,
+ list);
+
+ err = add_dep(func_def->name, init_def->function);
+ if (err)
+ return err;
+
+ list_del(dep_pos);
+
+ free(func_def->name);
+ free(func_def);
+ }
+
+ /* Move mandatory deps into pre-deps list */
+ list_for_each_safe(dep_pos, q, &init_def->mandatory_deps)
+ {
+ func_def = list_entry(dep_pos,
+ struct func_def,
+ list);
+
+ list_del(dep_pos);
+
+ found = 0;
+
+ list_for_each(pre_dep_pos, &init_def->pre_deps)
+ {
+ pre_dep_id = list_entry(pre_dep_pos,
+ struct func_def,
+ list);
+
+ if (!strcmp(func_def->name, pre_dep_id->name)) {
+ found = 1;
+ break;
+ }
+
+ }
+
+ if (!found) {
+ list_add(&func_def->list,
+ &init_def->pre_deps);
+ } else {
+ free(func_def->name);
+ free(func_def);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int check_unique_root_function(void)
+{
+ struct list_head *init_def_pos;
+ struct init_def *init_def;
+
+ int root_functions = 0;
+
+ list_for_each(init_def_pos , &init_defs)
+ {
+ init_def = list_entry(init_def_pos, struct init_def, list);
+
+ if (list_empty(&init_def->pre_deps))
+ root_functions++;
+ }
+
+ if (root_functions != 1)
+ return -EINVAL;
+ else
+ return 0;
+}
+
+static void dump_dep_stack(struct list_head *dep_stack, const char *function)
+{
+ struct list_head *func_def_pos;
+ struct func_def *func_def;
+
+ list_for_each(func_def_pos , dep_stack) {
+ func_def = list_entry(func_def_pos, struct func_def, list);
+
+ fprintf(stderr, " %s\n", func_def->name);
+
+ if (!strcmp(func_def->name, function))
+ return;
+ }
+}
+
+static struct init_def *find_init_def_by_function(const char *function)
+{
+ struct list_head *init_def_pos;
+ struct init_def *init_def;
+
+ list_for_each(init_def_pos , &init_defs)
+ {
+ init_def = list_entry(init_def_pos, struct init_def, list);
+
+ if (!strcmp(init_def->function, function))
+ return init_def;
+ }
+
+ fprintf(stderr, "Cannot find %s\n", function);
+
+ return NULL;
+}
+
+static int check_init_def_cyclic(struct init_def *init_def,
+ struct list_head *dep_stack)
+{
+ int err = 0;
+
+ struct list_head *func_def_pos;
+ struct func_def *func_def;
+
+ struct list_head *dep_init_func_pos;
+ struct func_def *dep_init_func;
+ struct init_def *dep_init_def;
+
+ if (init_def->cyclic_checked)
+ return 0;
+
+ /* Check if this function already in the dependency stack */
+ list_for_each(func_def_pos , dep_stack) {
+ func_def = list_entry(func_def_pos, struct func_def, list);
+
+ if (!strcmp(init_def->function, func_def->name)) {
+ fprintf(stderr,
+ "Function '%s' has cyclic dependency\n",
+ init_def->function);
+
+ /* Dump the dependency stack */
+ dump_dep_stack(dep_stack, init_def->function);
+
+ init_def->cyclic_checked = 1;
+ return -EEXIST;
+ }
+ }
+
+ /* Add this function to the check stack */
+ func_def = malloc(sizeof(struct func_def));
+
+ if (!func_def)
+ return -ENOMEM;
+
+ func_def->name = strdup(init_def->function);
+
+ if (!func_def->name) {
+ free(func_def);
+ return -ENOMEM;
+ }
+
+ list_add(&func_def->list, dep_stack);
+
+ /* Now check the all the dependencies of this function */
+ list_for_each(dep_init_func_pos , &init_def->pre_deps)
+ {
+ dep_init_func = list_entry(dep_init_func_pos,
+ struct func_def,
+ list);
+
+ dep_init_def = find_init_def_by_function(dep_init_func->name);
+
+ if (!dep_init_def)
+ return 1;
+
+ if (check_init_def_cyclic(dep_init_def, dep_stack))
+ err = 1;
+ }
+
+ init_def->cyclic_checked = 1;
+
+ return err;
+}
+
+static void clear_dep_stack(struct list_head *dep_stack)
+{
+ struct list_head *func_def_pos;
+ struct list_head *q;
+ struct func_def *func_def;
+
+ list_for_each_safe(func_def_pos, q, dep_stack) {
+ func_def = list_entry(func_def_pos,
+ struct func_def,
+ list);
+
+ list_del(func_def_pos);
+ free(func_def->name);
+ free(func_def);
+ }
+}
+
+static int check_for_cyclic_deps(void)
+{
+ int err = 0;
+ struct list_head *init_def_pos;
+ struct init_def *init_def;
+
+ struct list_head dep_stack;
+
+
+ INIT_LIST_HEAD(&dep_stack);
+
+ list_for_each(init_def_pos , &init_defs)
+ {
+ clear_dep_stack(&dep_stack);
+
+ init_def = list_entry(init_def_pos, struct init_def, list);
+
+ if (!init_def->cyclic_checked)
+ if (check_init_def_cyclic(init_def, &dep_stack))
+ err = 1;
+ }
+
+ clear_dep_stack(&dep_stack);
+
+ return err;
+}
+
+int generate_init_sequence(void)
+{
+ struct init_def *init_def;
+
+ while (!list_empty(&init_defs)) {
+ init_def = pop_first_independent_function();
+
+ if (!init_def) {
+ fprintf(stderr, "Cyclic deps\n");
+ return 0;
+ }
+
+ list_add_tail(&init_def->list, &init_sequence);
+
+ delete_dep_from_init_defs(init_def->function);
+ }
+
+ return 0;
+}
+
+int generate_c_file(const char *file)
+{
+ struct list_head *init_def_pos;
+ struct init_def *init_def;
+
+ FILE *file_ptr = fopen(file, "w");
+
+ if (!file_ptr) {
+ fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno));
+ return errno;
+ }
+
+ fputs("/*\n", file_ptr);
+ fputs(" * DO NOT MODIFY.\n", file_ptr);
+ fputs(" *\n", file_ptr);
+ fputs(" * This file was generated by mkinitseq\n", file_ptr);
+ fputs(" *\n", file_ptr);
+ fputs(" */\n", file_ptr);
+ fputs("\n", file_ptr);
+ fputs("#include <init_func.h>\n", file_ptr);
+ fputs("#include <linux/stddef.h>\n", file_ptr);
+ fputs("\n", file_ptr);
+
+ list_for_each(init_def_pos , &init_sequence)
+ {
+ init_def = list_entry(init_def_pos, struct init_def, list);
+
+ if (strcmp(init_def->function, "RESET") &
+ strcmp(init_def->function, "SDRAM") &
+ strcmp(init_def->function, "RELOC")) {
+ fprintf(file_ptr, "int %s(void);\n",
+ init_def->function);
+ }
+ }
+
+ list_for_each(init_def_pos , &init_sequence)
+ {
+ init_def = list_entry(init_def_pos, struct init_def, list);
+
+ if (!strcmp(init_def->function, "RESET")) {
+ fputs("init_fnc_t *init_sequence_f[] = {\n",
+ file_ptr);
+ } else if (!strcmp(init_def->function, "SDRAM")) {
+ fputs("\n", file_ptr);
+ fputs("\t\tNULL,\n", file_ptr);
+ fputs("\t};\n", file_ptr);
+
+ fputs("\n", file_ptr);
+ fputs("init_fnc_t *init_sequence_f_r[] = {\n",
+ file_ptr);
+ } else if (!strcmp(init_def->function, "RELOC")) {
+ fputs("\n", file_ptr);
+ fputs("\t\tNULL,\n", file_ptr);
+ fputs("\t};\n", file_ptr);
+
+ fputs("\n", file_ptr);
+ fputs("init_fnc_t *init_sequence_r[] = {\n",
+ file_ptr);
+ } else {
+ fprintf(file_ptr, "\t\t%s,\n", init_def->function);
+ }
+ }
+
+ fputs("\n", file_ptr);
+ fputs("\t\tNULL,\n", file_ptr);
+ fputs("\t};\n", file_ptr);
+
+ fclose(file_ptr);
+
+ return 0;
+}
+
+void init_lists(void)
+{
+ INIT_LIST_HEAD(&init_defs);
+ INIT_LIST_HEAD(&skip_defs);
+ INIT_LIST_HEAD(&replace_defs);
+
+ INIT_LIST_HEAD(&mandatory_functions);
+ INIT_LIST_HEAD(&init_groups);
+
+ INIT_LIST_HEAD(&init_sequence);
+}
+
+int main(int argc, const char **argv)
+{
+ int err;
+ int buf_size = 0;
+ char *local_buffer = NULL;
+ char *x;
+
+ printf("Generating init sequence from %s\n", argv[1]);
+
+ /* Read the init function definitions into a local buffer */
+ err = open_file(argv[1], &local_buffer, &buf_size);
+
+ if (err || !local_buffer)
+ exit(EXIT_FAILURE);
+
+ /*
+ * Convert all the NULLs (except the last one) to non-NULL so
+ * the buffer can be processed using standard string functions
+ */
+ for (x = local_buffer; x != &local_buffer[buf_size]; x++) {
+ if (*x == 0x00)
+ *x = 0x01;
+ }
+
+ init_lists();
+
+ if (build_function_list(local_buffer))
+ exit(EXIT_FAILURE);
+
+ if (check_mandatory_list())
+ exit(EXIT_FAILURE);
+
+ if (process_skip_list())
+ exit(EXIT_FAILURE);
+
+ if (process_replace_list())
+ exit(EXIT_FAILURE);
+
+ if (check_for_empty_groups())
+ exit(EXIT_FAILURE);
+
+ if (expand_dep_lists())
+ exit(EXIT_FAILURE);
+
+ if (strip_unmet_deps())
+ exit(EXIT_FAILURE);
+
+ if (cleanup_dep_lists())
+ exit(EXIT_FAILURE);
+
+ if (check_unique_root_function())
+ exit(EXIT_FAILURE);
+
+ if (check_for_cyclic_deps())
+ exit(EXIT_FAILURE);
+
+ if (generate_init_sequence())
+ exit(EXIT_FAILURE);
+
+ if (generate_c_file(argv[2]))
+ exit(EXIT_FAILURE);
+
+ free(local_buffer);
+ exit(EXIT_SUCCESS);
+}
--
1.7.7.6