linux-bk/arch/ppc/boot/simple/relocate.S
<<
>>
Prefs
   1/*
   2 * arch/ppc/boot/simple/relocate.S
   3 *
   4 * This is the common part of the loader relocation and initialization
   5 * process.  All of the board/processor specific initialization is
   6 * done before we get here.
   7 *
   8 * Author: Tom Rini
   9 *         trini@mvista.com
  10 * Derived from arch/ppc/boot/prep/head.S (Cort Dougan, many others).
  11 *
  12 * 2001-2002 (c) MontaVista, Software, Inc.  This file is licensed under
  13 * the terms of the GNU General Public License version 2.  This program
  14 * is licensed "as is" without any warranty of any kind, whether express
  15 * or implied.
  16 */
  17
  18#include <linux/config.h>
  19#include <asm/cache.h>
  20#include <asm/ppc_asm.h>
  21
  22#define GETSYM(reg, sym)        \
  23        lis     reg, sym@h; ori reg, reg, sym@l
  24
  25        .text
  26        /* We get called from the early initialization code.
  27         * Register 3 has the address where we were loaded,
  28         * Register 4 contains any residual data passed from the
  29         * boot rom.
  30         */
  31        .globl  relocate
  32relocate:
  33        /* Save r3, r4 for later.
  34         * The r8/r11 are legacy registers so I don't have to
  35         * rewrite the code below :-).
  36         */
  37        mr      r8, r3
  38        mr      r11, r4
  39
  40        /* compute the size of the whole image in words. */
  41        GETSYM(r4,start)
  42        GETSYM(r5,end)
  43
  44        addi    r5,r5,3         /* round up */
  45        sub     r5,r5,r4        /* end - start */
  46        srwi    r5,r5,2
  47        mr      r7,r5           /* Save for later use. */
  48
  49        /*
  50         * Check if we need to relocate ourselves to the link addr or were
  51         * we loaded there to begin with.
  52         */
  53        cmp     cr0,r3,r4
  54        beq     start_ldr       /* If 0, we don't need to relocate */
  55
  56        /* Move this code somewhere safe.  This is max(load + size, end)
  57         * r8 == load address
  58         */
  59        GETSYM(r4, start)
  60        GETSYM(r5, end)
  61
  62        sub     r6,r5,r4
  63        add     r6,r8,r6        /* r6 == phys(load + size) */
  64
  65        cmpw    r5,r6
  66        bgt     1f
  67        b       2f
  681:
  69        mr      r6, r5
  702:
  71        /* dest is in r6 */
  72        /* Ensure alignment --- this code is precautionary */
  73        addi    r6,r6,4
  74        li      r5,0x0003
  75        andc    r6,r6,r5
  76
  77        /* Find physical address and size of do_relocate */
  78        GETSYM(r5, __relocate_start)
  79        GETSYM(r4, __relocate_end)
  80        GETSYM(r3, start)
  81
  82        /* Size to copy */
  83        sub     r4,r4,r5
  84        srwi    r4,r4,2
  85
  86        /* Src addr to copy (= __relocate_start - start + where_loaded) */
  87        sub     r3,r5,r3
  88        add     r5,r8,r3
  89
  90        /* Save dest */
  91        mr      r3, r6
  92
  93        /* Do the copy */
  94        mtctr   r4
  953:      lwz     r4,0(r5)
  96        stw     r4,0(r3)
  97        addi    r3,r3,4
  98        addi    r5,r5,4
  99        bdnz    3b
 100
 101        GETSYM(r4, __relocate_start)
 102        GETSYM(r5, do_relocate)
 103
 104        sub     r4,r5,r4        /* Get entry point for do_relocate in
 105        add     r6,r6,r4       * relocated section */
 106
 107        /* This will return to the relocated do_relocate */
 108        mtlr    r6
 109        b       flush_instruction_cache
 110
 111        .section ".relocate_code","xa"
 112        
 113do_relocate:
 114        /* We have 2 cases --- start < load, or start > load
 115         * This determines whether we copy from the end, or the start.
 116         * Its easier to have 2 loops than to have paramaterised
 117         * loops.  Sigh.
 118         */
 119        li      r6,0            /* Clear checksum */
 120        mtctr   r7              /* Setup for a loop */
 121        
 122        GETSYM(r4, start)
 123        mr      r3,r8           /* Get the load addr */
 124
 125        cmp     cr0,r4,r3       /* If we need to copy from the end, do so */
 126        bgt     do_relocate_from_end
 127
 128do_relocate_from_start:
 1291:      lwz     r5,0(r3)        /* Load and decrement */
 130        stw     r5,0(r4)        /* Store and decrement */
 131        addi    r3,r3,4
 132        addi    r4,r4,4
 133        xor     r6,r6,r5        /* Update checksum */
 134        bdnz    1b              /* Are we done? */
 135        b       do_relocate_out /* Finished */
 136
 137do_relocate_from_end:
 138        GETSYM(r3, end)
 139        slwi    r4,r7,2
 140        add     r4,r8,r4        /* Get the physical end */
 1411:      lwzu    r5,-4(r4)
 142        stwu    r5, -4(r3)
 143        xor     r6,r6,r5
 144        bdnz    1b
 145
 146do_relocate_out:
 147        GETSYM(r3,start_ldr)
 148        mtlr    r3              /* Easiest way to do an absolute jump */
 149/* Some boards don't boot up with the I-cache enabled.  Do that
 150 * now because the decompress runs much faster that way.
 151 * As a side effect, we have to ensure the data cache is not enabled
 152 * so we can access the serial I/O without trouble.
 153 */
 154        b       flush_instruction_cache
 155
 156        .previous
 157
 158start_ldr:
 159/* Clear all of BSS and set up stack for C calls */
 160        lis     r3,edata@h
 161        ori     r3,r3,edata@l
 162        lis     r4,end@h
 163        ori     r4,r4,end@l
 164        subi    r3,r3,4
 165        subi    r4,r4,4
 166        li      r0,0
 16750:     stwu    r0,4(r3)
 168        cmp     cr0,r3,r4
 169        bne     50b
 17090:     mr      r9,r1           /* Save old stack pointer (in case it matters) */
 171        lis     r1,.stack@h
 172        ori     r1,r1,.stack@l
 173        addi    r1,r1,4096*2
 174        subi    r1,r1,256
 175        li      r2,0x000F       /* Mask pointer to 16-byte boundary */
 176        andc    r1,r1,r2
 177
 178        /*
 179         * Exec kernel loader
 180         */
 181        mr      r3,r8           /* Load point */
 182        mr      r4,r7           /* Program length */
 183        mr      r5,r6           /* Checksum */
 184        mr      r6,r11          /* Residual data */
 185        bl      load_kernel
 186
 187        /*
 188         * Make sure the kernel knows we don't have things set in
 189         * registers.  -- Tom
 190         */
 191        li      r4,0
 192        li      r5,0
 193        li      r6,0
 194
 195        /*
 196         * Start at the begining.
 197         */
 198        li      r9,0x0000
 199        mtlr    r9
 200        blr
 201
 202        .comm   .stack,4096*2,4
 203
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.