s390/protvirt: add ultravisor initialization
authorVasily Gorbik <gor@linux.ibm.com>
Wed, 23 Oct 2019 11:56:39 +0000 (13:56 +0200)
committerChristian Borntraeger <borntraeger@de.ibm.com>
Thu, 27 Feb 2020 18:44:40 +0000 (19:44 +0100)
Before being able to host protected virtual machines, donate some of
the memory to the ultravisor. Besides that the ultravisor might impose
addressing limitations for memory used to back protected VM storage. Treat
that limit as protected virtualization host's virtual memory limit.

Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
[borntraeger@de.ibm.com: patch merging, splitting, fixing]
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
arch/s390/include/asm/uv.h
arch/s390/kernel/setup.c
arch/s390/kernel/uv.c

index c6a330740e5d610786159fc8278b9deebeb58aef..1af6ce8023cc2338cd102d9d07868e5285ec45bb 100644 (file)
 #define UVC_RC_NO_RESUME       0x0007
 
 #define UVC_CMD_QUI                    0x0001
+#define UVC_CMD_INIT_UV                        0x000f
 #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_INIT_UV = 1,
        BIT_UVC_CMD_SET_SHARED_ACCESS = 8,
        BIT_UVC_CMD_REMOVE_SHARED_ACCESS = 9,
 };
@@ -59,6 +61,14 @@ struct uv_cb_qui {
        u8  reserveda0[200 - 160];
 } __packed __aligned(8);
 
+struct uv_cb_init {
+       struct uv_cb_header header;
+       u64 reserved08[2];
+       u64 stor_origin;
+       u64 stor_len;
+       u64 reserved28[4];
+} __packed __aligned(8);
+
 struct uv_cb_share {
        struct uv_cb_header header;
        u64 reserved08[3];
@@ -160,8 +170,13 @@ static inline int is_prot_virt_host(void)
 {
        return prot_virt_host;
 }
+
+void setup_uv(void);
+void adjust_to_uv_max(unsigned long *vmax);
 #else
 #define is_prot_virt_host() 0
+static inline void setup_uv(void) {}
+static inline void adjust_to_uv_max(unsigned long *vmax) {}
 #endif
 
 #if defined(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) || IS_ENABLED(CONFIG_KVM)
index a2496382175eafe20e5d5fbba6da274a1c1446d1..1423090a22593098ced062b08fd519872e739d14 100644 (file)
@@ -560,6 +560,9 @@ static void __init setup_memory_end(void)
                        vmax = _REGION1_SIZE; /* 4-level kernel page table */
        }
 
+       if (is_prot_virt_host())
+               adjust_to_uv_max(&vmax);
+
        /* module area is at the end of the kernel address space. */
        MODULES_END = vmax;
        MODULES_VADDR = MODULES_END - MODULES_LEN;
@@ -1134,6 +1137,8 @@ void __init setup_arch(char **cmdline_p)
         */
        memblock_trim_memory(1UL << (MAX_ORDER - 1 + PAGE_SHIFT));
 
+       if (is_prot_virt_host())
+               setup_uv();
        setup_memory_end();
        setup_memory();
        dma_contiguous_reserve(memory_end);
index b1f9367103603c6bd7d68aaeeccc8a561a58a6e5..1ddc42154ef6570262f5389ff21aaeeb47234f08 100644 (file)
@@ -49,4 +49,52 @@ static int __init prot_virt_setup(char *val)
        return rc;
 }
 early_param("prot_virt", prot_virt_setup);
+
+static int __init uv_init(unsigned long stor_base, unsigned long stor_len)
+{
+       struct uv_cb_init uvcb = {
+               .header.cmd = UVC_CMD_INIT_UV,
+               .header.len = sizeof(uvcb),
+               .stor_origin = stor_base,
+               .stor_len = stor_len,
+       };
+
+       if (uv_call(0, (uint64_t)&uvcb)) {
+               pr_err("Ultravisor init failed with rc: 0x%x rrc: 0%x\n",
+                      uvcb.header.rc, uvcb.header.rrc);
+               return -1;
+       }
+       return 0;
+}
+
+void __init setup_uv(void)
+{
+       unsigned long uv_stor_base;
+
+       uv_stor_base = (unsigned long)memblock_alloc_try_nid(
+               uv_info.uv_base_stor_len, SZ_1M, SZ_2G,
+               MEMBLOCK_ALLOC_ACCESSIBLE, NUMA_NO_NODE);
+       if (!uv_stor_base) {
+               pr_warn("Failed to reserve %lu bytes for ultravisor base storage\n",
+                       uv_info.uv_base_stor_len);
+               goto fail;
+       }
+
+       if (uv_init(uv_stor_base, uv_info.uv_base_stor_len)) {
+               memblock_free(uv_stor_base, uv_info.uv_base_stor_len);
+               goto fail;
+       }
+
+       pr_info("Reserving %luMB as ultravisor base storage\n",
+               uv_info.uv_base_stor_len >> 20);
+       return;
+fail:
+       pr_info("Disabling support for protected virtualization");
+       prot_virt_host = 0;
+}
+
+void adjust_to_uv_max(unsigned long *vmax)
+{
+       *vmax = min_t(unsigned long, *vmax, uv_info.max_sec_stor_addr);
+}
 #endif