]> git.baikalelectronics.ru Git - kernel.git/commitdiff
s390/uv: introduce guest side ultravisor code
authorVasily Gorbik <gor@linux.ibm.com>
Mon, 1 Apr 2019 17:11:03 +0000 (19:11 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 10 Apr 2019 15:47:21 +0000 (17:47 +0200)
The Ultravisor Call Facility (stfle bit 158) defines an API to the
Ultravisor (UV calls), a mini hypervisor located at machine
level. With help of the Ultravisor, KVM will be able to run
"protected" VMs, special VMs whose memory and management data are
unavailable to KVM.

The protected VMs can also request services from the Ultravisor.
The guest api consists of UV calls to share and unshare memory with the
kvm hypervisor.

To enable this feature support PROTECTED_VIRTUALIZATION_GUEST kconfig
option has been introduced.

Co-developed-by: Janosch Frank <frankja@de.ibm.com>
Signed-off-by: Janosch Frank <frankja@de.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/Kconfig
arch/s390/boot/Makefile
arch/s390/boot/startup.c
arch/s390/boot/uv.c [new file with mode: 0644]
arch/s390/include/asm/uv.h [new file with mode: 0644]
arch/s390/kernel/setup.c

index b6e3d0653002af7a8eb20b5a0f3e0d8b27ba0b16..4ac8d49e206a8286454488fe0ad99cc9a2bd89fe 100644 (file)
@@ -837,6 +837,17 @@ config HAVE_PNETID
 
 menu "Virtualization"
 
+config PROTECTED_VIRTUALIZATION_GUEST
+       def_bool n
+       prompt "Protected virtualization guest support"
+       help
+         Select this option, if you want to be able to run this
+         kernel as a protected virtualization KVM guest.
+         Protected virtualization capable machines have a mini hypervisor
+         located at machine level (an ultravisor). With help of the
+         Ultravisor, KVM will be able to run "protected" VMs, special
+         VMs whose memory and management data are unavailable to KVM.
+
 config PFAULT
        def_bool y
        prompt "Pseudo page fault support"
index 458d18c44c67dd9ae4edb7849cd6af11d23caa1a..a5ae68b2aa844f3063c7347d00c1cba7c1ef3780 100644 (file)
@@ -30,6 +30,7 @@ CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char
 
 obj-y  := head.o als.o startup.o mem_detect.o ipl_parm.o string.o ebcdic.o
 obj-y  += sclp_early_core.o mem.o ipl_vmparm.o cmdline.o ctype.o
+obj-$(CONFIG_PROTECTED_VIRTUALIZATION_GUEST)   += uv.o
 targets        := bzImage startup.a section_cmp.boot.data section_cmp.boot.preserved.data $(obj-y)
 subdir-        := compressed
 
index 57d7f9446e29e19baa55745359b579b2960a42ea..2bd4a62d436c19b82a871c1e06581d85db7268ee 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/string.h>
 #include <asm/setup.h>
 #include <asm/sclp.h>
+#include <asm/uv.h>
 #include "compressed/decompressor.h"
 #include "boot.h"
 
@@ -53,6 +54,7 @@ void startup_kernel(void)
 {
        void *img;
 
+       uv_query_info();
        rescue_initrd();
        sclp_early_read_info();
        store_ipl_parmblock();
diff --git a/arch/s390/boot/uv.c b/arch/s390/boot/uv.c
new file mode 100644 (file)
index 0000000..ed007f4
--- /dev/null
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <asm/uv.h>
+#include <asm/facility.h>
+#include <asm/sections.h>
+
+int __bootdata_preserved(prot_virt_guest);
+
+void uv_query_info(void)
+{
+       struct uv_cb_qui uvcb = {
+               .header.cmd = UVC_CMD_QUI,
+               .header.len = sizeof(uvcb)
+       };
+
+       if (!test_facility(158))
+               return;
+
+       if (uv_call(0, (uint64_t)&uvcb))
+               return;
+
+       if (test_bit_inv(BIT_UVC_CMD_SET_SHARED_ACCESS, (unsigned long *)uvcb.inst_calls_list) &&
+           test_bit_inv(BIT_UVC_CMD_REMOVE_SHARED_ACCESS, (unsigned long *)uvcb.inst_calls_list))
+               prot_virt_guest = 1;
+}
diff --git a/arch/s390/include/asm/uv.h b/arch/s390/include/asm/uv.h
new file mode 100644 (file)
index 0000000..ef3c00b
--- /dev/null
@@ -0,0 +1,132 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Ultravisor Interfaces
+ *
+ * Copyright IBM Corp. 2019
+ *
+ * Author(s):
+ *     Vasily Gorbik <gor@linux.ibm.com>
+ *     Janosch Frank <frankja@linux.ibm.com>
+ */
+#ifndef _ASM_S390_UV_H
+#define _ASM_S390_UV_H
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include <asm/page.h>
+
+#define UVC_RC_EXECUTED                0x0001
+#define UVC_RC_INV_CMD         0x0002
+#define UVC_RC_INV_STATE       0x0003
+#define UVC_RC_INV_LEN         0x0005
+#define UVC_RC_NO_RESUME       0x0007
+
+#define UVC_CMD_QUI                    0x0001
+#define UVC_CMD_SET_SHARED_ACCESS      0x1000
+#define UVC_CMD_REMOVE_SHARED_ACCESS   0x1001
+
+/* Bits in installed uv calls */
+enum uv_cmds_inst {
+       BIT_UVC_CMD_QUI = 0,
+       BIT_UVC_CMD_SET_SHARED_ACCESS = 8,
+       BIT_UVC_CMD_REMOVE_SHARED_ACCESS = 9,
+};
+
+struct uv_cb_header {
+       u16 len;
+       u16 cmd;        /* Command Code */
+       u16 rc;         /* Response Code */
+       u16 rrc;        /* Return Reason Code */
+} __packed __aligned(8);
+
+struct uv_cb_qui {
+       struct uv_cb_header header;
+       u64 reserved08;
+       u64 inst_calls_list[4];
+       u64 reserved30[15];
+} __packed __aligned(8);
+
+struct uv_cb_share {
+       struct uv_cb_header header;
+       u64 reserved08[3];
+       u64 paddr;
+       u64 reserved28;
+} __packed __aligned(8);
+
+static inline int uv_call(unsigned long r1, unsigned long r2)
+{
+       int cc;
+
+       asm volatile(
+               "0:     .insn rrf,0xB9A40000,%[r1],%[r2],0,0\n"
+               "               brc     3,0b\n"
+               "               ipm     %[cc]\n"
+               "               srl     %[cc],28\n"
+               : [cc] "=d" (cc)
+               : [r1] "a" (r1), [r2] "a" (r2)
+               : "memory", "cc");
+       return cc;
+}
+
+#ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST
+extern int prot_virt_guest;
+
+static inline int is_prot_virt_guest(void)
+{
+       return prot_virt_guest;
+}
+
+static inline int share(unsigned long addr, u16 cmd)
+{
+       struct uv_cb_share uvcb = {
+               .header.cmd = cmd,
+               .header.len = sizeof(uvcb),
+               .paddr = addr
+       };
+
+       if (!is_prot_virt_guest())
+               return -ENOTSUPP;
+       /*
+        * Sharing is page wise, if we encounter addresses that are
+        * not page aligned, we assume something went wrong. If
+        * malloced structs are passed to this function, we could leak
+        * data to the hypervisor.
+        */
+       BUG_ON(addr & ~PAGE_MASK);
+
+       if (!uv_call(0, (u64)&uvcb))
+               return 0;
+       return -EINVAL;
+}
+
+/*
+ * Guest 2 request to the Ultravisor to make a page shared with the
+ * hypervisor for IO.
+ *
+ * @addr: Real or absolute address of the page to be shared
+ */
+static inline int uv_set_shared(unsigned long addr)
+{
+       return share(addr, UVC_CMD_SET_SHARED_ACCESS);
+}
+
+/*
+ * Guest 2 request to the Ultravisor to make a page unshared.
+ *
+ * @addr: Real or absolute address of the page to be unshared
+ */
+static inline int uv_remove_shared(unsigned long addr)
+{
+       return share(addr, UVC_CMD_REMOVE_SHARED_ACCESS);
+}
+
+void uv_query_info(void);
+#else
+#define is_prot_virt_guest() 0
+static inline int uv_set_shared(unsigned long addr) { return 0; }
+static inline int uv_remove_shared(unsigned long addr) { return 0; }
+static inline void uv_query_info(void) {}
+#endif
+
+#endif /* _ASM_S390_UV_H */
index 2c642af526ce83658504e50b7d95700086589bd2..70197a68e6fab4cd59e40435dca34611bcf72a1d 100644 (file)
@@ -70,6 +70,7 @@
 #include <asm/alternative.h>
 #include <asm/nospec-branch.h>
 #include <asm/mem_detect.h>
+#include <asm/uv.h>
 #include "entry.h"
 
 /*
@@ -89,6 +90,10 @@ char elf_platform[ELF_PLATFORM_SIZE];
 
 unsigned long int_hwcap = 0;
 
+#ifdef CONFIG_PROTECTED_VIRTUALIZATION_GUEST
+int __bootdata_preserved(prot_virt_guest);
+#endif
+
 int __bootdata(noexec_disabled);
 int __bootdata(memory_end_set);
 unsigned long __bootdata(memory_end);