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 26relocate_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 139relocate_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 167identity_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 1941: 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 2040: /* top, read another word from the indirection page */ 205 movl (%ebx), %ecx 206 addl $4, %ebx 2071: 208 testl $0x1, %ecx /* is it a destination page */ 209 jz 2f 210 movl %ecx, %edi 211 andl $0xfffff000, %edi 212 jmp 0b 2132: 214 testl $0x2, %ecx /* is it an indirection page */ 215 jz 2f 216 movl %ecx, %ebx 217 andl $0xfffff000, %ebx 218 jmp 0b 2192: 220 testl $0x4, %ecx /* is it the done indicator */ 221 jz 2f 222 jmp 3f 2232: 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 2333: 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 253