As we now have access to the protection state of the cpus, we can implement special handling of diag 308 subcodes for cpus in the protected state.
For subcodes 0 and 1 we need to unshare all pages before continuing, so the guest doesn't accidentally expose data when dumping. For subcode 3/4 we tear down the protected VM and reboot into unprotected mode. We do not provide a secure reboot. Before we can do the unshare calls, we need to mark all cpus as stopped. Signed-off-by: Janosch Frank <fran...@linux.ibm.com> --- hw/s390x/s390-virtio-ccw.c | 37 ++++++++++++++++++++++++++++++++++--- target/s390x/diag.c | 4 ++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 79f472c309..9983165b05 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -335,6 +335,7 @@ static void s390_machine_unprotect(S390CcwMachineState *ms) } ms->pv = false; } + migrate_del_blocker(pv_mig_blocker); } static int s390_machine_protect(S390CcwMachineState *ms) @@ -396,12 +397,27 @@ static void s390_machine_inject_pv_error(CPUState *cs) env->regs[r1 + 1] = 0xa02; } +static void s390_pv_prepare_reset(CPUS390XState *env) +{ + CPUState *cs; + + if (!env->pv) { + return; + } + 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) { enum s390_reset reset_type; CPUState *cs, *t; S390CPU *cpu; S390CcwMachineState *ms = S390_CCW_MACHINE(machine); + CPUS390XState *env; /* get the reset parameters, reset them once done */ s390_ipl_get_reset_request(&cs, &reset_type); @@ -410,10 +426,15 @@ static void s390_machine_reset(MachineState *machine) s390_cmma_reset(); cpu = S390_CPU(cs); + env = &cpu->env; switch (reset_type) { case S390_RESET_EXTERNAL: case S390_RESET_REIPL: + if (ms->pv) { + s390_machine_unprotect(ms); + } + qemu_devices_reset(); s390_crypto_reset(); @@ -421,21 +442,31 @@ 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 loose access to VIRTIO structures in guest memory. + */ + subsystem_reset(); + s390_crypto_reset(); + s390_pv_prepare_reset(env); 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 loose access to VIRTIO structures in guest memory. + */ + subsystem_reset(); + s390_pv_prepare_reset(env); 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; diff --git a/target/s390x/diag.c b/target/s390x/diag.c index d6ceb1f75d..840335d40a 100644 --- a/target/s390x/diag.c +++ b/target/s390x/diag.c @@ -68,6 +68,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 (env->pv) { + return 0; + } if ((r1 & 1) || (addr & ~TARGET_PAGE_MASK)) { s390_program_interrupt(env, PGM_SPECIFICATION, ra); return -1; -- 2.20.1