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.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 << 3) 20#define PAGE_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) 21 22 .text 23 .align PAGE_SIZE 24 .code64 25 .globl relocate_kernel 26relocate_kernel: 27 /* %rdi indirection_page 28 * %rsi page_list 29 * %rdx start address 30 */ 31 32 /* map the control page at its virtual address */ 33 34 movq $0x0000ff8000000000, %r10 /* mask */ 35 mov $(39 - 3), %cl /* bits to shift */ 36 movq PTR(VA_CONTROL_PAGE)(%rsi), %r11 /* address to map */ 37 38 movq %r11, %r9 39 andq %r10, %r9 40 shrq %cl, %r9 41 42 movq PTR(VA_PGD)(%rsi), %r8 43 addq %r8, %r9 44 movq PTR(PA_PUD_0)(%rsi), %r8 45 orq $PAGE_ATTR, %r8 46 movq %r8, (%r9) 47 48 shrq $9, %r10 49 sub $9, %cl 50 51 movq %r11, %r9 52 andq %r10, %r9 53 shrq %cl, %r9 54 55 movq PTR(VA_PUD_0)(%rsi), %r8 56 addq %r8, %r9 57 movq PTR(PA_PMD_0)(%rsi), %r8 58 orq $PAGE_ATTR, %r8 59 movq %r8, (%r9) 60 61 shrq $9, %r10 62 sub $9, %cl 63 64 movq %r11, %r9 65 andq %r10, %r9 66 shrq %cl, %r9 67 68 movq PTR(VA_PMD_0)(%rsi), %r8 69 addq %r8, %r9 70 movq PTR(PA_PTE_0)(%rsi), %r8 71 orq $PAGE_ATTR, %r8 72 movq %r8, (%r9) 73 74 shrq $9, %r10 75 sub $9, %cl 76 77 movq %r11, %r9 78 andq %r10, %r9 79 shrq %cl, %r9 80 81 movq PTR(VA_PTE_0)(%rsi), %r8 82 addq %r8, %r9 83 movq PTR(PA_CONTROL_PAGE)(%rsi), %r8 84 orq $PAGE_ATTR, %r8 85 movq %r8, (%r9) 86 87 /* identity map the control page at its physical address */ 88 89 movq $0x0000ff8000000000, %r10 /* mask */ 90 mov $(39 - 3), %cl /* bits to shift */ 91 movq PTR(PA_CONTROL_PAGE)(%rsi), %r11 /* address to map */ 92 93 movq %r11, %r9 94 andq %r10, %r9 95 shrq %cl, %r9 96 97 movq PTR(VA_PGD)(%rsi), %r8 98 addq %r8, %r9 99 movq PTR(PA_PUD_1)(%rsi), %r8 100 orq $PAGE_ATTR, %r8 101 movq %r8, (%r9) 102 103 shrq $9, %r10 104 sub $9, %cl 105 106 movq %r11, %r9 107 andq %r10, %r9 108 shrq %cl, %r9 109 110 movq PTR(VA_PUD_1)(%rsi), %r8 111 addq %r8, %r9 112 movq PTR(PA_PMD_1)(%rsi), %r8 113 orq $PAGE_ATTR, %r8 114 movq %r8, (%r9) 115 116 shrq $9, %r10 117 sub $9, %cl 118 119 movq %r11, %r9 120 andq %r10, %r9 121 shrq %cl, %r9 122 123 movq PTR(VA_PMD_1)(%rsi), %r8 124 addq %r8, %r9 125 movq PTR(PA_PTE_1)(%rsi), %r8 126 orq $PAGE_ATTR, %r8 127 movq %r8, (%r9) 128 129 shrq $9, %r10 130 sub $9, %cl 131 132 movq %r11, %r9 133 andq %r10, %r9 134 shrq %cl, %r9 135 136 movq PTR(VA_PTE_1)(%rsi), %r8 137 addq %r8, %r9 138 movq PTR(PA_CONTROL_PAGE)(%rsi), %r8 139 orq $PAGE_ATTR, %r8 140 movq %r8, (%r9) 141 142relocate_new_kernel: 143 /* %rdi indirection_page 144 * %rsi page_list 145 * %rdx start address 146 */ 147 148 /* zero out flags, and disable interrupts */ 149 pushq $0 150 popfq 151 152 /* get physical address of control page now */ 153 /* this is impossible after page table switch */ 154 movq PTR(PA_CONTROL_PAGE)(%rsi), %r8 155 156 /* get physical address of page table now too */ 157 movq PTR(PA_TABLE_PAGE)(%rsi), %rcx 158 159 /* switch to new set of page tables */ 160 movq PTR(PA_PGD)(%rsi), %r9 161 movq %r9, %cr3 162 163 /* setup a new stack at the end of the physical control page */ 164 lea PAGE_SIZE(%r8), %rsp 165 166 /* jump to identity mapped page */ 167 addq $(identity_mapped - relocate_kernel), %r8 168 pushq %r8 169 ret 170 171identity_mapped: 172 /* store the start address on the stack */ 173 pushq %rdx 174 175 /* Set cr0 to a known state: 176 * - Paging enabled 177 * - Alignment check disabled 178 * - Write protect disabled 179 * - No task switch 180 * - Don't do FP software emulation. 181 * - Proctected mode enabled 182 */ 183 movq %cr0, %rax 184 andq $~(X86_CR0_AM | X86_CR0_WP | X86_CR0_TS | X86_CR0_EM), %rax 185 orl $(X86_CR0_PG | X86_CR0_PE), %eax 186 movq %rax, %cr0 187 188 /* Set cr4 to a known state: 189 * - physical address extension enabled 190 */ 191 movq $X86_CR4_PAE, %rax 192 movq %rax, %cr4 193 194 jmp 1f 1951: 196 197 /* Switch to the identity mapped page tables, 198 * and flush the TLB. 199 */ 200 movq %rcx, %cr3 201 202 /* Do the copies */ 203 movq %rdi, %rcx /* Put the page_list in %rcx */ 204 xorq %rdi, %rdi 205 xorq %rsi, %rsi 206 jmp 1f 207 2080: /* top, read another word for the indirection page */ 209 210 movq (%rbx), %rcx 211 addq $8, %rbx 2121: 213 testq $0x1, %rcx /* is it a destination page? */ 214 jz 2f 215 movq %rcx, %rdi 216 andq $0xfffffffffffff000, %rdi 217 jmp 0b 2182: 219 testq $0x2, %rcx /* is it an indirection page? */ 220 jz 2f 221 movq %rcx, %rbx 222 andq $0xfffffffffffff000, %rbx 223 jmp 0b 2242: 225 testq $0x4, %rcx /* is it the done indicator? */ 226 jz 2f 227 jmp 3f 2282: 229 testq $0x8, %rcx /* is it the source indicator? */ 230 jz 0b /* Ignore it otherwise */ 231 movq %rcx, %rsi /* For ever source page do a copy */ 232 andq $0xfffffffffffff000, %rsi 233 234 movq $512, %rcx 235 rep ; movsq 236 jmp 0b 2373: 238 239 /* To be certain of avoiding problems with self-modifying code 240 * I need to execute a serializing instruction here. 241 * So I flush the TLB by reloading %cr3 here, it's handy, 242 * and not processor dependent. 243 */ 244 movq %cr3, %rax 245 movq %rax, %cr3 246 247 /* set all of the registers to known values */ 248 /* leave %rsp alone */ 249 250 xorq %rax, %rax 251 xorq %rbx, %rbx 252 xorq %rcx, %rcx 253 xorq %rdx, %rdx 254 xorq %rsi, %rsi 255 xorq %rdi, %rdi 256 xorq %rbp, %rbp 257 xorq %r8, %r8 258 xorq %r9, %r9 259 xorq %r10, %r9 260 xorq %r11, %r11 261 xorq %r12, %r12 262 xorq %r13, %r13 263 xorq %r14, %r14 264 xorq %r15, %r15 265 266 ret 267