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> 20*f4f97af0SJanosch 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 }; 26*f4f97af0SJanosch Frank static uint64_t uv_init_mem; 27*f4f97af0SJanosch 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 5007ac63dcSJanosch Frank int uv_setup(void) 5107ac63dcSJanosch Frank { 5207ac63dcSJanosch Frank if (!test_facility(158)) 5307ac63dcSJanosch Frank return 0; 5407ac63dcSJanosch Frank 5578168306SJanosch Frank uv_call(0, (u64)&uvcb_qui); 5678168306SJanosch Frank 5778168306SJanosch Frank assert(uvcb_qui.header.rc == 1 || uvcb_qui.header.rc == 0x100); 5807ac63dcSJanosch Frank return 1; 5907ac63dcSJanosch Frank } 60*f4f97af0SJanosch Frank 61*f4f97af0SJanosch Frank void uv_init(void) 62*f4f97af0SJanosch Frank { 63*f4f97af0SJanosch Frank struct uv_cb_init uvcb_init = { 64*f4f97af0SJanosch Frank .header.len = sizeof(uvcb_init), 65*f4f97af0SJanosch Frank .header.cmd = UVC_CMD_INIT_UV, 66*f4f97af0SJanosch Frank }; 67*f4f97af0SJanosch Frank static bool initialized; 68*f4f97af0SJanosch Frank int cc; 69*f4f97af0SJanosch Frank 70*f4f97af0SJanosch Frank /* Let's not do this twice */ 71*f4f97af0SJanosch Frank assert(!initialized); 72*f4f97af0SJanosch Frank /* Query is done on initialization but let's check anyway */ 73*f4f97af0SJanosch Frank assert(uvcb_qui.header.rc == 1 || uvcb_qui.header.rc == 0x100); 74*f4f97af0SJanosch Frank 75*f4f97af0SJanosch Frank /* Donated storage needs to be over 2GB aligned to 1MB */ 76*f4f97af0SJanosch Frank uv_init_mem = (uint64_t)memalign_pages_flags(HPAGE_SIZE, uvcb_qui.uv_base_stor_len, AREA_NORMAL); 77*f4f97af0SJanosch Frank uvcb_init.stor_origin = uv_init_mem; 78*f4f97af0SJanosch Frank uvcb_init.stor_len = uvcb_qui.uv_base_stor_len; 79*f4f97af0SJanosch Frank 80*f4f97af0SJanosch Frank cc = uv_call(0, (uint64_t)&uvcb_init); 81*f4f97af0SJanosch Frank assert(cc == 0); 82*f4f97af0SJanosch Frank initialized = true; 83*f4f97af0SJanosch Frank } 84*f4f97af0SJanosch Frank 85*f4f97af0SJanosch Frank void uv_create_guest(struct vm *vm) 86*f4f97af0SJanosch Frank { 87*f4f97af0SJanosch Frank struct uv_cb_cgc uvcb_cgc = { 88*f4f97af0SJanosch Frank .header.cmd = UVC_CMD_CREATE_SEC_CONF, 89*f4f97af0SJanosch Frank .header.len = sizeof(uvcb_cgc), 90*f4f97af0SJanosch Frank }; 91*f4f97af0SJanosch Frank struct uv_cb_csc uvcb_csc = { 92*f4f97af0SJanosch Frank .header.len = sizeof(uvcb_csc), 93*f4f97af0SJanosch Frank .header.cmd = UVC_CMD_CREATE_SEC_CPU, 94*f4f97af0SJanosch Frank .state_origin = (uint64_t)vm->sblk, 95*f4f97af0SJanosch Frank .num = 0, 96*f4f97af0SJanosch Frank }; 97*f4f97af0SJanosch Frank unsigned long vsize; 98*f4f97af0SJanosch Frank int cc; 99*f4f97af0SJanosch Frank 100*f4f97af0SJanosch Frank uvcb_cgc.guest_stor_origin = vm->sblk->mso; 101*f4f97af0SJanosch Frank uvcb_cgc.guest_stor_len = vm->sblk->msl; 102*f4f97af0SJanosch Frank 103*f4f97af0SJanosch Frank /* Config allocation */ 104*f4f97af0SJanosch Frank vsize = uvcb_qui.conf_base_virt_stor_len + 105*f4f97af0SJanosch Frank ((uvcb_cgc.guest_stor_len / HPAGE_SIZE) * uvcb_qui.conf_virt_var_stor_len); 106*f4f97af0SJanosch Frank 107*f4f97af0SJanosch Frank vm->uv.conf_base_stor = memalign_pages_flags(PAGE_SIZE * 4, uvcb_qui.conf_base_phys_stor_len, 0); 108*f4f97af0SJanosch Frank /* 109*f4f97af0SJanosch Frank * This allocation needs to be below the max guest storage 110*f4f97af0SJanosch Frank * address so let's simply put it into the physical memory 111*f4f97af0SJanosch Frank */ 112*f4f97af0SJanosch Frank vm->uv.conf_var_stor = memalign_pages_flags(PAGE_SIZE, vsize,0); 113*f4f97af0SJanosch Frank uvcb_cgc.conf_base_stor_origin = (uint64_t)vm->uv.conf_base_stor; 114*f4f97af0SJanosch Frank uvcb_cgc.conf_var_stor_origin = (uint64_t)vm->uv.conf_var_stor; 115*f4f97af0SJanosch Frank 116*f4f97af0SJanosch Frank /* CPU allocation */ 117*f4f97af0SJanosch Frank vm->uv.cpu_stor = memalign_pages_flags(PAGE_SIZE, uvcb_qui.cpu_stor_len, 0); 118*f4f97af0SJanosch Frank uvcb_csc.stor_origin = (uint64_t)vm->uv.cpu_stor; 119*f4f97af0SJanosch Frank 120*f4f97af0SJanosch Frank uvcb_cgc.guest_asce = (uint64_t)stctg(1); 121*f4f97af0SJanosch Frank uvcb_cgc.guest_sca = (uint64_t)vm->sca; 122*f4f97af0SJanosch Frank 123*f4f97af0SJanosch Frank cc = uv_call(0, (uint64_t)&uvcb_cgc); 124*f4f97af0SJanosch Frank assert(!cc); 125*f4f97af0SJanosch Frank 126*f4f97af0SJanosch Frank vm->uv.vm_handle = uvcb_cgc.guest_handle; 127*f4f97af0SJanosch Frank uvcb_csc.guest_handle = uvcb_cgc.guest_handle; 128*f4f97af0SJanosch Frank cc = uv_call(0, (uint64_t)&uvcb_csc); 129*f4f97af0SJanosch Frank vm->uv.vcpu_handle = uvcb_csc.cpu_handle; 130*f4f97af0SJanosch Frank assert(!cc); 131*f4f97af0SJanosch Frank 132*f4f97af0SJanosch Frank /* 133*f4f97af0SJanosch Frank * Convert guest to format 4: 134*f4f97af0SJanosch Frank * 135*f4f97af0SJanosch Frank * - Set format 4 136*f4f97af0SJanosch Frank * - Write UV handles into sblk 137*f4f97af0SJanosch Frank * - Allocate and set SIDA 138*f4f97af0SJanosch Frank */ 139*f4f97af0SJanosch Frank vm->sblk->sdf = 2; 140*f4f97af0SJanosch Frank vm->sblk->sidad = (uint64_t)alloc_page(); 141*f4f97af0SJanosch Frank vm->sblk->pv_handle_cpu = uvcb_csc.cpu_handle; 142*f4f97af0SJanosch Frank vm->sblk->pv_handle_config = uvcb_cgc.guest_handle; 143*f4f97af0SJanosch Frank } 144*f4f97af0SJanosch Frank 145*f4f97af0SJanosch Frank void uv_destroy_guest(struct vm *vm) 146*f4f97af0SJanosch Frank { 147*f4f97af0SJanosch Frank int cc; 148*f4f97af0SJanosch Frank u16 rc, rrc; 149*f4f97af0SJanosch Frank 150*f4f97af0SJanosch Frank cc = uv_cmd_nodata(vm->sblk->pv_handle_cpu, 151*f4f97af0SJanosch Frank UVC_CMD_DESTROY_SEC_CPU, &rc, &rrc); 152*f4f97af0SJanosch Frank assert(cc == 0); 153*f4f97af0SJanosch Frank free_page((void *)vm->sblk->sidad); 154*f4f97af0SJanosch Frank free_pages(vm->uv.cpu_stor); 155*f4f97af0SJanosch Frank 156*f4f97af0SJanosch Frank cc = uv_cmd_nodata(vm->sblk->pv_handle_config, 157*f4f97af0SJanosch Frank UVC_CMD_DESTROY_SEC_CONF, &rc, &rrc); 158*f4f97af0SJanosch Frank assert(cc == 0); 159*f4f97af0SJanosch Frank free_pages(vm->uv.conf_base_stor); 160*f4f97af0SJanosch Frank free_pages(vm->uv.conf_var_stor); 161*f4f97af0SJanosch Frank } 162*f4f97af0SJanosch Frank 163*f4f97af0SJanosch Frank int uv_unpack(struct vm *vm, uint64_t addr, uint64_t len, uint64_t tweak) 164*f4f97af0SJanosch Frank { 165*f4f97af0SJanosch Frank int i, cc; 166*f4f97af0SJanosch Frank 167*f4f97af0SJanosch Frank for (i = 0; i < len / PAGE_SIZE; i++) { 168*f4f97af0SJanosch Frank cc = uv_unp_page(vm->uv.vm_handle, addr, tweak, i * PAGE_SIZE); 169*f4f97af0SJanosch Frank assert(!cc); 170*f4f97af0SJanosch Frank addr += PAGE_SIZE; 171*f4f97af0SJanosch Frank } 172*f4f97af0SJanosch Frank return cc; 173*f4f97af0SJanosch Frank } 174*f4f97af0SJanosch Frank 175*f4f97af0SJanosch Frank void uv_verify_load(struct vm *vm) 176*f4f97af0SJanosch Frank { 177*f4f97af0SJanosch Frank uint16_t rc, rrc; 178*f4f97af0SJanosch Frank int cc; 179*f4f97af0SJanosch Frank 180*f4f97af0SJanosch Frank cc = uv_cmd_nodata(vm->uv.vm_handle, UVC_CMD_VERIFY_IMG, &rc, &rrc); 181*f4f97af0SJanosch Frank assert(!cc); 182*f4f97af0SJanosch Frank cc = uv_set_cpu_state(vm->uv.vcpu_handle, PV_CPU_STATE_OPR_LOAD); 183*f4f97af0SJanosch Frank assert(!cc); 184*f4f97af0SJanosch Frank } 185