1aa8794b1SJanosch Frank /* SPDX-License-Identifier: GPL-2.0-only */ 2aa8794b1SJanosch Frank /* 3aa8794b1SJanosch Frank * Ultravisor related functionality 4aa8794b1SJanosch Frank * 5aa8794b1SJanosch Frank * Copyright 2020 IBM Corp. 6aa8794b1SJanosch Frank * 7aa8794b1SJanosch Frank * Authors: 8aa8794b1SJanosch Frank * Janosch Frank <frankja@linux.ibm.com> 9aa8794b1SJanosch Frank */ 1007ac63dcSJanosch Frank #include <libcflat.h> 1107ac63dcSJanosch Frank #include <bitops.h> 1207ac63dcSJanosch Frank #include <alloc.h> 1307ac63dcSJanosch Frank #include <alloc_page.h> 1407ac63dcSJanosch Frank #include <asm/page.h> 1507ac63dcSJanosch Frank #include <asm/arch_def.h> 1607ac63dcSJanosch Frank 1707ac63dcSJanosch Frank #include <asm/facility.h> 1807ac63dcSJanosch Frank #include <asm/uv.h> 1907ac63dcSJanosch Frank #include <uv.h> 20f4f97af0SJanosch Frank #include <sie.h> 2107ac63dcSJanosch Frank 2207ac63dcSJanosch Frank static struct uv_cb_qui uvcb_qui = { 2307ac63dcSJanosch Frank .header.cmd = UVC_CMD_QUI, 2407ac63dcSJanosch Frank .header.len = sizeof(uvcb_qui), 2507ac63dcSJanosch Frank }; 26f4f97af0SJanosch Frank static uint64_t uv_init_mem; 27f4f97af0SJanosch Frank 2807ac63dcSJanosch Frank 2907ac63dcSJanosch Frank bool uv_os_is_guest(void) 3007ac63dcSJanosch Frank { 3107ac63dcSJanosch Frank return test_facility(158) && 3207ac63dcSJanosch Frank uv_query_test_call(BIT_UVC_CMD_SET_SHARED_ACCESS) && 3307ac63dcSJanosch Frank uv_query_test_call(BIT_UVC_CMD_REMOVE_SHARED_ACCESS); 3407ac63dcSJanosch Frank } 3507ac63dcSJanosch Frank 3607ac63dcSJanosch Frank bool uv_os_is_host(void) 3707ac63dcSJanosch Frank { 3807ac63dcSJanosch Frank return test_facility(158) && uv_query_test_call(BIT_UVC_CMD_INIT_UV); 3907ac63dcSJanosch Frank } 4007ac63dcSJanosch Frank 4107ac63dcSJanosch Frank bool uv_query_test_call(unsigned int nr) 4207ac63dcSJanosch Frank { 4307ac63dcSJanosch Frank /* Query needs to be called first */ 4407ac63dcSJanosch Frank assert(uvcb_qui.header.rc); 4507ac63dcSJanosch Frank assert(nr < BITS_PER_LONG * ARRAY_SIZE(uvcb_qui.inst_calls_list)); 4607ac63dcSJanosch Frank 4707ac63dcSJanosch Frank return test_bit_inv(nr, uvcb_qui.inst_calls_list); 4807ac63dcSJanosch Frank } 4907ac63dcSJanosch Frank 5026184212SSteffen Eiden const struct uv_cb_qui *uv_get_query_data(void) 5126184212SSteffen Eiden { 5226184212SSteffen Eiden /* Query needs to be called first */ 5326184212SSteffen Eiden assert(uvcb_qui.header.rc == 1 || uvcb_qui.header.rc == 0x100); 5426184212SSteffen Eiden 5526184212SSteffen Eiden return &uvcb_qui; 5626184212SSteffen Eiden } 5726184212SSteffen Eiden 5807ac63dcSJanosch Frank int uv_setup(void) 5907ac63dcSJanosch Frank { 6007ac63dcSJanosch Frank if (!test_facility(158)) 6107ac63dcSJanosch Frank return 0; 6207ac63dcSJanosch Frank 6378168306SJanosch Frank uv_call(0, (u64)&uvcb_qui); 6478168306SJanosch Frank 6578168306SJanosch Frank assert(uvcb_qui.header.rc == 1 || uvcb_qui.header.rc == 0x100); 6607ac63dcSJanosch Frank return 1; 6707ac63dcSJanosch Frank } 68f4f97af0SJanosch Frank 69f4f97af0SJanosch Frank void uv_init(void) 70f4f97af0SJanosch Frank { 71f4f97af0SJanosch Frank struct uv_cb_init uvcb_init = { 72f4f97af0SJanosch Frank .header.len = sizeof(uvcb_init), 73f4f97af0SJanosch Frank .header.cmd = UVC_CMD_INIT_UV, 74f4f97af0SJanosch Frank }; 75f4f97af0SJanosch Frank static bool initialized; 76f4f97af0SJanosch Frank int cc; 77f4f97af0SJanosch Frank 78f4f97af0SJanosch Frank /* Let's not do this twice */ 79*d558b81cSJanosch Frank if (initialized) 80*d558b81cSJanosch Frank return; 81f4f97af0SJanosch Frank /* Query is done on initialization but let's check anyway */ 82f4f97af0SJanosch Frank assert(uvcb_qui.header.rc == 1 || uvcb_qui.header.rc == 0x100); 83f4f97af0SJanosch Frank 84f4f97af0SJanosch Frank /* Donated storage needs to be over 2GB aligned to 1MB */ 85f4f97af0SJanosch Frank uv_init_mem = (uint64_t)memalign_pages_flags(HPAGE_SIZE, uvcb_qui.uv_base_stor_len, AREA_NORMAL); 86f4f97af0SJanosch Frank uvcb_init.stor_origin = uv_init_mem; 87f4f97af0SJanosch Frank uvcb_init.stor_len = uvcb_qui.uv_base_stor_len; 88f4f97af0SJanosch Frank 89f4f97af0SJanosch Frank cc = uv_call(0, (uint64_t)&uvcb_init); 90f4f97af0SJanosch Frank assert(cc == 0); 91f4f97af0SJanosch Frank initialized = true; 92f4f97af0SJanosch Frank } 93f4f97af0SJanosch Frank 949e3cff66SJanosch Frank /* 959e3cff66SJanosch Frank * Create a new ASCE for the UV config because they can't be shared 969e3cff66SJanosch Frank * for security reasons. We just simply copy the top most table into a 979e3cff66SJanosch Frank * fresh set of allocated pages and use those pages as the asce. 989e3cff66SJanosch Frank */ 999e3cff66SJanosch Frank static uint64_t create_asce(void) 1009e3cff66SJanosch Frank { 1019e3cff66SJanosch Frank void *pgd_new, *pgd_old; 1029e3cff66SJanosch Frank uint64_t asce = stctg(1); 1039e3cff66SJanosch Frank 1049e3cff66SJanosch Frank pgd_new = memalign_pages(PAGE_SIZE, PAGE_SIZE * 4); 1059e3cff66SJanosch Frank pgd_old = (void *)(asce & PAGE_MASK); 1069e3cff66SJanosch Frank 1079e3cff66SJanosch Frank memcpy(pgd_new, pgd_old, PAGE_SIZE * 4); 1089e3cff66SJanosch Frank 1099e3cff66SJanosch Frank asce = __pa(pgd_new) | ASCE_P | (asce & (ASCE_DT | ASCE_TL)); 1109e3cff66SJanosch Frank return asce; 1119e3cff66SJanosch Frank } 1129e3cff66SJanosch Frank 113f4f97af0SJanosch Frank void uv_create_guest(struct vm *vm) 114f4f97af0SJanosch Frank { 115f4f97af0SJanosch Frank struct uv_cb_cgc uvcb_cgc = { 116f4f97af0SJanosch Frank .header.cmd = UVC_CMD_CREATE_SEC_CONF, 117f4f97af0SJanosch Frank .header.len = sizeof(uvcb_cgc), 118f4f97af0SJanosch Frank }; 119f4f97af0SJanosch Frank struct uv_cb_csc uvcb_csc = { 120f4f97af0SJanosch Frank .header.len = sizeof(uvcb_csc), 121f4f97af0SJanosch Frank .header.cmd = UVC_CMD_CREATE_SEC_CPU, 122f4f97af0SJanosch Frank .state_origin = (uint64_t)vm->sblk, 123f4f97af0SJanosch Frank .num = 0, 124f4f97af0SJanosch Frank }; 125f4f97af0SJanosch Frank unsigned long vsize; 126f4f97af0SJanosch Frank int cc; 127f4f97af0SJanosch Frank 128f4f97af0SJanosch Frank uvcb_cgc.guest_stor_origin = vm->sblk->mso; 129f4f97af0SJanosch Frank uvcb_cgc.guest_stor_len = vm->sblk->msl; 130f4f97af0SJanosch Frank 131f4f97af0SJanosch Frank /* Config allocation */ 132f4f97af0SJanosch Frank vsize = uvcb_qui.conf_base_virt_stor_len + 133f4f97af0SJanosch Frank ((uvcb_cgc.guest_stor_len / HPAGE_SIZE) * uvcb_qui.conf_virt_var_stor_len); 134f4f97af0SJanosch Frank 135f4f97af0SJanosch Frank vm->uv.conf_base_stor = memalign_pages_flags(PAGE_SIZE * 4, uvcb_qui.conf_base_phys_stor_len, 0); 136f4f97af0SJanosch Frank /* 137f4f97af0SJanosch Frank * This allocation needs to be below the max guest storage 138f4f97af0SJanosch Frank * address so let's simply put it into the physical memory 139f4f97af0SJanosch Frank */ 140f4f97af0SJanosch Frank vm->uv.conf_var_stor = memalign_pages_flags(PAGE_SIZE, vsize,0); 141f4f97af0SJanosch Frank uvcb_cgc.conf_base_stor_origin = (uint64_t)vm->uv.conf_base_stor; 142f4f97af0SJanosch Frank uvcb_cgc.conf_var_stor_origin = (uint64_t)vm->uv.conf_var_stor; 143f4f97af0SJanosch Frank 144f4f97af0SJanosch Frank /* CPU allocation */ 145f4f97af0SJanosch Frank vm->uv.cpu_stor = memalign_pages_flags(PAGE_SIZE, uvcb_qui.cpu_stor_len, 0); 146f4f97af0SJanosch Frank uvcb_csc.stor_origin = (uint64_t)vm->uv.cpu_stor; 147f4f97af0SJanosch Frank 1489e3cff66SJanosch Frank uvcb_cgc.guest_asce = create_asce(); 1499e3cff66SJanosch Frank vm->save_area.guest.asce = uvcb_cgc.guest_asce; 150f4f97af0SJanosch Frank uvcb_cgc.guest_sca = (uint64_t)vm->sca; 151f4f97af0SJanosch Frank 152f4f97af0SJanosch Frank cc = uv_call(0, (uint64_t)&uvcb_cgc); 153f4f97af0SJanosch Frank assert(!cc); 154f4f97af0SJanosch Frank 155f4f97af0SJanosch Frank vm->uv.vm_handle = uvcb_cgc.guest_handle; 156f4f97af0SJanosch Frank uvcb_csc.guest_handle = uvcb_cgc.guest_handle; 157f4f97af0SJanosch Frank cc = uv_call(0, (uint64_t)&uvcb_csc); 158f4f97af0SJanosch Frank vm->uv.vcpu_handle = uvcb_csc.cpu_handle; 159f4f97af0SJanosch Frank assert(!cc); 160f4f97af0SJanosch Frank 161f4f97af0SJanosch Frank /* 162f4f97af0SJanosch Frank * Convert guest to format 4: 163f4f97af0SJanosch Frank * 164f4f97af0SJanosch Frank * - Set format 4 165f4f97af0SJanosch Frank * - Write UV handles into sblk 166f4f97af0SJanosch Frank * - Allocate and set SIDA 167f4f97af0SJanosch Frank */ 168f4f97af0SJanosch Frank vm->sblk->sdf = 2; 169f4f97af0SJanosch Frank vm->sblk->sidad = (uint64_t)alloc_page(); 170f4f97af0SJanosch Frank vm->sblk->pv_handle_cpu = uvcb_csc.cpu_handle; 171f4f97af0SJanosch Frank vm->sblk->pv_handle_config = uvcb_cgc.guest_handle; 172f4f97af0SJanosch Frank } 173f4f97af0SJanosch Frank 174f4f97af0SJanosch Frank void uv_destroy_guest(struct vm *vm) 175f4f97af0SJanosch Frank { 176f4f97af0SJanosch Frank int cc; 177f4f97af0SJanosch Frank u16 rc, rrc; 178f4f97af0SJanosch Frank 179f4f97af0SJanosch Frank cc = uv_cmd_nodata(vm->sblk->pv_handle_cpu, 180f4f97af0SJanosch Frank UVC_CMD_DESTROY_SEC_CPU, &rc, &rrc); 181f4f97af0SJanosch Frank assert(cc == 0); 182f4f97af0SJanosch Frank free_page((void *)vm->sblk->sidad); 183f4f97af0SJanosch Frank free_pages(vm->uv.cpu_stor); 184f4f97af0SJanosch Frank 185f4f97af0SJanosch Frank cc = uv_cmd_nodata(vm->sblk->pv_handle_config, 186f4f97af0SJanosch Frank UVC_CMD_DESTROY_SEC_CONF, &rc, &rrc); 187f4f97af0SJanosch Frank assert(cc == 0); 188f4f97af0SJanosch Frank free_pages(vm->uv.conf_base_stor); 189f4f97af0SJanosch Frank free_pages(vm->uv.conf_var_stor); 1909e3cff66SJanosch Frank 1919e3cff66SJanosch Frank free_pages((void *)(vm->uv.asce & PAGE_MASK)); 192*d558b81cSJanosch Frank memset(&vm->uv, 0, sizeof(vm->uv)); 193*d558b81cSJanosch Frank 194*d558b81cSJanosch Frank /* Convert the sblk back to non-PV */ 195*d558b81cSJanosch Frank vm->save_area.guest.asce = stctg(1); 196*d558b81cSJanosch Frank vm->sblk->sdf = 0; 197*d558b81cSJanosch Frank vm->sblk->sidad = 0; 198*d558b81cSJanosch Frank vm->sblk->pv_handle_cpu = 0; 199*d558b81cSJanosch Frank vm->sblk->pv_handle_config = 0; 200f4f97af0SJanosch Frank } 201f4f97af0SJanosch Frank 202f4f97af0SJanosch Frank int uv_unpack(struct vm *vm, uint64_t addr, uint64_t len, uint64_t tweak) 203f4f97af0SJanosch Frank { 204f4f97af0SJanosch Frank int i, cc; 205f4f97af0SJanosch Frank 206f4f97af0SJanosch Frank for (i = 0; i < len / PAGE_SIZE; i++) { 207f4f97af0SJanosch Frank cc = uv_unp_page(vm->uv.vm_handle, addr, tweak, i * PAGE_SIZE); 208f4f97af0SJanosch Frank assert(!cc); 209f4f97af0SJanosch Frank addr += PAGE_SIZE; 210f4f97af0SJanosch Frank } 211f4f97af0SJanosch Frank return cc; 212f4f97af0SJanosch Frank } 213f4f97af0SJanosch Frank 214f4f97af0SJanosch Frank void uv_verify_load(struct vm *vm) 215f4f97af0SJanosch Frank { 216f4f97af0SJanosch Frank uint16_t rc, rrc; 217f4f97af0SJanosch Frank int cc; 218f4f97af0SJanosch Frank 219f4f97af0SJanosch Frank cc = uv_cmd_nodata(vm->uv.vm_handle, UVC_CMD_VERIFY_IMG, &rc, &rrc); 220f4f97af0SJanosch Frank assert(!cc); 221f4f97af0SJanosch Frank cc = uv_set_cpu_state(vm->uv.vcpu_handle, PV_CPU_STATE_OPR_LOAD); 222f4f97af0SJanosch Frank assert(!cc); 223f4f97af0SJanosch Frank } 224