2020-03-23 11:36:06 +03:00
|
|
|
/*
|
|
|
|
* Protected Virtualization functions
|
|
|
|
*
|
|
|
|
* Copyright IBM Corp. 2020
|
|
|
|
* Author(s):
|
|
|
|
* Janosch Frank <frankja@linux.ibm.com>
|
|
|
|
*
|
|
|
|
* This work is licensed under the terms of the GNU GPL, version 2 or (at
|
|
|
|
* your option) any later version. See the COPYING file in the top-level
|
|
|
|
* directory.
|
|
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
|
|
|
|
|
|
#include <linux/kvm.h>
|
|
|
|
|
s390: Recognize confidential-guest-support option
At least some s390 cpu models support "Protected Virtualization" (PV),
a mechanism to protect guests from eavesdropping by a compromised
hypervisor.
This is similar in function to other mechanisms like AMD's SEV and
POWER's PEF, which are controlled by the "confidential-guest-support"
machine option. s390 is a slightly special case, because we already
supported PV, simply by using a CPU model with the required feature
(S390_FEAT_UNPACK).
To integrate this with the option used by other platforms, we
implement the following compromise:
- When the confidential-guest-support option is set, s390 will
recognize it, verify that the CPU can support PV (failing if not)
and set virtio default options necessary for encrypted or protected
guests, as on other platforms. i.e. if confidential-guest-support
is set, we will either create a guest capable of entering PV mode,
or fail outright.
- If confidential-guest-support is not set, guests might still be
able to enter PV mode, if the CPU has the right model. This may be
a little surprising, but shouldn't actually be harmful.
To start a guest supporting Protected Virtualization using the new
option use the command line arguments:
-object s390-pv-guest,id=pv0 -machine confidential-guest-support=pv0
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Tested-by: Christian Borntraeger <borntraeger@de.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
2020-07-23 07:36:45 +03:00
|
|
|
#include "qapi/error.h"
|
2020-03-23 11:36:06 +03:00
|
|
|
#include "qemu/error-report.h"
|
|
|
|
#include "sysemu/kvm.h"
|
s390: Recognize confidential-guest-support option
At least some s390 cpu models support "Protected Virtualization" (PV),
a mechanism to protect guests from eavesdropping by a compromised
hypervisor.
This is similar in function to other mechanisms like AMD's SEV and
POWER's PEF, which are controlled by the "confidential-guest-support"
machine option. s390 is a slightly special case, because we already
supported PV, simply by using a CPU model with the required feature
(S390_FEAT_UNPACK).
To integrate this with the option used by other platforms, we
implement the following compromise:
- When the confidential-guest-support option is set, s390 will
recognize it, verify that the CPU can support PV (failing if not)
and set virtio default options necessary for encrypted or protected
guests, as on other platforms. i.e. if confidential-guest-support
is set, we will either create a guest capable of entering PV mode,
or fail outright.
- If confidential-guest-support is not set, guests might still be
able to enter PV mode, if the CPU has the right model. This may be
a little surprising, but shouldn't actually be harmful.
To start a guest supporting Protected Virtualization using the new
option use the command line arguments:
-object s390-pv-guest,id=pv0 -machine confidential-guest-support=pv0
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Tested-by: Christian Borntraeger <borntraeger@de.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
2020-07-23 07:36:45 +03:00
|
|
|
#include "qom/object_interfaces.h"
|
|
|
|
#include "exec/confidential-guest-support.h"
|
2020-04-06 13:01:58 +03:00
|
|
|
#include "hw/s390x/ipl.h"
|
2020-03-23 11:36:06 +03:00
|
|
|
#include "hw/s390x/pv.h"
|
2022-10-17 11:38:19 +03:00
|
|
|
#include "target/s390x/kvm/kvm_s390x.h"
|
|
|
|
|
|
|
|
static bool info_valid;
|
|
|
|
static struct kvm_s390_pv_info_vm info_vm;
|
|
|
|
static struct kvm_s390_pv_info_dump info_dump;
|
2020-03-23 11:36:06 +03:00
|
|
|
|
|
|
|
static int __s390_pv_cmd(uint32_t cmd, const char *cmdname, void *data)
|
|
|
|
{
|
|
|
|
struct kvm_pv_cmd pv_cmd = {
|
|
|
|
.cmd = cmd,
|
|
|
|
.data = (uint64_t)data,
|
|
|
|
};
|
2020-03-27 15:46:16 +03:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
do {
|
|
|
|
rc = kvm_vm_ioctl(kvm_state, KVM_S390_PV_COMMAND, &pv_cmd);
|
|
|
|
} while (rc == -EINTR);
|
2020-03-23 11:36:06 +03:00
|
|
|
|
|
|
|
if (rc) {
|
|
|
|
error_report("KVM PV command %d (%s) failed: header rc %x rrc %x "
|
|
|
|
"IOCTL rc: %d", cmd, cmdname, pv_cmd.rc, pv_cmd.rrc,
|
|
|
|
rc);
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This macro lets us pass the command as a string to the function so
|
|
|
|
* we can print it on an error.
|
|
|
|
*/
|
2022-10-10 18:10:41 +03:00
|
|
|
#define s390_pv_cmd(cmd, data) __s390_pv_cmd(cmd, #cmd, data)
|
2020-03-23 11:36:06 +03:00
|
|
|
#define s390_pv_cmd_exit(cmd, data) \
|
|
|
|
{ \
|
|
|
|
int rc; \
|
|
|
|
\
|
|
|
|
rc = __s390_pv_cmd(cmd, #cmd, data);\
|
|
|
|
if (rc) { \
|
|
|
|
exit(1); \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
2022-10-17 11:38:19 +03:00
|
|
|
int s390_pv_query_info(void)
|
|
|
|
{
|
|
|
|
struct kvm_s390_pv_info info = {
|
|
|
|
.header.id = KVM_PV_INFO_VM,
|
|
|
|
.header.len_max = sizeof(info.header) + sizeof(info.vm),
|
|
|
|
};
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
/* Info API's first user is dump so they are bundled */
|
|
|
|
if (!kvm_s390_get_protected_dump()) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = s390_pv_cmd(KVM_PV_INFO, &info);
|
|
|
|
if (rc) {
|
|
|
|
error_report("KVM PV INFO cmd %x failed: %s",
|
|
|
|
info.header.id, strerror(-rc));
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
memcpy(&info_vm, &info.vm, sizeof(info.vm));
|
|
|
|
|
|
|
|
info.header.id = KVM_PV_INFO_DUMP;
|
|
|
|
info.header.len_max = sizeof(info.header) + sizeof(info.dump);
|
|
|
|
rc = s390_pv_cmd(KVM_PV_INFO, &info);
|
|
|
|
if (rc) {
|
|
|
|
error_report("KVM PV INFO cmd %x failed: %s",
|
|
|
|
info.header.id, strerror(-rc));
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(&info_dump, &info.dump, sizeof(info.dump));
|
|
|
|
info_valid = true;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2020-03-23 11:36:06 +03:00
|
|
|
int s390_pv_vm_enable(void)
|
|
|
|
{
|
|
|
|
return s390_pv_cmd(KVM_PV_ENABLE, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void s390_pv_vm_disable(void)
|
|
|
|
{
|
|
|
|
s390_pv_cmd_exit(KVM_PV_DISABLE, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
int s390_pv_set_sec_parms(uint64_t origin, uint64_t length)
|
|
|
|
{
|
|
|
|
struct kvm_s390_pv_sec_parm args = {
|
|
|
|
.origin = origin,
|
|
|
|
.length = length,
|
|
|
|
};
|
|
|
|
|
|
|
|
return s390_pv_cmd(KVM_PV_SET_SEC_PARMS, &args);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Called for each component in the SE type IPL parameter block 0.
|
|
|
|
*/
|
|
|
|
int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak)
|
|
|
|
{
|
|
|
|
struct kvm_s390_pv_unp args = {
|
|
|
|
.addr = addr,
|
|
|
|
.size = size,
|
|
|
|
.tweak = tweak,
|
|
|
|
};
|
|
|
|
|
|
|
|
return s390_pv_cmd(KVM_PV_UNPACK, &args);
|
|
|
|
}
|
|
|
|
|
2020-05-05 15:41:59 +03:00
|
|
|
void s390_pv_prep_reset(void)
|
2020-03-23 11:36:06 +03:00
|
|
|
{
|
|
|
|
s390_pv_cmd_exit(KVM_PV_PREP_RESET, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
int s390_pv_verify(void)
|
|
|
|
{
|
|
|
|
return s390_pv_cmd(KVM_PV_VERIFY, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void s390_pv_unshare(void)
|
|
|
|
{
|
|
|
|
s390_pv_cmd_exit(KVM_PV_UNSHARE_ALL, NULL);
|
|
|
|
}
|
2020-04-06 13:01:58 +03:00
|
|
|
|
|
|
|
void s390_pv_inject_reset_error(CPUState *cs)
|
|
|
|
{
|
|
|
|
int r1 = (cs->kvm_run->s390_sieic.ipa & 0x00f0) >> 4;
|
|
|
|
CPUS390XState *env = &S390_CPU(cs)->env;
|
|
|
|
|
|
|
|
/* Report that we are unable to enter protected mode */
|
|
|
|
env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV;
|
|
|
|
}
|
s390: Recognize confidential-guest-support option
At least some s390 cpu models support "Protected Virtualization" (PV),
a mechanism to protect guests from eavesdropping by a compromised
hypervisor.
This is similar in function to other mechanisms like AMD's SEV and
POWER's PEF, which are controlled by the "confidential-guest-support"
machine option. s390 is a slightly special case, because we already
supported PV, simply by using a CPU model with the required feature
(S390_FEAT_UNPACK).
To integrate this with the option used by other platforms, we
implement the following compromise:
- When the confidential-guest-support option is set, s390 will
recognize it, verify that the CPU can support PV (failing if not)
and set virtio default options necessary for encrypted or protected
guests, as on other platforms. i.e. if confidential-guest-support
is set, we will either create a guest capable of entering PV mode,
or fail outright.
- If confidential-guest-support is not set, guests might still be
able to enter PV mode, if the CPU has the right model. This may be
a little surprising, but shouldn't actually be harmful.
To start a guest supporting Protected Virtualization using the new
option use the command line arguments:
-object s390-pv-guest,id=pv0 -machine confidential-guest-support=pv0
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Tested-by: Christian Borntraeger <borntraeger@de.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
2020-07-23 07:36:45 +03:00
|
|
|
|
2022-10-17 11:38:19 +03:00
|
|
|
uint64_t kvm_s390_pv_dmp_get_size_cpu(void)
|
|
|
|
{
|
|
|
|
return info_dump.dump_cpu_buffer_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t kvm_s390_pv_dmp_get_size_completion_data(void)
|
|
|
|
{
|
|
|
|
return info_dump.dump_config_finalize_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t kvm_s390_pv_dmp_get_size_mem_state(void)
|
|
|
|
{
|
|
|
|
return info_dump.dump_config_mem_buffer_per_1m;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool kvm_s390_pv_info_basic_valid(void)
|
|
|
|
{
|
|
|
|
return info_valid;
|
|
|
|
}
|
|
|
|
|
2022-10-17 11:38:21 +03:00
|
|
|
static int s390_pv_dump_cmd(uint64_t subcmd, uint64_t uaddr, uint64_t gaddr,
|
|
|
|
uint64_t len)
|
|
|
|
{
|
|
|
|
struct kvm_s390_pv_dmp dmp = {
|
|
|
|
.subcmd = subcmd,
|
|
|
|
.buff_addr = uaddr,
|
|
|
|
.buff_len = len,
|
|
|
|
.gaddr = gaddr,
|
|
|
|
};
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = s390_pv_cmd(KVM_PV_DUMP, (void *)&dmp);
|
|
|
|
if (ret) {
|
|
|
|
error_report("KVM DUMP command %ld failed", subcmd);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvm_s390_dump_cpu(S390CPU *cpu, void *buff)
|
|
|
|
{
|
|
|
|
struct kvm_s390_pv_dmp dmp = {
|
|
|
|
.subcmd = KVM_PV_DUMP_CPU,
|
|
|
|
.buff_addr = (uint64_t)buff,
|
|
|
|
.gaddr = 0,
|
|
|
|
.buff_len = info_dump.dump_cpu_buffer_len,
|
|
|
|
};
|
|
|
|
struct kvm_pv_cmd pv = {
|
|
|
|
.cmd = KVM_PV_DUMP,
|
|
|
|
.data = (uint64_t)&dmp,
|
|
|
|
};
|
|
|
|
|
|
|
|
return kvm_vcpu_ioctl(CPU(cpu), KVM_S390_PV_CPU_COMMAND, &pv);
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvm_s390_dump_init(void)
|
|
|
|
{
|
|
|
|
return s390_pv_dump_cmd(KVM_PV_DUMP_INIT, 0, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvm_s390_dump_mem_state(uint64_t gaddr, size_t len, void *dest)
|
|
|
|
{
|
|
|
|
return s390_pv_dump_cmd(KVM_PV_DUMP_CONFIG_STOR_STATE, (uint64_t)dest,
|
|
|
|
gaddr, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvm_s390_dump_completion_data(void *buff)
|
|
|
|
{
|
|
|
|
return s390_pv_dump_cmd(KVM_PV_DUMP_COMPLETE, (uint64_t)buff, 0,
|
|
|
|
info_dump.dump_config_finalize_len);
|
|
|
|
}
|
|
|
|
|
s390: Recognize confidential-guest-support option
At least some s390 cpu models support "Protected Virtualization" (PV),
a mechanism to protect guests from eavesdropping by a compromised
hypervisor.
This is similar in function to other mechanisms like AMD's SEV and
POWER's PEF, which are controlled by the "confidential-guest-support"
machine option. s390 is a slightly special case, because we already
supported PV, simply by using a CPU model with the required feature
(S390_FEAT_UNPACK).
To integrate this with the option used by other platforms, we
implement the following compromise:
- When the confidential-guest-support option is set, s390 will
recognize it, verify that the CPU can support PV (failing if not)
and set virtio default options necessary for encrypted or protected
guests, as on other platforms. i.e. if confidential-guest-support
is set, we will either create a guest capable of entering PV mode,
or fail outright.
- If confidential-guest-support is not set, guests might still be
able to enter PV mode, if the CPU has the right model. This may be
a little surprising, but shouldn't actually be harmful.
To start a guest supporting Protected Virtualization using the new
option use the command line arguments:
-object s390-pv-guest,id=pv0 -machine confidential-guest-support=pv0
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Tested-by: Christian Borntraeger <borntraeger@de.ibm.com>
Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
2020-07-23 07:36:45 +03:00
|
|
|
#define TYPE_S390_PV_GUEST "s390-pv-guest"
|
|
|
|
OBJECT_DECLARE_SIMPLE_TYPE(S390PVGuest, S390_PV_GUEST)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* S390PVGuest:
|
|
|
|
*
|
|
|
|
* The S390PVGuest object is basically a dummy used to tell the
|
|
|
|
* confidential guest support system to use s390's PV mechanism.
|
|
|
|
*
|
|
|
|
* # $QEMU \
|
|
|
|
* -object s390-pv-guest,id=pv0 \
|
|
|
|
* -machine ...,confidential-guest-support=pv0
|
|
|
|
*/
|
|
|
|
struct S390PVGuest {
|
|
|
|
ConfidentialGuestSupport parent_obj;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct S390PVGuestClass S390PVGuestClass;
|
|
|
|
|
|
|
|
struct S390PVGuestClass {
|
|
|
|
ConfidentialGuestSupportClass parent_class;
|
|
|
|
};
|
|
|
|
|
|
|
|
int s390_pv_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
|
|
|
|
{
|
|
|
|
if (!object_dynamic_cast(OBJECT(cgs), TYPE_S390_PV_GUEST)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!s390_has_feat(S390_FEAT_UNPACK)) {
|
|
|
|
error_setg(errp,
|
|
|
|
"CPU model does not support Protected Virtualization");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
cgs->ready = true;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
OBJECT_DEFINE_TYPE_WITH_INTERFACES(S390PVGuest,
|
|
|
|
s390_pv_guest,
|
|
|
|
S390_PV_GUEST,
|
|
|
|
CONFIDENTIAL_GUEST_SUPPORT,
|
|
|
|
{ TYPE_USER_CREATABLE },
|
|
|
|
{ NULL })
|
|
|
|
|
|
|
|
static void s390_pv_guest_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void s390_pv_guest_init(Object *obj)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void s390_pv_guest_finalize(Object *obj)
|
|
|
|
{
|
|
|
|
}
|