diff mbox

[v2] ARM: xip: Move XIP linking to a separate file

Message ID 1447952889-18561-1-git-send-email-chris.brandt@renesas.com (mailing list archive)
State New, archived
Headers show

Commit Message

Chris Brandt Nov. 19, 2015, 5:08 p.m. UTC
When building an XIP kernel, the linker script needs to be much different
than a conventional kernel's script. Over time, it's been difficult to
maintain both XIP and non-XIP layouts in one linker script. Therefore,
this patch separates the two procedures into two completely different
files.

The new linker script is essentially a straight copy of the current script
with all the non-CONFIG_XIP_KERNEL portions removed.

Additionally, all CONFIG_XIP_KERNEL portions have been removed from the
existing linker script...never to return again.

It should be noted that this does not fix any current XIP issues, but
rather is the first move in fixing them properly with subsequent patches.

Signed-off-by: Chris Brandt <chris.brandt@renesas.com>
---
v2:
* Removed modifications to main Makefile and instead just #include
---
 arch/arm/kernel/vmlinux-xip.lds.S |  322 +++++++++++++++++++++++++++++++++++++
 arch/arm/kernel/vmlinux.lds.S     |   37 ++---
 2 files changed, 332 insertions(+), 27 deletions(-)
 create mode 100644 arch/arm/kernel/vmlinux-xip.lds.S

Comments

Nicolas Pitre Nov. 19, 2015, 5:31 p.m. UTC | #1
On Thu, 19 Nov 2015, Chris Brandt wrote:

> When building an XIP kernel, the linker script needs to be much different
> than a conventional kernel's script. Over time, it's been difficult to
> maintain both XIP and non-XIP layouts in one linker script. Therefore,
> this patch separates the two procedures into two completely different
> files.
> 
> The new linker script is essentially a straight copy of the current script
> with all the non-CONFIG_XIP_KERNEL portions removed.
> 
> Additionally, all CONFIG_XIP_KERNEL portions have been removed from the
> existing linker script...never to return again.
> 
> It should be noted that this does not fix any current XIP issues, but
> rather is the first move in fixing them properly with subsequent patches.
> 
> Signed-off-by: Chris Brandt <chris.brandt@renesas.com>

Acked-by: Nicolas Pitre <nico@linaro.org>

> ---
> v2:
> * Removed modifications to main Makefile and instead just #include
> ---
>  arch/arm/kernel/vmlinux-xip.lds.S |  322 +++++++++++++++++++++++++++++++++++++
>  arch/arm/kernel/vmlinux.lds.S     |   37 ++---
>  2 files changed, 332 insertions(+), 27 deletions(-)
>  create mode 100644 arch/arm/kernel/vmlinux-xip.lds.S
> 
> diff --git a/arch/arm/kernel/vmlinux-xip.lds.S b/arch/arm/kernel/vmlinux-xip.lds.S
> new file mode 100644
> index 0000000..1fd938d
> --- /dev/null
> +++ b/arch/arm/kernel/vmlinux-xip.lds.S
> @@ -0,0 +1,322 @@
> +/* ld script to make ARM Linux kernel
> + * taken from the i386 version by Russell King
> + * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
> + */
> +
> +#include <asm-generic/vmlinux.lds.h>
> +#include <asm/cache.h>
> +#include <asm/thread_info.h>
> +#include <asm/memory.h>
> +#include <asm/page.h>
> +#ifdef CONFIG_ARM_KERNMEM_PERMS
> +#include <asm/pgtable.h>
> +#endif
> +
> +#define PROC_INFO							\
> +	. = ALIGN(4);							\
> +	VMLINUX_SYMBOL(__proc_info_begin) = .;				\
> +	*(.proc.info.init)						\
> +	VMLINUX_SYMBOL(__proc_info_end) = .;
> +
> +#define IDMAP_TEXT							\
> +	ALIGN_FUNCTION();						\
> +	VMLINUX_SYMBOL(__idmap_text_start) = .;				\
> +	*(.idmap.text)							\
> +	VMLINUX_SYMBOL(__idmap_text_end) = .;				\
> +	. = ALIGN(PAGE_SIZE);						\
> +	VMLINUX_SYMBOL(__hyp_idmap_text_start) = .;			\
> +	*(.hyp.idmap.text)						\
> +	VMLINUX_SYMBOL(__hyp_idmap_text_end) = .;
> +
> +#ifdef CONFIG_HOTPLUG_CPU
> +#define ARM_CPU_DISCARD(x)
> +#define ARM_CPU_KEEP(x)		x
> +#else
> +#define ARM_CPU_DISCARD(x)	x
> +#define ARM_CPU_KEEP(x)
> +#endif
> +
> +#if (defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)) || \
> +	defined(CONFIG_GENERIC_BUG)
> +#define ARM_EXIT_KEEP(x)	x
> +#define ARM_EXIT_DISCARD(x)
> +#else
> +#define ARM_EXIT_KEEP(x)
> +#define ARM_EXIT_DISCARD(x)	x
> +#endif
> +
> +OUTPUT_ARCH(arm)
> +ENTRY(stext)
> +
> +#ifndef __ARMEB__
> +jiffies = jiffies_64;
> +#else
> +jiffies = jiffies_64 + 4;
> +#endif
> +
> +SECTIONS
> +{
> +	/*
> +	 * XXX: The linker does not define how output sections are
> +	 * assigned to input sections when there are multiple statements
> +	 * matching the same input section name.  There is no documented
> +	 * order of matching.
> +	 *
> +	 * unwind exit sections must be discarded before the rest of the
> +	 * unwind sections get included.
> +	 */
> +	/DISCARD/ : {
> +		*(.ARM.exidx.exit.text)
> +		*(.ARM.extab.exit.text)
> +		ARM_CPU_DISCARD(*(.ARM.exidx.cpuexit.text))
> +		ARM_CPU_DISCARD(*(.ARM.extab.cpuexit.text))
> +		ARM_EXIT_DISCARD(EXIT_TEXT)
> +		ARM_EXIT_DISCARD(EXIT_DATA)
> +		EXIT_CALL
> +#ifndef CONFIG_MMU
> +		*(.text.fixup)
> +		*(__ex_table)
> +#endif
> +#ifndef CONFIG_SMP_ON_UP
> +		*(.alt.smp.init)
> +#endif
> +		*(.discard)
> +		*(.discard.*)
> +	}
> +
> +	. = XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR);
> +
> +	.head.text : {
> +		_text = .;
> +		HEAD_TEXT
> +	}
> +
> +#ifdef CONFIG_ARM_KERNMEM_PERMS
> +	. = ALIGN(1<<SECTION_SHIFT);
> +#endif
> +
> +	.text : {			/* Real text segment		*/
> +		_stext = .;		/* Text and read-only data	*/
> +			IDMAP_TEXT
> +			__exception_text_start = .;
> +			*(.exception.text)
> +			__exception_text_end = .;
> +			IRQENTRY_TEXT
> +			TEXT_TEXT
> +			SCHED_TEXT
> +			LOCK_TEXT
> +			KPROBES_TEXT
> +			*(.gnu.warning)
> +			*(.glue_7)
> +			*(.glue_7t)
> +		. = ALIGN(4);
> +		*(.got)			/* Global offset table		*/
> +			ARM_CPU_KEEP(PROC_INFO)
> +	}
> +
> +#ifdef CONFIG_DEBUG_RODATA
> +	. = ALIGN(1<<SECTION_SHIFT);
> +#endif
> +	RO_DATA(PAGE_SIZE)
> +
> +	. = ALIGN(4);
> +	__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
> +		__start___ex_table = .;
> +#ifdef CONFIG_MMU
> +		*(__ex_table)
> +#endif
> +		__stop___ex_table = .;
> +	}
> +
> +#ifdef CONFIG_ARM_UNWIND
> +	/*
> +	 * Stack unwinding tables
> +	 */
> +	. = ALIGN(8);
> +	.ARM.unwind_idx : {
> +		__start_unwind_idx = .;
> +		*(.ARM.exidx*)
> +		__stop_unwind_idx = .;
> +	}
> +	.ARM.unwind_tab : {
> +		__start_unwind_tab = .;
> +		*(.ARM.extab*)
> +		__stop_unwind_tab = .;
> +	}
> +#endif
> +
> +	NOTES
> +
> +	_etext = .;			/* End of text and rodata section */
> +
> +	/*
> +	 * The vectors and stubs are relocatable code, and the
> +	 * only thing that matters is their relative offsets
> +	 */
> +	__vectors_start = .;
> +	.vectors 0 : AT(__vectors_start) {
> +		*(.vectors)
> +	}
> +	. = __vectors_start + SIZEOF(.vectors);
> +	__vectors_end = .;
> +
> +	__stubs_start = .;
> +	.stubs 0x1000 : AT(__stubs_start) {
> +		*(.stubs)
> +	}
> +	. = __stubs_start + SIZEOF(.stubs);
> +	__stubs_end = .;
> +
> +	INIT_TEXT_SECTION(8)
> +	.exit.text : {
> +		ARM_EXIT_KEEP(EXIT_TEXT)
> +	}
> +	.init.proc.info : {
> +		ARM_CPU_DISCARD(PROC_INFO)
> +	}
> +	.init.arch.info : {
> +		__arch_info_begin = .;
> +		*(.arch.info.init)
> +		__arch_info_end = .;
> +	}
> +	.init.tagtable : {
> +		__tagtable_begin = .;
> +		*(.taglist.init)
> +		__tagtable_end = .;
> +	}
> +#ifdef CONFIG_SMP_ON_UP
> +	.init.smpalt : {
> +		__smpalt_begin = .;
> +		*(.alt.smp.init)
> +		__smpalt_end = .;
> +	}
> +#endif
> +	.init.pv_table : {
> +		__pv_table_begin = .;
> +		*(.pv_table)
> +		__pv_table_end = .;
> +	}
> +	.init.data : {
> +		INIT_SETUP(16)
> +		INIT_CALLS
> +		CON_INITCALL
> +		SECURITY_INITCALL
> +		INIT_RAM_FS
> +	}
> +
> +#ifdef CONFIG_SMP
> +	PERCPU_SECTION(L1_CACHE_BYTES)
> +#endif
> +
> +	__data_loc = ALIGN(4);		/* location in binary */
> +	. = PAGE_OFFSET + TEXT_OFFSET;
> +
> +	.data : AT(__data_loc) {
> +		_data = .;		/* address in memory */
> +		_sdata = .;
> +
> +		/*
> +		 * first, the init task union, aligned
> +		 * to an 8192 byte boundary.
> +		 */
> +		INIT_TASK_DATA(THREAD_SIZE)
> +
> +		. = ALIGN(PAGE_SIZE);
> +		__init_begin = .;
> +		INIT_DATA
> +		ARM_EXIT_KEEP(EXIT_DATA)
> +		. = ALIGN(PAGE_SIZE);
> +		__init_end = .;
> +
> +		NOSAVE_DATA
> +		CACHELINE_ALIGNED_DATA(L1_CACHE_BYTES)
> +		READ_MOSTLY_DATA(L1_CACHE_BYTES)
> +
> +		/*
> +		 * and the usual data section
> +		 */
> +		DATA_DATA
> +		CONSTRUCTORS
> +
> +		_edata = .;
> +	}
> +	_edata_loc = __data_loc + SIZEOF(.data);
> +
> +#ifdef CONFIG_HAVE_TCM
> +        /*
> +	 * We align everything to a page boundary so we can
> +	 * free it after init has commenced and TCM contents have
> +	 * been copied to its destination.
> +	 */
> +	.tcm_start : {
> +		. = ALIGN(PAGE_SIZE);
> +		__tcm_start = .;
> +		__itcm_start = .;
> +	}
> +
> +	/*
> +	 * Link these to the ITCM RAM
> +	 * Put VMA to the TCM address and LMA to the common RAM
> +	 * and we'll upload the contents from RAM to TCM and free
> +	 * the used RAM after that.
> +	 */
> +	.text_itcm ITCM_OFFSET : AT(__itcm_start)
> +	{
> +		__sitcm_text = .;
> +		*(.tcm.text)
> +		*(.tcm.rodata)
> +		. = ALIGN(4);
> +		__eitcm_text = .;
> +	}
> +
> +	/*
> +	 * Reset the dot pointer, this is needed to create the
> +	 * relative __dtcm_start below (to be used as extern in code).
> +	 */
> +	. = ADDR(.tcm_start) + SIZEOF(.tcm_start) + SIZEOF(.text_itcm);
> +
> +	.dtcm_start : {
> +		__dtcm_start = .;
> +	}
> +
> +	/* TODO: add remainder of ITCM as well, that can be used for data! */
> +	.data_dtcm DTCM_OFFSET : AT(__dtcm_start)
> +	{
> +		. = ALIGN(4);
> +		__sdtcm_data = .;
> +		*(.tcm.data)
> +		. = ALIGN(4);
> +		__edtcm_data = .;
> +	}
> +
> +	/* Reset the dot pointer or the linker gets confused */
> +	. = ADDR(.dtcm_start) + SIZEOF(.data_dtcm);
> +
> +	/* End marker for freeing TCM copy in linked object */
> +	.tcm_end : AT(ADDR(.dtcm_start) + SIZEOF(.data_dtcm)){
> +		. = ALIGN(PAGE_SIZE);
> +		__tcm_end = .;
> +	}
> +#endif
> +
> +	BSS_SECTION(0, 0, 0)
> +	_end = .;
> +
> +	STABS_DEBUG
> +}
> +
> +/*
> + * These must never be empty
> + * If you have to comment these two assert statements out, your
> + * binutils is too old (for other reasons as well)
> + */
> +ASSERT((__proc_info_end - __proc_info_begin), "missing CPU support")
> +ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined")
> +
> +/*
> + * The HYP init code can't be more than a page long,
> + * and should not cross a page boundary.
> + * The above comment applies as well.
> + */
> +ASSERT(__hyp_idmap_text_end - (__hyp_idmap_text_start & PAGE_MASK) <= PAGE_SIZE,
> +	"HYP init code too big or misaligned")
> diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
> index 8b60fde..093d532 100644
> --- a/arch/arm/kernel/vmlinux.lds.S
> +++ b/arch/arm/kernel/vmlinux.lds.S
> @@ -3,6 +3,10 @@
>   * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
>   */
>  
> +#ifdef CONFIG_XIP_KERNEL
> +#include "vmlinux-xip.lds.S"
> +#else
> +
>  #include <asm-generic/vmlinux.lds.h>
>  #include <asm/cache.h>
>  #include <asm/thread_info.h>
> @@ -84,11 +88,7 @@ SECTIONS
>  		*(.discard.*)
>  	}
>  
> -#ifdef CONFIG_XIP_KERNEL
> -	. = XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR);
> -#else
>  	. = PAGE_OFFSET + TEXT_OFFSET;
> -#endif
>  	.head.text : {
>  		_text = .;
>  		HEAD_TEXT
> @@ -152,14 +152,13 @@ SECTIONS
>  
>  	_etext = .;			/* End of text and rodata section */
>  
> -#ifndef CONFIG_XIP_KERNEL
> -# ifdef CONFIG_ARM_KERNMEM_PERMS
> +#ifdef CONFIG_ARM_KERNMEM_PERMS
>  	. = ALIGN(1<<SECTION_SHIFT);
> -# else
> +#else
>  	. = ALIGN(PAGE_SIZE);
> -# endif
> -	__init_begin = .;
>  #endif
> +	__init_begin = .;
> +
>  	/*
>  	 * The vectors and stubs are relocatable code, and the
>  	 * only thing that matters is their relative offsets
> @@ -208,29 +207,21 @@ SECTIONS
>  		__pv_table_end = .;
>  	}
>  	.init.data : {
> -#ifndef CONFIG_XIP_KERNEL
>  		INIT_DATA
> -#endif
>  		INIT_SETUP(16)
>  		INIT_CALLS
>  		CON_INITCALL
>  		SECURITY_INITCALL
>  		INIT_RAM_FS
>  	}
> -#ifndef CONFIG_XIP_KERNEL
>  	.exit.data : {
>  		ARM_EXIT_KEEP(EXIT_DATA)
>  	}
> -#endif
>  
>  #ifdef CONFIG_SMP
>  	PERCPU_SECTION(L1_CACHE_BYTES)
>  #endif
>  
> -#ifdef CONFIG_XIP_KERNEL
> -	__data_loc = ALIGN(4);		/* location in binary */
> -	. = PAGE_OFFSET + TEXT_OFFSET;
> -#else
>  #ifdef CONFIG_ARM_KERNMEM_PERMS
>  	. = ALIGN(1<<SECTION_SHIFT);
>  #else
> @@ -238,7 +229,6 @@ SECTIONS
>  #endif
>  	__init_end = .;
>  	__data_loc = .;
> -#endif
>  
>  	.data : AT(__data_loc) {
>  		_data = .;		/* address in memory */
> @@ -250,15 +240,6 @@ SECTIONS
>  		 */
>  		INIT_TASK_DATA(THREAD_SIZE)
>  
> -#ifdef CONFIG_XIP_KERNEL
> -		. = ALIGN(PAGE_SIZE);
> -		__init_begin = .;
> -		INIT_DATA
> -		ARM_EXIT_KEEP(EXIT_DATA)
> -		. = ALIGN(PAGE_SIZE);
> -		__init_end = .;
> -#endif
> -
>  		NOSAVE_DATA
>  		CACHELINE_ALIGNED_DATA(L1_CACHE_BYTES)
>  		READ_MOSTLY_DATA(L1_CACHE_BYTES)
> @@ -351,3 +332,5 @@ ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined")
>   */
>  ASSERT(__hyp_idmap_text_end - (__hyp_idmap_text_start & PAGE_MASK) <= PAGE_SIZE,
>  	"HYP init code too big or misaligned")
> +
> +#endif /* CONFIG_XIP_KERNEL */
> -- 
> 1.7.9.5
> 
> 
>
diff mbox

Patch

diff --git a/arch/arm/kernel/vmlinux-xip.lds.S b/arch/arm/kernel/vmlinux-xip.lds.S
new file mode 100644
index 0000000..1fd938d
--- /dev/null
+++ b/arch/arm/kernel/vmlinux-xip.lds.S
@@ -0,0 +1,322 @@ 
+/* ld script to make ARM Linux kernel
+ * taken from the i386 version by Russell King
+ * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <asm-generic/vmlinux.lds.h>
+#include <asm/cache.h>
+#include <asm/thread_info.h>
+#include <asm/memory.h>
+#include <asm/page.h>
+#ifdef CONFIG_ARM_KERNMEM_PERMS
+#include <asm/pgtable.h>
+#endif
+
+#define PROC_INFO							\
+	. = ALIGN(4);							\
+	VMLINUX_SYMBOL(__proc_info_begin) = .;				\
+	*(.proc.info.init)						\
+	VMLINUX_SYMBOL(__proc_info_end) = .;
+
+#define IDMAP_TEXT							\
+	ALIGN_FUNCTION();						\
+	VMLINUX_SYMBOL(__idmap_text_start) = .;				\
+	*(.idmap.text)							\
+	VMLINUX_SYMBOL(__idmap_text_end) = .;				\
+	. = ALIGN(PAGE_SIZE);						\
+	VMLINUX_SYMBOL(__hyp_idmap_text_start) = .;			\
+	*(.hyp.idmap.text)						\
+	VMLINUX_SYMBOL(__hyp_idmap_text_end) = .;
+
+#ifdef CONFIG_HOTPLUG_CPU
+#define ARM_CPU_DISCARD(x)
+#define ARM_CPU_KEEP(x)		x
+#else
+#define ARM_CPU_DISCARD(x)	x
+#define ARM_CPU_KEEP(x)
+#endif
+
+#if (defined(CONFIG_SMP_ON_UP) && !defined(CONFIG_DEBUG_SPINLOCK)) || \
+	defined(CONFIG_GENERIC_BUG)
+#define ARM_EXIT_KEEP(x)	x
+#define ARM_EXIT_DISCARD(x)
+#else
+#define ARM_EXIT_KEEP(x)
+#define ARM_EXIT_DISCARD(x)	x
+#endif
+
+OUTPUT_ARCH(arm)
+ENTRY(stext)
+
+#ifndef __ARMEB__
+jiffies = jiffies_64;
+#else
+jiffies = jiffies_64 + 4;
+#endif
+
+SECTIONS
+{
+	/*
+	 * XXX: The linker does not define how output sections are
+	 * assigned to input sections when there are multiple statements
+	 * matching the same input section name.  There is no documented
+	 * order of matching.
+	 *
+	 * unwind exit sections must be discarded before the rest of the
+	 * unwind sections get included.
+	 */
+	/DISCARD/ : {
+		*(.ARM.exidx.exit.text)
+		*(.ARM.extab.exit.text)
+		ARM_CPU_DISCARD(*(.ARM.exidx.cpuexit.text))
+		ARM_CPU_DISCARD(*(.ARM.extab.cpuexit.text))
+		ARM_EXIT_DISCARD(EXIT_TEXT)
+		ARM_EXIT_DISCARD(EXIT_DATA)
+		EXIT_CALL
+#ifndef CONFIG_MMU
+		*(.text.fixup)
+		*(__ex_table)
+#endif
+#ifndef CONFIG_SMP_ON_UP
+		*(.alt.smp.init)
+#endif
+		*(.discard)
+		*(.discard.*)
+	}
+
+	. = XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR);
+
+	.head.text : {
+		_text = .;
+		HEAD_TEXT
+	}
+
+#ifdef CONFIG_ARM_KERNMEM_PERMS
+	. = ALIGN(1<<SECTION_SHIFT);
+#endif
+
+	.text : {			/* Real text segment		*/
+		_stext = .;		/* Text and read-only data	*/
+			IDMAP_TEXT
+			__exception_text_start = .;
+			*(.exception.text)
+			__exception_text_end = .;
+			IRQENTRY_TEXT
+			TEXT_TEXT
+			SCHED_TEXT
+			LOCK_TEXT
+			KPROBES_TEXT
+			*(.gnu.warning)
+			*(.glue_7)
+			*(.glue_7t)
+		. = ALIGN(4);
+		*(.got)			/* Global offset table		*/
+			ARM_CPU_KEEP(PROC_INFO)
+	}
+
+#ifdef CONFIG_DEBUG_RODATA
+	. = ALIGN(1<<SECTION_SHIFT);
+#endif
+	RO_DATA(PAGE_SIZE)
+
+	. = ALIGN(4);
+	__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
+		__start___ex_table = .;
+#ifdef CONFIG_MMU
+		*(__ex_table)
+#endif
+		__stop___ex_table = .;
+	}
+
+#ifdef CONFIG_ARM_UNWIND
+	/*
+	 * Stack unwinding tables
+	 */
+	. = ALIGN(8);
+	.ARM.unwind_idx : {
+		__start_unwind_idx = .;
+		*(.ARM.exidx*)
+		__stop_unwind_idx = .;
+	}
+	.ARM.unwind_tab : {
+		__start_unwind_tab = .;
+		*(.ARM.extab*)
+		__stop_unwind_tab = .;
+	}
+#endif
+
+	NOTES
+
+	_etext = .;			/* End of text and rodata section */
+
+	/*
+	 * The vectors and stubs are relocatable code, and the
+	 * only thing that matters is their relative offsets
+	 */
+	__vectors_start = .;
+	.vectors 0 : AT(__vectors_start) {
+		*(.vectors)
+	}
+	. = __vectors_start + SIZEOF(.vectors);
+	__vectors_end = .;
+
+	__stubs_start = .;
+	.stubs 0x1000 : AT(__stubs_start) {
+		*(.stubs)
+	}
+	. = __stubs_start + SIZEOF(.stubs);
+	__stubs_end = .;
+
+	INIT_TEXT_SECTION(8)
+	.exit.text : {
+		ARM_EXIT_KEEP(EXIT_TEXT)
+	}
+	.init.proc.info : {
+		ARM_CPU_DISCARD(PROC_INFO)
+	}
+	.init.arch.info : {
+		__arch_info_begin = .;
+		*(.arch.info.init)
+		__arch_info_end = .;
+	}
+	.init.tagtable : {
+		__tagtable_begin = .;
+		*(.taglist.init)
+		__tagtable_end = .;
+	}
+#ifdef CONFIG_SMP_ON_UP
+	.init.smpalt : {
+		__smpalt_begin = .;
+		*(.alt.smp.init)
+		__smpalt_end = .;
+	}
+#endif
+	.init.pv_table : {
+		__pv_table_begin = .;
+		*(.pv_table)
+		__pv_table_end = .;
+	}
+	.init.data : {
+		INIT_SETUP(16)
+		INIT_CALLS
+		CON_INITCALL
+		SECURITY_INITCALL
+		INIT_RAM_FS
+	}
+
+#ifdef CONFIG_SMP
+	PERCPU_SECTION(L1_CACHE_BYTES)
+#endif
+
+	__data_loc = ALIGN(4);		/* location in binary */
+	. = PAGE_OFFSET + TEXT_OFFSET;
+
+	.data : AT(__data_loc) {
+		_data = .;		/* address in memory */
+		_sdata = .;
+
+		/*
+		 * first, the init task union, aligned
+		 * to an 8192 byte boundary.
+		 */
+		INIT_TASK_DATA(THREAD_SIZE)
+
+		. = ALIGN(PAGE_SIZE);
+		__init_begin = .;
+		INIT_DATA
+		ARM_EXIT_KEEP(EXIT_DATA)
+		. = ALIGN(PAGE_SIZE);
+		__init_end = .;
+
+		NOSAVE_DATA
+		CACHELINE_ALIGNED_DATA(L1_CACHE_BYTES)
+		READ_MOSTLY_DATA(L1_CACHE_BYTES)
+
+		/*
+		 * and the usual data section
+		 */
+		DATA_DATA
+		CONSTRUCTORS
+
+		_edata = .;
+	}
+	_edata_loc = __data_loc + SIZEOF(.data);
+
+#ifdef CONFIG_HAVE_TCM
+        /*
+	 * We align everything to a page boundary so we can
+	 * free it after init has commenced and TCM contents have
+	 * been copied to its destination.
+	 */
+	.tcm_start : {
+		. = ALIGN(PAGE_SIZE);
+		__tcm_start = .;
+		__itcm_start = .;
+	}
+
+	/*
+	 * Link these to the ITCM RAM
+	 * Put VMA to the TCM address and LMA to the common RAM
+	 * and we'll upload the contents from RAM to TCM and free
+	 * the used RAM after that.
+	 */
+	.text_itcm ITCM_OFFSET : AT(__itcm_start)
+	{
+		__sitcm_text = .;
+		*(.tcm.text)
+		*(.tcm.rodata)
+		. = ALIGN(4);
+		__eitcm_text = .;
+	}
+
+	/*
+	 * Reset the dot pointer, this is needed to create the
+	 * relative __dtcm_start below (to be used as extern in code).
+	 */
+	. = ADDR(.tcm_start) + SIZEOF(.tcm_start) + SIZEOF(.text_itcm);
+
+	.dtcm_start : {
+		__dtcm_start = .;
+	}
+
+	/* TODO: add remainder of ITCM as well, that can be used for data! */
+	.data_dtcm DTCM_OFFSET : AT(__dtcm_start)
+	{
+		. = ALIGN(4);
+		__sdtcm_data = .;
+		*(.tcm.data)
+		. = ALIGN(4);
+		__edtcm_data = .;
+	}
+
+	/* Reset the dot pointer or the linker gets confused */
+	. = ADDR(.dtcm_start) + SIZEOF(.data_dtcm);
+
+	/* End marker for freeing TCM copy in linked object */
+	.tcm_end : AT(ADDR(.dtcm_start) + SIZEOF(.data_dtcm)){
+		. = ALIGN(PAGE_SIZE);
+		__tcm_end = .;
+	}
+#endif
+
+	BSS_SECTION(0, 0, 0)
+	_end = .;
+
+	STABS_DEBUG
+}
+
+/*
+ * These must never be empty
+ * If you have to comment these two assert statements out, your
+ * binutils is too old (for other reasons as well)
+ */
+ASSERT((__proc_info_end - __proc_info_begin), "missing CPU support")
+ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined")
+
+/*
+ * The HYP init code can't be more than a page long,
+ * and should not cross a page boundary.
+ * The above comment applies as well.
+ */
+ASSERT(__hyp_idmap_text_end - (__hyp_idmap_text_start & PAGE_MASK) <= PAGE_SIZE,
+	"HYP init code too big or misaligned")
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 8b60fde..093d532 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -3,6 +3,10 @@ 
  * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
  */
 
+#ifdef CONFIG_XIP_KERNEL
+#include "vmlinux-xip.lds.S"
+#else
+
 #include <asm-generic/vmlinux.lds.h>
 #include <asm/cache.h>
 #include <asm/thread_info.h>
@@ -84,11 +88,7 @@  SECTIONS
 		*(.discard.*)
 	}
 
-#ifdef CONFIG_XIP_KERNEL
-	. = XIP_VIRT_ADDR(CONFIG_XIP_PHYS_ADDR);
-#else
 	. = PAGE_OFFSET + TEXT_OFFSET;
-#endif
 	.head.text : {
 		_text = .;
 		HEAD_TEXT
@@ -152,14 +152,13 @@  SECTIONS
 
 	_etext = .;			/* End of text and rodata section */
 
-#ifndef CONFIG_XIP_KERNEL
-# ifdef CONFIG_ARM_KERNMEM_PERMS
+#ifdef CONFIG_ARM_KERNMEM_PERMS
 	. = ALIGN(1<<SECTION_SHIFT);
-# else
+#else
 	. = ALIGN(PAGE_SIZE);
-# endif
-	__init_begin = .;
 #endif
+	__init_begin = .;
+
 	/*
 	 * The vectors and stubs are relocatable code, and the
 	 * only thing that matters is their relative offsets
@@ -208,29 +207,21 @@  SECTIONS
 		__pv_table_end = .;
 	}
 	.init.data : {
-#ifndef CONFIG_XIP_KERNEL
 		INIT_DATA
-#endif
 		INIT_SETUP(16)
 		INIT_CALLS
 		CON_INITCALL
 		SECURITY_INITCALL
 		INIT_RAM_FS
 	}
-#ifndef CONFIG_XIP_KERNEL
 	.exit.data : {
 		ARM_EXIT_KEEP(EXIT_DATA)
 	}
-#endif
 
 #ifdef CONFIG_SMP
 	PERCPU_SECTION(L1_CACHE_BYTES)
 #endif
 
-#ifdef CONFIG_XIP_KERNEL
-	__data_loc = ALIGN(4);		/* location in binary */
-	. = PAGE_OFFSET + TEXT_OFFSET;
-#else
 #ifdef CONFIG_ARM_KERNMEM_PERMS
 	. = ALIGN(1<<SECTION_SHIFT);
 #else
@@ -238,7 +229,6 @@  SECTIONS
 #endif
 	__init_end = .;
 	__data_loc = .;
-#endif
 
 	.data : AT(__data_loc) {
 		_data = .;		/* address in memory */
@@ -250,15 +240,6 @@  SECTIONS
 		 */
 		INIT_TASK_DATA(THREAD_SIZE)
 
-#ifdef CONFIG_XIP_KERNEL
-		. = ALIGN(PAGE_SIZE);
-		__init_begin = .;
-		INIT_DATA
-		ARM_EXIT_KEEP(EXIT_DATA)
-		. = ALIGN(PAGE_SIZE);
-		__init_end = .;
-#endif
-
 		NOSAVE_DATA
 		CACHELINE_ALIGNED_DATA(L1_CACHE_BYTES)
 		READ_MOSTLY_DATA(L1_CACHE_BYTES)
@@ -351,3 +332,5 @@  ASSERT((__arch_info_end - __arch_info_begin), "no machine record defined")
  */
 ASSERT(__hyp_idmap_text_end - (__hyp_idmap_text_start & PAGE_MASK) <= PAGE_SIZE,
 	"HYP init code too big or misaligned")
+
+#endif /* CONFIG_XIP_KERNEL */