Re: [RFC PATCH] KVM: x86: Allow Qemu/KVM to use PVH entry point

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

 



On 28/11/17 19:34, 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/hvmlite.html

Just FYI, this link has recently become stale, following some cleanup. 
The document is now:

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

~Andrew

>
> This PoC patch enables Qemu to use that same entry point for booting KVM
> guests.
>
> Even though the code is still PoC quality, I'm sending this as an RFC now
> since there are a number of different ways the specific implementation
> details can be handled. I chose a shared code path for Xen and KVM guests
> but could just as easily create a separate code path that is advertised by
> a different ELF note for KVM. There also seems to be some flexibility in
> how the e820 table data is passed and how (or if) it should be identified
> as e820 data. As a starting point, I've chosen the options that seem to
> result in the smallest patch with minimal to no changes required of the
> x86/HVM direct boot ABI.
> ---
>  arch/x86/xen/enlighten_pvh.c | 74 ++++++++++++++++++++++++++++++++------------
>  1 file changed, 55 insertions(+), 19 deletions(-)
>
> diff --git a/arch/x86/xen/enlighten_pvh.c b/arch/x86/xen/enlighten_pvh.c
> index 98ab176..d93f711 100644
> --- a/arch/x86/xen/enlighten_pvh.c
> +++ b/arch/x86/xen/enlighten_pvh.c
> @@ -31,21 +31,46 @@ 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);
> -		BUG();
> +	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 if (pvh_start_info.nr_modules > 1) {
> +		/* The second module should be the e820 data for KVM guests */
> +		struct hvm_modlist_entry *modaddr;
> +		char e820_sig[] = "e820 data";
> +		struct boot_e820_entry *ep;
> +		struct e820_table *tp;
> +		char *cmdline_str;
> +		int idx;
> +
> +		modaddr = __va(pvh_start_info.modlist_paddr +
> +			       sizeof(struct hvm_modlist_entry));
> +		cmdline_str = __va(modaddr->cmdline_paddr);
> +
> +		if ((modaddr->cmdline_paddr) &&
> +		    (!strncmp(e820_sig, cmdline_str, sizeof(e820_sig)))) {
> +			tp = __va(modaddr->paddr);
> +			ep = (struct boot_e820_entry *)tp->entries;
> +
> +			pvh_bootparams.e820_entries = tp->nr_entries;
> +
> +			for (idx = 0; idx < tp->nr_entries ; idx++, ep++)
> +				pvh_bootparams.e820_table[idx] = *ep;
> +		}
>  	}
> -	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 =
> @@ -55,8 +80,9 @@ static void __init init_pvh_bootparams(void)
>  		pvh_bootparams.e820_table[pvh_bootparams.e820_entries].type =
>  			E820_TYPE_RESERVED;
>  		pvh_bootparams.e820_entries++;
> -	} else
> +	} else if (xen_guest) {
>  		xen_raw_printk("Warning: Can fit ISA range into e820\n");
> +	}
>  
>  	pvh_bootparams.hdr.cmd_line_ptr =
>  		pvh_start_info.cmdline_paddr;
> @@ -76,7 +102,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,22 +111,32 @@ 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 ? true : false;
>  
>  	if (pvh_start_info.magic != XEN_HVM_START_MAGIC_VALUE) {
> -		xen_raw_printk("Error: Unexpected magic value (0x%08x)\n",
> -				pvh_start_info.magic);
> +		if (xen_guest)
> +			xen_raw_printk("Error: Unexpected magic value (0x%08x)\n",
> +					pvh_start_info.magic);
>  		BUG();
>  	}
>  
> -	xen_pvh = 1;
> +	if (xen_guest) {
> +		xen_pvh = 1;
> +
> +		msr = cpuid_ebx(msr + 2);
> +		pfn = __pa(hypercall_page);
> +		wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32));
> +
> +	} else if (!hypervisor_cpuid_base("KVMKVMKVM\0\0\0", 0)) {
> +		BUG();
> +	}
>  
> -	msr = cpuid_ebx(xen_cpuid_base() + 2);
> -	pfn = __pa(hypercall_page);
> -	wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32));
> +	init_pvh_bootparams(xen_guest);
>  
> -	init_pvh_bootparams();
> +	if (xen_guest)
> +		x86_init.oem.arch_setup = xen_pvh_arch_setup;
>  
> -	x86_init.oem.arch_setup = xen_pvh_arch_setup;
>  }




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux