diff mbox

[RFC,v3,2/2] KVM: x86: Allow Qemu/KVM to use PVH entry point

Message ID 1513122151-5371-3-git-send-email-maran.wilson@oracle.com (mailing list archive)
State New, archived
Headers show

Commit Message

Maran Wilson Dec. 12, 2017, 11:42 p.m. UTC
For certain applications it is desirable to rapidly boot a KVM virtual
machine. In cases where legacy hardware and software support within the
guest is not needed, Qemu should be able to boot directly into the
uncompressed Linux kernel binary without the need to run firmware.

There already exists an ABI to allow this for Xen PVH guests and the ABI
is supported by Linux and FreeBSD:

   https://xenbits.xen.org/docs/unstable/misc/pvh.html

This patch enables Qemu to use that same entry point for booting KVM
guests.
---
 arch/x86/xen/enlighten_pvh.c | 51 +++++++++++++++++++++++++++++++-------------
 1 file changed, 36 insertions(+), 15 deletions(-)

Comments

Jürgen Groß Dec. 15, 2017, 3:55 p.m. UTC | #1
On 13/12/17 00:42, Maran Wilson wrote:
> For certain applications it is desirable to rapidly boot a KVM virtual
> machine. In cases where legacy hardware and software support within the
> guest is not needed, Qemu should be able to boot directly into the
> uncompressed Linux kernel binary without the need to run firmware.
> 
> There already exists an ABI to allow this for Xen PVH guests and the ABI
> is supported by Linux and FreeBSD:
> 
>    https://xenbits.xen.org/docs/unstable/misc/pvh.html
> 
> This patch enables Qemu to use that same entry point for booting KVM
> guests.

I'm fine with the general idea.

I'm wondering whether you really want to require CONFIG_XEN for the
KVM case, though.

Wouldn't it be better to rename arch/x86/xen/enlighten_pvh.c to
arch/x86/pvh.c and arch/x86/xen/xen-pvh.S to arch/x86/pvh-head.S,
put both under CONFIG_PVH umbrella and select this from CONFIG_XEN_PVH
and KVM_PVH (or what you like to call it)?

In the two moved source files you can make Xen/KVM-specific parts
optional via their CONFIG_ options.

And you might want to add an own ELF note for the KVM case?

> ---
>  arch/x86/xen/enlighten_pvh.c | 51 +++++++++++++++++++++++++++++++-------------
>  1 file changed, 36 insertions(+), 15 deletions(-)
> 
> diff --git a/arch/x86/xen/enlighten_pvh.c b/arch/x86/xen/enlighten_pvh.c
> index 98ab176..12f3716 100644
> --- a/arch/x86/xen/enlighten_pvh.c
> +++ b/arch/x86/xen/enlighten_pvh.c
> @@ -31,21 +31,38 @@ static void xen_pvh_arch_setup(void)
>  		acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM;
>  }
>  
> -static void __init init_pvh_bootparams(void)
> +static void __init init_pvh_bootparams(bool xen_guest)
>  {
>  	struct xen_memory_map memmap;
>  	int rc;
>  
>  	memset(&pvh_bootparams, 0, sizeof(pvh_bootparams));
>  
> -	memmap.nr_entries = ARRAY_SIZE(pvh_bootparams.e820_table);
> -	set_xen_guest_handle(memmap.buffer, pvh_bootparams.e820_table);
> -	rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap);
> -	if (rc) {
> -		xen_raw_printk("XENMEM_memory_map failed (%d)\n", rc);
> +	if ((pvh_start_info.version > 0) && (pvh_start_info.memmap_entries)) {
> +		struct hvm_memmap_table_entry *ep;
> +		int i;
> +
> +		ep = __va(pvh_start_info.memmap_paddr);
> +		pvh_bootparams.e820_entries = pvh_start_info.memmap_entries;
> +
> +		for (i = 0; i < pvh_bootparams.e820_entries ; i++, ep++) {
> +			pvh_bootparams.e820_table[i].addr = ep->addr;
> +			pvh_bootparams.e820_table[i].size = ep->size;
> +			pvh_bootparams.e820_table[i].type = ep->type;
> +		}
> +	} else if (xen_guest) {
> +		memmap.nr_entries = ARRAY_SIZE(pvh_bootparams.e820_table);
> +		set_xen_guest_handle(memmap.buffer, pvh_bootparams.e820_table);
> +		rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap);
> +		if (rc) {
> +			xen_raw_printk("XENMEM_memory_map failed (%d)\n", rc);
> +			BUG();
> +		}
> +		pvh_bootparams.e820_entries = memmap.nr_entries;
> +	} else {
> +		xen_raw_printk("Error: Could not find memory map\n");

xen_raw_printk() without being a Xen guest?


Juergen
Paolo Bonzini Dec. 15, 2017, 5:25 p.m. UTC | #2
On 15/12/2017 16:55, Juergen Gross wrote:
> I'm fine with the general idea.
> 
> I'm wondering whether you really want to require CONFIG_XEN for the
> KVM case, though.
> 
> Wouldn't it be better to rename arch/x86/xen/enlighten_pvh.c to
> arch/x86/pvh.c and arch/x86/xen/xen-pvh.S to arch/x86/pvh-head.S,

Yes, sounds good.

> put both under CONFIG_PVH umbrella and select this from CONFIG_XEN_PVH
> and KVM_PVH (or what you like to call it)?

CONFIG_KVM_GUEST will be good enough.

> In the two moved source files you can make Xen/KVM-specific parts
> optional via their CONFIG_ options.
> 
> And you might want to add an own ELF note for the KVM case?

As long as it's compatible with Xen, it's not needed.  Only the startup
code changes between a KVM "PVH" kernel and a KVM "HVM" kernel.

Paolo
diff mbox

Patch

diff --git a/arch/x86/xen/enlighten_pvh.c b/arch/x86/xen/enlighten_pvh.c
index 98ab176..12f3716 100644
--- a/arch/x86/xen/enlighten_pvh.c
+++ b/arch/x86/xen/enlighten_pvh.c
@@ -31,21 +31,38 @@  static void xen_pvh_arch_setup(void)
 		acpi_irq_model = ACPI_IRQ_MODEL_PLATFORM;
 }
 
-static void __init init_pvh_bootparams(void)
+static void __init init_pvh_bootparams(bool xen_guest)
 {
 	struct xen_memory_map memmap;
 	int rc;
 
 	memset(&pvh_bootparams, 0, sizeof(pvh_bootparams));
 
-	memmap.nr_entries = ARRAY_SIZE(pvh_bootparams.e820_table);
-	set_xen_guest_handle(memmap.buffer, pvh_bootparams.e820_table);
-	rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap);
-	if (rc) {
-		xen_raw_printk("XENMEM_memory_map failed (%d)\n", rc);
+	if ((pvh_start_info.version > 0) && (pvh_start_info.memmap_entries)) {
+		struct hvm_memmap_table_entry *ep;
+		int i;
+
+		ep = __va(pvh_start_info.memmap_paddr);
+		pvh_bootparams.e820_entries = pvh_start_info.memmap_entries;
+
+		for (i = 0; i < pvh_bootparams.e820_entries ; i++, ep++) {
+			pvh_bootparams.e820_table[i].addr = ep->addr;
+			pvh_bootparams.e820_table[i].size = ep->size;
+			pvh_bootparams.e820_table[i].type = ep->type;
+		}
+	} else if (xen_guest) {
+		memmap.nr_entries = ARRAY_SIZE(pvh_bootparams.e820_table);
+		set_xen_guest_handle(memmap.buffer, pvh_bootparams.e820_table);
+		rc = HYPERVISOR_memory_op(XENMEM_memory_map, &memmap);
+		if (rc) {
+			xen_raw_printk("XENMEM_memory_map failed (%d)\n", rc);
+			BUG();
+		}
+		pvh_bootparams.e820_entries = memmap.nr_entries;
+	} else {
+		xen_raw_printk("Error: Could not find memory map\n");
 		BUG();
 	}
-	pvh_bootparams.e820_entries = memmap.nr_entries;
 
 	if (pvh_bootparams.e820_entries < E820_MAX_ENTRIES_ZEROPAGE - 1) {
 		pvh_bootparams.e820_table[pvh_bootparams.e820_entries].addr =
@@ -76,7 +93,7 @@  static void __init init_pvh_bootparams(void)
 	 * environment (i.e. hardware_subarch 0).
 	 */
 	pvh_bootparams.hdr.version = 0x212;
-	pvh_bootparams.hdr.type_of_loader = (9 << 4) | 0; /* Xen loader */
+	pvh_bootparams.hdr.type_of_loader = ((xen_guest ? 0x9 : 0xb) << 4) | 0;
 }
 
 /*
@@ -85,8 +102,10 @@  static void __init init_pvh_bootparams(void)
  */
 void __init xen_prepare_pvh(void)
 {
-	u32 msr;
+
+	u32 msr = xen_cpuid_base();
 	u64 pfn;
+	bool xen_guest = !!msr;
 
 	if (pvh_start_info.magic != XEN_HVM_START_MAGIC_VALUE) {
 		xen_raw_printk("Error: Unexpected magic value (0x%08x)\n",
@@ -94,13 +113,15 @@  void __init xen_prepare_pvh(void)
 		BUG();
 	}
 
-	xen_pvh = 1;
+	if (xen_guest) {
+		xen_pvh = 1;
 
-	msr = cpuid_ebx(xen_cpuid_base() + 2);
-	pfn = __pa(hypercall_page);
-	wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32));
+		msr = cpuid_ebx(msr + 2);
+		pfn = __pa(hypercall_page);
+		wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32));
 
-	init_pvh_bootparams();
+		x86_init.oem.arch_setup = xen_pvh_arch_setup;
+	}
 
-	x86_init.oem.arch_setup = xen_pvh_arch_setup;
+	init_pvh_bootparams(xen_guest);
 }