#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,
 };
        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];
 {
        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)
 
                        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;
         */
        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);
 
        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