Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / arch / x86 / kernel / relocate_kernel_64.S
1 /*
2  * relocate_kernel.S - put the kernel image in place to boot
3  * Copyright (C) 2002-2005 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_types.h>
11 #include <asm/kexec.h>
12 #include <asm/processor-flags.h>
13 #include <asm/pgtable_types.h>
14
15 /*
16  * Must be relocatable PIC code callable as a C function
17  */
18
19 #define PTR(x) (x << 3)
20 #define PAGE_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
21
22 /*
23  * control_page + KEXEC_CONTROL_CODE_MAX_SIZE
24  * ~ control_page + PAGE_SIZE are used as data storage and stack for
25  * jumping back
26  */
27 #define DATA(offset)            (KEXEC_CONTROL_CODE_MAX_SIZE+(offset))
28
29 /* Minimal CPU state */
30 #define RSP                     DATA(0x0)
31 #define CR0                     DATA(0x8)
32 #define CR3                     DATA(0x10)
33 #define CR4                     DATA(0x18)
34
35 /* other data */
36 #define CP_PA_TABLE_PAGE        DATA(0x20)
37 #define CP_PA_SWAP_PAGE         DATA(0x28)
38 #define CP_PA_BACKUP_PAGES_MAP  DATA(0x30)
39
40         .text
41         .align PAGE_SIZE
42         .code64
43         .globl relocate_kernel
44 relocate_kernel:
45         /*
46          * %rdi indirection_page
47          * %rsi page_list
48          * %rdx start address
49          * %rcx preserve_context
50          */
51
52         /* Save the CPU context, used for jumping back */
53         pushq %rbx
54         pushq %rbp
55         pushq %r12
56         pushq %r13
57         pushq %r14
58         pushq %r15
59         pushf
60
61         movq    PTR(VA_CONTROL_PAGE)(%rsi), %r11
62         movq    %rsp, RSP(%r11)
63         movq    %cr0, %rax
64         movq    %rax, CR0(%r11)
65         movq    %cr3, %rax
66         movq    %rax, CR3(%r11)
67         movq    %cr4, %rax
68         movq    %rax, CR4(%r11)
69
70         /* zero out flags, and disable interrupts */
71         pushq $0
72         popfq
73
74         /*
75          * get physical address of control page now
76          * this is impossible after page table switch
77          */
78         movq    PTR(PA_CONTROL_PAGE)(%rsi), %r8
79
80         /* get physical address of page table now too */
81         movq    PTR(PA_TABLE_PAGE)(%rsi), %r9
82
83         /* get physical address of swap page now */
84         movq    PTR(PA_SWAP_PAGE)(%rsi), %r10
85
86         /* save some information for jumping back */
87         movq    %r9, CP_PA_TABLE_PAGE(%r11)
88         movq    %r10, CP_PA_SWAP_PAGE(%r11)
89         movq    %rdi, CP_PA_BACKUP_PAGES_MAP(%r11)
90
91         /* Switch to the identity mapped page tables */
92         movq    %r9, %cr3
93
94         /* setup idt */
95         lidtq   idt_80 - relocate_kernel(%r8)
96
97         /* setup gdt */
98         leaq    gdt - relocate_kernel(%r8), %rax
99         movq    %rax, (gdt_80 - relocate_kernel) + 2(%r8)
100         lgdtq   gdt_80 - relocate_kernel(%r8)
101
102         /* setup data segment registers */
103         xorl    %eax, %eax
104         movl    %eax, %ds
105         movl    %eax, %es
106         movl    %eax, %fs
107         movl    %eax, %gs
108         movl    %eax, %ss
109
110         /* setup a new stack at the end of the physical control page */
111         lea     PAGE_SIZE(%r8), %rsp
112
113         /* load new code segment and jump to identity mapped page */
114         addq    $(identity_mapped - relocate_kernel), %r8
115         pushq   $(gdt_cs - gdt)
116         pushq   %r8
117         lretq
118
119 identity_mapped:
120         /* set return address to 0 if not preserving context */
121         pushq   $0
122         /* store the start address on the stack */
123         pushq   %rdx
124
125         /*
126          * Set cr0 to a known state:
127          *  - Paging enabled
128          *  - Alignment check disabled
129          *  - Write protect disabled
130          *  - No task switch
131          *  - Don't do FP software emulation.
132          *  - Proctected mode enabled
133          */
134         movq    %cr0, %rax
135         andq    $~(X86_CR0_AM | X86_CR0_WP | X86_CR0_TS | X86_CR0_EM), %rax
136         orl     $(X86_CR0_PG | X86_CR0_PE), %eax
137         movq    %rax, %cr0
138
139         /*
140          * Set cr4 to a known state:
141          *  - physical address extension enabled
142          */
143         movq    $X86_CR4_PAE, %rax
144         movq    %rax, %cr4
145
146         jmp 1f
147 1:
148
149         /* Flush the TLB (needed?) */
150         movq    %r9, %cr3
151
152         movq    %rcx, %r11
153         call    swap_pages
154
155         /*
156          * To be certain of avoiding problems with self-modifying code
157          * I need to execute a serializing instruction here.
158          * So I flush the TLB by reloading %cr3 here, it's handy,
159          * and not processor dependent.
160          */
161         movq    %cr3, %rax
162         movq    %rax, %cr3
163
164         /*
165          * set all of the registers to known values
166          * leave %rsp alone
167          */
168
169         testq   %r11, %r11
170         jnz 1f
171         xorq    %rax, %rax
172         xorq    %rbx, %rbx
173         xorq    %rcx, %rcx
174         xorq    %rdx, %rdx
175         xorq    %rsi, %rsi
176         xorq    %rdi, %rdi
177         xorq    %rbp, %rbp
178         xorq    %r8,  %r8
179         xorq    %r9,  %r9
180         xorq    %r10, %r9
181         xorq    %r11, %r11
182         xorq    %r12, %r12
183         xorq    %r13, %r13
184         xorq    %r14, %r14
185         xorq    %r15, %r15
186
187         ret
188
189 1:
190         popq    %rdx
191         leaq    PAGE_SIZE(%r10), %rsp
192         call    *%rdx
193
194         /* get the re-entry point of the peer system */
195         movq    0(%rsp), %rbp
196         call    1f
197 1:
198         popq    %r8
199         subq    $(1b - relocate_kernel), %r8
200         movq    CP_PA_SWAP_PAGE(%r8), %r10
201         movq    CP_PA_BACKUP_PAGES_MAP(%r8), %rdi
202         movq    CP_PA_TABLE_PAGE(%r8), %rax
203         movq    %rax, %cr3
204         lea     PAGE_SIZE(%r8), %rsp
205         call    swap_pages
206         movq    $virtual_mapped, %rax
207         pushq   %rax
208         ret
209
210 virtual_mapped:
211         movq    RSP(%r8), %rsp
212         movq    CR4(%r8), %rax
213         movq    %rax, %cr4
214         movq    CR3(%r8), %rax
215         movq    CR0(%r8), %r8
216         movq    %rax, %cr3
217         movq    %r8, %cr0
218         movq    %rbp, %rax
219
220         popf
221         popq    %r15
222         popq    %r14
223         popq    %r13
224         popq    %r12
225         popq    %rbp
226         popq    %rbx
227         ret
228
229         /* Do the copies */
230 swap_pages:
231         movq    %rdi, %rcx      /* Put the page_list in %rcx */
232         xorq    %rdi, %rdi
233         xorq    %rsi, %rsi
234         jmp     1f
235
236 0:      /* top, read another word for the indirection page */
237
238         movq    (%rbx), %rcx
239         addq    $8,     %rbx
240 1:
241         testq   $0x1,   %rcx  /* is it a destination page? */
242         jz      2f
243         movq    %rcx,   %rdi
244         andq    $0xfffffffffffff000, %rdi
245         jmp     0b
246 2:
247         testq   $0x2,   %rcx  /* is it an indirection page? */
248         jz      2f
249         movq    %rcx,   %rbx
250         andq    $0xfffffffffffff000, %rbx
251         jmp     0b
252 2:
253         testq   $0x4,   %rcx  /* is it the done indicator? */
254         jz      2f
255         jmp     3f
256 2:
257         testq   $0x8,   %rcx  /* is it the source indicator? */
258         jz      0b            /* Ignore it otherwise */
259         movq    %rcx,   %rsi  /* For ever source page do a copy */
260         andq    $0xfffffffffffff000, %rsi
261
262         movq    %rdi, %rdx
263         movq    %rsi, %rax
264
265         movq    %r10, %rdi
266         movq    $512,   %rcx
267         rep ; movsq
268
269         movq    %rax, %rdi
270         movq    %rdx, %rsi
271         movq    $512,   %rcx
272         rep ; movsq
273
274         movq    %rdx, %rdi
275         movq    %r10, %rsi
276         movq    $512,   %rcx
277         rep ; movsq
278
279         lea     PAGE_SIZE(%rax), %rsi
280         jmp     0b
281 3:
282         ret
283
284         .align  16
285 gdt:
286         .quad   0x0000000000000000      /* NULL descriptor */
287 gdt_cs:
288         .quad   0x00af9a000000ffff
289 gdt_end:
290
291 gdt_80:
292         .word   gdt_end - gdt - 1       /* limit */
293         .quad   0                       /* base - filled in by code above */
294
295 idt_80:
296         .word   0                       /* limit */
297         .quad   0                       /* base */
298
299         .globl kexec_control_code_size
300 .set kexec_control_code_size, . - relocate_kernel