]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - arch/ppc/boot/simple/relocate.S
Linux-2.6.12-rc2
[mirror_ubuntu-artful-kernel.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 cmpw 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 cmpw 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 cmpw 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