- Update to 2.6.25-rc3.
[linux-flexiantxendom0-3.2.10.git] / arch / x86 / kernel / machine_kexec_64.c
index de3c921..236d2f8 100644 (file)
@@ -25,104 +25,6 @@ static u64 kexec_pud1[512] PAGE_ALIGNED;
 static u64 kexec_pmd1[512] PAGE_ALIGNED;
 static u64 kexec_pte1[512] PAGE_ALIGNED;
 
-#ifdef CONFIG_XEN
-
-/* In the case of Xen, override hypervisor functions to be able to create
- * a regular identity mapping page table...
- */
-
-#include <xen/interface/kexec.h>
-#include <xen/interface/memory.h>
-
-#define x__pmd(x) ((pmd_t) { (x) } )
-#define x__pud(x) ((pud_t) { (x) } )
-#define x__pgd(x) ((pgd_t) { (x) } )
-
-#define x_pmd_val(x)   ((x).pmd)
-#define x_pud_val(x)   ((x).pud)
-#define x_pgd_val(x)   ((x).pgd)
-
-static inline void x_set_pmd(pmd_t *dst, pmd_t val)
-{
-       x_pmd_val(*dst) = x_pmd_val(val);
-}
-
-static inline void x_set_pud(pud_t *dst, pud_t val)
-{
-       x_pud_val(*dst) = phys_to_machine(x_pud_val(val));
-}
-
-static inline void x_pud_clear (pud_t *pud)
-{
-       x_pud_val(*pud) = 0;
-}
-
-static inline void x_set_pgd(pgd_t *dst, pgd_t val)
-{
-       x_pgd_val(*dst) = phys_to_machine(x_pgd_val(val));
-}
-
-static inline void x_pgd_clear (pgd_t * pgd)
-{
-       x_pgd_val(*pgd) = 0;
-}
-
-#define X__PAGE_KERNEL_LARGE_EXEC \
-         _PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_PSE
-#define X_KERNPG_TABLE _PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY
-
-#define __ma(x) (pfn_to_mfn(__pa((x)) >> PAGE_SHIFT) << PAGE_SHIFT)
-
-#if PAGES_NR > KEXEC_XEN_NO_PAGES
-#error PAGES_NR is greater than KEXEC_XEN_NO_PAGES - Xen support will break
-#endif
-
-#if PA_CONTROL_PAGE != 0
-#error PA_CONTROL_PAGE is non zero - Xen support will break
-#endif
-
-void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, struct kimage *image)
-{
-       void *control_page;
-       void *table_page;
-
-       memset(xki->page_list, 0, sizeof(xki->page_list));
-
-       control_page = page_address(image->control_code_page) + PAGE_SIZE;
-       memcpy(control_page, relocate_kernel, PAGE_SIZE);
-
-       table_page = page_address(image->control_code_page);
-
-       xki->page_list[PA_CONTROL_PAGE] = __ma(control_page);
-       xki->page_list[PA_TABLE_PAGE] = __ma(table_page);
-
-       xki->page_list[PA_PGD] = __ma(kexec_pgd);
-       xki->page_list[PA_PUD_0] = __ma(kexec_pud0);
-       xki->page_list[PA_PUD_1] = __ma(kexec_pud1);
-       xki->page_list[PA_PMD_0] = __ma(kexec_pmd0);
-       xki->page_list[PA_PMD_1] = __ma(kexec_pmd1);
-       xki->page_list[PA_PTE_0] = __ma(kexec_pte0);
-       xki->page_list[PA_PTE_1] = __ma(kexec_pte1);
-}
-
-#else /* CONFIG_XEN */
-
-#define x__pmd(x) __pmd(x)
-#define x__pud(x) __pud(x)
-#define x__pgd(x) __pgd(x)
-
-#define x_set_pmd(x, y) set_pmd(x, y)
-#define x_set_pud(x, y) set_pud(x, y)
-#define x_set_pgd(x, y) set_pgd(x, y)
-
-#define x_pud_clear(x) pud_clear(x)
-#define x_pgd_clear(x) pgd_clear(x)
-
-#define X__PAGE_KERNEL_LARGE_EXEC __PAGE_KERNEL_LARGE_EXEC
-#define X_KERNPG_TABLE _KERNPG_TABLE
-
-#endif /* CONFIG_XEN */
-
 static void init_level2_page(pmd_t *level2p, unsigned long addr)
 {
        unsigned long end_addr;
@@ -130,7 +32,7 @@ static void init_level2_page(pmd_t *level2p, unsigned long addr)
        addr &= PAGE_MASK;
        end_addr = addr + PUD_SIZE;
        while (addr < end_addr) {
-               x_set_pmd(level2p++, x__pmd(addr | X__PAGE_KERNEL_LARGE_EXEC));
+               set_pmd(level2p++, __pmd(addr | __PAGE_KERNEL_LARGE_EXEC));
                addr += PMD_SIZE;
        }
 }
@@ -155,12 +57,12 @@ static int init_level3_page(struct kimage *image, pud_t *level3p,
                }
                level2p = (pmd_t *)page_address(page);
                init_level2_page(level2p, addr);
-               x_set_pud(level3p++, x__pud(__pa(level2p) | X_KERNPG_TABLE));
+               set_pud(level3p++, __pud(__pa(level2p) | _KERNPG_TABLE));
                addr += PUD_SIZE;
        }
        /* clear the unused entries */
        while (addr < end_addr) {
-               x_pud_clear(level3p++);
+               pud_clear(level3p++);
                addr += PUD_SIZE;
        }
 out:
@@ -191,12 +93,12 @@ static int init_level4_page(struct kimage *image, pgd_t *level4p,
                if (result) {
                        goto out;
                }
-               x_set_pgd(level4p++, x__pgd(__pa(level3p) | X_KERNPG_TABLE));
+               set_pgd(level4p++, __pgd(__pa(level3p) | _KERNPG_TABLE));
                addr += PGDIR_SIZE;
        }
        /* clear the unused entries */
        while (addr < end_addr) {
-               x_pgd_clear(level4p++);
+               pgd_clear(level4p++);
                addr += PGDIR_SIZE;
        }
 out:
@@ -207,14 +109,49 @@ out:
 static int init_pgtable(struct kimage *image, unsigned long start_pgtable)
 {
        pgd_t *level4p;
-       unsigned long x_end_pfn = end_pfn;
+       level4p = (pgd_t *)__va(start_pgtable);
+       return init_level4_page(image, level4p, 0, end_pfn << PAGE_SHIFT);
+}
 
-#ifdef CONFIG_XEN
-       x_end_pfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL);
-#endif
+static void set_idt(void *newidt, u16 limit)
+{
+       struct desc_ptr curidt;
 
-       level4p = (pgd_t *)__va(start_pgtable);
-       return init_level4_page(image, level4p, 0, x_end_pfn << PAGE_SHIFT);
+       /* x86-64 supports unaliged loads & stores */
+       curidt.size    = limit;
+       curidt.address = (unsigned long)newidt;
+
+       __asm__ __volatile__ (
+               "lidtq %0\n"
+               : : "m" (curidt)
+               );
+};
+
+
+static void set_gdt(void *newgdt, u16 limit)
+{
+       struct desc_ptr curgdt;
+
+       /* x86-64 supports unaligned loads & stores */
+       curgdt.size    = limit;
+       curgdt.address = (unsigned long)newgdt;
+
+       __asm__ __volatile__ (
+               "lgdtq %0\n"
+               : : "m" (curgdt)
+               );
+};
+
+static void load_segments(void)
+{
+       __asm__ __volatile__ (
+               "\tmovl %0,%%ds\n"
+               "\tmovl %0,%%es\n"
+               "\tmovl %0,%%ss\n"
+               "\tmovl %0,%%fs\n"
+               "\tmovl %0,%%gs\n"
+               : : "a" (__KERNEL_DS) : "memory"
+               );
 }
 
 int machine_kexec_prepare(struct kimage *image)
@@ -238,7 +175,6 @@ void machine_kexec_cleanup(struct kimage *image)
        return;
 }
 
-#ifndef CONFIG_XEN
 /*
  * Do not allocate memory (or fail in any way) in machine_kexec().
  * We are past the point of no return, committed to rebooting now.
@@ -274,16 +210,32 @@ NORET_TYPE void machine_kexec(struct kimage *image)
        page_list[PA_TABLE_PAGE] =
          (unsigned long)__pa(page_address(image->control_code_page));
 
+       /* The segment registers are funny things, they have both a
+        * visible and an invisible part.  Whenever the visible part is
+        * set to a specific selector, the invisible part is loaded
+        * with from a table in memory.  At no other time is the
+        * descriptor table in memory accessed.
+        *
+        * I take advantage of this here by force loading the
+        * segments, before I zap the gdt with an invalid value.
+        */
+       load_segments();
+       /* The gdt & idt are now invalid.
+        * If you want to load them you must set up your own idt & gdt.
+        */
+       set_gdt(phys_to_virt(0),0);
+       set_idt(phys_to_virt(0),0);
+
+       /* now call it */
        relocate_kernel((unsigned long)image->head, (unsigned long)page_list,
                        image->start);
 }
-#endif
 
 void arch_crash_save_vmcoreinfo(void)
 {
        VMCOREINFO_SYMBOL(init_level4_pgt);
 
-#ifdef CONFIG_ARCH_DISCONTIGMEM_ENABLE
+#ifdef CONFIG_NUMA
        VMCOREINFO_SYMBOL(node_data);
        VMCOREINFO_LENGTH(node_data, MAX_NUMNODES);
 #endif