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 d66434c..55d6599 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 fae5b11..da2cd90 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 8905224..2719bb5 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 1e0a150..f411c0f 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 9e5b5a9..d4fd3fc 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 879b2e2..6fb10e3 100644 (file)
@@ -30,4 +30,4 @@
 # (mem base + reserved)
 
 # For use with external or internal boots.
-TEXT_BASE = 0x80e80000
+TEXT_BASE = 0x80008000
index 3f6e803..2463be4 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 */