ARM: implement relocation for ARM V7 (OMAP)
authorHeiko Schocher <hs@denx.de>
Fri, 17 Sep 2010 11:10:41 +0000 (13:10 +0200)
committerWolfgang Denk <wd@denx.de>
Sun, 19 Sep 2010 17:29:53 +0000 (19:29 +0200)
Change the implementation for ARM V7 to relocate the code to an
arbitrary address in RAM.

Adapt the Beagle board (Cortex A8) to test the changes.

Portions of this work were supported by funding from
the CE Linux Forum.

Signed-off-by: Heiko Schocher <hs@denx.de>
arch/arm/cpu/armv7/mx51/u-boot.lds
arch/arm/cpu/armv7/omap3/emif4.c
arch/arm/cpu/armv7/omap3/sdrc.c
arch/arm/cpu/armv7/start.S
arch/arm/cpu/armv7/u-boot.lds
board/ti/beagle/config.mk
include/configs/omap3_beagle.h

index d66434c95d62ce4a8405a5fc105c431c081f4e3a..55d6599b41c6cb20d636fc3e3a5faf4863f285c0 100644 (file)
@@ -44,10 +44,22 @@ SECTIONS
        .rodata : { *(.rodata) }
 
        . = ALIGN(4);
-       .data : { *(.data) }
+       .data : {
+               *(.data)
+       __datarel_start = .;
+               *(.data.rel)
+       __datarelrolocal_start = .;
+               *(.data.rel.ro.local)
+       __datarellocal_start = .;
+               *(.data.rel.local)
+       __datarelro_start = .;
+               *(.data.rel.ro)
+       }
 
+       __got_start = .;
        . = ALIGN(4);
        .got : { *(.got) }
+       __got_end = .;
 
        . = .;
        __u_boot_cmd_start = .;
index fae5b1161b03408a1af654f6ad5a98bf7f799633..da2cd9001303c1c23e3e7c4ab613dc8bc17a4391 100644 (file)
@@ -136,6 +136,7 @@ void do_emif4_init(void)
  * dram_init -
  *  - Sets uboots idea of sdram size
  */
+#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
 int dram_init(void)
 {
        DECLARE_GLOBAL_DATA_PTR;
@@ -157,6 +158,39 @@ int dram_init(void)
 
        return 0;
 }
+#else
+int dram_init(void)
+{
+       DECLARE_GLOBAL_DATA_PTR;
+       unsigned int size0 = 0, size1 = 0;
+
+       size0 = get_sdr_cs_size(CS0);
+       /*
+        * If a second bank of DDR is attached to CS1 this is
+        * where it can be started.  Early init code will init
+        * memory on CS0.
+        */
+       if ((sysinfo.mtype == DDR_COMBO) || (sysinfo.mtype == DDR_STACKED))
+               size1 = get_sdr_cs_size(CS1);
+
+       gd->ram_size = size0 + size1;
+       return 0;
+}
+
+void dram_init_banksize (void)
+{
+       DECLARE_GLOBAL_DATA_PTR;
+       unsigned int size0 = 0, size1 = 0;
+
+       size0 = get_sdr_cs_size(CS0);
+       size1 = get_sdr_cs_size(CS1);
+
+       gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
+       gd->bd->bi_dram[0].size = size0;
+       gd->bd->bi_dram[1].start = PHYS_SDRAM_1 + get_sdr_cs_offset(CS1);
+       gd->bd->bi_dram[1].size = size1;
+}
+#endif
 
 /*
  * mem_init() -
index 8905224439b5e7d07204c2b5b2b4f180c5599ce8..2719bb53a7cc343a2e677493d682fbf27905aeee 100644 (file)
@@ -163,6 +163,7 @@ void do_sdrc_init(u32 cs, u32 early)
  * dram_init -
  *  - Sets uboots idea of sdram size
  */
+#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
 int dram_init(void)
 {
        DECLARE_GLOBAL_DATA_PTR;
@@ -188,6 +189,43 @@ int dram_init(void)
 
        return 0;
 }
+#else
+int dram_init(void)
+{
+       DECLARE_GLOBAL_DATA_PTR;
+       unsigned int size0 = 0, size1 = 0;
+
+       size0 = get_sdr_cs_size(CS0);
+       /*
+        * If a second bank of DDR is attached to CS1 this is
+        * where it can be started.  Early init code will init
+        * memory on CS0.
+        */
+       if ((sysinfo.mtype == DDR_COMBO) || (sysinfo.mtype == DDR_STACKED)) {
+               do_sdrc_init(CS1, NOT_EARLY);
+               make_cs1_contiguous();
+
+               size1 = get_sdr_cs_size(CS1);
+       }
+       gd->ram_size = size0 + size1;
+
+       return 0;
+}
+
+void dram_init_banksize (void)
+{
+       DECLARE_GLOBAL_DATA_PTR;
+       unsigned int size0 = 0, size1 = 0;
+
+       size0 = get_sdr_cs_size(CS0);
+       size1 = get_sdr_cs_size(CS1);
+
+       gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
+       gd->bd->bi_dram[0].size = size0;
+       gd->bd->bi_dram[1].start = PHYS_SDRAM_1 + get_sdr_cs_offset(CS1);
+       gd->bd->bi_dram[1].size = size1;
+}
+#endif
 
 /*
  * mem_init -
index 1e0a1504bfc28a2ec413935c9464e63be1852ff5..f411c0f4f058f9bd44f5412e2137fe868d8f2782 100644 (file)
@@ -65,12 +65,15 @@ _end_vect:
  *
  *************************************************************************/
 
+.globl _TEXT_BASE
 _TEXT_BASE:
        .word   TEXT_BASE
 
+#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
 .globl _armboot_start
 _armboot_start:
        .word _start
+#endif
 
 /*
  * These are defined in the board-specific linker script.
@@ -95,6 +98,176 @@ FIQ_STACK_START:
        .word 0x0badc0de
 #endif
 
+#if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
+/* IRQ stack memory (calculated at run-time) + 8 bytes */
+.globl IRQ_STACK_START_IN
+IRQ_STACK_START_IN:
+       .word   0x0badc0de
+
+.globl _datarel_start
+_datarel_start:
+       .word __datarel_start
+
+.globl _datarelrolocal_start
+_datarelrolocal_start:
+       .word __datarelrolocal_start
+
+.globl _datarellocal_start
+_datarellocal_start:
+       .word __datarellocal_start
+
+.globl _datarelro_start
+_datarelro_start:
+       .word __datarelro_start
+
+.globl _got_start
+_got_start:
+       .word __got_start
+
+.globl _got_end
+_got_end:
+       .word __got_end
+
+/*
+ * the actual reset code
+ */
+
+reset:
+       /*
+        * set the cpu to SVC32 mode
+        */
+       mrs     r0, cpsr
+       bic     r0, r0, #0x1f
+       orr     r0, r0, #0xd3
+       msr     cpsr,r0
+
+#if (CONFIG_OMAP34XX)
+       /* Copy vectors to mask ROM indirect addr */
+       adr     r0, _start              @ r0 <- current position of code
+       add     r0, r0, #4              @ skip reset vector
+       mov     r2, #64                 @ r2 <- size to copy
+       add     r2, r0, r2              @ r2 <- source end address
+       mov     r1, #SRAM_OFFSET0       @ build vect addr
+       mov     r3, #SRAM_OFFSET1
+       add     r1, r1, r3
+       mov     r3, #SRAM_OFFSET2
+       add     r1, r1, r3
+next:
+       ldmia   r0!, {r3 - r10}         @ copy from source address [r0]
+       stmia   r1!, {r3 - r10}         @ copy to   target address [r1]
+       cmp     r0, r2                  @ until source end address [r2]
+       bne     next                    @ loop until equal */
+#if !defined(CONFIG_SYS_NAND_BOOT) && !defined(CONFIG_SYS_ONENAND_BOOT)
+       /* No need to copy/exec the clock code - DPLL adjust already done
+        * in NAND/oneNAND Boot.
+        */
+       bl      cpy_clk_code            @ put dpll adjust code behind vectors
+#endif /* NAND Boot */
+#endif
+       /* the mask ROM code should have PLL and others stable */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+       bl      cpu_init_crit
+#endif
+
+/* Set stackpointer in internal RAM to call board_init_f */
+call_board_init_f:
+       ldr     sp, =(CONFIG_SYS_INIT_SP_ADDR)
+       ldr     r0,=0x00000000
+       bl      board_init_f
+
+/*------------------------------------------------------------------------------*/
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ */
+       .globl  relocate_code
+relocate_code:
+       mov     r4, r0  /* save addr_sp */
+       mov     r5, r1  /* save addr of gd */
+       mov     r6, r2  /* save addr of destination */
+       mov     r7, r2  /* save addr of destination */
+
+       /* Set up the stack                                                 */
+stack_setup:
+       mov     sp, r4
+
+#ifndef CONFIG_SKIP_RELOCATE_UBOOT
+       adr     r0, _start
+       ldr     r2, _TEXT_BASE
+       ldr     r3, _bss_start
+       sub     r2, r3, r2              /* r2 <- size of armboot            */
+       add     r2, r0, r2              /* r2 <- source end address         */
+       cmp     r0, r6
+#ifndef CONFIG_PRELOADER
+       beq     jump_2_ram
+#endif
+
+copy_loop:
+       ldmia   r0!, {r9-r10}           /* copy from source address [r0]    */
+       stmia   r6!, {r9-r10}           /* copy to   target address [r1]    */
+       cmp     r0, r2                  /* until source end addreee [r2]    */
+       ble     copy_loop
+
+#ifndef CONFIG_PRELOADER
+       /* fix got entries */
+       ldr     r1, _TEXT_BASE
+       mov     r0, r7                  /* reloc addr */
+       ldr     r2, _got_start          /* addr in Flash */
+       ldr     r3, _got_end            /* addr in Flash */
+       sub     r3, r3, r1
+       add     r3, r3, r0
+       sub     r2, r2, r1
+       add     r2, r2, r0
+
+fixloop:
+       ldr     r4, [r2]
+       sub     r4, r4, r1
+       add     r4, r4, r0
+       str     r4, [r2]
+       add     r2, r2, #4
+       cmp     r2, r3
+       bne     fixloop
+
+clear_bss:
+       ldr     r0, _bss_start
+       ldr     r1, _bss_end
+       ldr     r3, _TEXT_BASE          /* Text base */
+       mov     r4, r7                  /* reloc addr */
+       sub     r0, r0, r3
+       add     r0, r0, r4
+       sub     r1, r1, r3
+       add     r1, r1, r4
+       mov     r2, #0x00000000         /* clear                            */
+
+clbss_l:str    r2, [r0]                /* clear loop...                    */
+       add     r0, r0, #4
+       cmp     r0, r1
+       bne     clbss_l
+#endif /* #ifndef CONFIG_PRELOADER */
+#endif /* #ifndef CONFIG_SKIP_RELOCATE_UBOOT */
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+jump_2_ram:
+       ldr     r0, _TEXT_BASE
+       ldr     r2, _board_init_r
+       sub     r2, r2, r0
+       add     r2, r2, r7      /* position from board_init_r in RAM */
+       /* setup parameters for board_init_r */
+       mov     r0, r5          /* gd_t */
+       mov     r1, r7          /* dest_addr */
+       /* jump to it ... */
+       mov     lr, r2
+       mov     pc, lr
+
+_board_init_r: .word board_init_r
+#else /* #if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC) */
 /*
  * the actual reset code
  */
@@ -180,7 +353,7 @@ clbss_l:
        ldr     pc, _start_armboot      @ jump to C code
 
 _start_armboot: .word start_armboot
-
+#endif /* #if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC) */
 
 /*************************************************************************
  *
@@ -263,11 +436,14 @@ cpu_init_crit:
                                                @ user stack
        stmia   sp, {r0 - r12}                  @ Save user registers (now in
                                                @ svc mode) r0-r12
-
+#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
        ldr     r2, _armboot_start
        sub     r2, r2, #(CONFIG_SYS_MALLOC_LEN)
        sub     r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE + 8) @ set base 2 words into abort
+#else
+       ldr     r2, IRQ_STACK_START_IN          @ set base 2 words into abort
                                                @ stack
+#endif
        ldmia   r2, {r2 - r3}                   @ get values for "aborted" pc
                                                @ and cpsr (into parm regs)
        add     r0, sp, #S_FRAME_SIZE           @ grab pointer to old stack
@@ -303,11 +479,14 @@ cpu_init_crit:
        .endm
 
        .macro get_bad_stack
+#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
        ldr     r13, _armboot_start             @ setup our mode stack (enter
-                                               @ in banked mode)
        sub     r13, r13, #(CONFIG_SYS_MALLOC_LEN)      @ move past malloc pool
        sub     r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE + 8) @ move to reserved a couple
-                                               @ spots for abort stack
+#else
+       ldr     r13, IRQ_STACK_START_IN         @ setup our mode stack (enter
+                                               @ in banked mode)
+#endif
 
        str     lr, [r13]                       @ save caller lr in position 0
                                                @ of saved stack
@@ -328,10 +507,14 @@ cpu_init_crit:
        sub     r13, r13, #4                    @ space on current stack for
                                                @ scratch reg.
        str     r0, [r13]                       @ save R0's value.
+#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
        ldr     r0, _armboot_start              @ get data regions start
        sub     r0, r0, #(CONFIG_SYS_MALLOC_LEN)        @ move past malloc pool
        sub     r0, r0, #(CONFIG_SYS_GBL_DATA_SIZE + 8) @ move past gbl and a couple
+#else
+       ldr     r0, IRQ_STACK_START_IN          @ get data regions start
                                                @ spots for abort stack
+#endif
        str     lr, [r0]                        @ save caller lr in position 0
                                                @ of saved stack
        mrs     r0, spsr                        @ get the spsr
index 9e5b5a97d7488de4bd4a7b1d08b04ee5da456f12..d4fd3fccee62d19c5f9bebdf61ffa63961b4cea4 100644 (file)
@@ -42,10 +42,22 @@ SECTIONS
        .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
        . = ALIGN(4);
-       .data : { *(.data) }
+       .data : {
+               *(.data)
+       __datarel_start = .;
+               *(.data.rel)
+       __datarelrolocal_start = .;
+               *(.data.rel.ro.local)
+       __datarellocal_start = .;
+               *(.data.rel.local)
+       __datarelro_start = .;
+               *(.data.rel.ro)
+       }
 
+       __got_start = .;
        . = ALIGN(4);
        .got : { *(.got) }
+       __got_end = .;
 
        __u_boot_cmd_start = .;
        .u_boot_cmd : { *(.u_boot_cmd) }
index 879b2e236fcf5a8aa4af58ceea1b5b32950f5d17..6fb10e31e333889b72b79af56acd509b3de23cc5 100644 (file)
@@ -30,4 +30,4 @@
 # (mem base + reserved)
 
 # For use with external or internal boots.
-TEXT_BASE = 0x80e80000
+TEXT_BASE = 0x80008000
index 3f6e803eb91b058c89bf4b49acb47a66840183b8..2463be416e044088033e179350b24789e7214292 100644 (file)
@@ -340,4 +340,9 @@ extern unsigned int boot_flash_sec;
 extern unsigned int boot_flash_type;
 #endif
 
+/* additions for new relocation code, must added to all boards */
+#undef CONFIG_SYS_ARM_WITHOUT_RELOC /* This board is tested with relocation support */
+#define CONFIG_SYS_SDRAM_BASE          PHYS_SDRAM_1
+#define CONFIG_SYS_INIT_SP_ADDR                (LOW_LEVEL_SRAM_STACK - CONFIG_SYS_GBL_DATA_SIZE)
+
 #endif /* __CONFIG_H */