1c3347ed0SJanosch Frank /* 2c3347ed0SJanosch Frank * Protected Virtualization functions 3c3347ed0SJanosch Frank * 4c3347ed0SJanosch Frank * Copyright IBM Corp. 2020 5c3347ed0SJanosch Frank * Author(s): 6c3347ed0SJanosch Frank * Janosch Frank <frankja@linux.ibm.com> 7c3347ed0SJanosch Frank * 8c3347ed0SJanosch Frank * This work is licensed under the terms of the GNU GPL, version 2 or (at 9c3347ed0SJanosch Frank * your option) any later version. See the COPYING file in the top-level 10c3347ed0SJanosch Frank * directory. 11c3347ed0SJanosch Frank */ 12c3347ed0SJanosch Frank #include "qemu/osdep.h" 13c3347ed0SJanosch Frank 14c3347ed0SJanosch Frank #include <linux/kvm.h> 15c3347ed0SJanosch Frank 16fbc1384cSChristian Borntraeger #include "cpu.h" 17651615d9SDavid Gibson #include "qapi/error.h" 18c3347ed0SJanosch Frank #include "qemu/error-report.h" 19c3347ed0SJanosch Frank #include "sysemu/kvm.h" 20651615d9SDavid Gibson #include "qom/object_interfaces.h" 21651615d9SDavid Gibson #include "exec/confidential-guest-support.h" 22fbc1384cSChristian Borntraeger #include "hw/s390x/ipl.h" 23c3347ed0SJanosch Frank #include "hw/s390x/pv.h" 24c3347ed0SJanosch Frank 25c3347ed0SJanosch Frank static int __s390_pv_cmd(uint32_t cmd, const char *cmdname, void *data) 26c3347ed0SJanosch Frank { 27c3347ed0SJanosch Frank struct kvm_pv_cmd pv_cmd = { 28c3347ed0SJanosch Frank .cmd = cmd, 29c3347ed0SJanosch Frank .data = (uint64_t)data, 30c3347ed0SJanosch Frank }; 31e8d12a55SChristian Borntraeger int rc; 32e8d12a55SChristian Borntraeger 33e8d12a55SChristian Borntraeger do { 34e8d12a55SChristian Borntraeger rc = kvm_vm_ioctl(kvm_state, KVM_S390_PV_COMMAND, &pv_cmd); 35e8d12a55SChristian Borntraeger } while (rc == -EINTR); 36c3347ed0SJanosch Frank 37c3347ed0SJanosch Frank if (rc) { 38c3347ed0SJanosch Frank error_report("KVM PV command %d (%s) failed: header rc %x rrc %x " 39c3347ed0SJanosch Frank "IOCTL rc: %d", cmd, cmdname, pv_cmd.rc, pv_cmd.rrc, 40c3347ed0SJanosch Frank rc); 41c3347ed0SJanosch Frank } 42c3347ed0SJanosch Frank return rc; 43c3347ed0SJanosch Frank } 44c3347ed0SJanosch Frank 45c3347ed0SJanosch Frank /* 46c3347ed0SJanosch Frank * This macro lets us pass the command as a string to the function so 47c3347ed0SJanosch Frank * we can print it on an error. 48c3347ed0SJanosch Frank */ 49c3347ed0SJanosch Frank #define s390_pv_cmd(cmd, data) __s390_pv_cmd(cmd, #cmd, data); 50c3347ed0SJanosch Frank #define s390_pv_cmd_exit(cmd, data) \ 51c3347ed0SJanosch Frank { \ 52c3347ed0SJanosch Frank int rc; \ 53c3347ed0SJanosch Frank \ 54c3347ed0SJanosch Frank rc = __s390_pv_cmd(cmd, #cmd, data);\ 55c3347ed0SJanosch Frank if (rc) { \ 56c3347ed0SJanosch Frank exit(1); \ 57c3347ed0SJanosch Frank } \ 58c3347ed0SJanosch Frank } 59c3347ed0SJanosch Frank 60c3347ed0SJanosch Frank int s390_pv_vm_enable(void) 61c3347ed0SJanosch Frank { 62c3347ed0SJanosch Frank return s390_pv_cmd(KVM_PV_ENABLE, NULL); 63c3347ed0SJanosch Frank } 64c3347ed0SJanosch Frank 65c3347ed0SJanosch Frank void s390_pv_vm_disable(void) 66c3347ed0SJanosch Frank { 67c3347ed0SJanosch Frank s390_pv_cmd_exit(KVM_PV_DISABLE, NULL); 68c3347ed0SJanosch Frank } 69c3347ed0SJanosch Frank 70c3347ed0SJanosch Frank int s390_pv_set_sec_parms(uint64_t origin, uint64_t length) 71c3347ed0SJanosch Frank { 72c3347ed0SJanosch Frank struct kvm_s390_pv_sec_parm args = { 73c3347ed0SJanosch Frank .origin = origin, 74c3347ed0SJanosch Frank .length = length, 75c3347ed0SJanosch Frank }; 76c3347ed0SJanosch Frank 77c3347ed0SJanosch Frank return s390_pv_cmd(KVM_PV_SET_SEC_PARMS, &args); 78c3347ed0SJanosch Frank } 79c3347ed0SJanosch Frank 80c3347ed0SJanosch Frank /* 81c3347ed0SJanosch Frank * Called for each component in the SE type IPL parameter block 0. 82c3347ed0SJanosch Frank */ 83c3347ed0SJanosch Frank int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak) 84c3347ed0SJanosch Frank { 85c3347ed0SJanosch Frank struct kvm_s390_pv_unp args = { 86c3347ed0SJanosch Frank .addr = addr, 87c3347ed0SJanosch Frank .size = size, 88c3347ed0SJanosch Frank .tweak = tweak, 89c3347ed0SJanosch Frank }; 90c3347ed0SJanosch Frank 91c3347ed0SJanosch Frank return s390_pv_cmd(KVM_PV_UNPACK, &args); 92c3347ed0SJanosch Frank } 93c3347ed0SJanosch Frank 949a432597SJanosch Frank void s390_pv_prep_reset(void) 95c3347ed0SJanosch Frank { 96c3347ed0SJanosch Frank s390_pv_cmd_exit(KVM_PV_PREP_RESET, NULL); 97c3347ed0SJanosch Frank } 98c3347ed0SJanosch Frank 99c3347ed0SJanosch Frank int s390_pv_verify(void) 100c3347ed0SJanosch Frank { 101c3347ed0SJanosch Frank return s390_pv_cmd(KVM_PV_VERIFY, NULL); 102c3347ed0SJanosch Frank } 103c3347ed0SJanosch Frank 104c3347ed0SJanosch Frank void s390_pv_unshare(void) 105c3347ed0SJanosch Frank { 106c3347ed0SJanosch Frank s390_pv_cmd_exit(KVM_PV_UNSHARE_ALL, NULL); 107c3347ed0SJanosch Frank } 108fbc1384cSChristian Borntraeger 109fbc1384cSChristian Borntraeger void s390_pv_inject_reset_error(CPUState *cs) 110fbc1384cSChristian Borntraeger { 111fbc1384cSChristian Borntraeger int r1 = (cs->kvm_run->s390_sieic.ipa & 0x00f0) >> 4; 112fbc1384cSChristian Borntraeger CPUS390XState *env = &S390_CPU(cs)->env; 113fbc1384cSChristian Borntraeger 114fbc1384cSChristian Borntraeger /* Report that we are unable to enter protected mode */ 115fbc1384cSChristian Borntraeger env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV; 116fbc1384cSChristian Borntraeger } 117651615d9SDavid Gibson 118651615d9SDavid Gibson #define TYPE_S390_PV_GUEST "s390-pv-guest" 119651615d9SDavid Gibson OBJECT_DECLARE_SIMPLE_TYPE(S390PVGuest, S390_PV_GUEST) 120651615d9SDavid Gibson 121651615d9SDavid Gibson /** 122651615d9SDavid Gibson * S390PVGuest: 123651615d9SDavid Gibson * 124651615d9SDavid Gibson * The S390PVGuest object is basically a dummy used to tell the 125651615d9SDavid Gibson * confidential guest support system to use s390's PV mechanism. 126651615d9SDavid Gibson * 127651615d9SDavid Gibson * # $QEMU \ 128651615d9SDavid Gibson * -object s390-pv-guest,id=pv0 \ 129651615d9SDavid Gibson * -machine ...,confidential-guest-support=pv0 130651615d9SDavid Gibson */ 131651615d9SDavid Gibson struct S390PVGuest { 132651615d9SDavid Gibson ConfidentialGuestSupport parent_obj; 133651615d9SDavid Gibson }; 134651615d9SDavid Gibson 135651615d9SDavid Gibson typedef struct S390PVGuestClass S390PVGuestClass; 136651615d9SDavid Gibson 137651615d9SDavid Gibson struct S390PVGuestClass { 138651615d9SDavid Gibson ConfidentialGuestSupportClass parent_class; 139651615d9SDavid Gibson }; 140651615d9SDavid Gibson 141651615d9SDavid Gibson int s390_pv_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) 142651615d9SDavid Gibson { 143651615d9SDavid Gibson if (!object_dynamic_cast(OBJECT(cgs), TYPE_S390_PV_GUEST)) { 144651615d9SDavid Gibson return 0; 145651615d9SDavid Gibson } 146651615d9SDavid Gibson 147651615d9SDavid Gibson if (!s390_has_feat(S390_FEAT_UNPACK)) { 148651615d9SDavid Gibson error_setg(errp, 149651615d9SDavid Gibson "CPU model does not support Protected Virtualization"); 150651615d9SDavid Gibson return -1; 151651615d9SDavid Gibson } 152651615d9SDavid Gibson 153651615d9SDavid Gibson cgs->ready = true; 154651615d9SDavid Gibson 155651615d9SDavid Gibson return 0; 156651615d9SDavid Gibson } 157651615d9SDavid Gibson 158651615d9SDavid Gibson OBJECT_DEFINE_TYPE_WITH_INTERFACES(S390PVGuest, 159651615d9SDavid Gibson s390_pv_guest, 160651615d9SDavid Gibson S390_PV_GUEST, 161651615d9SDavid Gibson CONFIDENTIAL_GUEST_SUPPORT, 162651615d9SDavid Gibson { TYPE_USER_CREATABLE }, 163651615d9SDavid Gibson { NULL }) 164651615d9SDavid Gibson 165651615d9SDavid Gibson static void s390_pv_guest_class_init(ObjectClass *oc, void *data) 166651615d9SDavid Gibson { 167651615d9SDavid Gibson } 168651615d9SDavid Gibson 169651615d9SDavid Gibson static void s390_pv_guest_init(Object *obj) 170651615d9SDavid Gibson { 171651615d9SDavid Gibson } 172651615d9SDavid Gibson 173651615d9SDavid Gibson static void s390_pv_guest_finalize(Object *obj) 174651615d9SDavid Gibson { 175651615d9SDavid Gibson } 176