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