156 lines
4.3 KiB
Diff
156 lines
4.3 KiB
Diff
|
Subject: kexec: Move asm segment handling code to the assembly file (i386)
|
||
|
From: http://xenbits.xensource.com/xen-unstable.hg (tip 13816)
|
||
|
Patch-mainline: n/a
|
||
|
|
||
|
This patch moves the idt, gdt, and segment handling code from machine_kexec.c
|
||
|
to relocate_kernel.S. The main reason behind this move is to avoid code
|
||
|
duplication in the Xen hypervisor. With this patch all code required to kexec
|
||
|
is put on the control page.
|
||
|
|
||
|
On top of that this patch also counts as a cleanup - I think it is much
|
||
|
nicer to write assembly directly in assembly files than wrap inline assembly
|
||
|
in C functions for no apparent reason.
|
||
|
|
||
|
Signed-off-by: Magnus Damm <magnus@valinux.co.jp>
|
||
|
Acked-by: jbeulich@novell.com
|
||
|
|
||
|
Applies to 2.6.19-rc1.
|
||
|
jb: fixed up register usage (paralleling what's needed for 2.6.30 on x86-64)
|
||
|
|
||
|
--- head-2010-01-19.orig/arch/x86/kernel/machine_kexec_32.c 2010-01-19 13:26:10.000000000 +0100
|
||
|
+++ head-2010-01-19/arch/x86/kernel/machine_kexec_32.c 2010-01-19 14:51:07.000000000 +0100
|
||
|
@@ -27,48 +27,6 @@
|
||
|
#include <asm/cacheflush.h>
|
||
|
#include <asm/debugreg.h>
|
||
|
|
||
|
-static void set_idt(void *newidt, __u16 limit)
|
||
|
-{
|
||
|
- struct desc_ptr curidt;
|
||
|
-
|
||
|
- /* ia32 supports unaliged loads & stores */
|
||
|
- curidt.size = limit;
|
||
|
- curidt.address = (unsigned long)newidt;
|
||
|
-
|
||
|
- load_idt(&curidt);
|
||
|
-}
|
||
|
-
|
||
|
-
|
||
|
-static void set_gdt(void *newgdt, __u16 limit)
|
||
|
-{
|
||
|
- struct desc_ptr curgdt;
|
||
|
-
|
||
|
- /* ia32 supports unaligned loads & stores */
|
||
|
- curgdt.size = limit;
|
||
|
- curgdt.address = (unsigned long)newgdt;
|
||
|
-
|
||
|
- load_gdt(&curgdt);
|
||
|
-}
|
||
|
-
|
||
|
-static void load_segments(void)
|
||
|
-{
|
||
|
-#define __STR(X) #X
|
||
|
-#define STR(X) __STR(X)
|
||
|
-
|
||
|
- __asm__ __volatile__ (
|
||
|
- "\tljmp $"STR(__KERNEL_CS)",$1f\n"
|
||
|
- "\t1:\n"
|
||
|
- "\tmovl $"STR(__KERNEL_DS)",%%eax\n"
|
||
|
- "\tmovl %%eax,%%ds\n"
|
||
|
- "\tmovl %%eax,%%es\n"
|
||
|
- "\tmovl %%eax,%%fs\n"
|
||
|
- "\tmovl %%eax,%%gs\n"
|
||
|
- "\tmovl %%eax,%%ss\n"
|
||
|
- : : : "eax", "memory");
|
||
|
-#undef STR
|
||
|
-#undef __STR
|
||
|
-}
|
||
|
-
|
||
|
static void machine_kexec_free_page_tables(struct kimage *image)
|
||
|
{
|
||
|
free_page((unsigned long)image->arch.pgd);
|
||
|
@@ -228,24 +186,6 @@ void machine_kexec(struct kimage *image)
|
||
|
page_list[PA_SWAP_PAGE] = (page_to_pfn(image->swap_page)
|
||
|
<< PAGE_SHIFT);
|
||
|
|
||
|
- /*
|
||
|
- * 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 */
|
||
|
image->start = relocate_kernel_ptr((unsigned long)image->head,
|
||
|
(unsigned long)page_list,
|
||
|
--- head-2010-01-19.orig/arch/x86/kernel/relocate_kernel_32.S 2009-06-10 05:05:27.000000000 +0200
|
||
|
+++ head-2010-01-19/arch/x86/kernel/relocate_kernel_32.S 2010-01-19 14:51:07.000000000 +0100
|
||
|
@@ -87,14 +87,32 @@ relocate_kernel:
|
||
|
movl PTR(PA_PGD)(%ebp), %eax
|
||
|
movl %eax, %cr3
|
||
|
|
||
|
+ /* setup idt */
|
||
|
+ lidtl idt_48 - relocate_kernel(%edi)
|
||
|
+
|
||
|
+ /* setup gdt */
|
||
|
+ leal gdt - relocate_kernel(%edi), %eax
|
||
|
+ movl %eax, (gdt_48 - relocate_kernel) + 2(%edi)
|
||
|
+ lgdtl gdt_48 - relocate_kernel(%edi)
|
||
|
+
|
||
|
+ /* setup data segment registers */
|
||
|
+ mov $(gdt_ds - gdt), %eax
|
||
|
+ mov %eax, %ds
|
||
|
+ mov %eax, %es
|
||
|
+ mov %eax, %fs
|
||
|
+ mov %eax, %gs
|
||
|
+ mov %eax, %ss
|
||
|
+
|
||
|
/* setup a new stack at the end of the physical control page */
|
||
|
lea PAGE_SIZE(%edi), %esp
|
||
|
|
||
|
- /* jump to identity mapped page */
|
||
|
+ /* load new code segment and jump to identity mapped page */
|
||
|
+ pushl $0
|
||
|
+ pushl $(gdt_cs - gdt)
|
||
|
movl %edi, %eax
|
||
|
addl $(identity_mapped - relocate_kernel), %eax
|
||
|
pushl %eax
|
||
|
- ret
|
||
|
+ iretl
|
||
|
|
||
|
identity_mapped:
|
||
|
/* store the start address on the stack */
|
||
|
@@ -271,5 +289,22 @@ swap_pages:
|
||
|
popl %ebp
|
||
|
ret
|
||
|
|
||
|
+ .align 16
|
||
|
+gdt:
|
||
|
+ .quad 0x0000000000000000 /* NULL descriptor */
|
||
|
+gdt_cs:
|
||
|
+ .quad 0x00cf9a000000ffff /* kernel 4GB code at 0x00000000 */
|
||
|
+gdt_ds:
|
||
|
+ .quad 0x00cf92000000ffff /* kernel 4GB data at 0x00000000 */
|
||
|
+gdt_end:
|
||
|
+
|
||
|
+gdt_48:
|
||
|
+ .word gdt_end - gdt - 1 /* limit */
|
||
|
+ .long 0 /* base - filled in by code above */
|
||
|
+
|
||
|
+idt_48:
|
||
|
+ .word 0 /* limit */
|
||
|
+ .long 0 /* base */
|
||
|
+
|
||
|
.globl kexec_control_code_size
|
||
|
.set kexec_control_code_size, . - relocate_kernel
|