ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / ppc / boot / simple / relocate.S
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-2004 (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
32 relocate:
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
68 1:
69         mr      r6, r5
70 2:
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
95 3:      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         
113 do_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
128 do_relocate_from_start:
129 1:      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
137 do_relocate_from_end:
138         GETSYM(r3, end)
139         slwi    r4,r7,2
140         add     r4,r8,r4        /* Get the physical end */
141 1:      lwzu    r5,-4(r4)
142         stwu    r5, -4(r3)
143         xor     r6,r6,r5
144         bdnz    1b
145
146 do_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
158 start_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
167 50:     stwu    r0,4(r3)
168         cmp     cr0,r3,r4
169         bne     50b
170 90:     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         mr      r7,r25          /* Validated OFW interface */
186         bl      load_kernel
187
188         /*
189          * Make sure the kernel knows we don't have things set in
190          * registers.  -- Tom
191          */
192         li      r4,0
193         li      r5,0
194         li      r6,0
195
196         /*
197          * Start at the begining.
198          */
199 #ifdef CONFIG_PPC_MULTIPLATFORM
200         li      r9,0xc
201         mtlr    r9
202         /* tell kernel we're prep, by putting 0xdeadc0de at KERNELLOAD,
203          * and tell the kernel to start on the 4th instruction since we
204          * overwrite the first 3 sometimes (which are 'nop').
205          */
206         lis     r10,0xdeadc0de@h
207         ori     r10,r10,0xdeadc0de@l
208         li      r9,0
209         stw     r10,0(r9)
210 #else
211         li      r9,0
212         mtlr    r9
213 #endif
214         blr
215
216         .comm   .stack,4096*2,4