1/* 2 * machine_kexec.c - handle transition of Linux booting another kernel 3 * Copyright (C) 2002-2005 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/mm.h> 10#include <linux/kexec.h> 11#include <linux/delay.h> 12#include <linux/init.h> 13#include <asm/pgtable.h> 14#include <asm/pgalloc.h> 15#include <asm/tlbflush.h> 16#include <asm/mmu_context.h> 17#include <asm/io.h> 18#include <asm/apic.h> 19#include <asm/cpufeature.h> 20#include <asm/desc.h> 21#include <asm/system.h> 22 23#define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE))) 24static u32 kexec_pgd[1024] PAGE_ALIGNED; 25#ifdef CONFIG_X86_PAE 26static u32 kexec_pmd0[1024] PAGE_ALIGNED; 27static u32 kexec_pmd1[1024] PAGE_ALIGNED; 28#endif 29static u32 kexec_pte0[1024] PAGE_ALIGNED; 30static u32 kexec_pte1[1024] PAGE_ALIGNED; 31 32static void set_idt(void *newidt, __u16 limit) 33{ 34 struct Xgt_desc_struct curidt; 35 36 /* ia32 supports unaliged loads & stores */ 37 curidt.size = limit; 38 curidt.address = (unsigned long)newidt; 39 40 load_idt(&curidt); 41}; 42 43 44static void set_gdt(void *newgdt, __u16 limit) 45{ 46 struct Xgt_desc_struct curgdt; 47 48 /* ia32 supports unaligned loads & stores */ 49 curgdt.size = limit; 50 curgdt.address = (unsigned long)newgdt; 51 52 load_gdt(&curgdt); 53}; 54 55static void load_segments(void) 56{ 57#define __STR(X) #X 58#define STR(X) __STR(X) 59 60 __asm__ __volatile__ ( 61 "\tljmp $"STR(__KERNEL_CS)",$1f\n" 62 "\t1:\n" 63 "\tmovl $"STR(__KERNEL_DS)",%%eax\n" 64 "\tmovl %%eax,%%ds\n" 65 "\tmovl %%eax,%%es\n" 66 "\tmovl %%eax,%%fs\n" 67 "\tmovl %%eax,%%gs\n" 68 "\tmovl %%eax,%%ss\n" 69 ::: "eax", "memory"); 70#undef STR 71#undef __STR 72} 73 74/* 75 * A architecture hook called to validate the 76 * proposed image and prepare the control pages 77 * as needed. The pages for KEXEC_CONTROL_CODE_SIZE 78 * have been allocated, but the segments have yet 79 * been copied into the kernel. 80 * 81 * Do what every setup is needed on image and the 82 * reboot code buffer to allow us to avoid allocations 83 * later. 84 * 85 * Currently nothing. 86 */ 87int machine_kexec_prepare(struct kimage *image) 88{ 89 return 0; 90} 91 92/* 93 * Undo anything leftover by machine_kexec_prepare 94 * when an image is freed. 95 */ 96void machine_kexec_cleanup(struct kimage *image) 97{ 98} 99 100/* 101 * Do not allocate memory (or fail in any way) in machine_kexec(). 102 * We are past the point of no return, committed to rebooting now. 103 */ 104NORET_TYPE void machine_kexec(struct kimage *image) 105{ 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 control_page = page_address(image->control_code_page); 113 memcpy(control_page, relocate_kernel, PAGE_SIZE); 114 115 page_list[PA_CONTROL_PAGE] = __pa(control_page); 116 page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel; 117 page_list[PA_PGD] = __pa(kexec_pgd); 118 page_list[VA_PGD] = (unsigned long)kexec_pgd; 119#ifdef CONFIG_X86_PAE 120 page_list[PA_PMD_0] = __pa(kexec_pmd0); 121 page_list[VA_PMD_0] = (unsigned long)kexec_pmd0; 122 page_list[PA_PMD_1] = __pa(kexec_pmd1); 123 page_list[VA_PMD_1] = (unsigned long)kexec_pmd1; 124#endif 125 page_list[PA_PTE_0] = __pa(kexec_pte0); 126 page_list[VA_PTE_0] = (unsigned long)kexec_pte0; 127 page_list[PA_PTE_1] = __pa(kexec_pte1); 128 page_list[VA_PTE_1] = (unsigned long)kexec_pte1; 129 130 /* The segment registers are funny things, they have both a 131 * visible and an invisible part. Whenever the visible part is 132 * set to a specific selector, the invisible part is loaded 133 * with from a table in memory. At no other time is the 134 * descriptor table in memory accessed. 135 * 136 * I take advantage of this here by force loading the 137 * segments, before I zap the gdt with an invalid value. 138 */ 139 load_segments(); 140 /* The gdt & idt are now invalid. 141 * If you want to load them you must set up your own idt & gdt. 142 */ 143 set_gdt(phys_to_virt(0),0); 144 set_idt(phys_to_virt(0),0); 145 146 /* now call it */ 147 relocate_kernel((unsigned long)image->head, (unsigned long)page_list, 148 image->start, cpu_has_pae); 149} 150 151/* crashkernel=size@addr specifies the location to reserve for 152 * a crash kernel. By reserving this memory we guarantee 153 * that linux never sets it up as a DMA target. 154 * Useful for holding code to do something appropriate 155 * after a kernel panic. 156 */ 157static int __init parse_crashkernel(char *arg) 158{ 159 unsigned long size, base; 160 size = memparse(arg, &arg); 161 if (*arg == '@') { 162 base = memparse(arg+1, &arg); 163 crashk_res.start = base; 164 crashk_res.end = base + size - 1; 165 } 166 return 0; 167} 168early_param("crashkernel", parse_crashkernel); 169