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