1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Ultravisor related functionality 4 * 5 * Copyright 2020 IBM Corp. 6 * 7 * Authors: 8 * Janosch Frank <frankja@linux.ibm.com> 9 */ 10 #include <libcflat.h> 11 #include <bitops.h> 12 #include <alloc.h> 13 #include <alloc_page.h> 14 #include <asm/page.h> 15 #include <asm/arch_def.h> 16 17 #include <asm/facility.h> 18 #include <asm/uv.h> 19 #include <uv.h> 20 #include <sie.h> 21 22 static struct uv_cb_qui uvcb_qui = { 23 .header.cmd = UVC_CMD_QUI, 24 .header.len = sizeof(uvcb_qui), 25 }; 26 static uint64_t uv_init_mem; 27 28 29 bool uv_os_is_guest(void) 30 { 31 return test_facility(158) && 32 uv_query_test_call(BIT_UVC_CMD_SET_SHARED_ACCESS) && 33 uv_query_test_call(BIT_UVC_CMD_REMOVE_SHARED_ACCESS); 34 } 35 36 bool uv_os_is_host(void) 37 { 38 return test_facility(158) && uv_query_test_call(BIT_UVC_CMD_INIT_UV); 39 } 40 41 bool uv_query_test_call(unsigned int nr) 42 { 43 /* Query needs to be called first */ 44 assert(uvcb_qui.header.rc); 45 assert(nr < BITS_PER_LONG * ARRAY_SIZE(uvcb_qui.inst_calls_list)); 46 47 return test_bit_inv(nr, uvcb_qui.inst_calls_list); 48 } 49 50 const struct uv_cb_qui *uv_get_query_data(void) 51 { 52 /* Query needs to be called first */ 53 assert(uvcb_qui.header.rc == 1 || uvcb_qui.header.rc == 0x100); 54 55 return &uvcb_qui; 56 } 57 58 int uv_setup(void) 59 { 60 if (!test_facility(158)) 61 return 0; 62 63 uv_call(0, (u64)&uvcb_qui); 64 65 assert(uvcb_qui.header.rc == 1 || uvcb_qui.header.rc == 0x100); 66 return 1; 67 } 68 69 void uv_init(void) 70 { 71 struct uv_cb_init uvcb_init = { 72 .header.len = sizeof(uvcb_init), 73 .header.cmd = UVC_CMD_INIT_UV, 74 }; 75 static bool initialized; 76 int cc; 77 78 /* Let's not do this twice */ 79 assert(!initialized); 80 /* Query is done on initialization but let's check anyway */ 81 assert(uvcb_qui.header.rc == 1 || uvcb_qui.header.rc == 0x100); 82 83 /* Donated storage needs to be over 2GB aligned to 1MB */ 84 uv_init_mem = (uint64_t)memalign_pages_flags(HPAGE_SIZE, uvcb_qui.uv_base_stor_len, AREA_NORMAL); 85 uvcb_init.stor_origin = uv_init_mem; 86 uvcb_init.stor_len = uvcb_qui.uv_base_stor_len; 87 88 cc = uv_call(0, (uint64_t)&uvcb_init); 89 assert(cc == 0); 90 initialized = true; 91 } 92 93 void uv_create_guest(struct vm *vm) 94 { 95 struct uv_cb_cgc uvcb_cgc = { 96 .header.cmd = UVC_CMD_CREATE_SEC_CONF, 97 .header.len = sizeof(uvcb_cgc), 98 }; 99 struct uv_cb_csc uvcb_csc = { 100 .header.len = sizeof(uvcb_csc), 101 .header.cmd = UVC_CMD_CREATE_SEC_CPU, 102 .state_origin = (uint64_t)vm->sblk, 103 .num = 0, 104 }; 105 unsigned long vsize; 106 int cc; 107 108 uvcb_cgc.guest_stor_origin = vm->sblk->mso; 109 uvcb_cgc.guest_stor_len = vm->sblk->msl; 110 111 /* Config allocation */ 112 vsize = uvcb_qui.conf_base_virt_stor_len + 113 ((uvcb_cgc.guest_stor_len / HPAGE_SIZE) * uvcb_qui.conf_virt_var_stor_len); 114 115 vm->uv.conf_base_stor = memalign_pages_flags(PAGE_SIZE * 4, uvcb_qui.conf_base_phys_stor_len, 0); 116 /* 117 * This allocation needs to be below the max guest storage 118 * address so let's simply put it into the physical memory 119 */ 120 vm->uv.conf_var_stor = memalign_pages_flags(PAGE_SIZE, vsize,0); 121 uvcb_cgc.conf_base_stor_origin = (uint64_t)vm->uv.conf_base_stor; 122 uvcb_cgc.conf_var_stor_origin = (uint64_t)vm->uv.conf_var_stor; 123 124 /* CPU allocation */ 125 vm->uv.cpu_stor = memalign_pages_flags(PAGE_SIZE, uvcb_qui.cpu_stor_len, 0); 126 uvcb_csc.stor_origin = (uint64_t)vm->uv.cpu_stor; 127 128 uvcb_cgc.guest_asce = (uint64_t)stctg(1); 129 uvcb_cgc.guest_sca = (uint64_t)vm->sca; 130 131 cc = uv_call(0, (uint64_t)&uvcb_cgc); 132 assert(!cc); 133 134 vm->uv.vm_handle = uvcb_cgc.guest_handle; 135 uvcb_csc.guest_handle = uvcb_cgc.guest_handle; 136 cc = uv_call(0, (uint64_t)&uvcb_csc); 137 vm->uv.vcpu_handle = uvcb_csc.cpu_handle; 138 assert(!cc); 139 140 /* 141 * Convert guest to format 4: 142 * 143 * - Set format 4 144 * - Write UV handles into sblk 145 * - Allocate and set SIDA 146 */ 147 vm->sblk->sdf = 2; 148 vm->sblk->sidad = (uint64_t)alloc_page(); 149 vm->sblk->pv_handle_cpu = uvcb_csc.cpu_handle; 150 vm->sblk->pv_handle_config = uvcb_cgc.guest_handle; 151 } 152 153 void uv_destroy_guest(struct vm *vm) 154 { 155 int cc; 156 u16 rc, rrc; 157 158 cc = uv_cmd_nodata(vm->sblk->pv_handle_cpu, 159 UVC_CMD_DESTROY_SEC_CPU, &rc, &rrc); 160 assert(cc == 0); 161 free_page((void *)vm->sblk->sidad); 162 free_pages(vm->uv.cpu_stor); 163 164 cc = uv_cmd_nodata(vm->sblk->pv_handle_config, 165 UVC_CMD_DESTROY_SEC_CONF, &rc, &rrc); 166 assert(cc == 0); 167 free_pages(vm->uv.conf_base_stor); 168 free_pages(vm->uv.conf_var_stor); 169 } 170 171 int uv_unpack(struct vm *vm, uint64_t addr, uint64_t len, uint64_t tweak) 172 { 173 int i, cc; 174 175 for (i = 0; i < len / PAGE_SIZE; i++) { 176 cc = uv_unp_page(vm->uv.vm_handle, addr, tweak, i * PAGE_SIZE); 177 assert(!cc); 178 addr += PAGE_SIZE; 179 } 180 return cc; 181 } 182 183 void uv_verify_load(struct vm *vm) 184 { 185 uint16_t rc, rrc; 186 int cc; 187 188 cc = uv_cmd_nodata(vm->uv.vm_handle, UVC_CMD_VERIFY_IMG, &rc, &rrc); 189 assert(!cc); 190 cc = uv_set_cpu_state(vm->uv.vcpu_handle, PV_CPU_STATE_OPR_LOAD); 191 assert(!cc); 192 } 193