[CPUFREQ] Crusoe: longrun cpufreq module reports false min freq
[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 #include <asm/processor-flags.h>
13 #include <asm/pgtable.h>
14
15 /*
16  * Must be relocatable PIC code callable as a C function
17  */
18
19 #define PTR(x) (x << 2)
20 #define PAGE_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
21 #define PAE_PGD_ATTR (_PAGE_PRESENT)
22
23         .text
24         .align PAGE_SIZE
25         .globl relocate_kernel
26 relocate_kernel:
27         movl    8(%esp), %ebp /* list of pages */
28
29 #ifdef CONFIG_X86_PAE
30         /* map the control page at its virtual address */
31
32         movl    PTR(VA_PGD)(%ebp), %edi
33         movl    PTR(VA_CONTROL_PAGE)(%ebp), %eax
34         andl    $0xc0000000, %eax
35         shrl    $27, %eax
36         addl    %edi, %eax
37
38         movl    PTR(PA_PMD_0)(%ebp), %edx
39         orl     $PAE_PGD_ATTR, %edx
40         movl    %edx, (%eax)
41
42         movl    PTR(VA_PMD_0)(%ebp), %edi
43         movl    PTR(VA_CONTROL_PAGE)(%ebp), %eax
44         andl    $0x3fe00000, %eax
45         shrl    $18, %eax
46         addl    %edi, %eax
47
48         movl    PTR(PA_PTE_0)(%ebp), %edx
49         orl     $PAGE_ATTR, %edx
50         movl    %edx, (%eax)
51
52         movl    PTR(VA_PTE_0)(%ebp), %edi
53         movl    PTR(VA_CONTROL_PAGE)(%ebp), %eax
54         andl    $0x001ff000, %eax
55         shrl    $9, %eax
56         addl    %edi, %eax
57
58         movl    PTR(PA_CONTROL_PAGE)(%ebp), %edx
59         orl     $PAGE_ATTR, %edx
60         movl    %edx, (%eax)
61
62         /* identity map the control page at its physical address */
63
64         movl    PTR(VA_PGD)(%ebp), %edi
65         movl    PTR(PA_CONTROL_PAGE)(%ebp), %eax
66         andl    $0xc0000000, %eax
67         shrl    $27, %eax
68         addl    %edi, %eax
69
70         movl    PTR(PA_PMD_1)(%ebp), %edx
71         orl     $PAE_PGD_ATTR, %edx
72         movl    %edx, (%eax)
73
74         movl    PTR(VA_PMD_1)(%ebp), %edi
75         movl    PTR(PA_CONTROL_PAGE)(%ebp), %eax
76         andl    $0x3fe00000, %eax
77         shrl    $18, %eax
78         addl    %edi, %eax
79
80         movl    PTR(PA_PTE_1)(%ebp), %edx
81         orl     $PAGE_ATTR, %edx
82         movl    %edx, (%eax)
83
84         movl    PTR(VA_PTE_1)(%ebp), %edi
85         movl    PTR(PA_CONTROL_PAGE)(%ebp), %eax
86         andl    $0x001ff000, %eax
87         shrl    $9, %eax
88         addl    %edi, %eax
89
90         movl    PTR(PA_CONTROL_PAGE)(%ebp), %edx
91         orl     $PAGE_ATTR, %edx
92         movl    %edx, (%eax)
93 #else
94         /* map the control page at its virtual address */
95
96         movl    PTR(VA_PGD)(%ebp), %edi
97         movl    PTR(VA_CONTROL_PAGE)(%ebp), %eax
98         andl    $0xffc00000, %eax
99         shrl    $20, %eax
100         addl    %edi, %eax
101
102         movl    PTR(PA_PTE_0)(%ebp), %edx
103         orl     $PAGE_ATTR, %edx
104         movl    %edx, (%eax)
105
106         movl    PTR(VA_PTE_0)(%ebp), %edi
107         movl    PTR(VA_CONTROL_PAGE)(%ebp), %eax
108         andl    $0x003ff000, %eax
109         shrl    $10, %eax
110         addl    %edi, %eax
111
112         movl    PTR(PA_CONTROL_PAGE)(%ebp), %edx
113         orl     $PAGE_ATTR, %edx
114         movl    %edx, (%eax)
115
116         /* identity map the control page at its physical address */
117
118         movl    PTR(VA_PGD)(%ebp), %edi
119         movl    PTR(PA_CONTROL_PAGE)(%ebp), %eax
120         andl    $0xffc00000, %eax
121         shrl    $20, %eax
122         addl    %edi, %eax
123
124         movl    PTR(PA_PTE_1)(%ebp), %edx
125         orl     $PAGE_ATTR, %edx
126         movl    %edx, (%eax)
127
128         movl    PTR(VA_PTE_1)(%ebp), %edi
129         movl    PTR(PA_CONTROL_PAGE)(%ebp), %eax
130         andl    $0x003ff000, %eax
131         shrl    $10, %eax
132         addl    %edi, %eax
133
134         movl    PTR(PA_CONTROL_PAGE)(%ebp), %edx
135         orl     $PAGE_ATTR, %edx
136         movl    %edx, (%eax)
137 #endif
138
139 relocate_new_kernel:
140         /* read the arguments and say goodbye to the stack */
141         movl  4(%esp), %ebx /* page_list */
142         movl  8(%esp), %ebp /* list of pages */
143         movl  12(%esp), %edx /* start address */
144         movl  16(%esp), %ecx /* cpu_has_pae */
145
146         /* zero out flags, and disable interrupts */
147         pushl $0
148         popfl
149
150         /* get physical address of control page now */
151         /* this is impossible after page table switch */
152         movl    PTR(PA_CONTROL_PAGE)(%ebp), %edi
153
154         /* switch to new set of page tables */
155         movl    PTR(PA_PGD)(%ebp), %eax
156         movl    %eax, %cr3
157
158         /* setup a new stack at the end of the physical control page */
159         lea     PAGE_SIZE(%edi), %esp
160
161         /* jump to identity mapped page */
162         movl    %edi, %eax
163         addl    $(identity_mapped - relocate_kernel), %eax
164         pushl   %eax
165         ret
166
167 identity_mapped:
168         /* store the start address on the stack */
169         pushl   %edx
170
171         /* Set cr0 to a known state:
172          *  - Paging disabled
173          *  - Alignment check disabled
174          *  - Write protect disabled
175          *  - No task switch
176          *  - Don't do FP software emulation.
177          *  - Proctected mode enabled
178          */
179         movl    %cr0, %eax
180         andl    $~(X86_CR0_PG | X86_CR0_AM | X86_CR0_WP | X86_CR0_TS | X86_CR0_EM), %eax
181         orl     $(X86_CR0_PE), %eax
182         movl    %eax, %cr0
183
184         /* clear cr4 if applicable */
185         testl   %ecx, %ecx
186         jz      1f
187         /* Set cr4 to a known state:
188          * Setting everything to zero seems safe.
189          */
190         xorl    %eax, %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