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

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

Signed-off-by: Heiko Schocher <hs@denx.de>
arch/arm/cpu/arm920t/start.S
arch/arm/cpu/arm920t/u-boot.lds

index e532f55bfcba4ba4cdf92af000cfa1c57d3d9530..a079bb27271cfe1f692d682235cdc7dcc57ebc3e 100644 (file)
@@ -70,12 +70,15 @@ _fiq:                       .word fiq
  *************************************************************************
  */
 
+.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.
@@ -100,6 +103,35 @@ 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 start code
@@ -176,6 +208,189 @@ copyex:
        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
+
+       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
+       beq     clear_bss
+
+#ifndef CONFIG_SKIP_RELOCATE_UBOOT
+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          /* 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
+#endif
+#endif /* #ifndef CONFIG_SKIP_RELOCATE_UBOOT */
+
+clear_bss:
+#ifndef CONFIG_PRELOADER
+       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
+
+       bl coloured_LED_init
+       bl red_LED_on
+#endif
+
+/*
+ * We are done. Do not return, instead branch to second part of board
+ * initialization, now running from RAM.
+ */
+#ifdef CONFIG_NAND_SPL
+       ldr     pc, _nand_boot
+
+_nand_boot: .word nand_boot
+#else
+       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
+#endif
+
+#else /* #if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC) */
+/*
+ * the actual start code
+ */
+
+start_code:
+       /*
+        * set the cpu to SVC32 mode
+        */
+       mrs     r0, cpsr
+       bic     r0, r0, #0x1f
+       orr     r0, r0, #0xd3
+       msr     cpsr, r0
+
+       bl      coloured_LED_init
+       bl      red_LED_on
+
+#if    defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)
+       /*
+        * relocate exception table
+        */
+       ldr     r0, =_start
+       ldr     r1, =0x0
+       mov     r2, #16
+copyex:
+       subs    r2, r2, #1
+       ldr     r3, [r0], #4
+       str     r3, [r1], #4
+       bne     copyex
+#endif
+
+#ifdef CONFIG_S3C24X0
+       /* turn off the watchdog */
+
+# if defined(CONFIG_S3C2400)
+#  define pWTCON       0x15300000
+#  define INTMSK       0x14400008      /* Interupt-Controller base addresses */
+#  define CLKDIVN      0x14800014      /* clock divisor register */
+#else
+#  define pWTCON       0x53000000
+#  define INTMSK       0x4A000008      /* Interupt-Controller base addresses */
+#  define INTSUBMSK    0x4A00001C
+#  define CLKDIVN      0x4C000014      /* clock divisor register */
+# endif
+
+       ldr     r0, =pWTCON
+       mov     r1, #0x0
+       str     r1, [r0]
+
+       /*
+        * mask all IRQs by setting all bits in the INTMR - default
+        */
+       mov     r1, #0xffffffff
+       ldr     r0, =INTMSK
+       str     r1, [r0]
+# if defined(CONFIG_S3C2410)
+       ldr     r1, =0x3ff
+       ldr     r0, =INTSUBMSK
+       str     r1, [r0]
+# endif
+
+       /* FCLK:HCLK:PCLK = 1:2:4 */
+       /* default FCLK is 120 MHz ! */
+       ldr     r0, =CLKDIVN
+       mov     r1, #3
+       str     r1, [r0]
+#endif /* CONFIG_S3C24X0 */
+
+       /*
+        * we do sys-critical inits only at reboot,
+        * not when booting from ram!
+        */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+       bl      cpu_init_crit
+#endif
+
 #ifndef CONFIG_SKIP_RELOCATE_UBOOT
 relocate:                              /* relocate U-Boot to RAM           */
        adr     r0, _start              /* r0 <- current position of code   */
@@ -219,7 +434,7 @@ clbss_l:str r2, [r0]                /* clear loop...                    */
        ldr     pc, _start_armboot
 
 _start_armboot:        .word start_armboot
-
+#endif /* #if !defined(CONFIG_SYS_ARM_WITHOUT_RELOC) */
 
 /*
  *************************************************************************
@@ -309,11 +524,15 @@ cpu_init_crit:
        .macro  bad_save_user_regs
        sub     sp, sp, #S_FRAME_SIZE
        stmia   sp, {r0 - r12}                  @ Calling r0-r12
+#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
        ldr     r2, _armboot_start
        sub     r2, r2, #(CONFIG_STACKSIZE)
        sub     r2, r2, #(CONFIG_SYS_MALLOC_LEN)
        /* set base 2 words into abort stack */
        sub     r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE+8)
+#else
+       ldr     r2, IRQ_STACK_START_IN
+#endif
        ldmia   r2, {r2 - r3}                   @ get pc, cpsr
        add     r0, sp, #S_FRAME_SIZE           @ restore sp_SVC
 
@@ -345,11 +564,15 @@ cpu_init_crit:
        .endm
 
        .macro get_bad_stack
+#if defined(CONFIG_SYS_ARM_WITHOUT_RELOC)
        ldr     r13, _armboot_start             @ setup our mode stack
        sub     r13, r13, #(CONFIG_STACKSIZE)
        sub     r13, r13, #(CONFIG_SYS_MALLOC_LEN)
        /* reserve a couple spots in abort stack */
        sub     r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE+8)
+#else
+       ldr     r13, IRQ_STACK_START_IN         @ setup our mode stack
+#endif
 
        str     lr, [r13]                       @ save caller lr / spsr
        mrs     lr, spsr
index a7decfcd7db221f46e82e578ee42f613373dea52..69854347952f11a6bed118d61bc6414b28ab7f2b 100644 (file)
@@ -47,11 +47,23 @@ 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) }