f151d6fae462a3fb204f4847018e846dfdcccbca
[sfrench/cifs-2.6.git] / arch / x86 / kernel / relocate_kernel_32.S
1 /*
2  * relocate_kernel.S - put the kernel image in place to boot
3  * Copyright (C) 2002-2004 Eric Biederman  <ebiederm@xmission.com>
4  *
5  * This source code is licensed under the GNU General Public License,
6  * Version 2.  See the file COPYING for more details.
7  */
8
9 #include <linux/linkage.h>
10 #include <asm/page.h>
11 #include <asm/kexec.h>
12
13 /*
14  * Must be relocatable PIC code callable as a C function
15  */
16
17 #define PTR(x) (x << 2)
18 #define PAGE_ALIGNED (1 << PAGE_SHIFT)
19 #define PAGE_ATTR 0x63 /* _PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY */
20 #define PAE_PGD_ATTR 0x01 /* _PAGE_PRESENT */
21
22         .text
23         .align PAGE_ALIGNED
24         .globl relocate_kernel
25 relocate_kernel:
26         movl    8(%esp), %ebp /* list of pages */
27
28 #ifdef CONFIG_X86_PAE
29         /* map the control page at its virtual address */
30
31         movl    PTR(VA_PGD)(%ebp), %edi
32         movl    PTR(VA_CONTROL_PAGE)(%ebp), %eax
33         andl    $0xc0000000, %eax
34         shrl    $27, %eax
35         addl    %edi, %eax
36
37         movl    PTR(PA_PMD_0)(%ebp), %edx
38         orl     $PAE_PGD_ATTR, %edx
39         movl    %edx, (%eax)
40
41         movl    PTR(VA_PMD_0)(%ebp), %edi
42         movl    PTR(VA_CONTROL_PAGE)(%ebp), %eax
43         andl    $0x3fe00000, %eax
44         shrl    $18, %eax
45         addl    %edi, %eax
46
47         movl    PTR(PA_PTE_0)(%ebp), %edx
48         orl     $PAGE_ATTR, %edx
49         movl    %edx, (%eax)
50
51         movl    PTR(VA_PTE_0)(%ebp), %edi
52         movl    PTR(VA_CONTROL_PAGE)(%ebp), %eax
53         andl    $0x001ff000, %eax
54         shrl    $9, %eax
55         addl    %edi, %eax
56
57         movl    PTR(PA_CONTROL_PAGE)(%ebp), %edx
58         orl     $PAGE_ATTR, %edx
59         movl    %edx, (%eax)
60
61         /* identity map the control page at its physical address */
62
63         movl    PTR(VA_PGD)(%ebp), %edi
64         movl    PTR(PA_CONTROL_PAGE)(%ebp), %eax
65         andl    $0xc0000000, %eax
66         shrl    $27, %eax
67         addl    %edi, %eax
68
69         movl    PTR(PA_PMD_1)(%ebp), %edx
70         orl     $PAE_PGD_ATTR, %edx
71         movl    %edx, (%eax)
72
73         movl    PTR(VA_PMD_1)(%ebp), %edi
74         movl    PTR(PA_CONTROL_PAGE)(%ebp), %eax
75         andl    $0x3fe00000, %eax
76         shrl    $18, %eax
77         addl    %edi, %eax
78
79         movl    PTR(PA_PTE_1)(%ebp), %edx
80         orl     $PAGE_ATTR, %edx
81         movl    %edx, (%eax)
82
83         movl    PTR(VA_PTE_1)(%ebp), %edi
84         movl    PTR(PA_CONTROL_PAGE)(%ebp), %eax
85         andl    $0x001ff000, %eax
86         shrl    $9, %eax
87         addl    %edi, %eax
88
89         movl    PTR(PA_CONTROL_PAGE)(%ebp), %edx
90         orl     $PAGE_ATTR, %edx
91         movl    %edx, (%eax)
92 #else
93         /* map the control page at its virtual address */
94
95         movl    PTR(VA_PGD)(%ebp), %edi
96         movl    PTR(VA_CONTROL_PAGE)(%ebp), %eax
97         andl    $0xffc00000, %eax
98         shrl    $20, %eax
99         addl    %edi, %eax
100
101         movl    PTR(PA_PTE_0)(%ebp), %edx
102         orl     $PAGE_ATTR, %edx
103         movl    %edx, (%eax)
104
105         movl    PTR(VA_PTE_0)(%ebp), %edi
106         movl    PTR(VA_CONTROL_PAGE)(%ebp), %eax
107         andl    $0x003ff000, %eax
108         shrl    $10, %eax
109         addl    %edi, %eax
110
111         movl    PTR(PA_CONTROL_PAGE)(%ebp), %edx
112         orl     $PAGE_ATTR, %edx
113         movl    %edx, (%eax)
114
115         /* identity map the control page at its physical address */
116
117         movl    PTR(VA_PGD)(%ebp), %edi
118         movl    PTR(PA_CONTROL_PAGE)(%ebp), %eax
119         andl    $0xffc00000, %eax
120         shrl    $20, %eax
121         addl    %edi, %eax
122
123         movl    PTR(PA_PTE_1)(%ebp), %edx
124         orl     $PAGE_ATTR, %edx
125         movl    %edx, (%eax)
126
127         movl    PTR(VA_PTE_1)(%ebp), %edi
128         movl    PTR(PA_CONTROL_PAGE)(%ebp), %eax
129         andl    $0x003ff000, %eax
130         shrl    $10, %eax
131         addl    %edi, %eax
132
133         movl    PTR(PA_CONTROL_PAGE)(%ebp), %edx
134         orl     $PAGE_ATTR, %edx
135         movl    %edx, (%eax)
136 #endif
137
138 relocate_new_kernel:
139         /* read the arguments and say goodbye to the stack */
140         movl  4(%esp), %ebx /* page_list */
141         movl  8(%esp), %ebp /* list of pages */
142         movl  12(%esp), %edx /* start address */
143         movl  16(%esp), %ecx /* cpu_has_pae */
144
145         /* zero out flags, and disable interrupts */
146         pushl $0
147         popfl
148
149         /* get physical address of control page now */
150         /* this is impossible after page table switch */
151         movl    PTR(PA_CONTROL_PAGE)(%ebp), %edi
152
153         /* switch to new set of page tables */
154         movl    PTR(PA_PGD)(%ebp), %eax
155         movl    %eax, %cr3
156
157         /* setup a new stack at the end of the physical control page */
158         lea     4096(%edi), %esp
159
160         /* jump to identity mapped page */
161         movl    %edi, %eax
162         addl    $(identity_mapped - relocate_kernel), %eax
163         pushl   %eax
164         ret
165
166 identity_mapped:
167         /* store the start address on the stack */
168         pushl   %edx
169
170         /* Set cr0 to a known state:
171          * 31 0 == Paging disabled
172          * 18 0 == Alignment check disabled
173          * 16 0 == Write protect disabled
174          * 3  0 == No task switch
175          * 2  0 == Don't do FP software emulation.
176          * 0  1 == Proctected mode enabled
177          */
178         movl    %cr0, %eax
179         andl    $~((1<<31)|(1<<18)|(1<<16)|(1<<3)|(1<<2)), %eax
180         orl     $(1<<0), %eax
181         movl    %eax, %cr0
182
183         /* clear cr4 if applicable */
184         testl   %ecx, %ecx
185         jz      1f
186         /* Set cr4 to a known state:
187          * Setting everything to zero seems safe.
188          */
189         movl    %cr4, %eax
190         andl    $0, %eax
191         movl    %eax, %cr4
192
193         jmp 1f
194 1:
195
196         /* Flush the TLB (needed?) */
197         xorl    %eax, %eax
198         movl    %eax, %cr3
199
200         /* Do the copies */
201         movl    %ebx, %ecx
202         jmp     1f
203
204 0:      /* top, read another word from the indirection page */
205         movl    (%ebx), %ecx
206         addl    $4, %ebx
207 1:
208         testl   $0x1,   %ecx  /* is it a destination page */
209         jz      2f
210         movl    %ecx,   %edi
211         andl    $0xfffff000, %edi
212         jmp     0b
213 2:
214         testl   $0x2,   %ecx  /* is it an indirection page */
215         jz      2f
216         movl    %ecx,   %ebx
217         andl    $0xfffff000, %ebx
218         jmp     0b
219 2:
220         testl   $0x4,   %ecx /* is it the done indicator */
221         jz      2f
222         jmp     3f
223 2:
224         testl   $0x8,   %ecx /* is it the source indicator */
225         jz      0b           /* Ignore it otherwise */
226         movl    %ecx,   %esi /* For every source page do a copy */
227         andl    $0xfffff000, %esi
228
229         movl    $1024, %ecx
230         rep ; movsl
231         jmp     0b
232
233 3:
234
235         /* To be certain of avoiding problems with self-modifying code
236          * I need to execute a serializing instruction here.
237          * So I flush the TLB, it's handy, and not processor dependent.
238          */
239         xorl    %eax, %eax
240         movl    %eax, %cr3
241
242         /* set all of the registers to known values */
243         /* leave %esp alone */
244
245         xorl    %eax, %eax
246         xorl    %ebx, %ebx
247         xorl    %ecx, %ecx
248         xorl    %edx, %edx
249         xorl    %esi, %esi
250         xorl    %edi, %edi
251         xorl    %ebp, %ebp
252         ret