[U-Boot] [PATCH 12/26] ARM: add relocation support

Heiko Schocher hs at denx.de
Wed Aug 11 20:16:07 CEST 2010


!! This breaks support for all arm boards !!

To compile in old style, you must define
CONFIG_SYS_ARM_WITHOUT_RELOC or you can compile
with "CONFIG_SYS_ARM_WITHOUT_RELOC=1 ./MAKEALL board"

!! This define will be removed soon, so convert your
board to use relocation support

Signed-off-by: Heiko Schocher <hs at denx.de>
---
- changes since previous patch set
  - as introducing CONFIG_SYS_ARM_WITHOUT_RELOC, seperate
    common arm changes in this patch

 arch/arm/config.mk                 |    8 +
 arch/arm/include/asm/config.h      |    3 +-
 arch/arm/include/asm/global_data.h |   11 +
 arch/arm/include/asm/u-boot-arm.h  |   14 +-
 arch/arm/lib/board.c               |  468 +++++++++++++++++++++++++++++++++++-
 arch/arm/lib/cache-cp15.c          |   37 +++-
 arch/arm/lib/interrupts.c          |   19 ++-
 common/cmd_bdinfo.c                |   11 +-
 common/cmd_bmp.c                   |    6 +
 common/cmd_i2c.c                   |    6 +
 doc/README.arm-relocation          |  321 ++++++++++++++++++++++++
 nand_spl/nand_boot.c               |    7 +
 nand_spl/nand_boot_fsl_nfc.c       |    7 +
 13 files changed, 910 insertions(+), 8 deletions(-)
 create mode 100644 doc/README.arm-relocation

diff --git a/arch/arm/config.mk b/arch/arm/config.mk
index e10dafc..6923f6d 100644
--- a/arch/arm/config.mk
+++ b/arch/arm/config.mk
@@ -33,6 +33,14 @@ STANDALONE_LOAD_ADDR = 0xc100000
 endif
 endif

+ifndef CONFIG_SYS_ARM_WITHOUT_RELOC
+# needed for relocation
+PLATFORM_RELFLAGS += -fPIC
+endif
+
+ifdef CONFIG_SYS_ARM_WITHOUT_RELOC
+PLATFORM_CPPFLAGS += -DCONFIG_SYS_ARM_WITHOUT_RELOC
+endif
 PLATFORM_CPPFLAGS += -DCONFIG_ARM -D__ARM__

 # Explicitly specifiy 32-bit ARM ISA since toolchain default can be -mthumb:
diff --git a/arch/arm/include/asm/config.h b/arch/arm/include/asm/config.h
index b76fd8e..4e8dfd7 100644
--- a/arch/arm/include/asm/config.h
+++ b/arch/arm/include/asm/config.h
@@ -21,7 +21,8 @@
 #ifndef _ASM_CONFIG_H_
 #define _ASM_CONFIG_H_

+#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
 /* Relocation to SDRAM works on all ARM boards */
 #define CONFIG_RELOC_FIXUP_WORKS
-
+#endif
 #endif
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index 02cfe45..488bae7 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -53,6 +53,17 @@ typedef	struct	global_data {
 	phys_size_t	ram_size;	/* RAM size */
 	unsigned long	reset_status;	/* reset status register at boot */
 #endif
+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+	unsigned long	relocaddr;	/* Start address of U-Boot in RAM */
+	phys_size_t	ram_size;	/* RAM size */
+	unsigned long	mon_len;	/* monitor len */
+	unsigned long	irq_sp;		/* irq stack pointer */
+	unsigned long	start_addr_sp;	/* start_addr_stackpointer */
+	unsigned long	reloc_off;
+#if !(defined(CONFIG_SYS_NO_ICACHE) && defined(CONFIG_SYS_NO_DCACHE))
+	unsigned long	tlb_addr;
+#endif
+#endif
 	void		**jt;		/* jump table */
 } gd_t;

diff --git a/arch/arm/include/asm/u-boot-arm.h b/arch/arm/include/asm/u-boot-arm.h
index 6d2f8bc..faf800a 100644
--- a/arch/arm/include/asm/u-boot-arm.h
+++ b/arch/arm/include/asm/u-boot-arm.h
@@ -30,11 +30,20 @@
 #define _U_BOOT_ARM_H_	1

 /* for the following variables, see start.S */
-extern ulong _armboot_start;	/* code start */
 extern ulong _bss_start;	/* code + data end == BSS start */
 extern ulong _bss_end;		/* BSS end */
 extern ulong IRQ_STACK_START;	/* top of IRQ stack */
 extern ulong FIQ_STACK_START;	/* top of FIQ stack */
+#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+extern ulong _armboot_start;	/* code start */
+#else
+extern ulong _TEXT_BASE;	/* code start */
+extern ulong _datarel_start;
+extern ulong _datarelrolocal_start;
+extern ulong _datarellocal_start;
+extern ulong _datarelro_start;
+extern ulong IRQ_STACK_START_IN;	/* 8 bytes in IRQ stack */
+#endif

 /* cpu/.../cpu.c */
 int	cpu_init(void);
@@ -47,6 +56,9 @@ int	arch_misc_init(void);
 /* board/.../... */
 int	board_init(void);
 int	dram_init (void);
+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+void	dram_init_banksize (void);
+#endif
 void	setup_serial_tag (struct tag **params);
 void	setup_revision_tag (struct tag **params);

diff --git a/arch/arm/lib/board.c b/arch/arm/lib/board.c
index 54519b0..88c6427 100644
--- a/arch/arm/lib/board.c
+++ b/arch/arm/lib/board.c
@@ -126,7 +126,12 @@ static int init_baudrate (void)
 {
 	char tmp[64];	/* long enough for environment variables */
 	int i = getenv_f("baudrate", tmp, sizeof (tmp));
+
+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+	gd->baudrate = (i > 0)
+#else
 	gd->bd->bi_baudrate = gd->baudrate = (i > 0)
+#endif
 			? (int) simple_strtoul (tmp, NULL, 10)
 			: CONFIG_BAUDRATE;

@@ -137,7 +142,12 @@ static int display_banner (void)
 {
 	printf ("\n\n%s\n\n", version_string);
 	debug ("U-Boot code: %08lX -> %08lX  BSS: -> %08lX\n",
-	       _armboot_start, _bss_start, _bss_end);
+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+	       _TEXT_BASE,
+#else
+	       _armboot_start,
+#endif
+	       _bss_start, _bss_end);
 #ifdef CONFIG_MODEM_SUPPORT
 	debug ("Modem Support enabled\n");
 #endif
@@ -180,6 +190,7 @@ static int display_dram_config (void)
 	return (0);
 }

+#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
 #ifndef CONFIG_SYS_NO_FLASH
 static void display_flash_config (ulong size)
 {
@@ -187,6 +198,7 @@ static void display_flash_config (ulong size)
 	print_size (size, "\n");
 }
 #endif /* CONFIG_SYS_NO_FLASH */
+#endif

 #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
 static int init_func_i2c (void)
@@ -234,6 +246,7 @@ typedef int (init_fnc_t) (void);

 int print_cpuinfo (void);

+#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
 init_fnc_t *init_sequence[] = {
 #if defined(CONFIG_ARCH_CPU_INIT)
 	arch_cpu_init,		/* basic arch cpu dependent setup */
@@ -444,6 +457,459 @@ extern void davinci_eth_set_mac_addr (const u_int8_t *addr);

 	/* NOTREACHED - no way out of command loop except booting */
 }
+#else
+void __dram_init_banksize(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size =  gd->ram_size;
+}
+void dram_init_banksize(void)
+	__attribute__((weak, alias("__dram_init_banksize")));
+
+init_fnc_t *init_sequence[] = {
+#if defined(CONFIG_ARCH_CPU_INIT)
+	arch_cpu_init,		/* basic arch cpu dependent setup */
+#endif
+#if defined(CONFIG_BOARD_EARLY_INIT_F)
+	board_early_init_f,
+#endif
+	timer_init,		/* initialize timer */
+#ifdef CONFIG_FSL_ESDHC
+	get_clocks,
+#endif
+	env_init,		/* initialize environment */
+	init_baudrate,		/* initialze baudrate settings */
+	serial_init,		/* serial communications setup */
+	console_init_f,		/* stage 1 init of console */
+	display_banner,		/* say that we are here */
+#if defined(CONFIG_DISPLAY_CPUINFO)
+	print_cpuinfo,		/* display cpu info (and speed) */
+#endif
+#if defined(CONFIG_DISPLAY_BOARDINFO)
+	checkboard,		/* display board info */
+#endif
+#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
+	init_func_i2c,
+#endif
+	dram_init,		/* configure available RAM banks */
+#if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)
+	arm_pci_init,
+#endif
+	NULL,
+};
+
+void board_init_f (ulong bootflag)
+{
+	bd_t *bd;
+	init_fnc_t **init_fnc_ptr;
+	gd_t *id;
+	ulong addr, addr_sp;
+
+	/* Pointer is writable since we allocated a register for it */
+	gd = (gd_t *) (CONFIG_SYS_INIT_SP_ADDR);
+	/* compiler optimization barrier needed for GCC >= 3.4 */
+	__asm__ __volatile__("": : :"memory");
+
+	memset ((void*)gd, 0, sizeof (gd_t));
+
+	gd->mon_len = _bss_end - _TEXT_BASE;
+
+	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
+		if ((*init_fnc_ptr)() != 0) {
+			hang ();
+		}
+	}
+
+	debug ("monitor len: %08lX\n", gd->mon_len);
+	/*
+	 * Ram is setup, size stored in gd !!
+	 */
+	debug ("ramsize: %08lX\n", gd->ram_size);
+#if defined(CONFIG_SYS_MEM_TOP_HIDE)
+	/*
+	 * Subtract specified amount of memory to hide so that it won't
+	 * get "touched" at all by U-Boot. By fixing up gd->ram_size
+	 * the Linux kernel should now get passed the now "corrected"
+	 * memory size and won't touch it either. This should work
+	 * for arch/ppc and arch/powerpc. Only Linux board ports in
+	 * arch/powerpc with bootwrapper support, that recalculate the
+	 * memory size from the SDRAM controller setup will have to
+	 * get fixed.
+	 */
+	gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;
+#endif
+
+	addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;
+
+#ifdef CONFIG_LOGBUFFER
+#ifndef CONFIG_ALT_LB_ADDR
+	/* reserve kernel log buffer */
+	addr -= (LOGBUFF_RESERVE);
+	debug ("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN, addr);
+#endif
+#endif
+
+#ifdef CONFIG_PRAM
+	/*
+	 * reserve protected RAM
+	 */
+	i = getenv_r ("pram", (char *)tmp, sizeof (tmp));
+	reg = (i > 0) ? simple_strtoul ((const char *)tmp, NULL, 10) : CONFIG_PRAM;
+	addr -= (reg << 10);		/* size is in kB */
+	debug ("Reserving %ldk for protected RAM at %08lx\n", reg, addr);
+#endif /* CONFIG_PRAM */
+
+#if !(defined(CONFIG_SYS_NO_ICACHE) && defined(CONFIG_SYS_NO_DCACHE))
+	/* reserve TLB table */
+	addr -= (4096 * 4);
+
+	/* round down to next 64 kB limit */
+	addr &= ~(0x10000 - 1);
+
+	gd->tlb_addr = addr;
+	debug ("TLB table at: %08lx\n", addr);
+#endif
+
+	/* round down to next 4 kB limit */
+	addr &= ~(4096 - 1);
+	debug ("Top of RAM usable for U-Boot at: %08lx\n", addr);
+
+#ifdef CONFIG_VFD
+#	ifndef PAGE_SIZE
+#	  define PAGE_SIZE 4096
+#	endif
+	/*
+	 * reserve memory for VFD display (always full pages)
+	 */
+	addr -= vfd_setmem (addr);
+	gd->fb_base = addr;
+#endif /* CONFIG_VFD */
+
+#ifdef CONFIG_LCD
+	/* reserve memory for LCD display (always full pages) */
+	addr = lcd_setmem (addr);
+	gd->fb_base = addr;
+#endif /* CONFIG_LCD */
+
+	/*
+	 * reserve memory for U-Boot code, data & bss
+	 * round down to next 4 kB limit
+	 */
+	addr -= gd->mon_len;
+	addr &= ~(4096 - 1);
+
+	debug ("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr);
+
+#ifndef CONFIG_PRELOADER
+	/*
+	 * reserve memory for malloc() arena
+	 */
+	addr_sp = addr - TOTAL_MALLOC_LEN;
+	debug ("Reserving %dk for malloc() at: %08lx\n",
+			TOTAL_MALLOC_LEN >> 10, addr_sp);
+	/*
+	 * (permanently) allocate a Board Info struct
+	 * and a permanent copy of the "global" data
+	 */
+	addr_sp -= sizeof (bd_t);
+	bd = (bd_t *) addr_sp;
+	gd->bd = bd;
+	debug ("Reserving %zu Bytes for Board Info at: %08lx\n",
+			sizeof (bd_t), addr_sp);
+	addr_sp -= sizeof (gd_t);
+	id = (gd_t *) addr_sp;
+	debug ("Reserving %zu Bytes for Global Data at: %08lx\n",
+			sizeof (gd_t), addr_sp);
+
+	/* setup stackpointer for exeptions */
+	gd->irq_sp = addr_sp;
+#ifdef CONFIG_USE_IRQ
+	addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
+	debug ("Reserving %zu Bytes for IRQ stack at: %08lx\n",
+		CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp);
+#endif
+	/* leave 3 words for abort-stack    */
+	addr_sp -= 3;
+
+	/* 8-byte alignment for ABI compliance */
+	addr_sp &= ~0x07;
+#else
+	addr_sp += 128;	/* leave 32 words for abort-stack   */
+	gd->irq_sp = addr_sp;
+#endif
+
+	debug ("New Stack Pointer is: %08lx\n", addr_sp);
+
+#ifdef CONFIG_POST
+	post_bootmode_init();
+	post_run (NULL, POST_ROM | post_bootmode_get(0));
+#endif
+
+	gd->bd->bi_baudrate = gd->baudrate;
+	/* Ram ist board specific, so move it to board code ... */
+	dram_init_banksize();
+	display_dram_config();	/* and display it */
+
+	gd->relocaddr = addr;
+	gd->start_addr_sp = addr_sp;
+	gd->reloc_off = addr - _TEXT_BASE;
+	debug ("relocation Offset is: %08lx\n", gd->reloc_off);
+	memcpy (id, (void *)gd, sizeof (gd_t));
+
+	relocate_code (addr_sp, id, addr);
+
+	/* NOTREACHED - relocate_code() does not return */
+}
+
+#if !defined(CONFIG_SYS_NO_FLASH)
+static char *failed = "*** failed ***\n";
+#endif
+
+/************************************************************************
+ *
+ * This is the next part if the initialization sequence: we are now
+ * running from RAM and have a "normal" C environment, i. e. global
+ * data can be written, BSS has been cleared, the stack size in not
+ * that critical any more, etc.
+ *
+ ************************************************************************
+ */
+void board_init_r (gd_t *id, ulong dest_addr)
+{
+	char *s;
+	bd_t *bd;
+	ulong malloc_start;
+#if !defined(CONFIG_SYS_NO_FLASH)
+	ulong flash_size;
+#endif
+#if !defined(CONFIG_RELOC_FIXUP_WORKS)
+	extern void malloc_bin_reloc (void);
+#if defined(CONFIG_CMD_BMP)
+	extern void bmp_reloc(void);
+#endif
+#if defined(CONFIG_CMD_I2C)
+	extern void i2c_reloc(void);
+#endif
+#endif
+
+	gd = id;
+	bd = gd->bd;
+
+	gd->flags |= GD_FLG_RELOC;	/* tell others: relocation done */
+
+	monitor_flash_len = _bss_start - _TEXT_BASE;
+	debug ("monitor flash len: %08lX\n", monitor_flash_len);
+	board_init();	/* Setup chipselects */
+
+#ifdef CONFIG_SERIAL_MULTI
+	serial_initialize();
+#endif
+
+	debug ("Now running in RAM - U-Boot at: %08lx\n", dest_addr);
+
+#if !defined(CONFIG_RELOC_FIXUP_WORKS)
+	/*
+	 * We have to relocate the command table manually
+	 */
+	fixup_cmdtable(&__u_boot_cmd_start,
+		(ulong)(&__u_boot_cmd_end - &__u_boot_cmd_start));
+#if defined(CONFIG_CMD_BMP)
+	bmp_reloc();
+#endif
+#if defined(CONFIG_CMD_I2C)
+	i2c_reloc();
+#endif
+#endif /* !defined(CONFIG_RELOC_FIXUP_WORKS) */
+
+#ifdef CONFIG_LOGBUFFER
+	logbuff_init_ptrs ();
+#endif
+#ifdef CONFIG_POST
+	post_output_backlog ();
+#ifndef CONFIG_RELOC_FIXUP_WORKS
+	post_reloc ();
+#endif
+#endif
+
+	/* The Malloc area is immediately below the monitor copy in DRAM */
+	malloc_start = dest_addr - TOTAL_MALLOC_LEN;
+	mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);
+#if !defined(CONFIG_RELOC_FIXUP_WORKS)
+	malloc_bin_reloc ();
+#endif
+
+#if !defined(CONFIG_SYS_NO_FLASH)
+	puts ("FLASH: ");
+
+	if ((flash_size = flash_init ()) > 0) {
+# ifdef CONFIG_SYS_FLASH_CHECKSUM
+		print_size (flash_size, "");
+		/*
+		 * Compute and print flash CRC if flashchecksum is set to 'y'
+		 *
+		 * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
+		 */
+		s = getenv ("flashchecksum");
+		if (s && (*s == 'y')) {
+			printf ("  CRC: %08X",
+				crc32 (0, (const unsigned char *) CONFIG_SYS_FLASH_BASE, flash_size)
+			);
+		}
+		putc ('\n');
+# else	/* !CONFIG_SYS_FLASH_CHECKSUM */
+		print_size (flash_size, "\n");
+# endif /* CONFIG_SYS_FLASH_CHECKSUM */
+	} else {
+		puts (failed);
+		hang ();
+	}
+#endif
+
+#if defined(CONFIG_CMD_NAND)
+	puts ("NAND:  ");
+	nand_init();		/* go init the NAND */
+#endif
+
+#if defined(CONFIG_CMD_ONENAND)
+	onenand_init();
+#endif
+
+#ifdef CONFIG_HAS_DATAFLASH
+	AT91F_DataflashInit();
+	dataflash_print_info();
+#endif
+
+	/* initialize environment */
+	env_relocate ();
+
+#ifdef CONFIG_VFD
+	/* must do this after the framebuffer is allocated */
+	drv_vfd_init();
+#endif /* CONFIG_VFD */
+
+	/* IP Address */
+	gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
+
+	stdio_init ();	/* get the devices list going. */
+
+	jumptable_init ();
+
+#if defined(CONFIG_API)
+	/* Initialize API */
+	api_init ();
+#endif
+
+	console_init_r ();	/* fully init console as a device */
+
+#if defined(CONFIG_ARCH_MISC_INIT)
+	/* miscellaneous arch dependent initialisations */
+	arch_misc_init ();
+#endif
+#if defined(CONFIG_MISC_INIT_R)
+	/* miscellaneous platform dependent initialisations */
+	misc_init_r ();
+#endif
+
+	 /* set up exceptions */
+	interrupt_init ();
+	/* enable exceptions */
+	enable_interrupts ();
+
+	/* Perform network card initialisation if necessary */
+#ifdef CONFIG_DRIVER_TI_EMAC
+	/* XXX: this needs to be moved to board init */
+extern void davinci_eth_set_mac_addr (const u_int8_t *addr);
+	if (getenv ("ethaddr")) {
+		uchar enetaddr[6];
+		eth_getenv_enetaddr("ethaddr", enetaddr);
+		davinci_eth_set_mac_addr(enetaddr);
+	}
+#endif
+
+#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
+	/* XXX: this needs to be moved to board init */
+	if (getenv ("ethaddr")) {
+		uchar enetaddr[6];
+		eth_getenv_enetaddr("ethaddr", enetaddr);
+		smc_set_mac_addr(enetaddr);
+	}
+#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */
+
+	/* Initialize from environment */
+	if ((s = getenv ("loadaddr")) != NULL) {
+		load_addr = simple_strtoul (s, NULL, 16);
+	}
+#if defined(CONFIG_CMD_NET)
+	if ((s = getenv ("bootfile")) != NULL) {
+		copy_filename (BootFile, s, sizeof (BootFile));
+	}
+#endif
+
+#ifdef BOARD_LATE_INIT
+	board_late_init ();
+#endif
+
+#ifdef CONFIG_GENERIC_MMC
+	puts ("MMC:   ");
+	mmc_initialize (gd->bd);
+#endif
+
+#ifdef CONFIG_BITBANGMII
+	bb_miiphy_init();
+#endif
+#if defined(CONFIG_CMD_NET)
+#if defined(CONFIG_NET_MULTI)
+	puts ("Net:   ");
+#endif
+	eth_initialize(gd->bd);
+#if defined(CONFIG_RESET_PHY_R)
+	debug ("Reset Ethernet PHY\n");
+	reset_phy();
+#endif
+#endif
+
+#ifdef CONFIG_POST
+	post_run (NULL, POST_RAM | post_bootmode_get(0));
+#endif
+
+#if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER)
+	/*
+	 * Export available size of memory for Linux,
+	 * taking into account the protected RAM at top of memory
+	 */
+	{
+		ulong pram;
+		uchar memsz[32];
+#ifdef CONFIG_PRAM
+		char *s;
+
+		if ((s = getenv ("pram")) != NULL) {
+			pram = simple_strtoul (s, NULL, 10);
+		} else {
+			pram = CONFIG_PRAM;
+		}
+#else
+		pram=0;
+#endif
+#ifdef CONFIG_LOGBUFFER
+#ifndef CONFIG_ALT_LB_ADDR
+		/* Also take the logbuffer into account (pram is in kB) */
+		pram += (LOGBUFF_LEN+LOGBUFF_OVERHEAD)/1024;
+#endif
+#endif
+		sprintf ((char *)memsz, "%ldk", (bd->bi_memsize / 1024) - pram);
+		setenv ("mem", (char *)memsz);
+	}
+#endif
+
+	/* main_loop() can return to retry autoboot, if so just run it again. */
+	for (;;) {
+		main_loop ();
+	}
+
+	/* NOTREACHED - no way out of command loop except booting */
+}
+#endif /* defined(CONFIG_SYS_ARM_WITHOUT_RELOC) */

 void hang (void)
 {
diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
index b2811f3..fe6d459 100644
--- a/arch/arm/lib/cache-cp15.c
+++ b/arch/arm/lib/cache-cp15.c
@@ -44,17 +44,44 @@ static void cp_delay (void)
 	asm volatile("" : : : "memory");
 }

-/* to activate the MMU we need to set up virtual memory: use 1M areas in bss */
+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+static inline void dram_bank_mmu_setup(int bank)
+{
+	u32 *page_table = (u32 *)gd->tlb_addr;
+	bd_t *bd = gd->bd;
+	int	i;
+
+	debug("%s: bank: %d\n", __func__, bank);
+	for (i = bd->bi_dram[bank].start >> 20;
+	     i < (bd->bi_dram[bank].start + bd->bi_dram[bank].size) >> 20;
+	     i++) {
+		page_table[i] = i << 20 | (3 << 10) | CACHE_SETUP;
+	}
+}
+#endif
+
+/* to activate the MMU we need to set up virtual memory: use 1M areas */
 static inline void mmu_setup(void)
 {
+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+	u32 *page_table = (u32 *)gd->tlb_addr;
+#else
 	static u32 __attribute__((aligned(16384))) page_table[4096];
 	bd_t *bd = gd->bd;
-	int i, j;
+	int j;
+#endif
+	int i;
 	u32 reg;

 	/* Set up an identity-mapping for all 4GB, rw for everyone */
 	for (i = 0; i < 4096; i++)
 		page_table[i] = i << 20 | (3 << 10) | 0x12;
+
+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+		dram_bank_mmu_setup(i);
+	}
+#else
 	/* Then, enable cacheable and bufferable for RAM only */
 	for (j = 0; j < CONFIG_NR_DRAM_BANKS; j++) {
 		for (i = bd->bi_dram[j].start >> 20;
@@ -63,6 +90,7 @@ static inline void mmu_setup(void)
 			page_table[i] = i << 20 | (3 << 10) | CACHE_SETUP;
 		}
 	}
+#endif

 	/* Copy the page table address to cp15 */
 	asm volatile("mcr p15, 0, %0, c2, c0, 0"
@@ -74,7 +102,6 @@ static inline void mmu_setup(void)
 	reg = get_cr();	/* get control reg. */
 	cp_delay();
 	set_cr(reg | CR_M);
-
 }

 /* cache_bit must be either CR_I or CR_C */
@@ -96,6 +123,10 @@ static void cache_disable(uint32_t cache_bit)
 	uint32_t reg;

 	if (cache_bit == CR_C) {
+		/* if cache isn;t enabled no need to disable */
+		reg = get_cr();
+		if ((reg & CR_C) != CR_C)
+			return;
 		/* if disabling data cache, disable mmu too */
 		cache_bit |= CR_M;
 		flush_cache(0, ~0);
diff --git a/arch/arm/lib/interrupts.c b/arch/arm/lib/interrupts.c
index 1f2b815..9a21e7b 100644
--- a/arch/arm/lib/interrupts.c
+++ b/arch/arm/lib/interrupts.c
@@ -38,15 +38,20 @@
 #include <common.h>
 #include <asm/proc-armv/ptrace.h>

-#ifdef CONFIG_USE_IRQ
 DECLARE_GLOBAL_DATA_PTR;

+#ifdef CONFIG_USE_IRQ
 int interrupt_init (void)
 {
 	/*
 	 * setup up stacks if necessary
 	 */
+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+	IRQ_STACK_START = gd->irq_sp - 4;
+	IRQ_STACK_START_IN = gd->irq_sp + 8;
+#else
 	IRQ_STACK_START = _armboot_start - CONFIG_SYS_MALLOC_LEN - CONFIG_SYS_GBL_DATA_SIZE - 4;
+#endif
 	FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;

 	return arch_interrupt_init();
@@ -81,6 +86,18 @@ int disable_interrupts (void)
 	return (old & 0x80) == 0;
 }
 #else
+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+int interrupt_init (void)
+{
+	/*
+	 * setup up stacks if necessary
+	 */
+	IRQ_STACK_START_IN = gd->irq_sp + 8;
+
+	return 0;
+}
+#endif
+
 void enable_interrupts (void)
 {
 	return;
diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c
index cc81543..4c3040a 100644
--- a/common/cmd_bdinfo.c
+++ b/common/cmd_bdinfo.c
@@ -343,7 +343,16 @@ int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	printf ("ip_addr     = %pI4\n", &bd->bi_ip_addr);
 #endif
 	printf ("baudrate    = %d bps\n", bd->bi_baudrate);
-
+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+#if !(defined(CONFIG_SYS_NO_ICACHE) && defined(CONFIG_SYS_NO_DCACHE))
+	print_num ("TLB addr", gd->tlb_addr);
+#endif
+	print_num ("relocaddr", gd->relocaddr);
+	print_num ("reloc off", gd->reloc_off);
+	print_num ("irq_sp", gd->irq_sp);	/* irq stack pointer */
+	print_num ("sp start ", gd->start_addr_sp);
+	print_num ("FB base  ", gd->fb_base);
+#endif
 	return 0;
 }

diff --git a/common/cmd_bmp.c b/common/cmd_bmp.c
index d51cc55..6fa8a15 100644
--- a/common/cmd_bmp.c
+++ b/common/cmd_bmp.c
@@ -137,6 +137,12 @@ static cmd_tbl_t cmd_bmp_sub[] = {
 	U_BOOT_CMD_MKENT(display, 5, 0, do_bmp_display, "", ""),
 };

+#ifndef CONFIG_RELOC_FIXUP_WORKS
+void bmp_reloc(void) {
+	fixup_cmdtable(cmd_bmp_sub, ARRAY_SIZE(cmd_bmp_sub));
+}
+#endif
+
 /*
  * Subroutine:  do_bmp
  *
diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c
index 5e9135e..48de54b 100644
--- a/common/cmd_i2c.c
+++ b/common/cmd_i2c.c
@@ -1287,6 +1287,12 @@ static cmd_tbl_t cmd_i2c_sub[] = {
 	U_BOOT_CMD_MKENT(speed, 1, 1, do_i2c_bus_speed, "", ""),
 };

+#ifndef CONFIG_RELOC_FIXUP_WORKS
+void i2c_reloc(void) {
+	fixup_cmdtable(cmd_i2c_sub, ARRAY_SIZE(cmd_i2c_sub));
+}
+#endif
+
 static int do_i2c(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 {
 	cmd_tbl_t *c;
diff --git a/doc/README.arm-relocation b/doc/README.arm-relocation
new file mode 100644
index 0000000..6be1a12
--- /dev/null
+++ b/doc/README.arm-relocation
@@ -0,0 +1,321 @@
+To make relocation on arm working, the following changes are done:
+
+Add new compilerflag:
+
+-fPIC
+
+	-> compiler generates position independent code
+
+changes in board code:
+
+- dram_init:
+  - bd pointer is now at this point not accessible, so only
+    detect the real dramsize, and store it in gd->ram_size.
+    best detected with get_ram_size();
+    ToDo: move there also the dram initialization on boards where
+          it is possible.
+  - setup the bd_t dram bank info in the new function
+    dram_init_banksize().
+
+- board.c code is adapted from ppc code
+
+- undef CONFIG_RELOC_FIXUP_WORKS
+
+  -> cmdtabl, and subcommand table must be handled from "hand"
+     collected in section "__datarellocal_start".
+
+  - How To fixup the sections:
+
+    __datarel_start, __datarelrolocal_start, __datarellocal_start and
+    __datarelro_start
+
+    automatically? Then it should be possible to define again
+    CONFIG_RELOC_FIXUP_WORKS
+
+- irq stack setup is now not longer on a fix position, instead it is
+  calculated in board_init_f, and stored in gd->irq_sp
+
+-------------------------------------------------------------------------------------
+
+To compile a board without relocation, define CONFIG_SYS_ARM_WITHOUT_RELOC
+This possibility will removed!! So please fix your board to compile without
+CONFIG_SYS_ARM_WITHOUT_RELOC defined!!!
+
+-------------------------------------------------------------------------------------
+
+ToDo:
+
+- fill in bd_t infos (check)
+- adapt all boards
+
+- maybe adapt TEXT_BASE (this must be checked from board maintainers)
+  This *must* be done for boards, which boot from NOR flash
+
+  on other boards if TEXT_BASE = relocation baseaddr, this saves
+  one copying from u-boot code.
+
+- new function dram_init_banksize() is actual board specific. Maybe
+  we make a weak default function in arch/arm/lib/board.c ?
+
+-------------------------------------------------------------------------------------
+
+Relocation with NAND_SPL (example for the tx25):
+
+- cpu copies the first page from NAND to 0xbb000000 (IMX_NFC_BASE)
+  and start with code execution on this address.
+
+- The First page contains u-boot code from u-boot:nand_spl/nand_boot_fsl_nfc.c
+  which inits the dram, cpu registers, reloacte itself to TEXT_BASE  and loads
+  the "real" u-boot to CONFIG_SYS_NAND_U_BOOT_DST and starts execution
+  @CONFIG_SYS_NAND_U_BOOT_START
+
+- This u-boot does no ram int, nor cpu register setup. Just looks
+  where it have to relocate and relocate itself to this address.
+  If relocate address = TEXT_BASE(not the same, as the TEXT_BASE
+  from the nand_spl code), no need to copy, just go on with bss clear
+  and jump to board_init_r.
+
+-------------------------------------------------------------------------------------
+
+Relocation:
+How to translate flash addresses in GOT to ram addresses.
+This is automagically done from code, but this example
+shows, how this magic code works ;-)
+(example on the qong board)
+
+Find a variable:
+
+a) search it in System.map
+(for example flash_info)
+
+a005b4c0 B BootpID
+a005b4c4 B BootpTry
+a005b4c8 b slave
+a005b4cc B flash_info
+^^^^^^^^
+a005c908 b saved_sector.4002
+a005c910 b cfi_mtd_info
+a005c9c0 b cfi_mtd_names
+a005c9d0 B mtd_table
+
+---------------------------------------
+
+b) create hexdump from u-boot code:
+
+hexdump -C u-boot > gnlmpfhex
+
+---------------------------------------
+
+c) search the variables address in the hexdump
+
+
+*
+0005fc80  00 00 00 00 00 00 00 00  2c 06 01 a0 18 cd 05 a0  |........,.......|
+0005fc90  9c d4 05 a0 bc b4 05 a0  1c 7f 05 a0 f0 05 01 a0  |................|
+0005fca0  08 5a 04 a0 1c ab 05 a0  ec a4 05 a0 98 c3 01 a0  |.Z..............|
+0005fcb0  a0 d6 05 a0 04 71 05 a0  c0 f9 00 a0 3c cd 05 a0  |.....q......<...|
+0005fcc0  cc b4 05 a0 f0 fa 00 a0  f0 d6 05 a0 10 86 05 a0  |................|
+          ^^^^^^^^^^^
+0005fcd0  a4 16 06 a0 dc 64 05 a0  18 86 05 a0 52 48 05 a0  |.....d......RH..|
+0005fce0  c0 86 05 a0 24 6e 02 a0  b4 6c 05 a0 b0 94 01 a0  |....$n...l......|
+0005fcf0  1c 86 05 a0 50 85 05 a0  d4 0c 06 a0 bc 0b 06 a0  |....P...........|
+
+
+-> 0005fcc0
+
+----------------------------------------
+
+d) know we calculate this address in RAM
+
+
+  8ff08000	(new address of code in RAM *1)
+
++ 0005fcc0
+
+- 00008000	(offset of text *2)
+
+----------
+
+  8ff5fcc0	-> Addr GOT in RAM
+
+*1:
+activate debug and look for the line:
+Now running in RAM - U-Boot at: 8ff08000
+                                ^^^^^^^^
+                                new address of u-boot code in RAM
+
+*2:
+Section Headers:
+  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
+  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
+  [ 1] .text             PROGBITS        a0000000 008000 04599c 00  AX  0   0 32
+                                                  ^^^^^^
+                                                  Offset of text
+
+----------------------------------------
+
+e) now we look in 8ff5fcc0 (RAM)
+
+
+QongEVB>md 0x8ff5fcc0
+8ff5fcc0 : a005b4cc a000faf0 a005d6f0 a0058610  ................
+           ^^^^^^^^
+           Bingo, here we have the old flash address (when relocation
+           is working, here is the fixed ram address. see @ f, how
+           it gets calculated)
+
+
+----------------------------------------
+
+f) now translate it in the new RAM address
+
+  a005b4cc
+
+- a0000000     TextBase
+
++ 8ff08000     new address of u-boot in ram
+----------
+  8ff634cc
+
+QongEVB>mm 0x8ff5fcc0 0x8ff634cc 1
+QongEVB>md 0x8ff5fcc0
+8ff5fcc0 : 8ff634cc a000faf0 a005d6f0 a0058610  .4..............
+8ff5fcd0 : a00616a4 a00564dc a0058618 a0054852  .....d......RH..
+
+As this must be done for all address in the GOT, the u-boot
+code did this automagically ... :-)
+
+----------------------------------------------
+
+g) check if the new address is really in the bss section:
+
+bss start:
+8ff6054c	(8ff08000 + 0005854C monitorlen)
+
+bss end:
+8ff698ac	(8ff08000 + 618AC)
+
+8ff634cc is in bss :-)
+
+----------------------------------------------
+
+h) u-boot prints:
+
+important  addresses:
+
+U-Boot code: A0000000 -> A005854C  BSS: -> A00618AC	TextBase 0xa0000000
+Now running in RAM - U-Boot at: 8ff08000		relocBase 0x8ff08000
+
+
+---------
+
+U-Boot 2010.06-rc2-00002-gf8fbb25-dirty (Jun 18 2010 - 17:07:19)
+
+U-Boot code: A0000000 -> A005854C  BSS: -> A00618AC
+CPU:   Freescale i.MX31 at 398 MHz
+Board: DAVE/DENX Qong
+mon: FFFFFFFF gd->monLen: 000618AC
+Top of RAM usable for U-Boot at: 90000000
+LCD panel info: 640 x 480, 16 bit/pix
+Reserving 600k for LCD Framebuffer at: 8ff6a000
+Reserving 390k for U-Boot at: 8ff08000
+Reserving 1280k for malloc() at: 8fdc8000
+Reserving 28 Bytes for Board Info at: 8fdc7fe4
+Reserving 48 Bytes for Global Data at: 8fdc7fb4
+New Stack Pointer is: 8fdc7fb0
+RAM Configuration:
+Bank #0: 80000000 256 MiB
+mon: 0005854C gd->monLen: 000618AC
+Now running in RAM - U-Boot at: 8ff08000
+
+-------------------------------------------------------------------------------------
+
+Debugging u-boot in RAM:
+(example on the qong board)
+
+a) add in config.mk:
+
+PLATFORM_CPPFLAGS += -DDEBUG
+
+-----------------
+
+b) start debugger
+
+arm-linux-gdb u-boot
+
+[hs at pollux u-boot]$ arm-linux-gdb u-boot
+GNU gdb Red Hat Linux (6.7-2rh)
+Copyright (C) 2007 Free Software Foundation, Inc.
+License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
+This is free software: you are free to change and redistribute it.
+There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
+and "show warranty" for details.
+This GDB was configured as "--host=i686-pc-linux-gnu --target=arm-linux".
+The target architecture is set automatically (currently arm)
+..
+(gdb)
+
+-----------------
+
+c) connect to target
+
+target remote bdi10:2001
+
+(gdb) target remote bdi10:2001
+Remote debugging using bdi10:2001
+0x8ff17f10 in ?? ()
+(gdb)
+
+-----------------
+
+d) discard symbol-file
+
+(gdb) symbol-file
+Discard symbol table from `/home/hs/celf/u-boot/u-boot'? (y or n) y
+No symbol file now.
+(gdb)
+
+-----------------
+
+e) load new symbol table:
+
+(gdb) add-symbol-file u-boot 0x8ff08000
+add symbol table from file "u-boot" at
+        .text_addr = 0x8ff08000
+(y or n) y
+Reading symbols from /home/hs/celf/u-boot/u-boot...done.
+(gdb) c
+Continuing.
+^C
+Program received signal SIGSTOP, Stopped (signal).
+0x8ff17f18 in serial_getc () at serial_mxc.c:192
+192             while (__REG(UART_PHYS + UTS) & UTS_RXEMPTY);
+(gdb)
+
+add-symbol-file u-boot 0x8ff08000
+                       ^^^^^^^^^^
+                       get this address from u-boot debug printfs
+
+U-Boot 2010.06-rc2-00009-gf77b8b8-dirty (Jun 22 2010 - 09:43:46)
+
+U-Boot code: A0000000 -> A0058BAC  BSS: -> A0061F10
+CPU:   Freescale i.MX31 at 398 MHz
+Board: DAVE/DENX Qong
+mon: FFFFFFFF gd->monLen: 00061F10
+Top of RAM usable for U-Boot at: 90000000
+LCD panel info: 640 x 480, 16 bit/pix
+Reserving 600k for LCD Framebuffer at: 8ff6a000
+Reserving 391k for U-Boot at: 8ff08000
+                              ^^^^^^^^
+Reserving 1280k for malloc() at: 8fdc8000
+Reserving 24 Bytes for Board Info at: 8fdc7fe8
+Reserving 52 Bytes for Global Data at: 8fdc7fb4
+New Stack Pointer is: 8fdc7fb0
+RAM Configuration:
+Bank #0: 80000000 256 MiB
+relocation Offset is: eff08000
+mon: 00058BAC gd->monLen: 00061F10
+Now running in RAM - U-Boot at: 8ff08000
+                                ^^^^^^^^
+
+Now you can use gdb as usual :-)
diff --git a/nand_spl/nand_boot.c b/nand_spl/nand_boot.c
index b9fd6f5..18ecbe1 100644
--- a/nand_spl/nand_boot.c
+++ b/nand_spl/nand_boot.c
@@ -221,6 +221,13 @@ static int nand_load(struct mtd_info *mtd, unsigned int offs,
 	return 0;
 }

+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+void board_init_f (ulong bootflag)
+{
+	relocate_code (TEXT_BASE - TOTAL_MALLOC_LEN, NULL, TEXT_BASE);
+}
+#endif
+
 /*
  * The main entry for NAND booting. It's necessary that SDRAM is already
  * configured and available since this code loads the main U-Boot image
diff --git a/nand_spl/nand_boot_fsl_nfc.c b/nand_spl/nand_boot_fsl_nfc.c
index ea3566b..3105657 100644
--- a/nand_spl/nand_boot_fsl_nfc.c
+++ b/nand_spl/nand_boot_fsl_nfc.c
@@ -263,6 +263,13 @@ static int nand_load(unsigned int from, unsigned int size, unsigned char *buf)
 	return 0;
 }

+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+void board_init_f (ulong bootflag)
+{
+	relocate_code (TEXT_BASE - TOTAL_MALLOC_LEN, NULL, TEXT_BASE);
+}
+#endif
+
 /*
  * The main entry for NAND booting. It's necessary that SDRAM is already
  * configured and available since this code loads the main U-Boot image
-- 
1.6.2.5

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany


More information about the U-Boot mailing list