diff mbox

[U-Boot,WIP] initcall: An outline of the idea

Message ID 1330686312-28712-1-git-send-email-graeme.russ@gmail.com
State RFC
Headers show

Commit Message

Graeme Russ March 2, 2012, 11:05 a.m. UTC
This is a very rough (i.e. it is not even close to finished and maybe won't
even appply as it sits on top of some other dev patches I have) but it
should give you an idea of what the INIT_FUNC implementation will look like.

Ultimately, tools/mkinitseq.c will process the dependencies and generate
a C file containing the three init sequence arrays which have been deleted
from arch/x86/lib/board.c

---
 Makefile                                    |   24 +++-
 arch/blackfin/cpu/initcode.c                |    1 +
 arch/blackfin/cpu/serial.c                  |    1 +
 arch/mips/cpu/mips32/au1x00/au1x00_serial.c |    1 +
 arch/mips/cpu/mips32/incaip/asc_serial.c    |    1 +
 arch/mips/cpu/xburst/jz_serial.c            |    1 +
 arch/powerpc/cpu/mpc512x/serial.c           |    1 +
 arch/powerpc/cpu/mpc5xx/serial.c            |    1 +
 arch/sparc/cpu/leon2/serial.c               |    1 +
 arch/sparc/cpu/leon3/serial.c               |    1 +
 arch/x86/cpu/cpu.c                          |    4 +-
 arch/x86/cpu/interrupts.c                   |    1 +
 arch/x86/cpu/sc520/sc520.c                  |    1 +
 arch/x86/cpu/sc520/sc520_sdram.c            |    2 +
 arch/x86/cpu/sc520/sc520_timer.c            |    1 +
 arch/x86/cpu/u-boot.lds                     |    1 +
 arch/x86/lib/board.c                        |  134 +-------------
 arch/x86/lib/init_helpers.c                 |   14 ++
 arch/x86/lib/init_wrappers.c                |   11 +
 arch/x86/lib/relocate.c                     |    3 +
 board/amirix/ap1000/serial.c                |    1 +
 board/bmw/serial.c                          |    1 +
 board/eNET/eNET.c                           |    3 +
 common/console.c                            |    2 +
 common/env_dataflash.c                      |    1 +
 common/env_eeprom.c                         |    1 +
 common/env_flash.c                          |    1 +
 common/env_mgdisk.c                         |    1 +
 common/env_mmc.c                            |    1 +
 common/env_nand.c                           |    1 +
 common/env_nowhere.c                        |    1 +
 common/env_nvram.c                          |    1 +
 common/env_onenand.c                        |    1 +
 common/env_sf.c                             |    1 +
 common/serial.c                             |    1 +
 common/stdio.c                              |    1 +
 config.mk                                   |    2 +
 doc/README.INIT_FUNC                        |   31 +++
 include/initcall.h                          |   19 ++
 tools/Makefile                              |    6 +
 tools/mkinitseq.c                           |  278 +++++++++++++++++++++++++++
 u-boot-init.lds                             |   25 +++
 42 files changed, 449 insertions(+), 136 deletions(-)
 create mode 100644 doc/README.INIT_FUNC
 create mode 100644 include/initcall.h
 create mode 100644 tools/mkinitseq.c
 create mode 100644 u-boot-init.lds

Comments

Laurence Withers March 3, 2012, 11:47 a.m. UTC | #1
Hi Graeme,

On Fri, Mar 02, 2012 at 10:05:12PM +1100, Graeme Russ wrote:
> diff --git a/doc/README.INIT_FUNC b/doc/README.INIT_FUNC
> new file mode 100644
> index 0000000..b545390
> --- /dev/null
> +++ b/doc/README.INIT_FUNC
> @@ -0,0 +1,31 @@
> +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
> +
> +The format of the INIT_FUNC macro is:
> +
> +INIT_FUNC({function_name}, {init_class}, {prerequisite init_class(es)})
> +
> +{function_name} 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
> +
> +{init_class} is a simple test string to describe the basic purpose of the init
> +function. Multiple init functions may share the same init_class string
> +
> +{prerequisite init_class(es)} is a list of init_class strings (see above) which
> +defines what init functions are executed before and after the given init
> +function. Each prerequisite init_class is seperated by a space and preceeded by
> +either:
> + * - At least one function of this init class must exist (i.e. there must be at
> +     least one INIT_FUNC entry with {init_class} set to the init class named
> +     after the '*' - All init functions with an init class matching the class
> +     named after the '*' will be executed before this function
> + + - All init functions with an init class matching the class named after the
> +     '+' will be executed before this function, but there does not need to be
> +     any functions with the named init class in the init sequence
> + - - This function will be called before any other functions with the init
> +     class named after the '-'

What happens if there's a set of dependencies that cannot be resolved? From
reading the above, it seems I can do something like this:

INIT_FUNC(ifunc1, class1, *class2);
INIT_FUNC(ifunc2, class2, *class1);

It would also seem that if you want to change the prerequisites for a given
init_class, you need to find every instance of INIT_FUNC for that init_class
and change it.

Perhaps there's a better way of solving this, but it maybe there should be a
separate place which names the init classes and their prerequisites?

> diff --git a/include/initcall.h b/include/initcall.h
> new file mode 100644
> index 0000000..a81cf21
> --- /dev/null
> +++ b/include/initcall.h
> @@ -0,0 +1,19 @@
> +#ifndef __INIT_CALL_H__
> +#define __INIT_CALL_H__
> +#include <linux/compiler.h>
> +#define INIT_FUNC(fn, init_name, deps) \
> +	static const char __init_func_ ## fn[] __used \
> +	__attribute__((__section__(".initfuncs"))) = \
> +	"(" #fn ":" #init_name ";" #deps ")\n";
> +
> +#define SKIP_INIT(init_name) \
> +	static const char __skip_init_ ## req[] __used \
> +	__attribute__((__section__(".initfuncs"))) = \
> +	"{" #init_name "}\n";
> +
> +#define REPLACE_INIT(old_func, new_func) \
> +	static const char __replace_init_ ## old_func[] __used \
> +	__attribute__((__section__(".initfuncs"))) = \
> +	"[" #old_func "," #new_func "]\n";
> +
> +#endif /* !__INIT_CALL_H__ */

What are SKIP_INIT() and REPLACE_INIT() used for?

Perhaps the macro could be expanded to include a prototype for the function,
so that gcc complains with a useful error message if there's a type mismatch.

Bye for now,
Graeme Russ March 3, 2012, 12:46 p.m. UTC | #2
Hi Laurence,

On 03/03/2012 10:47 PM, Laurence Withers wrote:
> Hi Graeme,
> 
> On Fri, Mar 02, 2012 at 10:05:12PM +1100, Graeme Russ wrote:
>> diff --git a/doc/README.INIT_FUNC b/doc/README.INIT_FUNC
>> new file mode 100644
>> index 0000000..b545390
>> --- /dev/null
>> +++ b/doc/README.INIT_FUNC
>> @@ -0,0 +1,31 @@
>> +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
>> +
>> +The format of the INIT_FUNC macro is:
>> +
>> +INIT_FUNC({function_name}, {init_class}, {prerequisite init_class(es)})
>> +
>> +{function_name} 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
>> +
>> +{init_class} is a simple test string to describe the basic purpose of the init
>> +function. Multiple init functions may share the same init_class string
>> +
>> +{prerequisite init_class(es)} is a list of init_class strings (see above) which
>> +defines what init functions are executed before and after the given init
>> +function. Each prerequisite init_class is seperated by a space and preceeded by
>> +either:
>> + * - At least one function of this init class must exist (i.e. there must be at
>> +     least one INIT_FUNC entry with {init_class} set to the init class named
>> +     after the '*' - All init functions with an init class matching the class
>> +     named after the '*' will be executed before this function
>> + + - All init functions with an init class matching the class named after the
>> +     '+' will be executed before this function, but there does not need to be
>> +     any functions with the named init class in the init sequence
>> + - - This function will be called before any other functions with the init
>> +     class named after the '-'
> 
> What happens if there's a set of dependencies that cannot be resolved? From
> reading the above, it seems I can do something like this:

tools/mkinitseq would return an error - It would be akin to a compilation error

> INIT_FUNC(ifunc1, class1, *class2);
> INIT_FUNC(ifunc2, class2, *class1);

What you need to keep in mind is that currently the init sequences are
maintained as a fixed array of function pointers (except in one corner case
arch, but that can be fixed) so you could just name the classes 'class1',
'class2', 'class3' and build the existing init sequences as-is. But there
is no guarantee the order is the same for all the arches, hence the desire
to group like functions together.

The dependencies are not really that complicated, so I don't imagine there
will be much difficultly in getting the current sequences migrated.

It's when someone adds a board specific init function that things might get
interesting...


> It would also seem that if you want to change the prerequisites for a given
> init_class, you need to find every instance of INIT_FUNC for that init_class
> and change it.

Yes, but this would be rare - The idea of init class is to say, for
example, 'PCI must be initialised before Ethernet' - The chance of this
dependency rule changing is very low

> Perhaps there's a better way of solving this, but it maybe there should be a
> separate place which names the init classes and their prerequisites?

Some board, SoCs or arches _may_ need slightly different prerequisites -
For example, arch 'A' may need GPIO before PCI while arch 'B' may need PCI
before GPIO

> 
>> diff --git a/include/initcall.h b/include/initcall.h
>> new file mode 100644
>> index 0000000..a81cf21
>> --- /dev/null
>> +++ b/include/initcall.h
>> @@ -0,0 +1,19 @@
>> +#ifndef __INIT_CALL_H__
>> +#define __INIT_CALL_H__
>> +#include <linux/compiler.h>
>> +#define INIT_FUNC(fn, init_name, deps) \
>> +	static const char __init_func_ ## fn[] __used \
>> +	__attribute__((__section__(".initfuncs"))) = \
>> +	"(" #fn ":" #init_name ";" #deps ")\n";
>> +
>> +#define SKIP_INIT(init_name) \
>> +	static const char __skip_init_ ## req[] __used \
>> +	__attribute__((__section__(".initfuncs"))) = \
>> +	"{" #init_name "}\n";
>> +
>> +#define REPLACE_INIT(old_func, new_func) \
>> +	static const char __replace_init_ ## old_func[] __used \
>> +	__attribute__((__section__(".initfuncs"))) = \
>> +	"[" #old_func "," #new_func "]\n";
>> +
>> +#endif /* !__INIT_CALL_H__ */
> 
> What are SKIP_INIT() and REPLACE_INIT() used for?

Glad you asked :) - They are more advanced functions...

SKIP_INIT() drops all initialisation of a given init class - This allows a
board to completely override an init class normally defined by the arch,
SoC or CPU

REPLACE_INIT() replaces one init function with another - It is similar to
weak functions

> 
> Perhaps the macro could be expanded to include a prototype for the function,

How so - Can you provide a code example?

> so that gcc complains with a useful error message if there's a type mismatch.

The type mismatch will be flagged when the file generated by mkinitseq is
compiled - All functions are int foo(void)

> 
> Bye for now,

Thanks & Regards,

Graeme
Laurence Withers March 4, 2012, 11:58 a.m. UTC | #3
On Sat, Mar 03, 2012 at 11:46:01PM +1100, Graeme Russ wrote:
> > Perhaps the macro could be expanded to include a prototype for the function,
> 
> How so - Can you provide a code example?

Sure, since all the functions are int(*)(void), just something like this:

+#define INIT_FUNC(fn, init_name, deps) \
+    static int ##fn (void); \
+    static const char __init_func_ ## fn[] __used \
+    __attribute__((__section__(".initfuncs"))) = \
+    "(" #fn ":" #init_name ";" #deps ")\n";

(I'm guessing static is OK for this use case?).

The patch overall looks like it will make it a lot simpler to understand and
change the sequence initialisation functions are called, which is a very good
thing. I'm just mindful of getting easy-to-diagnose error messages back when
things go wrong.

An example:

	static int f1(int x)
	{
		return x + 1;
	}

	#define INIT_FUNC(fn) \
		static void fn(int)

	INIT_FUNC(f1);

gcc immediately throws the following error:

	t2.c:9: error: conflicting types for ‘f1’
	t2.c:1: note: previous definition of ‘f1’ was here

which is pretty clear.

Bye for now,
Laurence Withers March 4, 2012, 12:04 p.m. UTC | #4
On Sun, Mar 04, 2012 at 11:58:27AM +0000, Laurence Withers wrote:
> +#define INIT_FUNC(fn, init_name, deps) \
> +    static int ##fn (void); \

                  ^^

Excuse the macro catenation operator; that shouldn't be there. Hopefully the
example made it clear.

Bye for now,
Simon Glass March 8, 2012, 6:48 a.m. UTC | #5
Hi Graeme,

On Fri, Mar 2, 2012 at 3:05 AM, Graeme Russ <graeme.russ@gmail.com> wrote:
> This is a very rough (i.e. it is not even close to finished and maybe won't
> even appply as it sits on top of some other dev patches I have) but it
> should give you an idea of what the INIT_FUNC implementation will look like.
>
> Ultimately, tools/mkinitseq.c will process the dependencies and generate
> a C file containing the three init sequence arrays which have been deleted
> from arch/x86/lib/board.c
>
> ---
>  Makefile                                    |   24 +++-
>  arch/blackfin/cpu/initcode.c                |    1 +
>  arch/blackfin/cpu/serial.c                  |    1 +
>  arch/mips/cpu/mips32/au1x00/au1x00_serial.c |    1 +
>  arch/mips/cpu/mips32/incaip/asc_serial.c    |    1 +
>  arch/mips/cpu/xburst/jz_serial.c            |    1 +
>  arch/powerpc/cpu/mpc512x/serial.c           |    1 +
>  arch/powerpc/cpu/mpc5xx/serial.c            |    1 +
>  arch/sparc/cpu/leon2/serial.c               |    1 +
>  arch/sparc/cpu/leon3/serial.c               |    1 +
>  arch/x86/cpu/cpu.c                          |    4 +-
>  arch/x86/cpu/interrupts.c                   |    1 +
>  arch/x86/cpu/sc520/sc520.c                  |    1 +
>  arch/x86/cpu/sc520/sc520_sdram.c            |    2 +
>  arch/x86/cpu/sc520/sc520_timer.c            |    1 +
>  arch/x86/cpu/u-boot.lds                     |    1 +
>  arch/x86/lib/board.c                        |  134 +-------------
>  arch/x86/lib/init_helpers.c                 |   14 ++
>  arch/x86/lib/init_wrappers.c                |   11 +
>  arch/x86/lib/relocate.c                     |    3 +
>  board/amirix/ap1000/serial.c                |    1 +
>  board/bmw/serial.c                          |    1 +
>  board/eNET/eNET.c                           |    3 +
>  common/console.c                            |    2 +
>  common/env_dataflash.c                      |    1 +
>  common/env_eeprom.c                         |    1 +
>  common/env_flash.c                          |    1 +
>  common/env_mgdisk.c                         |    1 +
>  common/env_mmc.c                            |    1 +
>  common/env_nand.c                           |    1 +
>  common/env_nowhere.c                        |    1 +
>  common/env_nvram.c                          |    1 +
>  common/env_onenand.c                        |    1 +
>  common/env_sf.c                             |    1 +
>  common/serial.c                             |    1 +
>  common/stdio.c                              |    1 +
>  config.mk                                   |    2 +
>  doc/README.INIT_FUNC                        |   31 +++
>  include/initcall.h                          |   19 ++
>  tools/Makefile                              |    6 +
>  tools/mkinitseq.c                           |  278 +++++++++++++++++++++++++++
>  u-boot-init.lds                             |   25 +++
>  42 files changed, 449 insertions(+), 136 deletions(-)
>  create mode 100644 doc/README.INIT_FUNC
>  create mode 100644 include/initcall.h
>  create mode 100644 tools/mkinitseq.c
>  create mode 100644 u-boot-init.lds
>

I read through this and it looks pretty nice. No point in commenting
on the code at this stage I suspect.

But I wonder if this could fit on top of the generic board init
series? Then we could move to initcalls for all boards rather than
just x86, and in fact for U-Boot as a whole.

Plus a few questions. What tool do we need to display the result init
sequence at build time? Can we make U-Boot print out the initcalls as
it runs them (perhaps with pre-console buffer)?

Hoping you can pull this off!

Regards,
Simon
diff mbox

Patch

diff --git a/Makefile b/Makefile
index f174996..d07f404 100644
--- a/Makefile
+++ b/Makefile
@@ -460,8 +460,30 @@  GEN_UBOOT = \
 			-Map u-boot.map -o u-boot
 endif
 
+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:	depend \
+		$(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT)
+		$(GEN_UBOOT_INIT)
+
+$(obj)u-boot-init.bin:	$(obj)u-boot-init
+		$(OBJCOPY) -j .initfuncs -O binary $< $@
+
+$(obj)init_seq.c:	tools $(obj)u-boot-init.bin
+		$(obj)tools/mkinitseq $(obj)u-boot-init.bin
+
 $(obj)u-boot:	depend \
-		$(SUBDIR_TOOLS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds
+		$(SUBDIR_TOOLS) \
+		$(OBJS) $(LIBBOARD) \
+		$(LIBS) \
+		$(LDSCRIPT) \
+		$(obj)init_seq.c \
+		$(obj)u-boot.lds
 		$(GEN_UBOOT)
 ifeq ($(CONFIG_KALLSYMS),y)
 		smap=`$(call SYSTEM_MAP,u-boot) | \
diff --git a/arch/blackfin/cpu/initcode.c b/arch/blackfin/cpu/initcode.c
index fb3a101..2f4cae5 100644
--- a/arch/blackfin/cpu/initcode.c
+++ b/arch/blackfin/cpu/initcode.c
@@ -78,6 +78,7 @@  static inline void serial_init(void)
 			serial_early_set_baud(uart_base, CONFIG_BAUDRATE);
 	}
 }
+INIT_FUNC(serial_init, serial_f, *baudrate_f -SDRAM);
 
 __attribute__((always_inline))
 static inline void serial_deinit(void)
diff --git a/arch/blackfin/cpu/serial.c b/arch/blackfin/cpu/serial.c
index 6603dc0..89026f2 100644
--- a/arch/blackfin/cpu/serial.c
+++ b/arch/blackfin/cpu/serial.c
@@ -318,6 +318,7 @@  int serial_init(void)
 	uart_lsr_clear(UART_DLL);
 	return 0;
 }
+INIT_FUNC(serial_init, serial_f, *baudrate_f -SDRAM);
 
 int serial_tstc(void)
 {
diff --git a/arch/mips/cpu/mips32/au1x00/au1x00_serial.c b/arch/mips/cpu/mips32/au1x00/au1x00_serial.c
index c25ba5a..d723dbf 100644
--- a/arch/mips/cpu/mips32/au1x00/au1x00_serial.c
+++ b/arch/mips/cpu/mips32/au1x00/au1x00_serial.c
@@ -61,6 +61,7 @@  int serial_init (void)
 
 	return 0;
 }
+INIT_FUNC(serial_init, serial_f, *baudrate_f -SDRAM);
 
 
 void serial_setbrg (void)
diff --git a/arch/mips/cpu/mips32/incaip/asc_serial.c b/arch/mips/cpu/mips32/incaip/asc_serial.c
index 7239804..21e5cf2 100644
--- a/arch/mips/cpu/mips32/incaip/asc_serial.c
+++ b/arch/mips/cpu/mips32/incaip/asc_serial.c
@@ -81,6 +81,7 @@  int serial_init (void)
 
     return 0;
 }
+INIT_FUNC(serial_init, serial_f, *baudrate_f -SDRAM);
 
 void serial_setbrg (void)
 {
diff --git a/arch/mips/cpu/xburst/jz_serial.c b/arch/mips/cpu/xburst/jz_serial.c
index e6c48e0..e306961 100644
--- a/arch/mips/cpu/xburst/jz_serial.c
+++ b/arch/mips/cpu/xburst/jz_serial.c
@@ -61,6 +61,7 @@  int serial_init(void)
 
 	return 0;
 }
+INIT_FUNC(serial_init, serial_f, *baudrate_f -SDRAM);
 
 void serial_setbrg(void)
 {
diff --git a/arch/powerpc/cpu/mpc512x/serial.c b/arch/powerpc/cpu/mpc512x/serial.c
index 7c53346..149ee73 100644
--- a/arch/powerpc/cpu/mpc512x/serial.c
+++ b/arch/powerpc/cpu/mpc512x/serial.c
@@ -376,6 +376,7 @@  int serial_init(void)
 {
 	return serial_init_dev(CONFIG_PSC_CONSOLE);
 }
+INIT_FUNC(serial_init, serial_f, *baudrate_f -SDRAM);
 
 void serial_putc(const char c)
 {
diff --git a/arch/powerpc/cpu/mpc5xx/serial.c b/arch/powerpc/cpu/mpc5xx/serial.c
index 88c6db8..14fd66c 100644
--- a/arch/powerpc/cpu/mpc5xx/serial.c
+++ b/arch/powerpc/cpu/mpc5xx/serial.c
@@ -62,6 +62,7 @@  int serial_init (void)
 #endif
 	return 0;
 }
+INIT_FUNC(serial_init, serial_f, *baudrate_f -SDRAM);
 
 void serial_putc(const char c)
 {
diff --git a/arch/sparc/cpu/leon2/serial.c b/arch/sparc/cpu/leon2/serial.c
index 4f41b8e..6ea7abd 100644
--- a/arch/sparc/cpu/leon2/serial.c
+++ b/arch/sparc/cpu/leon2/serial.c
@@ -71,6 +71,7 @@  int serial_init(void)
 
 	return 0;
 }
+INIT_FUNC(serial_init, serial_f, *baudrate_f -SDRAM);
 
 void serial_putc(const char c)
 {
diff --git a/arch/sparc/cpu/leon3/serial.c b/arch/sparc/cpu/leon3/serial.c
index 4b2fcb8..327b525 100644
--- a/arch/sparc/cpu/leon3/serial.c
+++ b/arch/sparc/cpu/leon3/serial.c
@@ -71,6 +71,7 @@  int serial_init(void)
 	}
 	return -1;		/* didn't find hardware */
 }
+INIT_FUNC(serial_init, serial_f, *baudrate_f -SDRAM);
 
 void serial_putc(const char c)
 {
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c
index e9bb0d7..d96ae1b 100644
--- a/arch/x86/cpu/cpu.c
+++ b/arch/x86/cpu/cpu.c
@@ -121,7 +121,7 @@  void setup_gdt(gd_t *id, u64 *gdt_addr)
 	load_fs(X86_GDT_ENTRY_32BIT_FS);
 }
 
-int x86_cpu_init_f(void)
+int cpu_init_f(void)
 {
 	const u32 em_rst = ~X86_CR0_EM;
 	const u32 mp_ne_set = X86_CR0_MP | X86_CR0_NE;
@@ -136,7 +136,7 @@  int x86_cpu_init_f(void)
 
 	return 0;
 }
-int cpu_init_f(void) __attribute__((weak, alias("x86_cpu_init_f")));
+INIT_FUNC(cpu_init_f, cpu_f, *RESET -SDRAM);
 
 int x86_cpu_init_r(void)
 {
diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c
index 43ec3f8..1414c79 100644
--- a/arch/x86/cpu/interrupts.c
+++ b/arch/x86/cpu/interrupts.c
@@ -227,6 +227,7 @@  int cpu_init_interrupts(void)
 
 	return 0;
 }
+INIT_FUNC(cpu_init_interrupts, interrupts, *exceptions);
 
 void __do_irq(int irq)
 {
diff --git a/arch/x86/cpu/sc520/sc520.c b/arch/x86/cpu/sc520/sc520.c
index 3fe85e7..8f350d4 100644
--- a/arch/x86/cpu/sc520/sc520.c
+++ b/arch/x86/cpu/sc520/sc520.c
@@ -64,3 +64,4 @@  int cpu_init_r(void)
 
 	return x86_cpu_init_r();
 }
+INIT_FUNC(cpu_init_r, cpu_r, *malloc);
diff --git a/arch/x86/cpu/sc520/sc520_sdram.c b/arch/x86/cpu/sc520/sc520_sdram.c
index 9dc1334..4df602b 100644
--- a/arch/x86/cpu/sc520/sc520_sdram.c
+++ b/arch/x86/cpu/sc520/sc520_sdram.c
@@ -51,6 +51,7 @@  int dram_init_f(void)
 
 	return 0;
 }
+INIT_FUNC(dram_init_f, dram_f, *console_f -SDRAM);
 
 static inline void sc520_dummy_write(void)
 {
@@ -477,3 +478,4 @@  int dram_init(void)
 
 	return 0;
 }
+INIT_FUNC(dram_init, dram_r, *interrupts board_early_r);
diff --git a/arch/x86/cpu/sc520/sc520_timer.c b/arch/x86/cpu/sc520/sc520_timer.c
index 495a694..569f612 100644
--- a/arch/x86/cpu/sc520/sc520_timer.c
+++ b/arch/x86/cpu/sc520/sc520_timer.c
@@ -69,6 +69,7 @@  int timer_init(void)
 
 	return 0;
 }
+INIT_FUNC(timer_init, timer, *interrupts);
 
 /* Allow boards to override udelay implementation */
 void __udelay(unsigned long usec)
diff --git a/arch/x86/cpu/u-boot.lds b/arch/x86/cpu/u-boot.lds
index 8abaae1..85fff3c 100644
--- a/arch/x86/cpu/u-boot.lds
+++ b/arch/x86/cpu/u-boot.lds
@@ -90,6 +90,7 @@  SECTIONS
 	/DISCARD/ : { *(.plt*) }
 	/DISCARD/ : { *(.interp*) }
 	/DISCARD/ : { *(.gnu*) }
+	/DISCARD/ : { *(.initfuncs*) }
 
 	/* 16bit realmode trampoline code */
 	.realmode REALMODE_BASE : AT ( LOADADDR(.rel.dyn) + SIZEOF(.rel.dyn) ) { KEEP(*(.realmode)) }
diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c
index dceb69c..ad7b518 100644
--- a/arch/x86/lib/board.c
+++ b/arch/x86/lib/board.c
@@ -39,6 +39,7 @@ 
 
 #include <asm/init_helpers.h>
 #include <asm/init_wrappers.h>
+#include <initcall.h>
 
 /*
  * Breath some life into the board...
@@ -77,139 +78,6 @@ 
  *      - All remaining initialisation
  */
 
-/*
- * 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);
-
-/*
- * init_sequence_f is the list of init functions which are run when U-Boot
- * is executing from Flash with a limited 'C' environment. The following
- * limitations must be considered when implementing an '_f' function:
- *  - 'static' variables are read-only
- *  - Global Data (gd->xxx) is read/write
- *  - Stack space is limited
- *
- * The '_f' sequence must, as a minimum, initialise SDRAM. It _should_
- * also initialise the console (to provide early debug output)
- */
-init_fnc_t *init_sequence_f[] = {
-	cpu_init_f,
-	board_early_init_f,
-	env_init,
-	init_baudrate_f,
-	serial_init,
-	console_init_f,
-	dram_init_f,
-	calculate_relocation_address,
-
-	NULL,
-};
-
-/*
- * init_sequence_f_r is the list of init functions which are run when
- * U-Boot is executing from Flash with a semi-limited 'C' environment.
- * The following limitations must be considered when implementing an
- * '_f_r' function:
- *  - 'static' variables are read-only
- *  - Global Data (gd->xxx) is read/write
- *
- * The '_f_r' sequence must, as a minimum, copy U-Boot to RAM (if
- * supported).  It _should_, if possible, copy global data to RAM and
- * initialise the CPU caches (to speed up the relocation process)
- */
-init_fnc_t *init_sequence_f_r[] = {
-	copy_gd_to_ram_f_r,
-	init_cache_f_r,
-	copy_uboot_to_ram,
-	clear_bss,
-	do_elf_reloc_fixups,
-
-	NULL,
-};
-
-/*
- * init_sequence_r is the list of init functions which are run when U-Boot
- * is executing from RAM with a full 'C' environment. There are no longer
- * any limitations which must be considered when implementing an '_r'
- * function, (i.e.'static' variables are read/write)
- *
- * If not already done, the '_r' sequence must copy global data to RAM and
- * (should) initialise the CPU caches.
- */
-init_fnc_t *init_sequence_r[] = {
-	set_reloc_flag_r,
-	init_bd_struct_r,
-	mem_malloc_init_r,
-	cpu_init_r,
-	board_early_init_r,
-	dram_init,
-	interrupt_init,
-	timer_init,
-	display_banner,
-	display_dram_config,
-#ifdef CONFIG_SERIAL_MULTI
-	serial_initialize_r,
-#endif
-#ifndef CONFIG_SYS_NO_FLASH
-	flash_init_r,
-#endif
-	env_relocate_r,
-#ifdef CONFIG_CMD_NET
-	init_ip_address_r,
-#endif
-#ifdef CONFIG_PCI
-	pci_init_r,
-#endif
-	stdio_init,
-	jumptable_init_r,
-	console_init_r,
-#ifdef CONFIG_MISC_INIT_R
-	misc_init_r,
-#endif
-#if defined(CONFIG_CMD_PCMCIA) && !defined(CONFIG_CMD_IDE)
-	pci_init_r,
-#endif
-#if defined(CONFIG_CMD_KGDB)
-	kgdb_init_r,
-#endif
-	enable_interrupts_r,
-#ifdef CONFIG_STATUS_LED
-	status_led_set_r,
-#endif
-	set_load_addr_r,
-#if defined(CONFIG_CMD_NET)
-	set_bootfile_r,
-#endif
-#if defined(CONFIG_CMD_IDE)
-	ide_init_r,
-#endif
-#if defined(CONFIG_CMD_SCSI)
-	scsi_init_r,
-#endif
-#if defined(CONFIG_CMD_DOC)
-	doc_init_r,
-#endif
-#ifdef CONFIG_BITBANGMII
-	bb_miiphy_init_r,
-#endif
-#if defined(CONFIG_CMD_NET)
-	eth_initialize_r,
-#ifdef CONFIG_RESET_PHY_R
-	reset_phy_r,
-#endif
-#endif
-#ifdef CONFIG_GENERIC_MMC
-	mmc_initialize_r,
-#endif
-#ifdef CONFIG_LAST_STAGE_INIT
-	last_stage_init,
-#endif
-	NULL,
-};
-
 static void do_init_loop(init_fnc_t **init_fnc_ptr)
 {
 	for (; *init_fnc_ptr; ++init_fnc_ptr) {
diff --git a/arch/x86/lib/init_helpers.c b/arch/x86/lib/init_helpers.c
index 9f4dee0..f469e4a 100644
--- a/arch/x86/lib/init_helpers.c
+++ b/arch/x86/lib/init_helpers.c
@@ -50,6 +50,7 @@  int display_banner(void)
 
 	return 0;
 }
+INIT_FUNC(display_banner, banner, *RELOC serial_multi);
 
 int display_dram_config(void)
 {
@@ -64,12 +65,14 @@  int display_dram_config(void)
 
 	return 0;
 }
+INIT_FUNC(display_dram_config, display_dram, *dram_r banner serial_multi);
 
 int init_baudrate_f(void)
 {
 	gd->baudrate = getenv_ulong("baudrate", 10, CONFIG_BAUDRATE);
 	return 0;
 }
+INIT_FUNC(init_baudrate_f, baudrate_f, *env_init -SDRAM);
 
 int calculate_relocation_address(void)
 {
@@ -106,6 +109,7 @@  int calculate_relocation_address(void)
 
 	return 0;
 }
+INIT_FUNC(calculate_relocation_address, calc_reloc, *dram_f -SDRAM);
 
 int copy_gd_to_ram_f_r(void)
 {
@@ -131,12 +135,14 @@  int copy_gd_to_ram_f_r(void)
 
 	return 0;
 }
+INIT_FUNC(copy_gd_to_ram_f_r, copy_gd, *SDRAM -RELOC);
 
 int init_cache_f_r(void)
 {
 	/* Initialise the CPU cache(s) */
 	return init_cache();
 }
+INIT_FUNC(init_cache_f_r, cache_f_r, *copy_gd -RELOC);
 
 int set_reloc_flag_r(void)
 {
@@ -144,6 +150,7 @@  int set_reloc_flag_r(void)
 
 	return 0;
 }
+INIT_FUNC(set_reloc_flag_r, reloc_flag, *RELOC);
 
 int mem_malloc_init_r(void)
 {
@@ -152,6 +159,7 @@  int mem_malloc_init_r(void)
 
 	return 0;
 }
+INIT_FUNC(mem_malloc_init_r, malloc, *bd_struct);
 
 bd_t bd_data;
 
@@ -162,6 +170,7 @@  int init_bd_struct_r(void)
 
 	return 0;
 }
+INIT_FUNC(init_bd_struct_r, bd_struct, *reloc_flag);
 
 #ifndef CONFIG_SYS_NO_FLASH
 int flash_init_r(void)
@@ -177,6 +186,7 @@  int flash_init_r(void)
 
 	return 0;
 }
+INIT_FUNC(flash_init_r, flash_r, *RELOC);
 #endif
 
 int init_ip_address_r(void)
@@ -186,6 +196,7 @@  int init_ip_address_r(void)
 
 	return 0;
 }
+INIT_FUNC(init_ip_address_r, ip_address, *env_reloc);
 
 #ifdef CONFIG_STATUS_LED
 int status_led_set_r(void)
@@ -194,6 +205,7 @@  int status_led_set_r(void)
 
 	return 0;
 }
+INIT_FUNC(status_led_set_r, status_led, *RELOC gpio);
 #endif
 
 int set_bootfile_r(void)
@@ -207,6 +219,7 @@  int set_bootfile_r(void)
 
 	return 0;
 }
+INIT_FUNC(set_bootfile_r, bootfile, *env_reloc);
 
 int set_load_addr_r(void)
 {
@@ -215,3 +228,4 @@  int set_load_addr_r(void)
 
 	return 0;
 }
+INIT_FUNC(set_load_addr_r, load_addr, *env_reloc);
diff --git a/arch/x86/lib/init_wrappers.c b/arch/x86/lib/init_wrappers.c
index adee8a4..893b0b9 100644
--- a/arch/x86/lib/init_wrappers.c
+++ b/arch/x86/lib/init_wrappers.c
@@ -36,6 +36,7 @@  int serial_initialize_r(void)
 
 	return 0;
 }
+INIT_FUNC(serial_initialize_r, serial_multi, *RELOC);
 
 int env_relocate_r(void)
 {
@@ -44,6 +45,7 @@  int env_relocate_r(void)
 
 	return 0;
 }
+INIT_FUNC(env_relocate_r, env_reloc, *RELOC *env_init);
 
 
 int pci_init_r(void)
@@ -53,6 +55,7 @@  int pci_init_r(void)
 
 	return 0;
 }
+INIT_FUNC(pci_init_r, pci, *cpu_r);
 
 int jumptable_init_r(void)
 {
@@ -60,6 +63,7 @@  int jumptable_init_r(void)
 
 	return 0;
 }
+INIT_FUNC(jumptable_init_r, jumptable, *malloc);
 
 int pcmcia_init_r(void)
 {
@@ -76,6 +80,7 @@  int kgdb_init_r(void)
 
 	return 0;
 }
+INIT_FUNC(kgdb_init_r, kgdb, *std_io *exceptions -enable_interrupts);
 
 int enable_interrupts_r(void)
 {
@@ -84,6 +89,7 @@  int enable_interrupts_r(void)
 
 	return 0;
 }
+INIT_FUNC(enable_interrupts_r, enable_interrupts, *interrupts);
 
 int eth_initialize_r(void)
 {
@@ -92,6 +98,7 @@  int eth_initialize_r(void)
 
 	return 0;
 }
+INIT_FUNC(eth_initialize_r, eth, *pci);
 
 int reset_phy_r(void)
 {
@@ -102,6 +109,7 @@  int reset_phy_r(void)
 
 	return 0;
 }
+INIT_FUNC(reset_phy_r, phy_reset, *eth);
 
 int ide_init_r(void)
 {
@@ -110,6 +118,7 @@  int ide_init_r(void)
 
 	return 0;
 }
+INIT_FUNC(ide_init_r, ide, *env_reloc pci);
 
 int scsi_init_r(void)
 {
@@ -118,6 +127,7 @@  int scsi_init_r(void)
 
 	return 0;
 }
+INIT_FUNC(scsi_init_r, scsi, *env_reloc pci);
 
 #ifdef CONFIG_BITBANGMII
 int bb_miiphy_init_r(void)
@@ -126,6 +136,7 @@  int bb_miiphy_init_r(void)
 
 	return 0;
 }
+INIT_FUNC(bb_miiphy_init_r, bb_miiphy, *RELOC);
 #endif
 
 #ifdef CONFIG_POST
diff --git a/arch/x86/lib/relocate.c b/arch/x86/lib/relocate.c
index 200baab..3c7fa79 100644
--- a/arch/x86/lib/relocate.c
+++ b/arch/x86/lib/relocate.c
@@ -45,6 +45,7 @@  int copy_uboot_to_ram(void)
 
 	return 0;
 }
+INIT_FUNC(copy_uboot_to_ram, copy_to_ram, *SDRAM +cache_f_r -RELOC);
 
 int clear_bss(void)
 {
@@ -55,6 +56,7 @@  int clear_bss(void)
 
 	return 0;
 }
+INIT_FUNC(clear_bss, clear_bss, *SDRAM +copy_to_ram -RELOC);
 
 int do_elf_reloc_fixups(void)
 {
@@ -89,3 +91,4 @@  int do_elf_reloc_fixups(void)
 
 	return 0;
 }
+INIT_FUNC(do_elf_reloc_fixups, elf_reloc, *copy_to_ram -RELOC);
diff --git a/board/amirix/ap1000/serial.c b/board/amirix/ap1000/serial.c
index 87003be..8f3bf6c 100644
--- a/board/amirix/ap1000/serial.c
+++ b/board/amirix/ap1000/serial.c
@@ -45,6 +45,7 @@  int serial_init (void)
 
 	return 0;
 }
+INIT_FUNC(serial_init, serial_f, *baudrate_f -SDRAM);
 
 void serial_putc (const char c)
 {
diff --git a/board/bmw/serial.c b/board/bmw/serial.c
index 0c97f12..f73a8f7 100644
--- a/board/bmw/serial.c
+++ b/board/bmw/serial.c
@@ -46,6 +46,7 @@  int serial_init (void)
 
 	return (0);
 }
+INIT_FUNC(serial_init, serial_f, *baudrate_f -SDRAM);
 
 void serial_putc (const char c)
 {
diff --git a/board/eNET/eNET.c b/board/eNET/eNET.c
index 429fe1b..3caee71 100644
--- a/board/eNET/eNET.c
+++ b/board/eNET/eNET.c
@@ -106,6 +106,7 @@  int board_early_init_f(void)
 
 	return 0;
 }
+INIT_FUNC(board_early_init_f, board_early_f, *cpu_f -SDRAM);
 
 static void enet_setup_pars(void)
 {
@@ -161,6 +162,7 @@  int board_early_init_r(void)
 
 	return 0;
 }
+INIT_FUNC(board_early_init_r, board_early_r, *interrupts -pci);
 
 void show_boot_progress(int val)
 {
@@ -191,6 +193,7 @@  int last_stage_init(void)
 
 	return 0;
 }
+INIT_FUNC(last_stage_init, last_stage, **);
 
 ulong board_flash_get_legacy(ulong base, int banknum, flash_info_t *info)
 {
diff --git a/common/console.c b/common/console.c
index 1d9fd7f..831eaa7 100644
--- a/common/console.c
+++ b/common/console.c
@@ -596,6 +596,7 @@  int console_init_f(void)
 
 	return 0;
 }
+INIT_FUNC(console_init_f, console_f, *serial_f -SDRAM);
 
 void stdio_print_current_devices(void)
 {
@@ -783,5 +784,6 @@  int console_init_r(void)
 
 	return 0;
 }
+INIT_FUNC(console_init_r, console_r, *std_io);
 
 #endif /* CONFIG_SYS_CONSOLE_IS_IN_ENV */
diff --git a/common/env_dataflash.c b/common/env_dataflash.c
index 3c5af37..8fe4379 100644
--- a/common/env_dataflash.c
+++ b/common/env_dataflash.c
@@ -114,3 +114,4 @@  int env_init(void)
 
 	return 0;
 }
+INIT_FUNC(env_init, env_init, *board_early_f -SDRAM);
diff --git a/common/env_eeprom.c b/common/env_eeprom.c
index b66bba2..855c378 100644
--- a/common/env_eeprom.c
+++ b/common/env_eeprom.c
@@ -289,3 +289,4 @@  int env_init(void)
 	return 0;
 }
 #endif
+INIT_FUNC(env_init, env_init, *board_early_f -SDRAM);
diff --git a/common/env_flash.c b/common/env_flash.c
index aa970d4..4f84cd3 100644
--- a/common/env_flash.c
+++ b/common/env_flash.c
@@ -240,6 +240,7 @@  int env_init(void)
 	gd->env_valid	= 0;
 	return 0;
 }
+INIT_FUNC(env_init, env_init, *board_early_f -SDRAM);
 
 #ifdef CMD_SAVEENV
 int saveenv(void)
diff --git a/common/env_mgdisk.c b/common/env_mgdisk.c
index d00e141..d6209f7 100644
--- a/common/env_mgdisk.c
+++ b/common/env_mgdisk.c
@@ -74,3 +74,4 @@  int env_init(void)
 
 	return 0;
 }
+INIT_FUNC(env_init, env_init, *board_early_f -SDRAM);
diff --git a/common/env_mmc.c b/common/env_mmc.c
index 0c58ae1..7722593 100644
--- a/common/env_mmc.c
+++ b/common/env_mmc.c
@@ -62,6 +62,7 @@  int env_init(void)
 
 	return 0;
 }
+INIT_FUNC(env_init, env_init, *board_early_f -SDRAM);
 
 static int init_mmc_for_env(struct mmc *mmc)
 {
diff --git a/common/env_nand.c b/common/env_nand.c
index e8daec9..d88ad09 100644
--- a/common/env_nand.c
+++ b/common/env_nand.c
@@ -134,6 +134,7 @@  int env_init(void)
 
 	return 0;
 }
+INIT_FUNC(env_init, env_init, *board_early_f -SDRAM);
 
 #ifdef CMD_SAVEENV
 /*
diff --git a/common/env_nowhere.c b/common/env_nowhere.c
index 18fcf2c..dce854a 100644
--- a/common/env_nowhere.c
+++ b/common/env_nowhere.c
@@ -49,3 +49,4 @@  int env_init(void)
 
 	return 0;
 }
+INIT_FUNC(env_init, env_init, *board_early_f -SDRAM);
diff --git a/common/env_nvram.c b/common/env_nvram.c
index 6483db3..1e998bb 100644
--- a/common/env_nvram.c
+++ b/common/env_nvram.c
@@ -134,3 +134,4 @@  int env_init(void)
 
 	return 0;
 }
+INIT_FUNC(env_init, env_init, *board_early_f -SDRAM);
diff --git a/common/env_onenand.c b/common/env_onenand.c
index 652665a..5e17a87 100644
--- a/common/env_onenand.c
+++ b/common/env_onenand.c
@@ -135,3 +135,4 @@  int env_init(void)
 
 	return 0;
 }
+INIT_FUNC(env_init, env_init, *board_early_f -SDRAM);
diff --git a/common/env_sf.c b/common/env_sf.c
index bbd472f..b455ed5 100644
--- a/common/env_sf.c
+++ b/common/env_sf.c
@@ -349,3 +349,4 @@  int env_init(void)
 
 	return 0;
 }
+INIT_FUNC(env_init, env_init, *board_early_f -SDRAM);
diff --git a/common/serial.c b/common/serial.c
index 75cc1bb..39bd931 100644
--- a/common/serial.c
+++ b/common/serial.c
@@ -190,6 +190,7 @@  int serial_init(void)
 {
 	return get_current()->init();
 }
+INIT_FUNC(serial_init, serial_f, *baudrate_f -SDRAM);
 
 void serial_setbrg(void)
 {
diff --git a/common/stdio.c b/common/stdio.c
index 1bf9ba0..81d3f21 100644
--- a/common/stdio.c
+++ b/common/stdio.c
@@ -242,3 +242,4 @@  int stdio_init (void)
 
 	return (0);
 }
+INIT_FUNC(stdio_init, std_io, *env_reloc serial_multi);
diff --git a/config.mk b/config.mk
index ddaa477..d781195 100644
--- a/config.mk
+++ b/config.mk
@@ -254,6 +254,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..b545390
--- /dev/null
+++ b/doc/README.INIT_FUNC
@@ -0,0 +1,31 @@ 
+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
+
+The format of the INIT_FUNC macro is:
+
+INIT_FUNC({function_name}, {init_class}, {prerequisite init_class(es)})
+
+{function_name} 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
+
+{init_class} is a simple test string to describe the basic purpose of the init
+function. Multiple init functions may share the same init_class string
+
+{prerequisite init_class(es)} is a list of init_class strings (see above) which
+defines what init functions are executed before and after the given init
+function. Each prerequisite init_class is seperated by a space and preceeded by
+either:
+ * - At least one function of this init class must exist (i.e. there must be at
+     least one INIT_FUNC entry with {init_class} set to the init class named
+     after the '*' - All init functions with an init class matching the class
+     named after the '*' will be executed before this function
+ + - All init functions with an init class matching the class named after the
+     '+' will be executed before this function, but there does not need to be
+     any functions with the named init class in the init sequence
+ - - This function will be called before any other functions with the init
+     class named after the '-'
diff --git a/include/initcall.h b/include/initcall.h
new file mode 100644
index 0000000..a81cf21
--- /dev/null
+++ b/include/initcall.h
@@ -0,0 +1,19 @@ 
+#ifndef __INIT_CALL_H__
+#define __INIT_CALL_H__
+#include <linux/compiler.h>
+#define INIT_FUNC(fn, init_name, deps) \
+	static const char __init_func_ ## fn[] __used \
+	__attribute__((__section__(".initfuncs"))) = \
+	"(" #fn ":" #init_name ";" #deps ")\n";
+
+#define SKIP_INIT(init_name) \
+	static const char __skip_init_ ## req[] __used \
+	__attribute__((__section__(".initfuncs"))) = \
+	"{" #init_name "}\n";
+
+#define REPLACE_INIT(old_func, new_func) \
+	static const char __replace_init_ ## old_func[] __used \
+	__attribute__((__section__(".initfuncs"))) = \
+	"[" #old_func "," #new_func "]\n";
+
+#endif /* !__INIT_CALL_H__ */
diff --git a/tools/Makefile b/tools/Makefile
index 64bcc4d..20afcef 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-y += mkinitseq$(SFX)
 BIN_FILES-$(CONFIG_MX28) += mxsboot$(SFX)
 BIN_FILES-$(CONFIG_NETCONSOLE) += ncb$(SFX)
 BIN_FILES-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1$(SFX)
@@ -94,6 +95,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-y += mkinitseq.o
 OBJ_FILES-$(CONFIG_MX28) += mxsboot.o
 OBJ_FILES-$(CONFIG_NETCONSOLE) += ncb.o
 NOPED_OBJ_FILES-y += os_support.o
@@ -213,6 +215,10 @@  $(obj)mkimage$(SFX):	$(obj)aisimage.o \
 	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
 	$(HOSTSTRIP) $@
 
+$(obj)mkinitseq$(SFX):	$(obj)mkinitseq.o
+	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+	$(HOSTSTRIP) $@
+
 $(obj)mpc86x_clk$(SFX):	$(obj)mpc86x_clk.o
 	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
 	$(HOSTSTRIP) $@
diff --git a/tools/mkinitseq.c b/tools/mkinitseq.c
new file mode 100644
index 0000000..1ee7d4c
--- /dev/null
+++ b/tools/mkinitseq.c
@@ -0,0 +1,278 @@ 
+/*
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2009
+ * DENX Software Engineering
+ * Wolfgang Denk, wd@denx.de
+ *
+ * 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 "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>
+
+#undef MKINITSEQ_DEBUG
+
+#ifdef MKINITSEQ_DEBUG
+#define debug(fmt,args...)	printf (fmt ,##args)
+#else
+#define debug(fmt,args...)
+#endif /* MKINITSEQ_DEBUG */
+
+#include <version.h>
+
+enum INIT_DEP_TYPE {
+	none,
+	pre_req_mandatory,
+	pre_req_optional,
+	post_req
+};
+
+struct init_dep {
+	struct list_head list;
+
+	enum INIT_DEP_TYPE dep_type;
+	char *init_id;
+};
+
+struct init_function {
+	struct list_head list;
+	char *function_name;
+	char *init_id;
+	struct init_dep deps;
+};
+
+
+static struct init_dep *create_init_dep(unsigned char *ptr,
+					int dep_id_start,
+					int dep_id_end,
+					enum INIT_DEP_TYPE dep_type)
+{
+	struct init_dep *tmp_dep;
+
+	tmp_dep = (struct init_dep *)malloc(sizeof(struct init_dep));
+
+	tmp_dep->dep_type = dep_type;
+
+	tmp_dep->init_id = (char *)malloc(dep_id_end - dep_id_start + 2);
+	memcpy(tmp_dep->init_id, &ptr[dep_id_start], dep_id_end - dep_id_start + 2);
+	tmp_dep->init_id[dep_id_end - dep_id_start + 1] = 0x00;
+
+	switch(dep_type) {
+	case pre_req_mandatory:
+		printf("Found Mandatory Pre-Req.: %s\n", tmp_dep->init_id);
+		break;
+
+	case pre_req_optional:
+		printf("Found Optional Pre-Req.: %s\n", tmp_dep->init_id);
+		break;
+
+	case post_req:
+		printf("Found Post Pre-Req.: %s\n", tmp_dep->init_id);
+		break;
+
+	case none:
+		printf("No dep type: %s\n", tmp_dep->init_id);
+		break;
+	}
+
+	return tmp_dep;
+}
+
+
+int main (int argc, char **argv)
+{
+	int init_funcs;
+	struct stat sbuf;
+	unsigned char *ptr;
+	int i;
+
+	printf("Generating init sequence from %s\n", argv[1]);
+
+	if ((init_funcs = open(argv[1], O_RDONLY|O_BINARY)) < 0) {
+		fprintf (stderr, "%s: Can't open %s: %s\n",
+			 argv[0], argv[1], strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	if (fstat(init_funcs, &sbuf) < 0) {
+		fprintf (stderr, "%s: Can't stat %s: %s\n",
+			 argv[0], argv[1], strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, init_funcs, 0);
+	if (ptr == MAP_FAILED) {
+		fprintf (stderr, "%s: Can't read %s: %s\n",
+			 argv[0], argv[1], strerror(errno));
+		exit (EXIT_FAILURE);
+	}
+
+	struct init_function init_functions;
+	INIT_LIST_HEAD(&init_functions.list);
+
+	int function_name_start = 0;
+	int function_name_end = 0;
+	int init_id_start = 0;
+	int init_id_end = 0;
+	struct init_function *tmp;
+	struct init_dep *tmp_dep;
+	enum INIT_DEP_TYPE dep_type = none;
+	int dep_id_start = -1;
+	int dep_id_end = -1;
+	int mandatory_dep_found = -1;
+
+	for(i = 0; i < sbuf.st_size; i++) {
+
+//		if(ptr[i])
+//			printf("%c", ptr[i]);
+
+		switch(ptr[i]) {
+		case '(':
+			function_name_start = i + 1;
+			break;
+		case ':':
+			function_name_end = i - 1;
+			init_id_start = i + 1;
+			break;
+		case ';':
+			init_id_end = i - 1;
+			tmp = (struct init_function *)malloc(sizeof(struct init_function));
+
+			INIT_LIST_HEAD(&tmp->deps.list);
+
+			tmp->function_name = (char *)malloc(function_name_end - function_name_start + 2);
+			memcpy(tmp->function_name, &ptr[function_name_start], function_name_end - function_name_start + 2);
+			tmp->function_name[function_name_end - function_name_start + 1] = 0x00;
+
+			tmp->init_id = (char *)malloc(init_id_end - init_id_start + 2);
+			memcpy(tmp->init_id, &ptr[init_id_start], init_id_end - init_id_start + 2);
+			tmp->init_id[init_id_end - init_id_start + 1] = 0x00;
+
+			printf("Found function: %s, ID: %s\n", tmp->function_name, tmp->init_id);
+			list_add(&(tmp->list), &(init_functions.list));
+			break;
+
+		case '*':
+			if(dep_id_start > 0) {
+				dep_id_end = i - 1;
+
+				while(ptr[dep_id_end] == ' ')
+					dep_id_end--;
+
+				tmp_dep = create_init_dep(ptr, dep_id_start, dep_id_end, dep_type);
+
+				if(dep_type == pre_req_mandatory)
+					mandatory_dep_found = 1;
+
+				list_add(&(tmp_dep->list), &(tmp->deps.list));
+
+			}
+
+			dep_type = pre_req_mandatory;
+			dep_id_start = i + 1;
+
+			while(ptr[dep_id_start] == ' ')
+				dep_id_start++;
+
+			break;
+
+		case '+':
+			if(dep_id_start > 0) {
+				dep_id_end = i - 1;
+
+				while(ptr[dep_id_end] == ' ')
+					dep_id_end--;
+
+				tmp_dep = create_init_dep(ptr, dep_id_start, dep_id_end, dep_type);
+
+				if(dep_type == pre_req_mandatory)
+					mandatory_dep_found = 1;
+
+				list_add(&(tmp_dep->list), &(tmp->deps.list));
+
+			}
+
+			dep_type = pre_req_optional;
+			dep_id_start = i + 1;
+			break;
+
+		case '-':
+			if(dep_id_start > 0) {
+				dep_id_end = i - 1;
+
+				while(ptr[dep_id_end] == ' ')
+					dep_id_end--;
+
+				tmp_dep = create_init_dep(ptr, dep_id_start, dep_id_end, dep_type);
+
+				if(dep_type == pre_req_mandatory)
+					mandatory_dep_found = 1;
+
+				list_add(&(tmp_dep->list), &(tmp->deps.list));
+
+			}
+
+			dep_type = post_req;
+			dep_id_start = i + 1;
+			break;
+
+		case ')':
+			if(dep_id_start > 0) {
+				dep_id_end = i - 1;
+
+				while(ptr[dep_id_end] == ' ')
+					dep_id_end--;
+
+				tmp_dep = create_init_dep(ptr, dep_id_start, dep_id_end, dep_type);
+
+				if(dep_type == pre_req_mandatory)
+					mandatory_dep_found = 1;
+
+				list_add(&(tmp_dep->list), &(tmp->deps.list));
+
+				if(mandatory_dep_found < 0)
+					printf("Error: No mandatory dependencies specified\n");
+
+			} else {
+				printf("Error: No dependencies specified\n");
+
+			}
+
+			mandatory_dep_found = -1;
+			dep_id_start = -1;
+			tmp = NULL;
+			break;
+
+		default:
+			break;
+		}
+	}
+
+
+
+	(void) munmap((void *)ptr, sbuf.st_size);
+	(void) close (init_funcs);
+	exit (EXIT_SUCCESS);
+}
diff --git a/u-boot-init.lds b/u-boot-init.lds
new file mode 100644
index 0000000..aca6c92
--- /dev/null
+++ b/u-boot-init.lds
@@ -0,0 +1,25 @@ 
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+SECTIONS
+{
+
+ .initfuncs : { KEEP(*(.initfuncs*)) }
+
+ /DISCARD/ : { *(.text*) }
+ /DISCARD/ : { *(.debug*) }
+ /DISCARD/ : { *(.u_boot_cmd*) }
+ /DISCARD/ : { *(.rodata*) }
+ /DISCARD/ : { *(.data*) }
+ /DISCARD/ : { *(.dynsym*) }
+ /DISCARD/ : { *(.hash*) }
+ /DISCARD/ : { *(.bss*) }
+ /DISCARD/ : { *(.bss) }
+ /DISCARD/ : { *(.rel.dyn*) }
+ /DISCARD/ : { *(.rel.dyn) }
+ /DISCARD/ : { *(.dynstr*) }
+ /DISCARD/ : { *(.dynamic*) }
+ /DISCARD/ : { *(.plt*) }
+ /DISCARD/ : { *(.interp*) }
+ /DISCARD/ : { *(.gnu*) }
+ /DISCARD/ : { *(.comment*) }
+}