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