@@ -207,6 +207,28 @@ config PV_SHIM_EXCLUSIVE
option is only intended for use when building a dedicated PV Shim
firmware, and will not function correctly in other scenarios.
+ If unsure, say N.
+
+config XEN_NESTED
+ bool "Xen PV driver interface for nested Xen" if EXPERT = "y"
+ depends on XEN_DETECT
+ ---help---
+ Enables a second PV driver interface in the hypervisor to support running
+ two sets of PV drivers within a single privileged guest (eg. guest dom0)
+ of a system running Xen under Xen:
+
+ 1) host set: frontends to access devices provided by lower hypervisor
+ 2) guest set: backends to support existing PV drivers in nested guest VMs
+
+ This interface supports the host set of drivers and performs proxying of a
+ limited set of hypercall operations from the guest to the host hypervisor.
+
+ This feature is for the guest hypervisor and is transparent to the
+ host hypervisor. Guest VMs of the guest hypervisor use the standard
+ PV driver interfaces and unmodified drivers.
+
+ Feature is also known as "The Xen-Blanket", presented at Eurosys 2012.
+
If unsure, say N.
endmenu
@@ -1,5 +1,8 @@
-obj-$(CONFIG_XEN_GUEST) += hypercall_page.o
+ifneq ($(filter y,$(CONFIG_XEN_GUEST) $(CONFIG_XEN_NESTED) $(CONFIG_PVH_GUEST)),)
+obj-y += hypercall_page.o
+endif
obj-y += xen.o
obj-$(CONFIG_XEN_GUEST) += xen-guest.o
+obj-$(CONFIG_XEN_NESTED) += xen-nested.o
obj-bin-$(CONFIG_PVH_GUEST) += pvh-boot.init.o
@@ -60,6 +60,7 @@ DECLARE_HYPERCALL(domctl)
DECLARE_HYPERCALL(kexec_op)
DECLARE_HYPERCALL(argo_op)
DECLARE_HYPERCALL(xenpmu_op)
+DECLARE_HYPERCALL(nested_xen_version)
DECLARE_HYPERCALL(arch_0)
DECLARE_HYPERCALL(arch_1)
new file mode 100644
@@ -0,0 +1,82 @@
+/*
+ * arch/x86/guest/xen-nested.c
+ *
+ * Hypercall implementations for nested PV drivers interface.
+ *
+ * Copyright (c) 2019 Star Lab Corp
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <xen/config.h>
+#include <xen/errno.h>
+#include <xen/guest_access.h>
+#include <xen/hypercall.h>
+#include <xen/lib.h>
+#include <xen/sched.h>
+
+#include <public/version.h>
+
+#include <asm/guest/hypercall.h>
+#include <asm/guest/xen.h>
+
+extern char hypercall_page[];
+
+/* xen_nested: support for nested PV interface enabled */
+static bool __read_mostly xen_nested;
+
+void xen_nested_enable(void)
+{
+ /* Fill the hypercall page. */
+ wrmsrl(cpuid_ebx(hypervisor_cpuid_base() + 2), __pa(hypercall_page));
+
+ xen_nested = true;
+}
+
+long do_nested_xen_version(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
+{
+ long ret;
+
+ if ( !xen_nested )
+ return -ENOSYS;
+
+ /* FIXME: apply XSM check here */
+ if ( !is_control_domain(current->domain) )
+ return -EPERM;
+
+ gprintk(XENLOG_DEBUG, "Nested xen_version: %d.\n", cmd);
+
+ switch ( cmd )
+ {
+ case XENVER_version:
+ return xen_hypercall_xen_version(XENVER_version, 0);
+
+ case XENVER_get_features:
+ {
+ xen_feature_info_t fi;
+
+ if ( copy_from_guest(&fi, arg, 1) )
+ return -EFAULT;
+
+ ret = xen_hypercall_xen_version(XENVER_get_features, &fi);
+ if ( ret )
+ return ret;
+
+ if ( __copy_to_guest(arg, &fi, 1) )
+ return -EFAULT;
+
+ return 0;
+ }
+
+ default:
+ gprintk(XENLOG_ERR, "Nested xen_version op %d not implemented.\n", cmd);
+ return -EOPNOTSUPP;
+ }
+}
@@ -74,7 +74,10 @@ void __init probe_hypervisor(void)
xen_detected = true;
- xen_guest_enable();
+ if ( pv_shim || pvh_boot )
+ xen_guest_enable();
+ else
+ xen_nested_enable();
}
void __init hypervisor_print_info(void)
@@ -72,6 +72,9 @@ const hypercall_args_t hypercall_args_table[NR_hypercalls] =
#ifdef CONFIG_HVM
ARGS(hvm_op, 2),
ARGS(dm_op, 3),
+#endif
+#ifdef CONFIG_XEN_NESTED
+ ARGS(nested_xen_version, 2),
#endif
ARGS(mca, 1),
ARGS(arch_1, 1),
@@ -83,6 +83,9 @@ const hypercall_table_t pv_hypercall_table[] = {
#ifdef CONFIG_HVM
HYPERCALL(hvm_op),
COMPAT_CALL(dm_op),
+#endif
+#ifdef CONFIG_XEN_NESTED
+ HYPERCALL(nested_xen_version),
#endif
HYPERCALL(mca),
HYPERCALL(arch_1),
@@ -19,7 +19,7 @@
#ifndef __X86_XEN_HYPERCALL_H__
#define __X86_XEN_HYPERCALL_H__
-#ifdef CONFIG_XEN_GUEST
+#if defined(CONFIG_XEN_GUEST) || defined (CONFIG_XEN_NESTED)
#include <xen/types.h>
@@ -123,6 +123,11 @@ static inline long xen_hypercall_hvm_op(unsigned int op, void *arg)
return _hypercall64_2(long, __HYPERVISOR_hvm_op, op, arg);
}
+static inline long xen_hypercall_xen_version(unsigned int op, void *arg)
+{
+ return _hypercall64_2(long, __HYPERVISOR_xen_version, op, arg);
+}
+
/*
* Higher level hypercall helpers
*/
@@ -43,6 +43,16 @@ static inline void hypervisor_print_info(void) {
#endif /* CONFIG_XEN_DETECT */
+#ifdef CONFIG_XEN_NESTED
+
+void xen_nested_enable(void);
+
+#else
+
+static inline void xen_nested_enable(void) {}
+
+#endif /* CONFIG_XEN_NESTED */
+
#ifdef CONFIG_XEN_GUEST
#define XEN_shared_info ((struct shared_info *)fix_to_virt(FIX_XEN_SHARED_INFO))
@@ -121,6 +121,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_ulong_t);
#define __HYPERVISOR_argo_op 39
#define __HYPERVISOR_xenpmu_op 40
#define __HYPERVISOR_dm_op 41
+#define __HYPERVISOR_nested_xen_version 42
/* Architecture-specific hypercall definitions. */
#define __HYPERVISOR_arch_0 48
@@ -150,6 +150,12 @@ do_dm_op(
unsigned int nr_bufs,
XEN_GUEST_HANDLE_PARAM(xen_dm_op_buf_t) bufs);
+#ifdef CONFIG_XEN_NESTED
+extern long do_nested_xen_version(
+ int cmd,
+ XEN_GUEST_HANDLE_PARAM(void) arg);
+#endif
+
#ifdef CONFIG_COMPAT
extern int
Provides proxying to the host hypervisor for XENVER_version and XENVER_get_features ops. The nested PV interface is only enabled when Xen is not running as either the PV shim or booted as PVH, since the initialization performed within the hypervisor in those cases - ie. as a Xen guest - claims resources that are normally operated by the control domain. This nested hypercall only permits access from the control domain. The XSM policy hook implementation is deferred to a subsequent commit. Signed-off-by: Christopher Clark <christopher.clark@starlab.io> --- xen/arch/x86/Kconfig | 22 +++++++ xen/arch/x86/guest/Makefile | 5 +- xen/arch/x86/guest/hypercall_page.S | 1 + xen/arch/x86/guest/xen-nested.c | 82 +++++++++++++++++++++++++++ xen/arch/x86/guest/xen.c | 5 +- xen/arch/x86/hypercall.c | 3 + xen/arch/x86/pv/hypercall.c | 3 + xen/include/asm-x86/guest/hypercall.h | 7 ++- xen/include/asm-x86/guest/xen.h | 10 ++++ xen/include/public/xen.h | 1 + xen/include/xen/hypercall.h | 6 ++ 11 files changed, 142 insertions(+), 3 deletions(-) create mode 100644 xen/arch/x86/guest/xen-nested.c