diff options
Diffstat (limited to 'hw/s390x/s390-virtio-ccw.c')
-rw-r--r-- | hw/s390x/s390-virtio-ccw.c | 137 |
1 files changed, 133 insertions, 4 deletions
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 0fa00a9fff..45292fb5a8 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -1,9 +1,10 @@ /* * virtio ccw machine * - * Copyright 2012 IBM Corp. + * Copyright 2012, 2020 IBM Corp. * Copyright (c) 2009 Alexander Graf <agraf@suse.de> * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> + * 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 @@ -42,6 +43,11 @@ #include "hw/qdev-properties.h" #include "hw/s390x/tod.h" #include "sysemu/sysemu.h" +#include "sysemu/balloon.h" +#include "hw/s390x/pv.h" +#include "migration/blocker.h" + +static Error *pv_mig_blocker; S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) { @@ -317,10 +323,93 @@ static inline void s390_do_cpu_ipl(CPUState *cs, run_on_cpu_data arg) s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu); } +static void s390_machine_unprotect(S390CcwMachineState *ms) +{ + s390_pv_vm_disable(); + ms->pv = false; + migrate_del_blocker(pv_mig_blocker); + error_free_or_abort(&pv_mig_blocker); + qemu_balloon_inhibit(false); +} + +static int s390_machine_protect(S390CcwMachineState *ms) +{ + Error *local_err = NULL; + int rc; + + /* + * Ballooning on protected VMs needs support in the guest for + * sharing and unsharing balloon pages. Block ballooning for + * now, until we have a solution to make at least Linux guests + * either support it or fail gracefully. + */ + qemu_balloon_inhibit(true); + error_setg(&pv_mig_blocker, + "protected VMs are currently not migrateable."); + rc = migrate_add_blocker(pv_mig_blocker, &local_err); + if (rc) { + qemu_balloon_inhibit(false); + error_report_err(local_err); + error_free_or_abort(&pv_mig_blocker); + return rc; + } + + /* Create SE VM */ + rc = s390_pv_vm_enable(); + if (rc) { + qemu_balloon_inhibit(false); + migrate_del_blocker(pv_mig_blocker); + error_free_or_abort(&pv_mig_blocker); + return rc; + } + + ms->pv = true; + + /* Set SE header and unpack */ + rc = s390_ipl_prepare_pv_header(); + if (rc) { + goto out_err; + } + + /* Decrypt image */ + rc = s390_ipl_pv_unpack(); + if (rc) { + goto out_err; + } + + /* Verify integrity */ + rc = s390_pv_verify(); + if (rc) { + goto out_err; + } + return rc; + +out_err: + s390_machine_unprotect(ms); + return rc; +} + +static void s390_pv_prepare_reset(S390CcwMachineState *ms) +{ + CPUState *cs; + + if (!s390_is_pv()) { + return; + } + /* Unsharing requires all cpus to be stopped */ + CPU_FOREACH(cs) { + s390_cpu_set_state(S390_CPU_STATE_STOPPED, S390_CPU(cs)); + } + s390_pv_unshare(); + s390_pv_perf_clear_reset(); +} + static void s390_machine_reset(MachineState *machine) { + S390CcwMachineState *ms = S390_CCW_MACHINE(machine); enum s390_reset reset_type; CPUState *cs, *t; + S390CPU *cpu; /* get the reset parameters, reset them once done */ s390_ipl_get_reset_request(&cs, &reset_type); @@ -328,9 +417,15 @@ static void s390_machine_reset(MachineState *machine) /* all CPUs are paused and synchronized at this point */ s390_cmma_reset(); + cpu = S390_CPU(cs); + switch (reset_type) { case S390_RESET_EXTERNAL: case S390_RESET_REIPL: + if (s390_is_pv()) { + s390_machine_unprotect(ms); + } + qemu_devices_reset(); s390_crypto_reset(); @@ -338,24 +433,58 @@ static void s390_machine_reset(MachineState *machine) run_on_cpu(cs, s390_do_cpu_ipl, RUN_ON_CPU_NULL); break; case S390_RESET_MODIFIED_CLEAR: + /* + * Susbsystem reset needs to be done before we unshare memory + * and lose access to VIRTIO structures in guest memory. + */ + subsystem_reset(); + s390_crypto_reset(); + s390_pv_prepare_reset(ms); CPU_FOREACH(t) { run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL); } - subsystem_reset(); - s390_crypto_reset(); run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL); break; case S390_RESET_LOAD_NORMAL: + /* + * Susbsystem reset needs to be done before we unshare memory + * and lose access to VIRTIO structures in guest memory. + */ + subsystem_reset(); + s390_pv_prepare_reset(ms); CPU_FOREACH(t) { if (t == cs) { continue; } run_on_cpu(t, s390_do_cpu_reset, RUN_ON_CPU_NULL); } - subsystem_reset(); run_on_cpu(cs, s390_do_cpu_initial_reset, RUN_ON_CPU_NULL); run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL); break; + case S390_RESET_PV: /* Subcode 10 */ + subsystem_reset(); + s390_crypto_reset(); + + CPU_FOREACH(t) { + if (t == cs) { + continue; + } + run_on_cpu(t, s390_do_cpu_full_reset, RUN_ON_CPU_NULL); + } + run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL); + + if (s390_machine_protect(ms)) { + s390_pv_inject_reset_error(cs); + /* + * Continue after the diag308 so the guest knows something + * went wrong. + */ + s390_cpu_set_state(S390_CPU_STATE_OPERATING, cpu); + return; + } + + run_on_cpu(cs, s390_do_cpu_load_normal, RUN_ON_CPU_NULL); + break; default: g_assert_not_reached(); } |