s390x: protvirt: Support unpack facility

The unpack facility provides the means to setup a protected guest. A
protected guest cannot be introspected by the hypervisor or any
user/administrator of the machine it is running on.

Protected guests are encrypted at rest and need a special boot
mechanism via diag308 subcode 8 and 10.

Code 8 sets the PV specific IPLB which is retained separately from
those set via code 5.

Code 10 is used to unpack the VM into protected memory, verify its
integrity and start it.

Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
Co-developed-by: Christian Borntraeger <borntraeger@de.ibm.com> [Changes
to machine]
Reviewed-by: David Hildenbrand <david@redhat.com>
Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Message-Id: <20200323083606.24520-1-frankja@linux.ibm.com>
[CH: fixed up KVM_PV_VM_ -> KVM_PV_]
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
This commit is contained in:
Janosch Frank 2020-03-23 04:36:06 -04:00 committed by Cornelia Huck
parent 9b39d29470
commit c3347ed0d2
14 changed files with 468 additions and 10 deletions

View file

@ -20,6 +20,8 @@
#include "sysemu/cpus.h"
#include "hw/s390x/ipl.h"
#include "hw/s390x/s390-virtio-ccw.h"
#include "hw/s390x/pv.h"
#include "kvm_s390x.h"
int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
{
@ -52,6 +54,10 @@ int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr,
uintptr_t ra, bool write)
{
/* Handled by the Ultravisor */
if (s390_is_pv()) {
return 0;
}
if ((r1 & 1) || (addr & ~TARGET_PAGE_MASK)) {
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return -1;
@ -67,6 +73,7 @@ static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr,
void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
{
bool valid;
CPUState *cs = env_cpu(env);
uint64_t addr = env->regs[r1];
uint64_t subcode = env->regs[r3];
@ -82,6 +89,11 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
return;
}
if (subcode >= DIAG308_PV_SET && !s390_has_feat(S390_FEAT_UNPACK)) {
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
return;
}
switch (subcode) {
case DIAG308_RESET_MOD_CLR:
s390_ipl_reset_request(cs, S390_RESET_MODIFIED_CLEAR);
@ -94,6 +106,7 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
s390_ipl_reset_request(cs, S390_RESET_REIPL);
break;
case DIAG308_SET:
case DIAG308_PV_SET:
if (diag308_parm_check(env, r1, addr, ra, false)) {
return;
}
@ -106,7 +119,8 @@ void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
if (!iplb_valid(iplb)) {
valid = subcode == DIAG308_PV_SET ? iplb_valid_pv(iplb) : iplb_valid(iplb);
if (!valid) {
env->regs[r1 + 1] = DIAG_308_RC_INVALID;
goto out;
}
@ -117,10 +131,15 @@ out:
g_free(iplb);
return;
case DIAG308_STORE:
case DIAG308_PV_STORE:
if (diag308_parm_check(env, r1, addr, ra, true)) {
return;
}
iplb = s390_ipl_get_iplb();
if (subcode == DIAG308_PV_STORE) {
iplb = s390_ipl_get_iplb_pv();
} else {
iplb = s390_ipl_get_iplb();
}
if (iplb) {
cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
env->regs[r1 + 1] = DIAG_308_RC_OK;
@ -128,6 +147,22 @@ out:
env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
}
return;
case DIAG308_PV_START:
iplb = s390_ipl_get_iplb_pv();
if (!iplb) {
env->regs[r1 + 1] = DIAG_308_RC_NO_PV_CONF;
return;
}
if (kvm_s390_get_hpage_1m()) {
error_report("Protected VMs can currently not be backed with "
"huge pages");
env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV;
return;
}
s390_ipl_reset_request(cs, S390_RESET_PV);
break;
default:
s390_program_interrupt(env, PGM_SPECIFICATION, ra);
break;