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_types.h> 11#include <asm/kexec.h> 12#include <asm/processor-flags.h> 13 14/* 15 * Must be relocatable PIC code callable as a C function 16 */ 17 18#define PTR(x) (x << 2) 19 20/* 21 * control_page + KEXEC_CONTROL_CODE_MAX_SIZE 22 * ~ control_page + PAGE_SIZE are used as data storage and stack for 23 * jumping back 24 */ 25#define DATA(offset) (KEXEC_CONTROL_CODE_MAX_SIZE+(offset)) 26 27/* Minimal CPU state */ 28#define ESP DATA(0x0) 29#define CR0 DATA(0x4) 30#define CR3 DATA(0x8) 31#define CR4 DATA(0xc) 32 33/* other data */ 34#define CP_VA_CONTROL_PAGE DATA(0x10) 35#define CP_PA_PGD DATA(0x14) 36#define CP_PA_SWAP_PAGE DATA(0x18) 37#define CP_PA_BACKUP_PAGES_MAP DATA(0x1c) 38 39 .text 40 .globl relocate_kernel 41relocate_kernel: 42 /* Save the CPU context, used for jumping back */ 43 44 pushl %ebx 45 pushl %esi 46 pushl %edi 47 pushl %ebp 48 pushf 49 50 movl 20+8(%esp), %ebp /* list of pages */ 51 movl PTR(VA_CONTROL_PAGE)(%ebp), %edi 52 movl %esp, ESP(%edi) 53 movl %cr0, %eax 54 movl %eax, CR0(%edi) 55 movl %cr3, %eax 56 movl %eax, CR3(%edi) 57 movl %cr4, %eax 58 movl %eax, CR4(%edi) 59 60 /* read the arguments and say goodbye to the stack */ 61 movl 20+4(%esp), %ebx /* page_list */ 62 movl 20+8(%esp), %ebp /* list of pages */ 63 movl 20+12(%esp), %edx /* start address */ 64 movl 20+16(%esp), %ecx /* cpu_has_pae */ 65 movl 20+20(%esp), %esi /* preserve_context */ 66 67 /* zero out flags, and disable interrupts */ 68 pushl $0 69 popfl 70 71 /* save some information for jumping back */ 72 movl PTR(VA_CONTROL_PAGE)(%ebp), %edi 73 movl %edi, CP_VA_CONTROL_PAGE(%edi) 74 movl PTR(PA_PGD)(%ebp), %eax 75 movl %eax, CP_PA_PGD(%edi) 76 movl PTR(PA_SWAP_PAGE)(%ebp), %eax 77 movl %eax, CP_PA_SWAP_PAGE(%edi) 78 movl %ebx, CP_PA_BACKUP_PAGES_MAP(%edi) 79 80 /* 81 * get physical address of control page now 82 * this is impossible after page table switch 83 */ 84 movl PTR(PA_CONTROL_PAGE)(%ebp), %edi 85 86 /* switch to new set of page tables */ 87 movl PTR(PA_PGD)(%ebp), %eax 88 movl %eax, %cr3 89 90 /* setup a new stack at the end of the physical control page */ 91 lea PAGE_SIZE(%edi), %esp 92 93 /* jump to identity mapped page */ 94 movl %edi, %eax 95 addl $(identity_mapped - relocate_kernel), %eax 96 pushl %eax 97 ret 98 99identity_mapped: 100 /* store the start address on the stack */ 101 pushl %edx 102 103 /* 104 * Set cr0 to a known state: 105 * - Paging disabled 106 * - Alignment check disabled 107 * - Write protect disabled 108 * - No task switch 109 * - Don't do FP software emulation. 110 * - Proctected mode enabled 111 */ 112 movl %cr0, %eax 113 andl $~(X86_CR0_PG | X86_CR0_AM | X86_CR0_WP | X86_CR0_TS | X86_CR0_EM), %eax 114 orl $(X86_CR0_PE), %eax 115 movl %eax, %cr0 116 117 /* clear cr4 if applicable */ 118 testl %ecx, %ecx 119 jz 1f 120 /* 121 * Set cr4 to a known state: 122 * Setting everything to zero seems safe. 123 */ 124 xorl %eax, %eax 125 movl %eax, %cr4 126 127 jmp 1f 1281: 129 130 /* Flush the TLB (needed?) */ 131 xorl %eax, %eax 132 movl %eax, %cr3 133 134 movl CP_PA_SWAP_PAGE(%edi), %eax 135 pushl %eax 136 pushl %ebx 137 call swap_pages 138 addl $8, %esp 139 140 /* 141 * To be certain of avoiding problems with self-modifying code 142 * I need to execute a serializing instruction here. 143 * So I flush the TLB, it's handy, and not processor dependent. 144 */ 145 xorl %eax, %eax 146 movl %eax, %cr3 147 148 /* 149 * set all of the registers to known values 150 * leave %esp alone 151 */ 152 153 testl %esi, %esi 154 jnz 1f 155 xorl %edi, %edi 156 xorl %eax, %eax 157 xorl %ebx, %ebx 158 xorl %ecx, %ecx 159 xorl %edx, %edx 160 xorl %esi, %esi 161 xorl %ebp, %ebp 162 ret 1631: 164 popl %edx 165 movl CP_PA_SWAP_PAGE(%edi), %esp 166 addl $PAGE_SIZE, %esp 1672: 168 call *%edx 169 170 /* get the re-entry point of the peer system */ 171 movl 0(%esp), %ebp 172 call 1f 1731: 174 popl %ebx 175 subl $(1b - relocate_kernel), %ebx 176 movl CP_VA_CONTROL_PAGE(%ebx), %edi 177 lea PAGE_SIZE(%ebx), %esp 178 movl CP_PA_SWAP_PAGE(%ebx), %eax 179 movl CP_PA_BACKUP_PAGES_MAP(%ebx), %edx 180 pushl %eax 181 pushl %edx 182 call swap_pages 183 addl $8, %esp 184 movl CP_PA_PGD(%ebx), %eax 185 movl %eax, %cr3 186 movl %cr0, %eax 187 orl $(1<<31), %eax 188 movl %eax, %cr0 189 lea PAGE_SIZE(%edi), %esp 190 movl %edi, %eax 191 addl $(virtual_mapped - relocate_kernel), %eax 192 pushl %eax 193 ret 194 195virtual_mapped: 196 movl CR4(%edi), %eax 197 movl %eax, %cr4 198 movl CR3(%edi), %eax 199 movl %eax, %cr3 200 movl CR0(%edi), %eax 201 movl %eax, %cr0 202 movl ESP(%edi), %esp 203 movl %ebp, %eax 204 205 popf 206 popl %ebp 207 popl %edi 208 popl %esi 209 popl %ebx 210 ret 211 212 /* Do the copies */ 213swap_pages: 214 movl 8(%esp), %edx 215 movl 4(%esp), %ecx 216 pushl %ebp 217 pushl %ebx 218 pushl %edi 219 pushl %esi 220 movl %ecx, %ebx 221 jmp 1f 222 2230: /* top, read another word from the indirection page */ 224 movl (%ebx), %ecx 225 addl $4, %ebx 2261: 227 testl $0x1, %ecx /* is it a destination page */ 228 jz 2f 229 movl %ecx, %edi 230 andl $0xfffff000, %edi 231 jmp 0b 2322: 233 testl $0x2, %ecx /* is it an indirection page */ 234 jz 2f 235 movl %ecx, %ebx 236 andl $0xfffff000, %ebx 237 jmp 0b 2382: 239 testl $0x4, %ecx /* is it the done indicator */ 240 jz 2f 241 jmp 3f 2422: 243 testl $0x8, %ecx /* is it the source indicator */ 244 jz 0b /* Ignore it otherwise */ 245 movl %ecx, %esi /* For every source page do a copy */ 246 andl $0xfffff000, %esi 247 248 movl %edi, %eax 249 movl %esi, %ebp 250 251 movl %edx, %edi 252 movl $1024, %ecx 253 rep ; movsl 254 255 movl %ebp, %edi 256 movl %eax, %esi 257 movl $1024, %ecx 258 rep ; movsl 259 260 movl %eax, %edi 261 movl %edx, %esi 262 movl $1024, %ecx 263 rep ; movsl 264 265 lea PAGE_SIZE(%ebp), %esi 266 jmp 0b 2673: 268 popl %esi 269 popl %edi 270 popl %ebx 271 popl %ebp 272 ret 273 274 .globl kexec_control_code_size 275.set kexec_control_code_size, . - relocate_kernel 276