[34] | 1 | diff -pruN ../orig-linux-2.6.18/arch/i386/kernel/machine_kexec.c ./arch/i386/kernel/machine_kexec.c |
---|
| 2 | --- ../orig-linux-2.6.18/arch/i386/kernel/machine_kexec.c 2006-09-20 04:42:06.000000000 +0100 |
---|
| 3 | +++ ./arch/i386/kernel/machine_kexec.c 2007-01-12 16:03:23.000000000 +0000 |
---|
| 4 | @@ -20,70 +20,13 @@ |
---|
| 5 | #include <asm/system.h> |
---|
| 6 | |
---|
| 7 | #define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE))) |
---|
| 8 | - |
---|
| 9 | -#define L0_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) |
---|
| 10 | -#define L1_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) |
---|
| 11 | -#define L2_ATTR (_PAGE_PRESENT) |
---|
| 12 | - |
---|
| 13 | -#define LEVEL0_SIZE (1UL << 12UL) |
---|
| 14 | - |
---|
| 15 | -#ifndef CONFIG_X86_PAE |
---|
| 16 | -#define LEVEL1_SIZE (1UL << 22UL) |
---|
| 17 | -static u32 pgtable_level1[1024] PAGE_ALIGNED; |
---|
| 18 | - |
---|
| 19 | -static void identity_map_page(unsigned long address) |
---|
| 20 | -{ |
---|
| 21 | - unsigned long level1_index, level2_index; |
---|
| 22 | - u32 *pgtable_level2; |
---|
| 23 | - |
---|
| 24 | - /* Find the current page table */ |
---|
| 25 | - pgtable_level2 = __va(read_cr3()); |
---|
| 26 | - |
---|
| 27 | - /* Find the indexes of the physical address to identity map */ |
---|
| 28 | - level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE; |
---|
| 29 | - level2_index = address / LEVEL1_SIZE; |
---|
| 30 | - |
---|
| 31 | - /* Identity map the page table entry */ |
---|
| 32 | - pgtable_level1[level1_index] = address | L0_ATTR; |
---|
| 33 | - pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR; |
---|
| 34 | - |
---|
| 35 | - /* Flush the tlb so the new mapping takes effect. |
---|
| 36 | - * Global tlb entries are not flushed but that is not an issue. |
---|
| 37 | - */ |
---|
| 38 | - load_cr3(pgtable_level2); |
---|
| 39 | -} |
---|
| 40 | - |
---|
| 41 | -#else |
---|
| 42 | -#define LEVEL1_SIZE (1UL << 21UL) |
---|
| 43 | -#define LEVEL2_SIZE (1UL << 30UL) |
---|
| 44 | -static u64 pgtable_level1[512] PAGE_ALIGNED; |
---|
| 45 | -static u64 pgtable_level2[512] PAGE_ALIGNED; |
---|
| 46 | - |
---|
| 47 | -static void identity_map_page(unsigned long address) |
---|
| 48 | -{ |
---|
| 49 | - unsigned long level1_index, level2_index, level3_index; |
---|
| 50 | - u64 *pgtable_level3; |
---|
| 51 | - |
---|
| 52 | - /* Find the current page table */ |
---|
| 53 | - pgtable_level3 = __va(read_cr3()); |
---|
| 54 | - |
---|
| 55 | - /* Find the indexes of the physical address to identity map */ |
---|
| 56 | - level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE; |
---|
| 57 | - level2_index = (address % LEVEL2_SIZE)/LEVEL1_SIZE; |
---|
| 58 | - level3_index = address / LEVEL2_SIZE; |
---|
| 59 | - |
---|
| 60 | - /* Identity map the page table entry */ |
---|
| 61 | - pgtable_level1[level1_index] = address | L0_ATTR; |
---|
| 62 | - pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR; |
---|
| 63 | - set_64bit(&pgtable_level3[level3_index], |
---|
| 64 | - __pa(pgtable_level2) | L2_ATTR); |
---|
| 65 | - |
---|
| 66 | - /* Flush the tlb so the new mapping takes effect. |
---|
| 67 | - * Global tlb entries are not flushed but that is not an issue. |
---|
| 68 | - */ |
---|
| 69 | - load_cr3(pgtable_level3); |
---|
| 70 | -} |
---|
| 71 | +static u32 kexec_pgd[1024] PAGE_ALIGNED; |
---|
| 72 | +#ifdef CONFIG_X86_PAE |
---|
| 73 | +static u32 kexec_pmd0[1024] PAGE_ALIGNED; |
---|
| 74 | +static u32 kexec_pmd1[1024] PAGE_ALIGNED; |
---|
| 75 | #endif |
---|
| 76 | +static u32 kexec_pte0[1024] PAGE_ALIGNED; |
---|
| 77 | +static u32 kexec_pte1[1024] PAGE_ALIGNED; |
---|
| 78 | |
---|
| 79 | static void set_idt(void *newidt, __u16 limit) |
---|
| 80 | { |
---|
| 81 | @@ -127,16 +70,6 @@ static void load_segments(void) |
---|
| 82 | #undef __STR |
---|
| 83 | } |
---|
| 84 | |
---|
| 85 | -typedef asmlinkage NORET_TYPE void (*relocate_new_kernel_t)( |
---|
| 86 | - unsigned long indirection_page, |
---|
| 87 | - unsigned long reboot_code_buffer, |
---|
| 88 | - unsigned long start_address, |
---|
| 89 | - unsigned int has_pae) ATTRIB_NORET; |
---|
| 90 | - |
---|
| 91 | -extern const unsigned char relocate_new_kernel[]; |
---|
| 92 | -extern void relocate_new_kernel_end(void); |
---|
| 93 | -extern const unsigned int relocate_new_kernel_size; |
---|
| 94 | - |
---|
| 95 | /* |
---|
| 96 | * A architecture hook called to validate the |
---|
| 97 | * proposed image and prepare the control pages |
---|
| 98 | @@ -169,25 +102,29 @@ void machine_kexec_cleanup(struct kimage |
---|
| 99 | */ |
---|
| 100 | NORET_TYPE void machine_kexec(struct kimage *image) |
---|
| 101 | { |
---|
| 102 | - unsigned long page_list; |
---|
| 103 | - unsigned long reboot_code_buffer; |
---|
| 104 | - |
---|
| 105 | - relocate_new_kernel_t rnk; |
---|
| 106 | + unsigned long page_list[PAGES_NR]; |
---|
| 107 | + void *control_page; |
---|
| 108 | |
---|
| 109 | /* Interrupts aren't acceptable while we reboot */ |
---|
| 110 | local_irq_disable(); |
---|
| 111 | |
---|
| 112 | - /* Compute some offsets */ |
---|
| 113 | - reboot_code_buffer = page_to_pfn(image->control_code_page) |
---|
| 114 | - << PAGE_SHIFT; |
---|
| 115 | - page_list = image->head; |
---|
| 116 | - |
---|
| 117 | - /* Set up an identity mapping for the reboot_code_buffer */ |
---|
| 118 | - identity_map_page(reboot_code_buffer); |
---|
| 119 | - |
---|
| 120 | - /* copy it out */ |
---|
| 121 | - memcpy((void *)reboot_code_buffer, relocate_new_kernel, |
---|
| 122 | - relocate_new_kernel_size); |
---|
| 123 | + control_page = page_address(image->control_code_page); |
---|
| 124 | + memcpy(control_page, relocate_kernel, PAGE_SIZE); |
---|
| 125 | + |
---|
| 126 | + page_list[PA_CONTROL_PAGE] = __pa(control_page); |
---|
| 127 | + page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel; |
---|
| 128 | + page_list[PA_PGD] = __pa(kexec_pgd); |
---|
| 129 | + page_list[VA_PGD] = (unsigned long)kexec_pgd; |
---|
| 130 | +#ifdef CONFIG_X86_PAE |
---|
| 131 | + page_list[PA_PMD_0] = __pa(kexec_pmd0); |
---|
| 132 | + page_list[VA_PMD_0] = (unsigned long)kexec_pmd0; |
---|
| 133 | + page_list[PA_PMD_1] = __pa(kexec_pmd1); |
---|
| 134 | + page_list[VA_PMD_1] = (unsigned long)kexec_pmd1; |
---|
| 135 | +#endif |
---|
| 136 | + page_list[PA_PTE_0] = __pa(kexec_pte0); |
---|
| 137 | + page_list[VA_PTE_0] = (unsigned long)kexec_pte0; |
---|
| 138 | + page_list[PA_PTE_1] = __pa(kexec_pte1); |
---|
| 139 | + page_list[VA_PTE_1] = (unsigned long)kexec_pte1; |
---|
| 140 | |
---|
| 141 | /* The segment registers are funny things, they have both a |
---|
| 142 | * visible and an invisible part. Whenever the visible part is |
---|
| 143 | @@ -206,6 +143,6 @@ NORET_TYPE void machine_kexec(struct kim |
---|
| 144 | set_idt(phys_to_virt(0),0); |
---|
| 145 | |
---|
| 146 | /* now call it */ |
---|
| 147 | - rnk = (relocate_new_kernel_t) reboot_code_buffer; |
---|
| 148 | - (*rnk)(page_list, reboot_code_buffer, image->start, cpu_has_pae); |
---|
| 149 | + relocate_kernel((unsigned long)image->head, (unsigned long)page_list, |
---|
| 150 | + image->start, cpu_has_pae); |
---|
| 151 | } |
---|
| 152 | diff -pruN ../orig-linux-2.6.18/arch/i386/kernel/relocate_kernel.S ./arch/i386/kernel/relocate_kernel.S |
---|
| 153 | --- ../orig-linux-2.6.18/arch/i386/kernel/relocate_kernel.S 2006-09-20 04:42:06.000000000 +0100 |
---|
| 154 | +++ ./arch/i386/kernel/relocate_kernel.S 2007-01-12 16:03:23.000000000 +0000 |
---|
| 155 | @@ -7,16 +7,138 @@ |
---|
| 156 | */ |
---|
| 157 | |
---|
| 158 | #include <linux/linkage.h> |
---|
| 159 | +#include <asm/page.h> |
---|
| 160 | +#include <asm/kexec.h> |
---|
| 161 | + |
---|
| 162 | +/* |
---|
| 163 | + * Must be relocatable PIC code callable as a C function |
---|
| 164 | + */ |
---|
| 165 | + |
---|
| 166 | +#define PTR(x) (x << 2) |
---|
| 167 | +#define PAGE_ALIGNED (1 << PAGE_SHIFT) |
---|
| 168 | +#define PAGE_ATTR 0x63 /* _PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY */ |
---|
| 169 | +#define PAE_PGD_ATTR 0x01 /* _PAGE_PRESENT */ |
---|
| 170 | + |
---|
| 171 | + .text |
---|
| 172 | + .align PAGE_ALIGNED |
---|
| 173 | + .globl relocate_kernel |
---|
| 174 | +relocate_kernel: |
---|
| 175 | + movl 8(%esp), %ebp /* list of pages */ |
---|
| 176 | + |
---|
| 177 | +#ifdef CONFIG_X86_PAE |
---|
| 178 | + /* map the control page at its virtual address */ |
---|
| 179 | + |
---|
| 180 | + movl PTR(VA_PGD)(%ebp), %edi |
---|
| 181 | + movl PTR(VA_CONTROL_PAGE)(%ebp), %eax |
---|
| 182 | + andl $0xc0000000, %eax |
---|
| 183 | + shrl $27, %eax |
---|
| 184 | + addl %edi, %eax |
---|
| 185 | + |
---|
| 186 | + movl PTR(PA_PMD_0)(%ebp), %edx |
---|
| 187 | + orl $PAE_PGD_ATTR, %edx |
---|
| 188 | + movl %edx, (%eax) |
---|
| 189 | + |
---|
| 190 | + movl PTR(VA_PMD_0)(%ebp), %edi |
---|
| 191 | + movl PTR(VA_CONTROL_PAGE)(%ebp), %eax |
---|
| 192 | + andl $0x3fe00000, %eax |
---|
| 193 | + shrl $18, %eax |
---|
| 194 | + addl %edi, %eax |
---|
| 195 | + |
---|
| 196 | + movl PTR(PA_PTE_0)(%ebp), %edx |
---|
| 197 | + orl $PAGE_ATTR, %edx |
---|
| 198 | + movl %edx, (%eax) |
---|
| 199 | + |
---|
| 200 | + movl PTR(VA_PTE_0)(%ebp), %edi |
---|
| 201 | + movl PTR(VA_CONTROL_PAGE)(%ebp), %eax |
---|
| 202 | + andl $0x001ff000, %eax |
---|
| 203 | + shrl $9, %eax |
---|
| 204 | + addl %edi, %eax |
---|
| 205 | + |
---|
| 206 | + movl PTR(PA_CONTROL_PAGE)(%ebp), %edx |
---|
| 207 | + orl $PAGE_ATTR, %edx |
---|
| 208 | + movl %edx, (%eax) |
---|
| 209 | + |
---|
| 210 | + /* identity map the control page at its physical address */ |
---|
| 211 | + |
---|
| 212 | + movl PTR(VA_PGD)(%ebp), %edi |
---|
| 213 | + movl PTR(PA_CONTROL_PAGE)(%ebp), %eax |
---|
| 214 | + andl $0xc0000000, %eax |
---|
| 215 | + shrl $27, %eax |
---|
| 216 | + addl %edi, %eax |
---|
| 217 | + |
---|
| 218 | + movl PTR(PA_PMD_1)(%ebp), %edx |
---|
| 219 | + orl $PAE_PGD_ATTR, %edx |
---|
| 220 | + movl %edx, (%eax) |
---|
| 221 | + |
---|
| 222 | + movl PTR(VA_PMD_1)(%ebp), %edi |
---|
| 223 | + movl PTR(PA_CONTROL_PAGE)(%ebp), %eax |
---|
| 224 | + andl $0x3fe00000, %eax |
---|
| 225 | + shrl $18, %eax |
---|
| 226 | + addl %edi, %eax |
---|
| 227 | + |
---|
| 228 | + movl PTR(PA_PTE_1)(%ebp), %edx |
---|
| 229 | + orl $PAGE_ATTR, %edx |
---|
| 230 | + movl %edx, (%eax) |
---|
| 231 | + |
---|
| 232 | + movl PTR(VA_PTE_1)(%ebp), %edi |
---|
| 233 | + movl PTR(PA_CONTROL_PAGE)(%ebp), %eax |
---|
| 234 | + andl $0x001ff000, %eax |
---|
| 235 | + shrl $9, %eax |
---|
| 236 | + addl %edi, %eax |
---|
| 237 | + |
---|
| 238 | + movl PTR(PA_CONTROL_PAGE)(%ebp), %edx |
---|
| 239 | + orl $PAGE_ATTR, %edx |
---|
| 240 | + movl %edx, (%eax) |
---|
| 241 | +#else |
---|
| 242 | + /* map the control page at its virtual address */ |
---|
| 243 | + |
---|
| 244 | + movl PTR(VA_PGD)(%ebp), %edi |
---|
| 245 | + movl PTR(VA_CONTROL_PAGE)(%ebp), %eax |
---|
| 246 | + andl $0xffc00000, %eax |
---|
| 247 | + shrl $20, %eax |
---|
| 248 | + addl %edi, %eax |
---|
| 249 | + |
---|
| 250 | + movl PTR(PA_PTE_0)(%ebp), %edx |
---|
| 251 | + orl $PAGE_ATTR, %edx |
---|
| 252 | + movl %edx, (%eax) |
---|
| 253 | + |
---|
| 254 | + movl PTR(VA_PTE_0)(%ebp), %edi |
---|
| 255 | + movl PTR(VA_CONTROL_PAGE)(%ebp), %eax |
---|
| 256 | + andl $0x003ff000, %eax |
---|
| 257 | + shrl $10, %eax |
---|
| 258 | + addl %edi, %eax |
---|
| 259 | + |
---|
| 260 | + movl PTR(PA_CONTROL_PAGE)(%ebp), %edx |
---|
| 261 | + orl $PAGE_ATTR, %edx |
---|
| 262 | + movl %edx, (%eax) |
---|
| 263 | + |
---|
| 264 | + /* identity map the control page at its physical address */ |
---|
| 265 | + |
---|
| 266 | + movl PTR(VA_PGD)(%ebp), %edi |
---|
| 267 | + movl PTR(PA_CONTROL_PAGE)(%ebp), %eax |
---|
| 268 | + andl $0xffc00000, %eax |
---|
| 269 | + shrl $20, %eax |
---|
| 270 | + addl %edi, %eax |
---|
| 271 | + |
---|
| 272 | + movl PTR(PA_PTE_1)(%ebp), %edx |
---|
| 273 | + orl $PAGE_ATTR, %edx |
---|
| 274 | + movl %edx, (%eax) |
---|
| 275 | + |
---|
| 276 | + movl PTR(VA_PTE_1)(%ebp), %edi |
---|
| 277 | + movl PTR(PA_CONTROL_PAGE)(%ebp), %eax |
---|
| 278 | + andl $0x003ff000, %eax |
---|
| 279 | + shrl $10, %eax |
---|
| 280 | + addl %edi, %eax |
---|
| 281 | + |
---|
| 282 | + movl PTR(PA_CONTROL_PAGE)(%ebp), %edx |
---|
| 283 | + orl $PAGE_ATTR, %edx |
---|
| 284 | + movl %edx, (%eax) |
---|
| 285 | +#endif |
---|
| 286 | |
---|
| 287 | - /* |
---|
| 288 | - * Must be relocatable PIC code callable as a C function, that once |
---|
| 289 | - * it starts can not use the previous processes stack. |
---|
| 290 | - */ |
---|
| 291 | - .globl relocate_new_kernel |
---|
| 292 | relocate_new_kernel: |
---|
| 293 | /* read the arguments and say goodbye to the stack */ |
---|
| 294 | movl 4(%esp), %ebx /* page_list */ |
---|
| 295 | - movl 8(%esp), %ebp /* reboot_code_buffer */ |
---|
| 296 | + movl 8(%esp), %ebp /* list of pages */ |
---|
| 297 | movl 12(%esp), %edx /* start address */ |
---|
| 298 | movl 16(%esp), %ecx /* cpu_has_pae */ |
---|
| 299 | |
---|
| 300 | @@ -24,11 +146,26 @@ relocate_new_kernel: |
---|
| 301 | pushl $0 |
---|
| 302 | popfl |
---|
| 303 | |
---|
| 304 | - /* set a new stack at the bottom of our page... */ |
---|
| 305 | - lea 4096(%ebp), %esp |
---|
| 306 | + /* get physical address of control page now */ |
---|
| 307 | + /* this is impossible after page table switch */ |
---|
| 308 | + movl PTR(PA_CONTROL_PAGE)(%ebp), %edi |
---|
| 309 | + |
---|
| 310 | + /* switch to new set of page tables */ |
---|
| 311 | + movl PTR(PA_PGD)(%ebp), %eax |
---|
| 312 | + movl %eax, %cr3 |
---|
| 313 | + |
---|
| 314 | + /* setup a new stack at the end of the physical control page */ |
---|
| 315 | + lea 4096(%edi), %esp |
---|
| 316 | |
---|
| 317 | - /* store the parameters back on the stack */ |
---|
| 318 | - pushl %edx /* store the start address */ |
---|
| 319 | + /* jump to identity mapped page */ |
---|
| 320 | + movl %edi, %eax |
---|
| 321 | + addl $(identity_mapped - relocate_kernel), %eax |
---|
| 322 | + pushl %eax |
---|
| 323 | + ret |
---|
| 324 | + |
---|
| 325 | +identity_mapped: |
---|
| 326 | + /* store the start address on the stack */ |
---|
| 327 | + pushl %edx |
---|
| 328 | |
---|
| 329 | /* Set cr0 to a known state: |
---|
| 330 | * 31 0 == Paging disabled |
---|
| 331 | @@ -113,8 +250,3 @@ relocate_new_kernel: |
---|
| 332 | xorl %edi, %edi |
---|
| 333 | xorl %ebp, %ebp |
---|
| 334 | ret |
---|
| 335 | -relocate_new_kernel_end: |
---|
| 336 | - |
---|
| 337 | - .globl relocate_new_kernel_size |
---|
| 338 | -relocate_new_kernel_size: |
---|
| 339 | - .long relocate_new_kernel_end - relocate_new_kernel |
---|
| 340 | diff -pruN ../orig-linux-2.6.18/include/asm-i386/kexec.h ./include/asm-i386/kexec.h |
---|
| 341 | --- ../orig-linux-2.6.18/include/asm-i386/kexec.h 2006-09-20 04:42:06.000000000 +0100 |
---|
| 342 | +++ ./include/asm-i386/kexec.h 2007-01-12 16:03:23.000000000 +0000 |
---|
| 343 | @@ -1,6 +1,26 @@ |
---|
| 344 | #ifndef _I386_KEXEC_H |
---|
| 345 | #define _I386_KEXEC_H |
---|
| 346 | |
---|
| 347 | +#define PA_CONTROL_PAGE 0 |
---|
| 348 | +#define VA_CONTROL_PAGE 1 |
---|
| 349 | +#define PA_PGD 2 |
---|
| 350 | +#define VA_PGD 3 |
---|
| 351 | +#define PA_PTE_0 4 |
---|
| 352 | +#define VA_PTE_0 5 |
---|
| 353 | +#define PA_PTE_1 6 |
---|
| 354 | +#define VA_PTE_1 7 |
---|
| 355 | +#ifdef CONFIG_X86_PAE |
---|
| 356 | +#define PA_PMD_0 8 |
---|
| 357 | +#define VA_PMD_0 9 |
---|
| 358 | +#define PA_PMD_1 10 |
---|
| 359 | +#define VA_PMD_1 11 |
---|
| 360 | +#define PAGES_NR 12 |
---|
| 361 | +#else |
---|
| 362 | +#define PAGES_NR 8 |
---|
| 363 | +#endif |
---|
| 364 | + |
---|
| 365 | +#ifndef __ASSEMBLY__ |
---|
| 366 | + |
---|
| 367 | #include <asm/fixmap.h> |
---|
| 368 | #include <asm/ptrace.h> |
---|
| 369 | #include <asm/string.h> |
---|
| 370 | @@ -72,5 +92,12 @@ static inline void crash_setup_regs(stru |
---|
| 371 | newregs->eip = (unsigned long)current_text_addr(); |
---|
| 372 | } |
---|
| 373 | } |
---|
| 374 | +asmlinkage NORET_TYPE void |
---|
| 375 | +relocate_kernel(unsigned long indirection_page, |
---|
| 376 | + unsigned long control_page, |
---|
| 377 | + unsigned long start_address, |
---|
| 378 | + unsigned int has_pae) ATTRIB_NORET; |
---|
| 379 | + |
---|
| 380 | +#endif /* __ASSEMBLY__ */ |
---|
| 381 | |
---|
| 382 | #endif /* _I386_KEXEC_H */ |
---|