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