Commit 460023a5 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-linus-4.21-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip

Pull xen updates from Juergen Gross:
 "Xen features and fixes:

   - a series to enable KVM guests to be booted by qemu via the Xen PVH
     boot entry for speeding up KVM guest tests

   - a series for a common driver to be used by Xen PV frontends (right
     now drm and sound)

   - two other fixes in Xen related code"

* tag 'for-linus-4.21-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
  ALSA: xen-front: Use Xen common shared buffer implementation
  drm/xen-front: Use Xen common shared buffer implementation
  xen: Introduce shared buffer helpers for page directory...
  xen/pciback: Check dev_data before using it
  kprobes/x86/xen: blacklist non-attachable xen interrupt functions
  KVM: x86: Allow Qemu/KVM to use PVH entry point
  xen/pvh: Add memory map pointer to hvm_start_info struct
  xen/pvh: Move Xen code for getting mem map via hcall out of common file
  xen/pvh: Move Xen specific PVH VM initialization out of common file
  xen/pvh: Create a new file for Xen specific PVH code
  xen/pvh: Move PVH entry code out of Xen specific tree
  xen/pvh: Split CONFIG_XEN_PVH into CONFIG_PVH and CONFIG_XEN_PVH
parents a5f2bd47 58f9d806
......@@ -16590,6 +16590,7 @@ L: xen-devel@lists.xenproject.org (moderated for non-subscribers)
T: git git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip.git
S: Supported
F: arch/x86/xen/
F: arch/x86/platform/pvh/
F: drivers/*/xen-*front.c
F: drivers/xen/
F: arch/x86/include/asm/xen/
......
......@@ -7,6 +7,8 @@ obj-$(CONFIG_KVM) += kvm/
# Xen paravirtualization support
obj-$(CONFIG_XEN) += xen/
obj-$(CONFIG_PVH) += platform/pvh/
# Hyper-V paravirtualization support
obj-$(subst m,y,$(CONFIG_HYPERV)) += hyperv/
......
......@@ -796,6 +796,12 @@ config KVM_GUEST
underlying device model, the host provides the guest with
timing infrastructure such as time of day, and system time
config PVH
bool "Support for running PVH guests"
---help---
This option enables the PVH entry point for guest virtual machines
as specified in the x86/HVM direct boot ABI.
config KVM_DEBUG_FS
bool "Enable debug information for KVM Guests in debugfs"
depends on KVM_GUEST && DEBUG_FS
......
......@@ -386,7 +386,7 @@ NEXT_PAGE(early_dynamic_pgts)
.data
#if defined(CONFIG_XEN_PV) || defined(CONFIG_XEN_PVH)
#if defined(CONFIG_XEN_PV) || defined(CONFIG_PVH)
NEXT_PGD_PAGE(init_top_pgt)
.quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC
.org init_top_pgt + L4_PAGE_OFFSET*8, 0
......
# SPDX-License-Identifier: GPL-2.0
OBJECT_FILES_NON_STANDARD_head.o := y
obj-$(CONFIG_PVH) += enlighten.o
obj-$(CONFIG_PVH) += head.o
// SPDX-License-Identifier: GPL-2.0
#include <linux/acpi.h>
#include <xen/hvc-console.h>
#include <asm/io_apic.h>
#include <asm/hypervisor.h>
#include <asm/e820/api.h>
#include <asm/x86_init.h>
#include <asm/xen/interface.h>
#include <xen/xen.h>
#include <xen/interface/hvm/start_info.h>
/*
* PVH variables.
*
* pvh_bootparams and pvh_start_info need to live in the data segment since
* they are used after startup_{32|64}, which clear .bss, are invoked.
*/
struct boot_params pvh_bootparams __attribute__((section(".data")));
struct hvm_start_info pvh_start_info __attribute__((section(".data")));
unsigned int pvh_start_info_sz = sizeof(pvh_start_info);
static u64 pvh_get_root_pointer(void)
{
return pvh_start_info.rsdp_paddr;
}
/*
* Xen guests are able to obtain the memory map from the hypervisor via the
* HYPERVISOR_memory_op hypercall.
* If we are trying to boot a Xen PVH guest, it is expected that the kernel
* will have been configured to provide an override for this routine to do
* just that.
*/
void __init __weak mem_map_via_hcall(struct boot_params *ptr __maybe_unused)
{
xen_raw_printk("Error: Could not find memory map\n");
BUG();
}
static void __init init_pvh_bootparams(bool xen_guest)
{
memset(&pvh_bootparams, 0, sizeof(pvh_bootparams));
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) {
mem_map_via_hcall(&pvh_bootparams);
} else {
/* Non-xen guests are not supported by version 0 */
BUG();
}
if (pvh_bootparams.e820_entries < E820_MAX_ENTRIES_ZEROPAGE - 1) {
pvh_bootparams.e820_table[pvh_bootparams.e820_entries].addr =
ISA_START_ADDRESS;
pvh_bootparams.e820_table[pvh_bootparams.e820_entries].size =
ISA_END_ADDRESS - ISA_START_ADDRESS;
pvh_bootparams.e820_table[pvh_bootparams.e820_entries].type =
E820_TYPE_RESERVED;
pvh_bootparams.e820_entries++;
} else
xen_raw_printk("Warning: Can fit ISA range into e820\n");
pvh_bootparams.hdr.cmd_line_ptr =
pvh_start_info.cmdline_paddr;
/* The first module is always ramdisk. */
if (pvh_start_info.nr_modules) {
struct hvm_modlist_entry *modaddr =
__va(pvh_start_info.modlist_paddr);
pvh_bootparams.hdr.ramdisk_image = modaddr->paddr;
pvh_bootparams.hdr.ramdisk_size = modaddr->size;
}
/*
* See Documentation/x86/boot.txt.
*
* Version 2.12 supports Xen entry point but we will use default x86/PC
* environment (i.e. hardware_subarch 0).
*/
pvh_bootparams.hdr.version = (2 << 8) | 12;
pvh_bootparams.hdr.type_of_loader = ((xen_guest ? 0x9 : 0xb) << 4) | 0;
x86_init.acpi.get_root_pointer = pvh_get_root_pointer;
}
/*
* If we are trying to boot a Xen PVH guest, it is expected that the kernel
* will have been configured to provide the required override for this routine.
*/
void __init __weak xen_pvh_init(void)
{
xen_raw_printk("Error: Missing xen PVH initialization\n");
BUG();
}
static void hypervisor_specific_init(bool xen_guest)
{
if (xen_guest)
xen_pvh_init();
}
/*
* This routine (and those that it might call) should not use
* anything that lives in .bss since that segment will be cleared later.
*/
void __init xen_prepare_pvh(void)
{
u32 msr = xen_cpuid_base();
bool xen_guest = !!msr;
if (pvh_start_info.magic != XEN_HVM_START_MAGIC_VALUE) {
xen_raw_printk("Error: Unexpected magic value (0x%08x)\n",
pvh_start_info.magic);
BUG();
}
hypervisor_specific_init(xen_guest);
init_pvh_bootparams(xen_guest);
}
......@@ -74,6 +74,7 @@ config XEN_DEBUG_FS
Enabling this option may incur a significant performance overhead.
config XEN_PVH
bool "Support for running as a PVH guest"
bool "Support for running as a Xen PVH guest"
depends on XEN && XEN_PVHVM && ACPI
select PVH
def_bool n
# SPDX-License-Identifier: GPL-2.0
OBJECT_FILES_NON_STANDARD_xen-asm_$(BITS).o := y
OBJECT_FILES_NON_STANDARD_xen-pvh.o := y
ifdef CONFIG_FUNCTION_TRACER
# Do not profile debug and lowlevel utilities
......@@ -38,7 +37,6 @@ obj-$(CONFIG_XEN_PV) += xen-asm.o
obj-$(CONFIG_XEN_PV) += xen-asm_$(BITS).o
obj-$(CONFIG_XEN_PVH) += enlighten_pvh.o
obj-$(CONFIG_XEN_PVH) += xen-pvh.o
obj-$(CONFIG_EVENT_TRACING) += trace.o
......
......@@ -6,103 +6,45 @@
#include <asm/io_apic.h>
#include <asm/hypervisor.h>
#include <asm/e820/api.h>
#include <asm/x86_init.h>
#include <xen/xen.h>
#include <asm/xen/interface.h>
#include <asm/xen/hypercall.h>
#include <xen/xen.h>
#include <xen/interface/memory.h>
#include <xen/interface/hvm/start_info.h>
/*
* PVH variables.
*
* xen_pvh pvh_bootparams and pvh_start_info need to live in data segment
* since they are used after startup_{32|64}, which clear .bss, are invoked.
* The variable xen_pvh needs to live in the data segment since it is used
* after startup_{32|64} is invoked, which will clear the .bss segment.
*/
bool xen_pvh __attribute__((section(".data"))) = 0;
struct boot_params pvh_bootparams __attribute__((section(".data")));
struct hvm_start_info pvh_start_info __attribute__((section(".data")));
unsigned int pvh_start_info_sz = sizeof(pvh_start_info);
static u64 pvh_get_root_pointer(void)
void __init xen_pvh_init(void)
{
return pvh_start_info.rsdp_paddr;
u32 msr;
u64 pfn;
xen_pvh = 1;
xen_start_flags = pvh_start_info.flags;
msr = cpuid_ebx(xen_cpuid_base() + 2);
pfn = __pa(hypercall_page);
wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32));
}
static void __init init_pvh_bootparams(void)
void __init mem_map_via_hcall(struct boot_params *boot_params_p)
{
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);
memmap.nr_entries = ARRAY_SIZE(boot_params_p->e820_table);
set_xen_guest_handle(memmap.buffer, boot_params_p->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;
if (pvh_bootparams.e820_entries < E820_MAX_ENTRIES_ZEROPAGE - 1) {
pvh_bootparams.e820_table[pvh_bootparams.e820_entries].addr =
ISA_START_ADDRESS;
pvh_bootparams.e820_table[pvh_bootparams.e820_entries].size =
ISA_END_ADDRESS - ISA_START_ADDRESS;
pvh_bootparams.e820_table[pvh_bootparams.e820_entries].type =
E820_TYPE_RESERVED;
pvh_bootparams.e820_entries++;
} else
xen_raw_printk("Warning: Can fit ISA range into e820\n");
pvh_bootparams.hdr.cmd_line_ptr =
pvh_start_info.cmdline_paddr;
/* The first module is always ramdisk. */
if (pvh_start_info.nr_modules) {
struct hvm_modlist_entry *modaddr =
__va(pvh_start_info.modlist_paddr);
pvh_bootparams.hdr.ramdisk_image = modaddr->paddr;
pvh_bootparams.hdr.ramdisk_size = modaddr->size;
}
/*
* See Documentation/x86/boot.txt.
*
* Version 2.12 supports Xen entry point but we will use default x86/PC
* environment (i.e. hardware_subarch 0).
*/
pvh_bootparams.hdr.version = (2 << 8) | 12;
pvh_bootparams.hdr.type_of_loader = (9 << 4) | 0; /* Xen loader */
x86_init.acpi.get_root_pointer = pvh_get_root_pointer;
}
/*
* This routine (and those that it might call) should not use
* anything that lives in .bss since that segment will be cleared later.
*/
void __init xen_prepare_pvh(void)
{
u32 msr;
u64 pfn;
if (pvh_start_info.magic != XEN_HVM_START_MAGIC_VALUE) {
xen_raw_printk("Error: Unexpected magic value (0x%08x)\n",
pvh_start_info.magic);
BUG();
}
xen_pvh = 1;
xen_start_flags = pvh_start_info.flags;
msr = cpuid_ebx(xen_cpuid_base() + 2);
pfn = __pa(hypercall_page);
wrmsr_safe(msr, (u32)pfn, (u32)(pfn >> 32));
init_pvh_bootparams();
boot_params_p->e820_entries = memmap.nr_entries;
}
......@@ -12,6 +12,7 @@
#include <asm/segment.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
#include <asm/asm.h>
#include <xen/interface/xen.h>
......@@ -24,6 +25,7 @@ ENTRY(xen_\name)
pop %r11
jmp \name
END(xen_\name)
_ASM_NOKPROBE(xen_\name)
.endm
xen_pv_trap divide_error
......
......@@ -12,6 +12,7 @@ config DRM_XEN_FRONTEND
select DRM_KMS_HELPER
select VIDEOMODE_HELPERS
select XEN_XENBUS_FRONTEND
select XEN_FRONT_PGDIR_SHBUF
help
Choose this option if you want to enable a para-virtualized
frontend DRM/KMS driver for Xen guest OSes.
......@@ -4,7 +4,6 @@ drm_xen_front-objs := xen_drm_front.o \
xen_drm_front_kms.o \
xen_drm_front_conn.o \
xen_drm_front_evtchnl.o \
xen_drm_front_shbuf.o \
xen_drm_front_cfg.o \
xen_drm_front_gem.o
......
......@@ -19,6 +19,7 @@
#include <xen/xen.h>
#include <xen/xenbus.h>
#include <xen/xen-front-pgdir-shbuf.h>
#include <xen/interface/io/displif.h>
#include "xen_drm_front.h"
......@@ -26,28 +27,20 @@
#include "xen_drm_front_evtchnl.h"
#include "xen_drm_front_gem.h"
#include "xen_drm_front_kms.h"
#include "xen_drm_front_shbuf.h"
struct xen_drm_front_dbuf {
struct list_head list;
u64 dbuf_cookie;
u64 fb_cookie;
struct xen_drm_front_shbuf *shbuf;
struct xen_front_pgdir_shbuf shbuf;
};
static int dbuf_add_to_list(struct xen_drm_front_info *front_info,
struct xen_drm_front_shbuf *shbuf, u64 dbuf_cookie)
static void dbuf_add_to_list(struct xen_drm_front_info *front_info,
struct xen_drm_front_dbuf *dbuf, u64 dbuf_cookie)
{
struct xen_drm_front_dbuf *dbuf;
dbuf = kzalloc(sizeof(*dbuf), GFP_KERNEL);
if (!dbuf)
return -ENOMEM;
dbuf->dbuf_cookie = dbuf_cookie;
dbuf->shbuf = shbuf;
list_add(&dbuf->list, &front_info->dbuf_list);
return 0;
}
static struct xen_drm_front_dbuf *dbuf_get(struct list_head *dbuf_list,
......@@ -62,15 +55,6 @@ static struct xen_drm_front_dbuf *dbuf_get(struct list_head *dbuf_list,
return NULL;
}
static void dbuf_flush_fb(struct list_head *dbuf_list, u64 fb_cookie)
{
struct xen_drm_front_dbuf *buf, *q;
list_for_each_entry_safe(buf, q, dbuf_list, list)
if (buf->fb_cookie == fb_cookie)
xen_drm_front_shbuf_flush(buf->shbuf);
}
static void dbuf_free(struct list_head *dbuf_list, u64 dbuf_cookie)
{
struct xen_drm_front_dbuf *buf, *q;
......@@ -78,8 +62,8 @@ static void dbuf_free(struct list_head *dbuf_list, u64 dbuf_cookie)
list_for_each_entry_safe(buf, q, dbuf_list, list)
if (buf->dbuf_cookie == dbuf_cookie) {
list_del(&buf->list);
xen_drm_front_shbuf_unmap(buf->shbuf);
xen_drm_front_shbuf_free(buf->shbuf);
xen_front_pgdir_shbuf_unmap(&buf->shbuf);
xen_front_pgdir_shbuf_free(&buf->shbuf);
kfree(buf);
break;
}
......@@ -91,8 +75,8 @@ static void dbuf_free_all(struct list_head *dbuf_list)
list_for_each_entry_safe(buf, q, dbuf_list, list) {
list_del(&buf->list);
xen_drm_front_shbuf_unmap(buf->shbuf);
xen_drm_front_shbuf_free(buf->shbuf);
xen_front_pgdir_shbuf_unmap(&buf->shbuf);
xen_front_pgdir_shbuf_free(&buf->shbuf);
kfree(buf);
}
}
......@@ -171,9 +155,9 @@ int xen_drm_front_dbuf_create(struct xen_drm_front_info *front_info,
u32 bpp, u64 size, struct page **pages)
{
struct xen_drm_front_evtchnl *evtchnl;
struct xen_drm_front_shbuf *shbuf;
struct xen_drm_front_dbuf *dbuf;
struct xendispl_req *req;
struct xen_drm_front_shbuf_cfg buf_cfg;
struct xen_front_pgdir_shbuf_cfg buf_cfg;
unsigned long flags;
int ret;
......@@ -181,28 +165,29 @@ int xen_drm_front_dbuf_create(struct xen_drm_front_info *front_info,
if (unlikely(!evtchnl))
return -EIO;
dbuf = kzalloc(sizeof(*dbuf), GFP_KERNEL);
if (!dbuf)
return -ENOMEM;
dbuf_add_to_list(front_info, dbuf, dbuf_cookie);
memset(&buf_cfg, 0, sizeof(buf_cfg));
buf_cfg.xb_dev = front_info->xb_dev;
buf_cfg.num_pages = DIV_ROUND_UP(size, PAGE_SIZE);
buf_cfg.pages = pages;
buf_cfg.size = size;
buf_cfg.pgdir = &dbuf->shbuf;
buf_cfg.be_alloc = front_info->cfg.be_alloc;
shbuf = xen_drm_front_shbuf_alloc(&buf_cfg);
if (IS_ERR(shbuf))
return PTR_ERR(shbuf);
ret = dbuf_add_to_list(front_info, shbuf, dbuf_cookie);
if (ret < 0) {
xen_drm_front_shbuf_free(shbuf);
return ret;
}
ret = xen_front_pgdir_shbuf_alloc(&buf_cfg);
if (ret < 0)
goto fail_shbuf_alloc;
mutex_lock(&evtchnl->u.req.req_io_lock);
spin_lock_irqsave(&front_info->io_lock, flags);
req = be_prepare_req(evtchnl, XENDISPL_OP_DBUF_CREATE);
req->op.dbuf_create.gref_directory =
xen_drm_front_shbuf_get_dir_start(shbuf);
xen_front_pgdir_shbuf_get_dir_start(&dbuf->shbuf);
req->op.dbuf_create.buffer_sz = size;
req->op.dbuf_create.dbuf_cookie = dbuf_cookie;
req->op.dbuf_create.width = width;
......@@ -221,7 +206,7 @@ int xen_drm_front_dbuf_create(struct xen_drm_front_info *front_info,
if (ret < 0)
goto fail;
ret = xen_drm_front_shbuf_map(shbuf);
ret = xen_front_pgdir_shbuf_map(&dbuf->shbuf);
if (ret < 0)
goto fail;
......@@ -230,6 +215,7 @@ int xen_drm_front_dbuf_create(struct xen_drm_front_info *front_info,
fail:
mutex_unlock(&evtchnl->u.req.req_io_lock);
fail_shbuf_alloc:
dbuf_free(&front_info->dbuf_list, dbuf_cookie);
return ret;
}
......@@ -358,7 +344,6 @@ int xen_drm_front_page_flip(struct xen_drm_front_info *front_info,
if (unlikely(conn_idx >= front_info->num_evt_pairs))
return -EINVAL;
dbuf_flush_fb(&front_info->dbuf_list, fb_cookie);
evtchnl = &front_info->evt_pairs[conn_idx].req;
mutex_lock(&evtchnl->u.req.req_io_lock);
......
......@@ -22,7 +22,6 @@
#include <xen/balloon.h>
#include "xen_drm_front.h"
#include "xen_drm_front_shbuf.h"
struct xen_gem_object {
struct drm_gem_object base;
......
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/*
* Xen para-virtual DRM device
*
* Copyright (C) 2016-2018 EPAM Systems Inc.
*
* Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
*/
#ifndef __XEN_DRM_FRONT_SHBUF_H_
#define __XEN_DRM_FRONT_SHBUF_H_
#include <linux/kernel.h>
#include <linux/scatterlist.h>
#include <xen/grant_table.h>
struct xen_drm_front_shbuf {
/*
* number of references granted for the backend use:
* - for allocated/imported dma-buf's this holds number of grant
* references for the page directory and pages of the buffer
* - for the buffer provided by the backend this holds number of
* grant references for the page directory as grant references for
* the buffer will be provided by the backend
*/
int num_grefs;
grant_ref_t *grefs;
unsigned char *directory;
int num_pages;
struct page **pages;
struct xenbus_device *xb_dev;
/* these are the ops used internally depending on be_alloc mode */
const struct xen_drm_front_shbuf_ops *ops;
/* Xen map handles for the buffer allocated by the backend */
grant_handle_t *backend_map_handles;
};
struct xen_drm_front_shbuf_cfg {
struct xenbus_device *xb_dev;
size_t size;
struct page **pages;
bool be_alloc;
};
struct xen_drm_front_shbuf *
xen_drm_front_shbuf_alloc(struct xen_drm_front_shbuf_cfg *cfg);
grant_ref_t xen_drm_front_shbuf_get_dir_start(struct xen_drm_front_shbuf *buf);
int xen_drm_front_shbuf_map(struct xen_drm_front_shbuf *buf);
int xen_drm_front_shbuf_unmap(struct xen_drm_front_shbuf *buf);
void xen_drm_front_shbuf_flush(struct xen_drm_front_shbuf *buf);
void xen_drm_front_shbuf_free(struct xen_drm_front_shbuf *buf);
#endif /* __XEN_DRM_FRONT_SHBUF_H_ */
......@@ -340,4 +340,7 @@ config XEN_SYMS
config XEN_HAVE_VPMU
bool
config XEN_FRONT_PGDIR_SHBUF
tristate
endmenu
......@@ -44,3 +44,4 @@ xen-gntdev-y := gntdev.o
xen-gntdev-$(CONFIG_XEN_GNTDEV_DMABUF) += gntdev-dmabuf.o
xen-gntalloc-y := gntalloc.o
xen-privcmd-y := privcmd.o privcmd-buf.o
obj-$(CONFIG_XEN_FRONT_PGDIR_SHBUF) += xen-front-pgdir-shbuf.o
// SPDX-License-Identifier: GPL-2.0 OR MIT
/*
* Xen para-virtual DRM device