[RFC] First (incomplete) cut of Xen paravirt binding

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sun, 2006-07-30 at 19:05 +0200, Andi Kleen wrote:
>  > (1) We can make startup_32 work for every known and future reasonable
> > hypervisor as well as native, by testing if ring isn't 0 and paging is
> > enabled and jumping to the paravirt entry path.
> 
> Somehow the right Hypervisor still needs to be discovered though
> so that the right paravirt ops can be installed.
> 
> We would need a standard interface for this.

Yes, that's %ebx here (0 == Xen): we call paravirts[%ebx]->init().

Of course if you do full virtualization and then later want to insert
paravirt_ops, you can just use the normal boot path (Zach has indicated
that VMWare will do this in the short to medium term anyway).

FYI, here's the actual patch.

Thanks!
Rusty.

First cut (compiles, untested) of generic startup_paravirt entry point.

1) Each hypervisor type creates a paravirt_ops struct and puts an
   agreed-on entry in the paravirts[] array.  Strictly, this need
   only have the init function populated.

2) The hypervisor type is handed through %ebx to the startup_paravirt
   function at boot.  Currently 0 = Xen 3.0, 1 = VMI.

3) The init function (called with all regs except for %ebx and %esp
   intact), with first arg pointing to the paravirt_ops structure
   we're using.  This is responsible for overwriting the paravirt_ops:
   a helper called initialize_ops_struct is provided.

Signed-off-by: Rusty Russell <rusty at rustcorp.com.au>

===================================================================
--- a/arch/i386/kernel/asm-offsets.c
+++ b/arch/i386/kernel/asm-offsets.c
@@ -81,5 +81,6 @@ void foo(void)
 	OFFSET(PARAVIRT_irq_enable_sysexit, paravirt_ops, irq_enable_sysexit);
 	OFFSET(PARAVIRT_iret, paravirt_ops, iret);
 	OFFSET(PARAVIRT_read_cr0, paravirt_ops, read_cr0);
+	OFFSET(PARAVIRT_init_offset, paravirt_ops, init);
 #endif
 }
===================================================================
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -54,6 +54,12 @@
  * can.
  */
 ENTRY(startup_32)
+
+#ifdef CONFIG_PARAVIRT
+        movl %cs, %eax
+        testl $0x3, %eax
+        jnz startup_paravirt
+#endif
 
 /*
  * Set segments to known values.
@@ -411,6 +417,17 @@ ignore_int:
 #endif
 	iret
 
+#ifdef CONFIG_PARAVIRT
+ENTRY(startup_paravirt)
+	cld
+ 	movl $(init_thread_union+THREAD_SIZE),%esp
+
+	/* ebx contains index into paravirt to copy.  hand to init as a ptr. */
+	movl paravirts(,%ebx,4), %ebx
+	call *PARAVIRT_init_offset(%ebx)
+1:	jmp 1b
+#endif
+
 /*
  * Real beginning of normal "text" segment
  */
===================================================================
--- a/arch/i386/kernel/paravirt.c
+++ b/arch/i386/kernel/paravirt.c
@@ -388,6 +388,25 @@ static unsigned nopara_patch(unsigned in
 	return insn_len;
 }
 
+
+/* Array of all the paravirtualization ops available.  See head.S. */
+struct paravirt_ops *paravirts[] = {
+#ifdef CONFIG_VMI
+	[1] = &vmi_paravirt_ops,
+#endif
+};
+
+/* Overwrite ops struct with non-NULL ops entries from this struct. */
+void initialize_ops_struct(const struct paravirt_ops *ops)
+{
+	unsigned int i;
+	void **src = (void **)ops, **dst = (void **)&paravirt_ops;
+
+	for (i = 0; i < offsetof(struct paravirt_ops, kernel_rpl) / 4; i++) {
+		if (src[i])
+			dst[i] = src[i];
+	}
+}
 
 struct paravirt_ops paravirt_ops = {
 	.kernel_rpl = 0,
===================================================================
--- a/include/asm-i386/paravirt.h
+++ b/include/asm-i386/paravirt.h
@@ -5,6 +5,7 @@
 #include <linux/config.h>
 #include <linux/linkage.h>
 #include <linux/stringify.h>
+#include <asm/linkage.h>
 
 #ifndef CONFIG_PARAVIRT
 #include <asm/no_paravirt.h>
@@ -22,8 +23,7 @@ struct Xgt_desc_struct;
 struct Xgt_desc_struct;
 struct paravirt_ops
 {
-	unsigned int kernel_rpl;
-
+	fastcall void (*init)(struct paravirt_ops *me);
 	unsigned (*patch)(unsigned int type, void *firstinsn, unsigned len);
 
 	/* All the function pointers here are declared as "fastcall"
@@ -87,9 +87,15 @@ struct paravirt_ops
 	/* These two are jmp to, not actually called. */
 	void (fastcall *irq_enable_sysexit)(void);
 	void (fastcall *iret)(void);
+
+	/* Here and below are not copied by initialize_ops_struct */
+	unsigned int kernel_rpl;
 };
 
 extern struct paravirt_ops paravirt_ops;
+
+/* Overwrite ops struct with non-NULL ops entries from this struct. */
+void initialize_ops_struct(const struct paravirt_ops *ops);
 
 /* The paravirtualized CPUID instruction. */
 static inline void __cpuid(unsigned int *eax, unsigned int *ebx,

-- 
Help! Save Australia from the worst of the DMCA: http://linux.org.au/law



[Index of Archives]     [KVM Development]     [Libvirt Development]     [Libvirt Users]     [CentOS Virtualization]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux