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 if (initialized) 80 return; 81 /* Query is done on initialization but let's check anyway */ 82 assert(uvcb_qui.header.rc == 1 || uvcb_qui.header.rc == 0x100); 83 84 /* Donated storage needs to be over 2GB aligned to 1MB */ 85 uv_init_mem = (uint64_t)memalign_pages_flags(HPAGE_SIZE, uvcb_qui.uv_base_stor_len, AREA_NORMAL); 86 uvcb_init.stor_origin = uv_init_mem; 87 uvcb_init.stor_len = uvcb_qui.uv_base_stor_len; 88 89 cc = uv_call(0, (uint64_t)&uvcb_init); 90 assert(cc == 0); 91 initialized = true; 92 } 93 94 /* 95 * Create a new ASCE for the UV config because they can't be shared 96 * for security reasons. We just simply copy the top most table into a 97 * fresh set of allocated pages and use those pages as the asce. 98 */ 99 static uint64_t create_asce(void) 100 { 101 void *pgd_new, *pgd_old; 102 uint64_t asce = stctg(1); 103 104 pgd_new = memalign_pages(PAGE_SIZE, PAGE_SIZE * 4); 105 pgd_old = (void *)(asce & PAGE_MASK); 106 107 memcpy(pgd_new, pgd_old, PAGE_SIZE * 4); 108 109 asce = __pa(pgd_new) | ASCE_P | (asce & (ASCE_DT | ASCE_TL)); 110 return asce; 111 } 112 113 void uv_create_guest(struct vm *vm) 114 { 115 struct uv_cb_cgc uvcb_cgc = { 116 .header.cmd = UVC_CMD_CREATE_SEC_CONF, 117 .header.len = sizeof(uvcb_cgc), 118 }; 119 struct uv_cb_csc uvcb_csc = { 120 .header.len = sizeof(uvcb_csc), 121 .header.cmd = UVC_CMD_CREATE_SEC_CPU, 122 .state_origin = (uint64_t)vm->sblk, 123 .num = 0, 124 }; 125 unsigned long vsize; 126 int cc; 127 128 uvcb_cgc.guest_stor_origin = vm->sblk->mso; 129 uvcb_cgc.guest_stor_len = vm->sblk->msl; 130 131 /* Config allocation */ 132 vsize = uvcb_qui.conf_base_virt_stor_len + 133 ((uvcb_cgc.guest_stor_len / HPAGE_SIZE) * uvcb_qui.conf_virt_var_stor_len); 134 135 vm->uv.conf_base_stor = memalign_pages_flags(PAGE_SIZE * 4, uvcb_qui.conf_base_phys_stor_len, 0); 136 /* 137 * This allocation needs to be below the max guest storage 138 * address so let's simply put it into the physical memory 139 */ 140 vm->uv.conf_var_stor = memalign_pages_flags(PAGE_SIZE, vsize,0); 141 uvcb_cgc.conf_base_stor_origin = (uint64_t)vm->uv.conf_base_stor; 142 uvcb_cgc.conf_var_stor_origin = (uint64_t)vm->uv.conf_var_stor; 143 144 /* CPU allocation */ 145 vm->uv.cpu_stor = memalign_pages_flags(PAGE_SIZE, uvcb_qui.cpu_stor_len, 0); 146 uvcb_csc.stor_origin = (uint64_t)vm->uv.cpu_stor; 147 148 uvcb_cgc.guest_asce = create_asce(); 149 vm->save_area.guest.asce = uvcb_cgc.guest_asce; 150 uvcb_cgc.guest_sca = (uint64_t)vm->sca; 151 152 cc = uv_call(0, (uint64_t)&uvcb_cgc); 153 assert(!cc); 154 155 vm->uv.vm_handle = uvcb_cgc.guest_handle; 156 uvcb_csc.guest_handle = uvcb_cgc.guest_handle; 157 cc = uv_call(0, (uint64_t)&uvcb_csc); 158 vm->uv.vcpu_handle = uvcb_csc.cpu_handle; 159 assert(!cc); 160 161 /* 162 * Convert guest to format 4: 163 * 164 * - Set format 4 165 * - Write UV handles into sblk 166 * - Allocate and set SIDA 167 */ 168 vm->sblk->sdf = 2; 169 vm->sblk->sidad = (uint64_t)alloc_page(); 170 vm->sblk->pv_handle_cpu = uvcb_csc.cpu_handle; 171 vm->sblk->pv_handle_config = uvcb_cgc.guest_handle; 172 } 173 174 void uv_destroy_guest(struct vm *vm) 175 { 176 int cc; 177 u16 rc, rrc; 178 179 cc = uv_cmd_nodata(vm->sblk->pv_handle_cpu, 180 UVC_CMD_DESTROY_SEC_CPU, &rc, &rrc); 181 assert(cc == 0); 182 free_page((void *)vm->sblk->sidad); 183 free_pages(vm->uv.cpu_stor); 184 185 cc = uv_cmd_nodata(vm->sblk->pv_handle_config, 186 UVC_CMD_DESTROY_SEC_CONF, &rc, &rrc); 187 assert(cc == 0); 188 free_pages(vm->uv.conf_base_stor); 189 free_pages(vm->uv.conf_var_stor); 190 191 free_pages((void *)(vm->uv.asce & PAGE_MASK)); 192 memset(&vm->uv, 0, sizeof(vm->uv)); 193 194 /* Convert the sblk back to non-PV */ 195 vm->save_area.guest.asce = stctg(1); 196 vm->sblk->sdf = 0; 197 vm->sblk->sidad = 0; 198 vm->sblk->pv_handle_cpu = 0; 199 vm->sblk->pv_handle_config = 0; 200 } 201 202 int uv_unpack(struct vm *vm, uint64_t addr, uint64_t len, uint64_t tweak) 203 { 204 int i, cc; 205 206 for (i = 0; i < len / PAGE_SIZE; i++) { 207 cc = uv_unp_page(vm->uv.vm_handle, addr, tweak, i * PAGE_SIZE); 208 assert(!cc); 209 addr += PAGE_SIZE; 210 } 211 return cc; 212 } 213 214 void uv_verify_load(struct vm *vm) 215 { 216 uint16_t rc, rrc; 217 int cc; 218 219 cc = uv_cmd_nodata(vm->uv.vm_handle, UVC_CMD_VERIFY_IMG, &rc, &rrc); 220 assert(!cc); 221 cc = uv_set_cpu_state(vm->uv.vcpu_handle, PV_CPU_STATE_OPR_LOAD); 222 assert(!cc); 223 } 224