diff --git a/Makefile b/Makefile
index 5e8c93171f8f4663be45cd1d3015de76c87f27e2..b28f52b4cfcb48e7376a0fad915627de7c082522 100644
--- a/Makefile
+++ b/Makefile
@@ -307,7 +307,8 @@ export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_ve
 # Files to ignore in find ... statements
 
 export RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o    \
-			  -name CVS -o -name .pc -o -name .hg -o -name .git \) \
+			  -name CVS -o -name .pc -o -name .hg -o -name .git    \
+			  -o -name sysroot \) \
 			  -prune -o
 export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn \
 			 --exclude CVS --exclude .pc --exclude .hg --exclude .git
@@ -587,6 +588,7 @@ core-y		:= arch/$(SRCARCH)/
 kernel-y	:= kernel/
 init-y		:= init/
 libs-y		:= lib/
+xentium-y	:= dsp/	# this should be CONFIG_XENTIUM_WHATEVER
 
 -include arch/$(ARCH)/Makefile
 
@@ -594,7 +596,8 @@ leanos-dirs	:= $(patsubst %/,%,$(filter %/, \
 		     $(init-y) \
 		     $(core-y) \
 		     $(kernel-y) \
-		     $(libs-y)))
+		     $(libs-y)) \
+		     $(xentium-y))
 #
 leanos-core	:= $(patsubst %/, %/built-in.o, $(core-y))
 leanos-kernel	:= $(patsubst %/, %/built-in.o, $(kernel-y))
diff --git a/dsp/Kbuild b/dsp/Kbuild
new file mode 100644
index 0000000000000000000000000000000000000000..17577dca6794bd748735190445e1af8b52c74aee
--- /dev/null
+++ b/dsp/Kbuild
@@ -0,0 +1 @@
+obj-y += xentium/
diff --git a/dsp/xentium/Makefile b/dsp/xentium/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..d0d66f8195a1b25f05042c480d9a8b4a76b2f600
--- /dev/null
+++ b/dsp/xentium/Makefile
@@ -0,0 +1,50 @@
+# we just hijack the host build system because it's the easiest way...
+#
+# Xentium kernels are built as executables, with library functions
+# explicitly listed as object dependencies. The executables are later collected
+# in scripts/link-leanos.sh and added to the embedded AR image.
+#
+# The address of the .text section for the first xentium kernel is determined
+# by the confiuration in dsp/xentium/sysroot/lib/default.ld, all subsequent
+# programs will start after the _end symbol of the previous
+#
+# To achieve this, list dsp kernel targets in hostprogs-y and configure targets
+# so that the next target depends on the finalised previous target and take
+# the value of the _end symbol as the new .text start
+#
+# This isn't a pretty solution, but that's what you get for not supporting
+# relocations. It works for now and it is at least slightly more comfortable
+# than configuring all text base addresses by hand
+#
+
+
+obj- := dummy.o
+
+
+HOSTCC := xentium-clang
+HOSTLD := xentium-ld
+
+HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -Idsp/xentium
+	     
+HOSTLDFLAGS += -Tdsp/xentium/sysroot/lib/default.ld
+HOSTLDFLAGS += --sysroot=dsp/xentium/sysroot
+
+
+hostprogs-y := testkernel.xen
+hostprogs-y += otherkernel.xen
+
+
+
+testkernelkernel.xen :
+HOSTLOADLIBES_testkernel.xen := 
+testkernel.xen-objs := testkernel.o xen_printf.o
+
+
+otherkernel.xen : testkernel.xen
+HOSTLOADLIBES_otherkernel.xen := -Ttext $$(readelf -s dsp/xentium/testkernel.xen|grep -w _end |awk '{print $$2}') 
+otherkernel.xen-objs := testkernel.o xen_printf.o
+
+
+
+
+always := $(hostprogs-y)
diff --git a/dsp/xentium/README b/dsp/xentium/README
new file mode 100644
index 0000000000000000000000000000000000000000..bd108042b6453018a1f374b983b88c0ab79d1627
--- /dev/null
+++ b/dsp/xentium/README
@@ -0,0 +1,4 @@
+
+WARNING
+
+the LD script is likely fucking us with the set up of the stack pointer, need to address this...
diff --git a/dsp/xentium/sysroot/lib/crt0.o b/dsp/xentium/sysroot/lib/crt0.o
new file mode 100755
index 0000000000000000000000000000000000000000..ae40b61eda71a5b802dc71cbd418a3cfde22ba17
Binary files /dev/null and b/dsp/xentium/sysroot/lib/crt0.o differ
diff --git a/dsp/xentium/sysroot/lib/default.ld b/dsp/xentium/sysroot/lib/default.ld
new file mode 100755
index 0000000000000000000000000000000000000000..eff9376464fba92f18bfdc967876c1db126287b6
--- /dev/null
+++ b/dsp/xentium/sysroot/lib/default.ld
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2011, Recore Systems B.V., The Netherlands,
+ * web: www.recoresystems.com, email: info@recoresystems.com
+ *
+ * Any reproduction in whole or in parts is prohibited
+ * without the written consent of the copyright owner.
+ *
+ * All Rights Reserved.
+ */
+
+STARTUP(crt0.o)
+INPUT(-lc -lcompiler_rt)
+
+OUTPUT_FORMAT("elf32-xentium")
+OUTPUT_ARCH(xentium)
+ENTRY(_start)
+
+_MINIMUM_STACK_SIZE = 1K;
+
+MEMORY
+{
+  dbank0 : ORIGIN = 0x00000000, LENGTH = 8K
+  dbank1 : ORIGIN = 0x00002000, LENGTH = 8K
+  dbank2 : ORIGIN = 0x00004000, LENGTH = 8K
+  dbank3 : ORIGIN = 0x00006000, LENGTH = 8K
+  ram    : ORIGIN = 0x50000000, LENGTH = 256M
+}
+
+PHDRS
+{
+  code    PT_LOAD;
+  data    PT_LOAD;
+  tcm     PT_LOAD;
+}
+
+SECTIONS
+{
+  /* RAM code and data */
+  .text : {
+    *(.text)
+    . = ALIGN(16*4) ; /* Align to the next cache line boundary */
+  } > ram : code
+  .rodata ALIGN(0x40) : {
+    *(.rodata .rodata.*)
+    . = ALIGN(4) ;
+  } > ram : data
+  .data ALIGN(0x40) : {
+    *(.data)
+    . = ALIGN(4) ;
+  } > ram : data
+  .bss ALIGN(0x40) : {
+   __bss_start = .;
+    *(.bss)
+    . = ALIGN(4) ;
+  } > ram : data
+  _end = __bss_start + SIZEOF(.bss);
+
+  /* TCM */
+  .dbank0        ORIGIN(dbank0)      : { *(.dbank0) }        > dbank0 : tcm
+  .dbank0_noinit ALIGN(0x4) (NOLOAD) : { *(.dbank0_noinit) } > dbank0 : tcm
+  .dbank1        ORIGIN(dbank1)      : { *(.dbank1) }        > dbank1 : tcm
+  .dbank1_noinit ALIGN(0x4) (NOLOAD) : { *(.dbank1_noinit) } > dbank1 : tcm
+  .dbank2        ORIGIN(dbank2)      : { *(.dbank2) }        > dbank2 : tcm
+  .dbank2_noinit ALIGN(0x4) (NOLOAD) : { *(.dbank2_noinit) } > dbank2 : tcm
+  .dbank3        ORIGIN(dbank3)      : { *(.dbank3) }        > dbank3 : tcm
+  .dbank3_noinit ALIGN(0x4) (NOLOAD) : { *(.dbank3_noinit) } > dbank3 : tcm
+
+  /*
+   * Set the stack pointer to top of data bank 3 or top of the RAM depending on
+   * the available space in data bank 3.
+   */
+  _remaining_db3 = (LENGTH(dbank3) - SIZEOF(.dbank3) - SIZEOF(.dbank3_noinit));
+  _top_db3       = ORIGIN(dbank3)+LENGTH(dbank3);
+  _top_ram       = ORIGIN(ram)+LENGTH(ram);
+  _stack         = (_remaining_db3 > _MINIMUM_STACK_SIZE) ? _top_db3 : _top_ram;
+
+  /* Check that there is enough space in the RAM for the stack */
+  _remaining_ram = (LENGTH(ram) - (_end - _start));
+  ASSERT(_remaining_ram > 0, "The stack does not fit in ram")
+}
diff --git a/dsp/xentium/sysroot/lib/libc.a b/dsp/xentium/sysroot/lib/libc.a
new file mode 100755
index 0000000000000000000000000000000000000000..febfa931cba74a4777b9dd441881099201fccd51
Binary files /dev/null and b/dsp/xentium/sysroot/lib/libc.a differ
diff --git a/dsp/xentium/sysroot/src/crt0.s b/dsp/xentium/sysroot/src/crt0.s
new file mode 100755
index 0000000000000000000000000000000000000000..e722bc29a46891b34fc05f481b1c008de3e24029
--- /dev/null
+++ b/dsp/xentium/sysroot/src/crt0.s
@@ -0,0 +1,118 @@
+%define SYS_argvlen	12
+%define SYS_argv	13
+
+  .file "crt0.s"
+  .text
+  .globl _start
+  .align 4
+  .type _start,@function
+_start:
+  ; Start by setting up a stack.
+  A0 OR 0, hi16(_stack)           ; The linker script specifies the address
+                                  ; where the stack should start with the
+                                  ; _stack symbol. Get the high part of it
+                                  ; on A0X...
+
+  A0 OR A0X, lo16(_stack)         ; or in the low part...
+
+  RA14 = A0X                      ; and assign it to the stack pointer register
+                                  ; (RA14).
+
+  ; Now that we have a stack we can start using function calls if needed.
+
+  A0 ADD RA14, -4                 ; Decrement stack pointer.
+  C0 LINK                         ; Get return address.
+
+  RA14 = A0X
+  E0 STW A0X[0], C0X              ; Store return address in the stack.
+
+  ; Zero the memory in the .bss section.
+  A0 OR 0, hi16(__bss_start)      ; The linker script specifies the address
+                                  ; where the .bss section should start with
+                                  ; the __bss_start symbol. Get the high part
+                                  ; of it on A0X.
+  S0 OR 0, hi16(_end)             ; The linker script specifies the address
+                                  ; where the .bss section should end with
+                                  ; the _end symbol. Get the high part
+                                  ; of it on S0X.
+
+  A0 OR A0X, lo16(__bss_start)    ; Or the low part of the address of the
+                                  ; __bss_start symbol into the high part
+                                  ; already on A0X.
+  S0 OR S0X, lo16(_end)           ; Or the low part of the address of the
+                                  ; _end symbol into the high part already on
+                                  ; S0X.
+
+; This commented out section of code uses the memset function to do the actual
+; zeroing of the .bss section. If we have an optimized implementation of the
+; memset function we might want to use this instead of the code below.
+; Currently however it just makes the executable bigger.
+;
+;  RA6 = A0X                       ; The first parameter of the memset function
+;                                  ; is the pointer to the block of memory to
+;                                  ; fill. Set it to the address the .bss
+;                                  ; section (__bss_start).
+;  A0 SUB S0X, A0X                 ; Calculate the size of the .bss section
+;                                  ; (_end - __bss_start)
+;
+;  RB6 = 0                         ; The second parameter of the memset function
+;                                  ; is the value the block of memory should be
+;                                  ; set to. Set it to 0.
+;  RC6 = A0X                       ; The third parameter of the memset function
+;                                  ; is the number of bytes to set. Set it to
+;                                  ; the size of the .bss section we just
+;                                  ; calculated.
+;
+;  C0 BR memset                    ; Call the memset function to do the actual
+;                                  ; zeroing.
+;
+;  NOP 2
+;
+
+  P0 CMPLTU A0X, S0X               ; Check if current address in .bss,
+                                   ; __bss_start, (A0X) is less than _end (S0X).
+
+  C0 BRZ P0X, .L2                  ; If it is not, the size of .bss is 0, so no
+                                   ; need to initialize .bss. Jump over the
+                                   ; .bss initialization loop.
+
+  NOP 2
+
+  ; Begin .bss initialization loop
+.L1:
+  E0 STB A0X[0], 0                 ; Write 0 to current address in .bss.
+  A0 ADD A0X, 1                    ; Increment current address in .bss
+
+  P0 CMPLTU A0X, S0X               ; Check if new current address in .bss is
+                                   ; still less than _end.
+
+  C0 BRNZ P0X, .L1                 ; If it is jump back to the beginning of the
+                                   ; .bss initialization loop.
+
+  NOP 2
+
+  ; End .bss initialization loop/
+
+  ; Initialisation for calls to main with arguments
+  ; from the command line
+.L2:
+	C0 TRAP SYS_argvlen
+
+	C0 TRAP SYS_argv
+
+.L3:
+  C0 BR main                      ; Call the main function.
+
+  NOP 2
+
+  E0 LDW RA14[0]
+  A0 ADD RA14, +4
+
+  RA14 = A0X
+
+  C0 BRA E0X                      ; Jump back to the MPPB Xentium bootloader.
+
+  NOP 2
+
+.Ltmp0:
+  .size _start, .Ltmp0-_start
diff --git a/include/kernel/ar.h b/include/kernel/ar.h
index 44fe2bcf376ece7a7d8eb54d0c5c47f29889832d..cb37e4bd107f1db02e532745aa05e428f3f41f11 100644
--- a/include/kernel/ar.h
+++ b/include/kernel/ar.h
@@ -44,8 +44,11 @@ struct archive {
 };
 
 
-void ar_list_files(struct archive *a);
-void ar_list_symbols(struct archive *a);
+void ar_print_files(struct archive *a);
+void ar_print_symbols(struct archive *a);
+
+char *ar_get_file_list(struct archive *a);
+
 void *ar_find_file(struct archive *a, const char *name);
 void *ar_find_symbol(struct archive *a, const char *name);
 void ar_free(struct archive *a);
diff --git a/include/kernel/string.h b/include/kernel/string.h
index c006b7815c56af586d206b8664da10cff88b5661..26825fae3082717b1b1876ce62a8564ecaa43e2c 100644
--- a/include/kernel/string.h
+++ b/include/kernel/string.h
@@ -12,7 +12,11 @@ int sprintf(char *str, const char *format, ...);
 int strcmp(const char *s1, const char *s2);
 char *strpbrk(const char *s, const char *accept);
 char *strsep(char **stringp, const char *delim);
+char *strdup(const char *s);
+
+char *strstr(const char *haystack, const char *needle);
 size_t strlen(const char *s);
+int memcmp(const void *s1, const void *s2, size_t n);
 
 void *memcpy(void *dest, const void *src, size_t n);
 char *strcpy(char *dest, const char *src);
diff --git a/init/main.c b/init/main.c
index 5a31e988cc44901605a037d4f74e098469838620..6819227e57f7dfcfd95ed1168e51410029caafb2 100644
--- a/init/main.c
+++ b/init/main.c
@@ -16,7 +16,6 @@
 #include <kernel/sbrk.h>
 #include <kernel/sysctl.h>
 
-#include <kernel/xentium.h>
 
 #define MSG "MAIN: "
 
@@ -24,6 +23,7 @@ void module_image_load_embedded(void);
 void *module_lookup_embedded(char *mod_name);
 void *module_lookup_symbol_embedded(char *sym_name);
 void *module_read_embedded(char *mod_name);
+void module_load_xen_kernels(void);
 
 static void kernel_init(void)
 {
@@ -40,7 +40,6 @@ int main(void)
 {
 	void *addr;
 	struct elf_module m;
-	struct xen_kernel x;
 
 	kernel_init();
 
@@ -65,14 +64,8 @@ int main(void)
 	/* addr = module_lookup_symbol_embedded("somefunction"); */
 	/* XXX the image is not necessary aligned properly, so we can't access
 	 * it directly, until we have a MNA trap */
-#if 1
-	addr = module_read_embedded("testkernel.ko");
 
-	printk(MSG "testkernel module address is %p\n", addr);
 
-	if (addr)
-		xentium_kernel_load(&x, addr);
-#endif
 
 #if 0
 	addr = module_read_embedded("noc_dma.ko");
@@ -86,6 +79,10 @@ int main(void)
 #if 0
 	modules_list_loaded();
 #endif
+
+	/* load all available Xentium kernels from the embedded modules image */
+	module_load_xen_kernels();
+
 	return 0;
 }
 
diff --git a/init/modules-image.c b/init/modules-image.c
index e00937b47968bdcdcb459ebaf1ad739f38fcfee6..5633f429898d920c608be3c912c415dc352b2fb1 100644
--- a/init/modules-image.c
+++ b/init/modules-image.c
@@ -5,6 +5,11 @@
 #include <kernel/printk.h>
 #include <kernel/ar.h>
 #include <kernel/kmem.h>
+#include <kernel/string.h>
+#include <kernel/xentium.h>
+
+#define MSG "MODIMG: "
+
 
 extern unsigned char _binary_modules_image_start __attribute__((weak));
 extern unsigned char _binary_modules_image_end __attribute__((weak));
@@ -19,8 +24,8 @@ void module_image_load_embedded(void)
 		(unsigned int)&_binary_modules_image_size, &mod_ar);
 
 #if 0
-	ar_list_files(&mod_ar);
-	ar_list_symbols(&mod_ar);
+	ar_print_files(&mod_ar);
+	ar_print_symbols(&mod_ar);
 #endif
 }
 
@@ -54,3 +59,49 @@ void *module_read_embedded(char *mod_name)
 
 	return ptr;
 }
+
+
+/**
+ * @brief try to load all xentium kernels found in the embedded image
+ *
+ * @note assumes all files with suffix ".xen" are a kernel
+ */
+
+void module_load_xen_kernels(void)
+{
+	char *list;
+	char *fname;
+	void *file;
+
+	struct xen_kernel x;
+
+
+	list = ar_get_file_list(&mod_ar);
+
+	if (!list)
+		return;
+
+
+	while (1) {
+		fname = strsep(&list, " ");
+		if (!fname)
+			break;
+
+		if (!strstr(fname, ".xen"))
+			continue;
+
+		pr_info(MSG "Loading Xentium kernel %s\n", fname);
+
+		file = module_read_embedded(fname);
+		if (!file)
+			pr_err(MSG "Failed to read file %s\n", fname);
+
+		if (!xentium_kernel_load(&x, file))
+			pr_err(MSG "Error loading Xentium kernel %s\n", fname);
+
+		kfree(file);
+
+	}
+
+	kfree(list);
+}
diff --git a/kernel/xentium.c b/kernel/xentium.c
index e1b09bacdf73918c5aafa0bb39e6e8f2f902520a..5ed29cd231fa9afefaa99a9386d4d604237abdb8 100644
--- a/kernel/xentium.c
+++ b/kernel/xentium.c
@@ -16,6 +16,50 @@
 
 
 
+#define BANK_SIZE               (   8*1024 )
+#define TCM_SIZE                (  32*1024 )
+#define XEN_MAILBOX_OFFSET      ( 512*1024 )
+
+//=============================================================
+// XENTIUM structure
+//=============================================================
+typedef struct {
+	// TCM
+	unsigned int tcm[TCM_SIZE/4];
+	unsigned int dummy[(XEN_MAILBOX_OFFSET-TCM_SIZE)/4];
+	// Status bits + control registers
+	unsigned int mlbx[4];      //0x00080000 .. 0x0008000C
+	unsigned int signal[8];    //0x00080010 .. 0x0008002C
+	unsigned int dma;          //0x00080030 .. 0x00080030
+	unsigned int dummy1;       //0x00080034 .. 0x00080034
+	unsigned int timer[2];     //0x00080038 .. 0x0008003C
+	unsigned int irq;          //0x00080040 .. 0x00080040
+	unsigned int dummy2;       //0x00080044 .. 0x00080044
+	unsigned int status;       //0x00080048 .. 0x00080048
+	unsigned int pc;           //0x0008004C .. 0x0008004C
+	unsigned int fsm_state;    //0x00080050 .. 0x00080050
+} volatile S_xen;
+
+typedef struct S_xdev{
+	/* Status bits + control registers */
+	volatile unsigned int mlbx[4];      //0x00080000 .. 0x0008000C
+	volatile unsigned int signal[8];    //0x00080010 .. 0x0008002C
+	volatile unsigned int dma;          //0x00080030 .. 0x00080030
+	volatile unsigned int dummy1;       //0x00080034 .. 0x00080034
+	volatile unsigned int timer[2];     //0x00080038 .. 0x0008003C
+	volatile unsigned int irq;          //0x00080040 .. 0x00080040
+	volatile unsigned int dummy2;       //0x00080044 .. 0x00080044
+	volatile unsigned int status;       //0x00080048 .. 0x00080048
+	volatile unsigned int pc;           //0x0008004C .. 0x0008004C
+	volatile unsigned int fsm_state;    //0x00080050 .. 0x00080050
+} S_xdev;
+
+typedef volatile unsigned int S_tcm;
+S_xen*       p_xen0                                             = (S_xen*)              (0x20000000);
+S_xen*       p_xen1               = (S_xen*)        (0x20100000);
+
+
+
 
 
 
@@ -278,6 +322,8 @@ int xentium_kernel_load(struct xen_kernel *x, void *p)
 	if (xentium_load_kernel(x))
 		goto cleanup;
 
+		p_xen0->mlbx[0] = 0x30000000;
+//	p_xen1->mlbx[0] = 0x30000000;
 
 
 	if (_xen.cnt == _xen.sz) {
diff --git a/lib/ar.c b/lib/ar.c
index af50ca1ec7b17040cd3abdb90c863f10589bc178..ec81d89525fc349840e612ef91ef2aec095b02c4 100644
--- a/lib/ar.c
+++ b/lib/ar.c
@@ -382,15 +382,12 @@ static unsigned int ar_get_filecount(char *p, struct archive *a)
 
 
 /**
- * @brief print symbols in the archive
+ * @brief print list of symbols in the archive
  *
  * @param a a struct archive
- * @param name the file name to search for
- *
- * @return a pointer or NULL if not found
  */
 
-void ar_list_symbols(struct archive *a)
+void ar_print_symbols(struct archive *a)
 {
 	unsigned long i;
 
@@ -421,15 +418,12 @@ void ar_list_symbols(struct archive *a)
 
 
 /**
- * @brief print files in the archive
+ * @brief print list of files in the archive
  *
  * @param a a struct archive
- * @param name the file name to search for
- *
- * @return a pointer or NULL if not found
  */
 
-void ar_list_files(struct archive *a)
+void ar_print_files(struct archive *a)
 {
 	unsigned long i;
 
@@ -459,6 +453,57 @@ void ar_list_files(struct archive *a)
 }
 
 
+/**
+ * @brief get a space-separated list of file names in the archive
+ *
+ * @param a a struct archive
+ *
+ * @return a pointer or NULL if not found
+ */
+
+char *ar_get_file_list(struct archive *a)
+{
+	unsigned long i;
+
+	size_t sz = 0;
+
+	char *files = NULL;
+
+
+	if (!a)
+		goto exit;	
+
+	if (!a->fname)
+		goto exit;	
+
+	if (!a->fnamesz)
+		goto exit;	
+
+	for (i = 0; i < a->n_file; i++)
+		sz += a->fnamesz[i] + 1;
+
+	if (!sz)
+		goto exit;	
+
+	files = (char *) kzalloc(sz);
+
+	if (!files)
+		goto exit;
+
+	sz = 0;
+	for (i = 0; i < a->n_file; i++) {
+		memcpy(&files[sz], a->fname[i], a->fnamesz[i]);
+		sz += a->fnamesz[i];
+		files[sz++] = ' ';
+	}
+
+	/* terminate end of string */
+	files[sz - 1] = '\0';
+
+exit:
+	return files;
+}
+
 
 /**
  * @brief return a pointer to an archive file
diff --git a/lib/string.c b/lib/string.c
index 3f08b9d7fe0987c9d08cff4d608a55c485521ff5..905e3b4df1d55deb5c538e537c4dd68c55fcb359 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -7,8 +7,10 @@
  */
 
 
+#include <kernel/kmem.h>
 #include <kernel/export.h>
 #include <kernel/types.h>
+#include <kernel/string.h>
 
 
 /**
@@ -90,8 +92,8 @@ char *strsep(char **stringp, const char *delim)
 	end = strpbrk(start, delim);
 
 	if (end) {
-		(*end)++;
 		(*end) = '\0';
+		end++;
 	}
 
 	*stringp = end;
@@ -101,6 +103,34 @@ char *strsep(char **stringp, const char *delim)
 EXPORT_SYMBOL(strsep);
 
 
+/**
+ * @brief return a pointer to a new string which is a duplicate of string s
+ *
+ * @parm s the string to duplicate
+ *
+ * @note the pointer is allocated using kmalloc() and may be freed with kfree()
+ */
+
+char *strdup(const char *s)
+{
+        size_t len;
+
+        char *dup;
+
+        if (!s)
+                return NULL;
+
+        len = strlen(s) + 1;
+        dup = kzalloc(len);
+
+        if (dup)
+                memcpy(dup, s, len);
+
+        return dup;
+}
+EXPORT_SYMBOL(strdup);
+
+
 /**
  * @brief calculate the length of a string
  *
@@ -121,6 +151,82 @@ size_t strlen(const char *s)
 EXPORT_SYMBOL(strlen);
 
 
+/**
+ * @brief finds the first occurrence of the substring needle in the string
+ *        haystack
+ *
+ * @param haystack the string to be searched
+ * @param needle   the string to search for
+ *
+ * @returns a pointer to the beginning of a substring or NULL if not found
+ */
+
+char *strstr(const char *haystack, const char *needle)
+{
+        size_t len_h;
+        size_t len_n;
+
+
+        len_n = strlen(needle);
+
+        if (!len_n)
+                return (char *) haystack;
+
+        len_h = strlen(haystack);
+
+        for ( ; len_h >= len_n; len_h--) {
+
+                if (!memcmp(haystack, needle, len_n))
+                        return (char *) haystack;
+
+                haystack++;
+        }
+
+        return NULL;
+}
+EXPORT_SYMBOL(strstr);
+
+/**
+ * @brief compares the first n bytes of the memory areas s1 and s2
+ *
+ * @param s1 the first string
+ * @param s2 the second string
+ * @param n the number of bytes to compare
+ *
+ * @returns <0, 0 or > 0 if s1 is the first n bytes are found of s1 are found to
+ *          be less than, to match or be greater than s2
+ *
+ * @note s1 and s2 are interpreted as unsigned char
+ */
+
+int memcmp(const void *s1, const void *s2, size_t n)
+{
+        const unsigned char *su1, *su2;
+
+        int res = 0;
+
+	su1 = (const unsigned char *) s1;
+	su2 = (const unsigned char *) s2;
+
+	while (n) {
+
+		if ((*su1) != (*su2)) {
+			if ((*su1) < (*su2))
+				return -1;
+			else
+				return  1;
+		}
+
+		su1++;
+		su2++;
+		n--;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(memcmp);
+
+
 /**
  * @brief copy a memory area
  *
@@ -168,12 +274,12 @@ EXPORT_SYMBOL(memcpy);
 char *strcpy(char *dest, const char *src)
 {
 	char *tmp;
-	
-	
+
+
 	tmp = dest;
 
 	while ((*dest++ = *src++) != '\0');
-	
+
 	return tmp;
 }
 EXPORT_SYMBOL(strcpy);
@@ -251,13 +357,13 @@ int isspace(int c)
 {
 	if (c == ' ')
 		return 1;
-	
+
 	if (c == '\t')
 		return 1;
 
 	if (c == '\n')
 		return 1;
-	
+
 	if (c == '\v')
 		return 1;
 
@@ -301,7 +407,7 @@ int atoi(const char *nptr)
 		d = (*nptr) - '0';
 
 		if (d > 9)
-			break;	
+			break;
 
 		res = res * 10 + (int) d;
 		nptr++;
diff --git a/scripts/link-leanos.sh b/scripts/link-leanos.sh
index 242da1062cf120bcde4c100781a5db2b8bd24cbc..807131caf9a612432ab07ab25b6dbf86259637a1 100755
--- a/scripts/link-leanos.sh
+++ b/scripts/link-leanos.sh
@@ -294,18 +294,21 @@ fi
 # this is a 3rd pass option, we need modules.order beforehand
 if [ "$1" = "embed" ]; then
 
-	if [ ! -s ${srctree}/modules.order ]; then
-		echo >&2
-		echo >&2 modules.order empty or nonexistant, cannot embed image.
-		echo >&2 Maybe you have no loadable modules configured?
-		echo >&2 Kernel image unchanged.
-		echo >&2
-		exit
-	fi
+#	if [ ! -s ${srctree}/modules.order ]; then
+#		echo >&2
+#		echo >&2 modules.order empty or nonexistant, cannot embed image.
+#		echo >&2 Maybe you have no loadable modules configured?
+#		echo >&2 Kernel image unchanged.
+#		echo >&2
+#		exit
+#	fi
 
 	embedflags="-Wl,--format=binary -Wl,modules.image -Wl,--format=default"
 	rm -f modules.image
-	${AR} rcs ${srctree}/modules.image $(tr '\n' ' ' < ${srctree}/modules.order)
+	${AR} rcs ${srctree}/modules.image \
+		$(tr '\n' ' ' < ${srctree}/modules.order) \
+		$(find dsp/xentium -name *.xen)
+
 	leanos_link "${kallsymso}" leanos "${embedflags}"
 	exit
 fi