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