diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2006-12-06 20:14:08 -0500 |
---|---|---|
committer | Andi Kleen <andi@basil.nowhere.org> | 2006-12-06 20:14:08 -0500 |
commit | c9ccf30d77f04064fe5436027ab9d2230c7cdd94 (patch) | |
tree | 95c028ae6f1e50275ff7a40b987300bb647e8ead /arch | |
parent | d7cd56111f30259e1b532a12e06f59f8e0a20355 (diff) |
[PATCH] paravirt: Add startup infrastructure for paravirtualization
1) Each hypervisor writes a probe function to detect whether we are
running under that hypervisor. paravirt_probe() registers this
function.
2) If vmlinux is booted with ring != 0, we call all the probe
functions (with registers except %esp intact) in link order: the
winner will not return.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Chris Wright <chrisw@sous-sol.org>
Signed-off-by: Andi Kleen <ak@suse.de>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Zachary Amsden <zach@vmware.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/i386/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/i386/kernel/head.S | 33 | ||||
-rw-r--r-- | arch/i386/kernel/paravirt.c | 4 | ||||
-rw-r--r-- | arch/i386/kernel/vmlinux.lds.S | 6 |
4 files changed, 45 insertions, 0 deletions
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 406612136049..1e8988e558c5 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile | |||
@@ -39,6 +39,8 @@ obj-$(CONFIG_VM86) += vm86.o | |||
39 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 39 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
40 | obj-$(CONFIG_HPET_TIMER) += hpet.o | 40 | obj-$(CONFIG_HPET_TIMER) += hpet.o |
41 | obj-$(CONFIG_K8_NB) += k8.o | 41 | obj-$(CONFIG_K8_NB) += k8.o |
42 | |||
43 | # Make sure this is linked after any other paravirt_ops structs: see head.S | ||
42 | obj-$(CONFIG_PARAVIRT) += paravirt.o | 44 | obj-$(CONFIG_PARAVIRT) += paravirt.o |
43 | 45 | ||
44 | EXTRA_AFLAGS := -traditional | 46 | EXTRA_AFLAGS := -traditional |
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S index 5b14e95ac8b9..edef5084ce17 100644 --- a/arch/i386/kernel/head.S +++ b/arch/i386/kernel/head.S | |||
@@ -55,6 +55,12 @@ | |||
55 | */ | 55 | */ |
56 | ENTRY(startup_32) | 56 | ENTRY(startup_32) |
57 | 57 | ||
58 | #ifdef CONFIG_PARAVIRT | ||
59 | movl %cs, %eax | ||
60 | testl $0x3, %eax | ||
61 | jnz startup_paravirt | ||
62 | #endif | ||
63 | |||
58 | /* | 64 | /* |
59 | * Set segments to known values. | 65 | * Set segments to known values. |
60 | */ | 66 | */ |
@@ -486,6 +492,33 @@ ignore_int: | |||
486 | #endif | 492 | #endif |
487 | iret | 493 | iret |
488 | 494 | ||
495 | #ifdef CONFIG_PARAVIRT | ||
496 | startup_paravirt: | ||
497 | cld | ||
498 | movl $(init_thread_union+THREAD_SIZE),%esp | ||
499 | |||
500 | /* We take pains to preserve all the regs. */ | ||
501 | pushl %edx | ||
502 | pushl %ecx | ||
503 | pushl %eax | ||
504 | |||
505 | /* paravirt.o is last in link, and that probe fn never returns */ | ||
506 | pushl $__start_paravirtprobe | ||
507 | 1: | ||
508 | movl 0(%esp), %eax | ||
509 | pushl (%eax) | ||
510 | movl 8(%esp), %eax | ||
511 | call *(%esp) | ||
512 | popl %eax | ||
513 | |||
514 | movl 4(%esp), %eax | ||
515 | movl 8(%esp), %ecx | ||
516 | movl 12(%esp), %edx | ||
517 | |||
518 | addl $4, (%esp) | ||
519 | jmp 1b | ||
520 | #endif | ||
521 | |||
489 | /* | 522 | /* |
490 | * Real beginning of normal "text" segment | 523 | * Real beginning of normal "text" segment |
491 | */ | 524 | */ |
diff --git a/arch/i386/kernel/paravirt.c b/arch/i386/kernel/paravirt.c index d46460426446..5a9bd3250a1a 100644 --- a/arch/i386/kernel/paravirt.c +++ b/arch/i386/kernel/paravirt.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/efi.h> | 20 | #include <linux/efi.h> |
21 | #include <linux/bcd.h> | 21 | #include <linux/bcd.h> |
22 | #include <linux/start_kernel.h> | ||
22 | 23 | ||
23 | #include <asm/bug.h> | 24 | #include <asm/bug.h> |
24 | #include <asm/paravirt.h> | 25 | #include <asm/paravirt.h> |
@@ -387,6 +388,9 @@ static int __init print_banner(void) | |||
387 | } | 388 | } |
388 | core_initcall(print_banner); | 389 | core_initcall(print_banner); |
389 | 390 | ||
391 | /* We simply declare start_kernel to be the paravirt probe of last resort. */ | ||
392 | paravirt_probe(start_kernel); | ||
393 | |||
390 | struct paravirt_ops paravirt_ops = { | 394 | struct paravirt_ops paravirt_ops = { |
391 | .name = "bare hardware", | 395 | .name = "bare hardware", |
392 | .paravirt_enabled = 0, | 396 | .paravirt_enabled = 0, |
diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S index 5c69cf0e5944..877dc5cfe3a8 100644 --- a/arch/i386/kernel/vmlinux.lds.S +++ b/arch/i386/kernel/vmlinux.lds.S | |||
@@ -65,6 +65,12 @@ SECTIONS | |||
65 | CONSTRUCTORS | 65 | CONSTRUCTORS |
66 | } :data | 66 | } :data |
67 | 67 | ||
68 | __start_paravirtprobe = .; | ||
69 | .paravirtprobe : AT(ADDR(.paravirtprobe) - LOAD_OFFSET) { | ||
70 | *(.paravirtprobe) | ||
71 | } | ||
72 | __stop_paravirtprobe = .; | ||
73 | |||
68 | . = ALIGN(4096); | 74 | . = ALIGN(4096); |
69 | .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { | 75 | .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { |
70 | __nosave_begin = .; | 76 | __nosave_begin = .; |