pv.c (6932B)
1 /* 2 * Protected Virtualization functions 3 * 4 * Copyright IBM Corp. 2020 5 * Author(s): 6 * Janosch Frank <frankja@linux.ibm.com> 7 * 8 * This work is licensed under the terms of the GNU GPL, version 2 or (at 9 * your option) any later version. See the COPYING file in the top-level 10 * directory. 11 */ 12 #include "qemu/osdep.h" 13 14 #include <linux/kvm.h> 15 16 #include "qapi/error.h" 17 #include "qemu/error-report.h" 18 #include "sysemu/kvm.h" 19 #include "qom/object_interfaces.h" 20 #include "exec/confidential-guest-support.h" 21 #include "hw/s390x/ipl.h" 22 #include "hw/s390x/pv.h" 23 #include "target/s390x/kvm/kvm_s390x.h" 24 25 static bool info_valid; 26 static struct kvm_s390_pv_info_vm info_vm; 27 static struct kvm_s390_pv_info_dump info_dump; 28 29 static int __s390_pv_cmd(uint32_t cmd, const char *cmdname, void *data) 30 { 31 struct kvm_pv_cmd pv_cmd = { 32 .cmd = cmd, 33 .data = (uint64_t)data, 34 }; 35 int rc; 36 37 do { 38 rc = kvm_vm_ioctl(kvm_state, KVM_S390_PV_COMMAND, &pv_cmd); 39 } while (rc == -EINTR); 40 41 if (rc) { 42 error_report("KVM PV command %d (%s) failed: header rc %x rrc %x " 43 "IOCTL rc: %d", cmd, cmdname, pv_cmd.rc, pv_cmd.rrc, 44 rc); 45 } 46 return rc; 47 } 48 49 /* 50 * This macro lets us pass the command as a string to the function so 51 * we can print it on an error. 52 */ 53 #define s390_pv_cmd(cmd, data) __s390_pv_cmd(cmd, #cmd, data) 54 #define s390_pv_cmd_exit(cmd, data) \ 55 { \ 56 int rc; \ 57 \ 58 rc = __s390_pv_cmd(cmd, #cmd, data);\ 59 if (rc) { \ 60 exit(1); \ 61 } \ 62 } 63 64 int s390_pv_query_info(void) 65 { 66 struct kvm_s390_pv_info info = { 67 .header.id = KVM_PV_INFO_VM, 68 .header.len_max = sizeof(info.header) + sizeof(info.vm), 69 }; 70 int rc; 71 72 /* Info API's first user is dump so they are bundled */ 73 if (!kvm_s390_get_protected_dump()) { 74 return 0; 75 } 76 77 rc = s390_pv_cmd(KVM_PV_INFO, &info); 78 if (rc) { 79 error_report("KVM PV INFO cmd %x failed: %s", 80 info.header.id, strerror(-rc)); 81 return rc; 82 } 83 memcpy(&info_vm, &info.vm, sizeof(info.vm)); 84 85 info.header.id = KVM_PV_INFO_DUMP; 86 info.header.len_max = sizeof(info.header) + sizeof(info.dump); 87 rc = s390_pv_cmd(KVM_PV_INFO, &info); 88 if (rc) { 89 error_report("KVM PV INFO cmd %x failed: %s", 90 info.header.id, strerror(-rc)); 91 return rc; 92 } 93 94 memcpy(&info_dump, &info.dump, sizeof(info.dump)); 95 info_valid = true; 96 97 return rc; 98 } 99 100 int s390_pv_vm_enable(void) 101 { 102 return s390_pv_cmd(KVM_PV_ENABLE, NULL); 103 } 104 105 void s390_pv_vm_disable(void) 106 { 107 s390_pv_cmd_exit(KVM_PV_DISABLE, NULL); 108 } 109 110 int s390_pv_set_sec_parms(uint64_t origin, uint64_t length) 111 { 112 struct kvm_s390_pv_sec_parm args = { 113 .origin = origin, 114 .length = length, 115 }; 116 117 return s390_pv_cmd(KVM_PV_SET_SEC_PARMS, &args); 118 } 119 120 /* 121 * Called for each component in the SE type IPL parameter block 0. 122 */ 123 int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak) 124 { 125 struct kvm_s390_pv_unp args = { 126 .addr = addr, 127 .size = size, 128 .tweak = tweak, 129 }; 130 131 return s390_pv_cmd(KVM_PV_UNPACK, &args); 132 } 133 134 void s390_pv_prep_reset(void) 135 { 136 s390_pv_cmd_exit(KVM_PV_PREP_RESET, NULL); 137 } 138 139 int s390_pv_verify(void) 140 { 141 return s390_pv_cmd(KVM_PV_VERIFY, NULL); 142 } 143 144 void s390_pv_unshare(void) 145 { 146 s390_pv_cmd_exit(KVM_PV_UNSHARE_ALL, NULL); 147 } 148 149 void s390_pv_inject_reset_error(CPUState *cs) 150 { 151 int r1 = (cs->kvm_run->s390_sieic.ipa & 0x00f0) >> 4; 152 CPUS390XState *env = &S390_CPU(cs)->env; 153 154 /* Report that we are unable to enter protected mode */ 155 env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV; 156 } 157 158 uint64_t kvm_s390_pv_dmp_get_size_cpu(void) 159 { 160 return info_dump.dump_cpu_buffer_len; 161 } 162 163 uint64_t kvm_s390_pv_dmp_get_size_completion_data(void) 164 { 165 return info_dump.dump_config_finalize_len; 166 } 167 168 uint64_t kvm_s390_pv_dmp_get_size_mem_state(void) 169 { 170 return info_dump.dump_config_mem_buffer_per_1m; 171 } 172 173 bool kvm_s390_pv_info_basic_valid(void) 174 { 175 return info_valid; 176 } 177 178 static int s390_pv_dump_cmd(uint64_t subcmd, uint64_t uaddr, uint64_t gaddr, 179 uint64_t len) 180 { 181 struct kvm_s390_pv_dmp dmp = { 182 .subcmd = subcmd, 183 .buff_addr = uaddr, 184 .buff_len = len, 185 .gaddr = gaddr, 186 }; 187 int ret; 188 189 ret = s390_pv_cmd(KVM_PV_DUMP, (void *)&dmp); 190 if (ret) { 191 error_report("KVM DUMP command %ld failed", subcmd); 192 } 193 return ret; 194 } 195 196 int kvm_s390_dump_cpu(S390CPU *cpu, void *buff) 197 { 198 struct kvm_s390_pv_dmp dmp = { 199 .subcmd = KVM_PV_DUMP_CPU, 200 .buff_addr = (uint64_t)buff, 201 .gaddr = 0, 202 .buff_len = info_dump.dump_cpu_buffer_len, 203 }; 204 struct kvm_pv_cmd pv = { 205 .cmd = KVM_PV_DUMP, 206 .data = (uint64_t)&dmp, 207 }; 208 209 return kvm_vcpu_ioctl(CPU(cpu), KVM_S390_PV_CPU_COMMAND, &pv); 210 } 211 212 int kvm_s390_dump_init(void) 213 { 214 return s390_pv_dump_cmd(KVM_PV_DUMP_INIT, 0, 0, 0); 215 } 216 217 int kvm_s390_dump_mem_state(uint64_t gaddr, size_t len, void *dest) 218 { 219 return s390_pv_dump_cmd(KVM_PV_DUMP_CONFIG_STOR_STATE, (uint64_t)dest, 220 gaddr, len); 221 } 222 223 int kvm_s390_dump_completion_data(void *buff) 224 { 225 return s390_pv_dump_cmd(KVM_PV_DUMP_COMPLETE, (uint64_t)buff, 0, 226 info_dump.dump_config_finalize_len); 227 } 228 229 #define TYPE_S390_PV_GUEST "s390-pv-guest" 230 OBJECT_DECLARE_SIMPLE_TYPE(S390PVGuest, S390_PV_GUEST) 231 232 /** 233 * S390PVGuest: 234 * 235 * The S390PVGuest object is basically a dummy used to tell the 236 * confidential guest support system to use s390's PV mechanism. 237 * 238 * # $QEMU \ 239 * -object s390-pv-guest,id=pv0 \ 240 * -machine ...,confidential-guest-support=pv0 241 */ 242 struct S390PVGuest { 243 ConfidentialGuestSupport parent_obj; 244 }; 245 246 typedef struct S390PVGuestClass S390PVGuestClass; 247 248 struct S390PVGuestClass { 249 ConfidentialGuestSupportClass parent_class; 250 }; 251 252 int s390_pv_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) 253 { 254 if (!object_dynamic_cast(OBJECT(cgs), TYPE_S390_PV_GUEST)) { 255 return 0; 256 } 257 258 if (!s390_has_feat(S390_FEAT_UNPACK)) { 259 error_setg(errp, 260 "CPU model does not support Protected Virtualization"); 261 return -1; 262 } 263 264 cgs->ready = true; 265 266 return 0; 267 } 268 269 OBJECT_DEFINE_TYPE_WITH_INTERFACES(S390PVGuest, 270 s390_pv_guest, 271 S390_PV_GUEST, 272 CONFIDENTIAL_GUEST_SUPPORT, 273 { TYPE_USER_CREATABLE }, 274 { NULL }) 275 276 static void s390_pv_guest_class_init(ObjectClass *oc, void *data) 277 { 278 } 279 280 static void s390_pv_guest_init(Object *obj) 281 { 282 } 283 284 static void s390_pv_guest_finalize(Object *obj) 285 { 286 }