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