#include "cpu.h"
#include "internal.h"
#include "kvm_s390x.h"
+#include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
#include "sysemu/hw_accel.h"
#include "hw/hw.h"
#include "sysemu/device_tree.h"
-#include "qapi/qmp/qjson.h"
#include "exec/gdbstub.h"
#include "exec/address-spaces.h"
#include "trace.h"
-#include "qapi-event.h"
#include "hw/s390x/s390-pci-inst.h"
#include "hw/s390x/s390-pci-bus.h"
#include "hw/s390x/ipl.h"
if (DEBUG_KVM) { \
fprintf(stderr, fmt, ## __VA_ARGS__); \
} \
-} while (0);
+} while (0)
#define kvm_vm_check_mem_attr(s, attr) \
kvm_vm_check_attr(s, KVM_S390_VM_MEM_CTRL, attr)
KVM_CAP_LAST_INFO
};
-static QemuMutex qemu_sigp_mutex;
-
static int cap_sync_regs;
static int cap_async_pf;
static int cap_mem_op;
static int active_cmma;
-static void *legacy_s390_alloc(size_t size, uint64_t *align);
+static void *legacy_s390_alloc(size_t size, uint64_t *align, bool shared);
static int kvm_s390_query_mem_limit(uint64_t *memory_limit)
{
int kvm_arch_init(MachineState *ms, KVMState *s)
{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+
+ mc->default_cpu_type = S390_CPU_TYPE_NAME("host");
cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS);
cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF);
cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP);
cap_ri = 1;
}
}
- if (gs_allowed()) {
+ if (cpu_model_allowed()) {
if (kvm_vm_enable_cap(s, KVM_CAP_S390_GS, 0) == 0) {
cap_gs = 1;
}
*/
/* kvm_vm_enable_cap(s, KVM_CAP_S390_AIS, 0); */
- qemu_mutex_init(&qemu_sigp_mutex);
-
return 0;
}
cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_GSCB;
}
+ if (can_sync_regs(cs, KVM_SYNC_BPBC)) {
+ cs->kvm_run->s.regs.bpbc = env->bpbc;
+ cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_BPBC;
+ }
+
/* Finally the prefix */
if (can_sync_regs(cs, KVM_SYNC_PREFIX)) {
cs->kvm_run->s.regs.prefix = env->psa;
memcpy(env->gscb, cs->kvm_run->s.regs.gscb, 32);
}
+ if (can_sync_regs(cs, KVM_SYNC_BPBC)) {
+ env->bpbc = cs->kvm_run->s.regs.bpbc;
+ }
+
/* pfault parameters */
if (can_sync_regs(cs, KVM_SYNC_PFAULT)) {
env->pfault_token = cs->kvm_run->s.regs.pft;
return kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
}
-int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_low)
+int kvm_s390_get_clock_ext(uint8_t *tod_high, uint64_t *tod_low)
{
int r;
+ struct kvm_s390_vm_tod_clock gtod;
+ struct kvm_device_attr attr = {
+ .group = KVM_S390_VM_TOD,
+ .attr = KVM_S390_VM_TOD_EXT,
+ .addr = (uint64_t)>od,
+ };
+ r = kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
+ *tod_high = gtod.epoch_idx;
+ *tod_low = gtod.tod;
+
+ return r;
+}
+
+int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_low)
+{
+ int r;
struct kvm_device_attr attr = {
.group = KVM_S390_VM_TOD,
.attr = KVM_S390_VM_TOD_LOW,
return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
}
+int kvm_s390_set_clock_ext(uint8_t *tod_high, uint64_t *tod_low)
+{
+ struct kvm_s390_vm_tod_clock gtod = {
+ .epoch_idx = *tod_high,
+ .tod = *tod_low,
+ };
+ struct kvm_device_attr attr = {
+ .group = KVM_S390_VM_TOD,
+ .attr = KVM_S390_VM_TOD_EXT,
+ .addr = (uint64_t)>od,
+ };
+
+ return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
+}
+
/**
* kvm_s390_mem_op:
* @addr: the logical start address in guest memory
* to grow. We also have to use MAP parameters that avoid
* read-only mapping of guest pages.
*/
-static void *legacy_s390_alloc(size_t size, uint64_t *align)
+static void *legacy_s390_alloc(size_t size, uint64_t *align, bool shared)
{
void *mem;
inject_vcpu_irq_legacy(cs, irq);
}
-static void __kvm_s390_floating_interrupt(struct kvm_s390_irq *irq)
+void kvm_s390_floating_interrupt_legacy(struct kvm_s390_irq *irq)
{
struct kvm_s390_interrupt kvmint = {};
int r;
}
}
-void kvm_s390_floating_interrupt(struct kvm_s390_irq *irq)
-{
- static bool use_flic = true;
- int r;
-
- if (use_flic) {
- r = kvm_s390_inject_flic(irq);
- if (r == -ENOSYS) {
- use_flic = false;
- }
- if (!r) {
- return;
- }
- }
- __kvm_s390_floating_interrupt(irq);
-}
-
-void kvm_s390_service_interrupt(uint32_t parm)
-{
- struct kvm_s390_irq irq = {
- .type = KVM_S390_INT_SERVICE,
- .u.ext.ext_params = parm,
- };
-
- kvm_s390_floating_interrupt(&irq);
-}
-
void kvm_s390_program_interrupt(S390CPU *cpu, uint16_t code)
{
struct kvm_s390_irq irq = {
uint32_t code;
int r = 0;
- cpu_synchronize_state(CPU(cpu));
sccb = env->regs[ipbh0 & 0xf];
code = env->regs[(ipbh0 & 0xf0) >> 4];
int rc = 0;
uint16_t ipbh0 = (run->s390_sieic.ipb & 0xffff0000) >> 16;
- cpu_synchronize_state(CPU(cpu));
-
switch (ipa1) {
case PRIV_B2_XSCH:
- ioinst_handle_xsch(cpu, env->regs[1]);
+ ioinst_handle_xsch(cpu, env->regs[1], RA_IGNORED);
break;
case PRIV_B2_CSCH:
- ioinst_handle_csch(cpu, env->regs[1]);
+ ioinst_handle_csch(cpu, env->regs[1], RA_IGNORED);
break;
case PRIV_B2_HSCH:
- ioinst_handle_hsch(cpu, env->regs[1]);
+ ioinst_handle_hsch(cpu, env->regs[1], RA_IGNORED);
break;
case PRIV_B2_MSCH:
- ioinst_handle_msch(cpu, env->regs[1], run->s390_sieic.ipb);
+ ioinst_handle_msch(cpu, env->regs[1], run->s390_sieic.ipb, RA_IGNORED);
break;
case PRIV_B2_SSCH:
- ioinst_handle_ssch(cpu, env->regs[1], run->s390_sieic.ipb);
+ ioinst_handle_ssch(cpu, env->regs[1], run->s390_sieic.ipb, RA_IGNORED);
break;
case PRIV_B2_STCRW:
- ioinst_handle_stcrw(cpu, run->s390_sieic.ipb);
+ ioinst_handle_stcrw(cpu, run->s390_sieic.ipb, RA_IGNORED);
break;
case PRIV_B2_STSCH:
- ioinst_handle_stsch(cpu, env->regs[1], run->s390_sieic.ipb);
+ ioinst_handle_stsch(cpu, env->regs[1], run->s390_sieic.ipb, RA_IGNORED);
break;
case PRIV_B2_TSCH:
/* We should only get tsch via KVM_EXIT_S390_TSCH. */
fprintf(stderr, "Spurious tsch intercept\n");
break;
case PRIV_B2_CHSC:
- ioinst_handle_chsc(cpu, run->s390_sieic.ipb);
+ ioinst_handle_chsc(cpu, run->s390_sieic.ipb, RA_IGNORED);
break;
case PRIV_B2_TPI:
/* This should have been handled by kvm already. */
break;
case PRIV_B2_SCHM:
ioinst_handle_schm(cpu, env->regs[1], env->regs[2],
- run->s390_sieic.ipb);
+ run->s390_sieic.ipb, RA_IGNORED);
break;
case PRIV_B2_RSCH:
- ioinst_handle_rsch(cpu, env->regs[1]);
+ ioinst_handle_rsch(cpu, env->regs[1], RA_IGNORED);
break;
case PRIV_B2_RCHP:
- ioinst_handle_rchp(cpu, env->regs[1]);
+ ioinst_handle_rchp(cpu, env->regs[1], RA_IGNORED);
break;
case PRIV_B2_STCPS:
/* We do not provide this instruction, it is suppressed. */
break;
case PRIV_B2_SAL:
- ioinst_handle_sal(cpu, env->regs[1]);
+ ioinst_handle_sal(cpu, env->regs[1], RA_IGNORED);
break;
case PRIV_B2_SIGA:
/* Not provided, set CC = 3 for subchannel not operational */
uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16;
if (s390_has_feat(S390_FEAT_ZPCI)) {
- return clp_service_call(cpu, r2);
+ return clp_service_call(cpu, r2, RA_IGNORED);
} else {
return -1;
}
uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16;
if (s390_has_feat(S390_FEAT_ZPCI)) {
- return pcilg_service_call(cpu, r1, r2);
+ return pcilg_service_call(cpu, r1, r2, RA_IGNORED);
} else {
return -1;
}
uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16;
if (s390_has_feat(S390_FEAT_ZPCI)) {
- return pcistg_service_call(cpu, r1, r2);
+ return pcistg_service_call(cpu, r1, r2, RA_IGNORED);
} else {
return -1;
}
uint8_t ar;
if (s390_has_feat(S390_FEAT_ZPCI)) {
- cpu_synchronize_state(CPU(cpu));
fiba = get_base_disp_rxy(cpu, run, &ar);
- return stpcifc_service_call(cpu, r1, fiba, ar);
+ return stpcifc_service_call(cpu, r1, fiba, ar, RA_IGNORED);
} else {
return -1;
}
uint16_t mode;
int r;
- cpu_synchronize_state(CPU(cpu));
mode = env->regs[r1] & 0xffff;
isc = (env->regs[r3] >> 27) & 0x7;
r = css_do_sic(env, isc, mode);
uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16;
if (s390_has_feat(S390_FEAT_ZPCI)) {
- return rpcit_service_call(cpu, r1, r2);
+ return rpcit_service_call(cpu, r1, r2, RA_IGNORED);
} else {
return -1;
}
uint8_t ar;
if (s390_has_feat(S390_FEAT_ZPCI)) {
- cpu_synchronize_state(CPU(cpu));
gaddr = get_base_disp_rsy(cpu, run, &ar);
- return pcistb_service_call(cpu, r1, r3, gaddr, ar);
+ return pcistb_service_call(cpu, r1, r3, gaddr, ar, RA_IGNORED);
} else {
return -1;
}
uint8_t ar;
if (s390_has_feat(S390_FEAT_ZPCI)) {
- cpu_synchronize_state(CPU(cpu));
fiba = get_base_disp_rxy(cpu, run, &ar);
- return mpcifc_service_call(cpu, r1, fiba, ar);
+ return mpcifc_service_call(cpu, r1, fiba, ar, RA_IGNORED);
} else {
return -1;
}
CPUS390XState *env = &cpu->env;
int ret;
- cpu_synchronize_state(CPU(cpu));
ret = s390_virtio_hypercall(env);
if (ret == -EINVAL) {
kvm_s390_program_interrupt(cpu, PGM_SPECIFICATION);
uint64_t r1, r3;
int rc;
- cpu_synchronize_state(CPU(cpu));
r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
r3 = run->s390_sieic.ipa & 0x000f;
rc = handle_diag_288(&cpu->env, r1, r3);
{
uint64_t r1, r3;
- cpu_synchronize_state(CPU(cpu));
r1 = (run->s390_sieic.ipa & 0x00f0) >> 4;
r3 = run->s390_sieic.ipa & 0x000f;
- handle_diag_308(&cpu->env, r1, r3);
+ handle_diag_308(&cpu->env, r1, r3, RA_IGNORED);
}
static int handle_sw_breakpoint(S390CPU *cpu, struct kvm_run *run)
CPUS390XState *env = &cpu->env;
unsigned long pc;
- cpu_synchronize_state(CPU(cpu));
-
pc = env->psw.addr - sw_bp_ilen;
if (kvm_find_sw_breakpoint(CPU(cpu), pc)) {
env->psw.addr = pc;
return r;
}
-typedef struct SigpInfo {
- uint64_t param;
- int cc;
- uint64_t *status_reg;
-} SigpInfo;
-
-static void set_sigp_status(SigpInfo *si, uint64_t status)
-{
- *si->status_reg &= 0xffffffff00000000ULL;
- *si->status_reg |= status;
- si->cc = SIGP_CC_STATUS_STORED;
-}
-
-static void sigp_start(CPUState *cs, run_on_cpu_data arg)
-{
- S390CPU *cpu = S390_CPU(cs);
- SigpInfo *si = arg.host_ptr;
-
- if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
- return;
- }
-
- s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
-}
-
-static void sigp_stop(CPUState *cs, run_on_cpu_data arg)
-{
- S390CPU *cpu = S390_CPU(cs);
- SigpInfo *si = arg.host_ptr;
- struct kvm_s390_irq irq = {
- .type = KVM_S390_SIGP_STOP,
- };
-
- if (s390_cpu_get_state(cpu) != CPU_STATE_OPERATING) {
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
- return;
- }
-
- /* disabled wait - sleeping in user space */
- if (cs->halted) {
- s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
- } else {
- /* execute the stop function */
- cpu->env.sigp_order = SIGP_STOP;
- kvm_s390_vcpu_interrupt(cpu, &irq);
- }
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
-}
-
-#define ADTL_GS_OFFSET 1024 /* offset of GS data in adtl save area */
-#define ADTL_GS_MIN_SIZE 2048 /* minimal size of adtl save area for GS */
-static int do_store_adtl_status(S390CPU *cpu, hwaddr addr, hwaddr len)
-{
- hwaddr save = len;
- void *mem;
-
- mem = cpu_physical_memory_map(addr, &save, 1);
- if (!mem) {
- return -EFAULT;
- }
- if (save != len) {
- cpu_physical_memory_unmap(mem, len, 1, 0);
- return -EFAULT;
- }
-
- if (s390_has_feat(S390_FEAT_VECTOR)) {
- memcpy(mem, &cpu->env.vregs, 512);
- }
- if (s390_has_feat(S390_FEAT_GUARDED_STORAGE) && len >= ADTL_GS_MIN_SIZE) {
- memcpy(mem + ADTL_GS_OFFSET, &cpu->env.gscb, 32);
- }
-
- cpu_physical_memory_unmap(mem, len, 1, len);
-
- return 0;
-}
-
-#define KVM_S390_STORE_STATUS_DEF_ADDR offsetof(LowCore, floating_pt_save_area)
-#define SAVE_AREA_SIZE 512
-static int kvm_s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch)
-{
- static const uint8_t ar_id = 1;
- uint64_t ckc = cpu->env.ckc >> 8;
- void *mem;
- int i;
- hwaddr len = SAVE_AREA_SIZE;
-
- mem = cpu_physical_memory_map(addr, &len, 1);
- if (!mem) {
- return -EFAULT;
- }
- if (len != SAVE_AREA_SIZE) {
- cpu_physical_memory_unmap(mem, len, 1, 0);
- return -EFAULT;
- }
-
- if (store_arch) {
- cpu_physical_memory_write(offsetof(LowCore, ar_access_id), &ar_id, 1);
- }
- for (i = 0; i < 16; ++i) {
- *((uint64_t *)mem + i) = get_freg(&cpu->env, i)->ll;
- }
- memcpy(mem + 128, &cpu->env.regs, 128);
- memcpy(mem + 256, &cpu->env.psw, 16);
- memcpy(mem + 280, &cpu->env.psa, 4);
- memcpy(mem + 284, &cpu->env.fpc, 4);
- memcpy(mem + 292, &cpu->env.todpr, 4);
- memcpy(mem + 296, &cpu->env.cputm, 8);
- memcpy(mem + 304, &ckc, 8);
- memcpy(mem + 320, &cpu->env.aregs, 64);
- memcpy(mem + 384, &cpu->env.cregs, 128);
-
- cpu_physical_memory_unmap(mem, len, 1, len);
-
- return 0;
-}
-
-static void sigp_stop_and_store_status(CPUState *cs, run_on_cpu_data arg)
-{
- S390CPU *cpu = S390_CPU(cs);
- SigpInfo *si = arg.host_ptr;
- struct kvm_s390_irq irq = {
- .type = KVM_S390_SIGP_STOP,
- };
-
- /* disabled wait - sleeping in user space */
- if (s390_cpu_get_state(cpu) == CPU_STATE_OPERATING && cs->halted) {
- s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
- }
-
- switch (s390_cpu_get_state(cpu)) {
- case CPU_STATE_OPERATING:
- cpu->env.sigp_order = SIGP_STOP_STORE_STATUS;
- kvm_s390_vcpu_interrupt(cpu, &irq);
- /* store will be performed when handling the stop intercept */
- break;
- case CPU_STATE_STOPPED:
- /* already stopped, just store the status */
- cpu_synchronize_state(cs);
- kvm_s390_store_status(cpu, KVM_S390_STORE_STATUS_DEF_ADDR, true);
- break;
- }
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
-}
-
-static void sigp_store_status_at_address(CPUState *cs, run_on_cpu_data arg)
-{
- S390CPU *cpu = S390_CPU(cs);
- SigpInfo *si = arg.host_ptr;
- uint32_t address = si->param & 0x7ffffe00u;
-
- /* cpu has to be stopped */
- if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
- set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
- return;
- }
-
- cpu_synchronize_state(cs);
-
- if (kvm_s390_store_status(cpu, address, false)) {
- set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
- return;
- }
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
-}
-
-#define ADTL_SAVE_LC_MASK 0xfUL
-static void sigp_store_adtl_status(CPUState *cs, run_on_cpu_data arg)
-{
- S390CPU *cpu = S390_CPU(cs);
- SigpInfo *si = arg.host_ptr;
- uint8_t lc = si->param & ADTL_SAVE_LC_MASK;
- hwaddr addr = si->param & ~ADTL_SAVE_LC_MASK;
- hwaddr len = 1UL << (lc ? lc : 10);
-
- if (!s390_has_feat(S390_FEAT_VECTOR) &&
- !s390_has_feat(S390_FEAT_GUARDED_STORAGE)) {
- set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
- return;
- }
-
- /* cpu has to be stopped */
- if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
- set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
- return;
- }
-
- /* address must be aligned to length */
- if (addr & (len - 1)) {
- set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
- return;
- }
-
- /* no GS: only lc == 0 is valid */
- if (!s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
- lc != 0) {
- set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
- return;
- }
-
- /* GS: 0, 10, 11, 12 are valid */
- if (s390_has_feat(S390_FEAT_GUARDED_STORAGE) &&
- lc != 0 &&
- lc != 10 &&
- lc != 11 &&
- lc != 12) {
- set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
- return;
- }
-
- cpu_synchronize_state(cs);
-
- if (do_store_adtl_status(cpu, addr, len)) {
- set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
- return;
- }
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
-}
-
-static void sigp_restart(CPUState *cs, run_on_cpu_data arg)
-{
- S390CPU *cpu = S390_CPU(cs);
- SigpInfo *si = arg.host_ptr;
- struct kvm_s390_irq irq = {
- .type = KVM_S390_RESTART,
- };
-
- switch (s390_cpu_get_state(cpu)) {
- case CPU_STATE_STOPPED:
- /* the restart irq has to be delivered prior to any other pending irq */
- cpu_synchronize_state(cs);
- do_restart_interrupt(&cpu->env);
- s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
- break;
- case CPU_STATE_OPERATING:
- kvm_s390_vcpu_interrupt(cpu, &irq);
- break;
- }
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
-}
-
-int kvm_s390_cpu_restart(S390CPU *cpu)
-{
- SigpInfo si = {};
-
- run_on_cpu(CPU(cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si));
- DPRINTF("DONE: KVM cpu restart: %p\n", &cpu->env);
- return 0;
-}
-
-static void sigp_initial_cpu_reset(CPUState *cs, run_on_cpu_data arg)
-{
- S390CPU *cpu = S390_CPU(cs);
- S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
- SigpInfo *si = arg.host_ptr;
-
- cpu_synchronize_state(cs);
- scc->initial_cpu_reset(cs);
- cpu_synchronize_post_reset(cs);
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
-}
-
-static void sigp_cpu_reset(CPUState *cs, run_on_cpu_data arg)
-{
- S390CPU *cpu = S390_CPU(cs);
- S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
- SigpInfo *si = arg.host_ptr;
-
- cpu_synchronize_state(cs);
- scc->cpu_reset(cs);
- cpu_synchronize_post_reset(cs);
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
-}
-
-static void sigp_set_prefix(CPUState *cs, run_on_cpu_data arg)
-{
- S390CPU *cpu = S390_CPU(cs);
- SigpInfo *si = arg.host_ptr;
- uint32_t addr = si->param & 0x7fffe000u;
-
- cpu_synchronize_state(cs);
-
- if (!address_space_access_valid(&address_space_memory, addr,
- sizeof(struct LowCore), false)) {
- set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
- return;
- }
-
- /* cpu has to be stopped */
- if (s390_cpu_get_state(cpu) != CPU_STATE_STOPPED) {
- set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
- return;
- }
-
- cpu->env.psa = addr;
- cpu_synchronize_post_init(cs);
- si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
-}
-
-static int handle_sigp_single_dst(S390CPU *dst_cpu, uint8_t order,
- uint64_t param, uint64_t *status_reg)
-{
- SigpInfo si = {
- .param = param,
- .status_reg = status_reg,
- };
-
- /* cpu available? */
- if (dst_cpu == NULL) {
- return SIGP_CC_NOT_OPERATIONAL;
- }
-
- /* only resets can break pending orders */
- if (dst_cpu->env.sigp_order != 0 &&
- order != SIGP_CPU_RESET &&
- order != SIGP_INITIAL_CPU_RESET) {
- return SIGP_CC_BUSY;
- }
-
- switch (order) {
- case SIGP_START:
- run_on_cpu(CPU(dst_cpu), sigp_start, RUN_ON_CPU_HOST_PTR(&si));
- break;
- case SIGP_STOP:
- run_on_cpu(CPU(dst_cpu), sigp_stop, RUN_ON_CPU_HOST_PTR(&si));
- break;
- case SIGP_RESTART:
- run_on_cpu(CPU(dst_cpu), sigp_restart, RUN_ON_CPU_HOST_PTR(&si));
- break;
- case SIGP_STOP_STORE_STATUS:
- run_on_cpu(CPU(dst_cpu), sigp_stop_and_store_status, RUN_ON_CPU_HOST_PTR(&si));
- break;
- case SIGP_STORE_STATUS_ADDR:
- run_on_cpu(CPU(dst_cpu), sigp_store_status_at_address, RUN_ON_CPU_HOST_PTR(&si));
- break;
- case SIGP_STORE_ADTL_STATUS:
- run_on_cpu(CPU(dst_cpu), sigp_store_adtl_status, RUN_ON_CPU_HOST_PTR(&si));
- break;
- case SIGP_SET_PREFIX:
- run_on_cpu(CPU(dst_cpu), sigp_set_prefix, RUN_ON_CPU_HOST_PTR(&si));
- break;
- case SIGP_INITIAL_CPU_RESET:
- run_on_cpu(CPU(dst_cpu), sigp_initial_cpu_reset, RUN_ON_CPU_HOST_PTR(&si));
- break;
- case SIGP_CPU_RESET:
- run_on_cpu(CPU(dst_cpu), sigp_cpu_reset, RUN_ON_CPU_HOST_PTR(&si));
- break;
- default:
- DPRINTF("KVM: unknown SIGP: 0x%x\n", order);
- set_sigp_status(&si, SIGP_STAT_INVALID_ORDER);
- }
-
- return si.cc;
-}
-
-static int sigp_set_architecture(S390CPU *cpu, uint32_t param,
- uint64_t *status_reg)
-{
- CPUState *cur_cs;
- S390CPU *cur_cpu;
- bool all_stopped = true;
-
- CPU_FOREACH(cur_cs) {
- cur_cpu = S390_CPU(cur_cs);
-
- if (cur_cpu == cpu) {
- continue;
- }
- if (s390_cpu_get_state(cur_cpu) != CPU_STATE_STOPPED) {
- all_stopped = false;
- }
- }
-
- *status_reg &= 0xffffffff00000000ULL;
-
- /* Reject set arch order, with czam we're always in z/Arch mode. */
- *status_reg |= (all_stopped ? SIGP_STAT_INVALID_PARAMETER :
- SIGP_STAT_INCORRECT_STATE);
- return SIGP_CC_STATUS_STORED;
-}
-
-static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
+static int kvm_s390_handle_sigp(S390CPU *cpu, uint8_t ipa1, uint32_t ipb)
{
CPUS390XState *env = &cpu->env;
const uint8_t r1 = ipa1 >> 4;
const uint8_t r3 = ipa1 & 0x0f;
int ret;
uint8_t order;
- uint64_t *status_reg;
- uint64_t param;
- S390CPU *dst_cpu = NULL;
-
- cpu_synchronize_state(CPU(cpu));
/* get order code */
- order = decode_basedisp_rs(env, run->s390_sieic.ipb, NULL)
- & SIGP_ORDER_MASK;
- status_reg = &env->regs[r1];
- param = (r1 % 2) ? env->regs[r1] : env->regs[r1 + 1];
-
- if (qemu_mutex_trylock(&qemu_sigp_mutex)) {
- ret = SIGP_CC_BUSY;
- goto out;
- }
-
- switch (order) {
- case SIGP_SET_ARCH:
- ret = sigp_set_architecture(cpu, param, status_reg);
- break;
- default:
- /* all other sigp orders target a single vcpu */
- dst_cpu = s390_cpu_addr2state(env->regs[r3]);
- ret = handle_sigp_single_dst(dst_cpu, order, param, status_reg);
- }
- qemu_mutex_unlock(&qemu_sigp_mutex);
+ order = decode_basedisp_rs(env, ipb, NULL) & SIGP_ORDER_MASK;
-out:
- trace_kvm_sigp_finished(order, CPU(cpu)->cpu_index,
- dst_cpu ? CPU(dst_cpu)->cpu_index : -1, ret);
-
- if (ret >= 0) {
- setcc(cpu, ret);
- return 0;
- }
-
- return ret;
+ ret = handle_sigp(env, order, r1, r3);
+ setcc(cpu, ret);
+ return 0;
}
static int handle_instruction(S390CPU *cpu, struct kvm_run *run)
r = handle_diag(cpu, run, run->s390_sieic.ipb);
break;
case IPA0_SIGP:
- r = handle_sigp(cpu, run, ipa1);
+ r = kvm_s390_handle_sigp(cpu, ipa1, run->s390_sieic.ipb);
break;
}
return r;
}
-static bool is_special_wait_psw(CPUState *cs)
-{
- /* signal quiesce */
- return cs->kvm_run->psw_addr == 0xfffUL;
-}
-
-static void unmanageable_intercept(S390CPU *cpu, const char *str, int pswoffset)
+static void unmanageable_intercept(S390CPU *cpu, S390CrashReason reason,
+ int pswoffset)
{
CPUState *cs = CPU(cpu);
- error_report("Unmanageable %s! CPU%i new PSW: 0x%016lx:%016lx",
- str, cs->cpu_index, ldq_phys(cs->as, cpu->env.psa + pswoffset),
- ldq_phys(cs->as, cpu->env.psa + pswoffset + 8));
s390_cpu_halt(cpu);
- qemu_system_guest_panicked(NULL);
+ cpu->env.crash_reason = reason;
+ qemu_system_guest_panicked(cpu_get_crash_info(cs));
}
/* try to detect pgm check loops */
CPUState *cs = CPU(cpu);
PSW oldpsw, newpsw;
- cpu_synchronize_state(cs);
newpsw.mask = ldq_phys(cs->as, cpu->env.psa +
offsetof(LowCore, program_new_psw));
newpsw.addr = ldq_phys(cs->as, cpu->env.psa +
!(oldpsw.mask & PSW_MASK_PSTATE) &&
(newpsw.mask & PSW_MASK_ASC) == (oldpsw.mask & PSW_MASK_ASC) &&
(newpsw.mask & PSW_MASK_DAT) == (oldpsw.mask & PSW_MASK_DAT)) {
- unmanageable_intercept(cpu, "operation exception loop",
+ unmanageable_intercept(cpu, S390_CRASH_REASON_OPINT_LOOP,
offsetof(LowCore, program_new_psw));
return EXCP_HALTED;
}
r = handle_instruction(cpu, run);
break;
case ICPT_PROGRAM:
- unmanageable_intercept(cpu, "program interrupt",
+ unmanageable_intercept(cpu, S390_CRASH_REASON_PGMINT_LOOP,
offsetof(LowCore, program_new_psw));
r = EXCP_HALTED;
break;
case ICPT_EXT_INT:
- unmanageable_intercept(cpu, "external interrupt",
+ unmanageable_intercept(cpu, S390_CRASH_REASON_EXTINT_LOOP,
offsetof(LowCore, external_new_psw));
r = EXCP_HALTED;
break;
case ICPT_WAITPSW:
/* disabled wait, since enabled wait is handled in kernel */
- cpu_synchronize_state(cs);
- if (s390_cpu_halt(cpu) == 0) {
- if (is_special_wait_psw(cs)) {
- qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
- } else {
- qemu_system_guest_panicked(NULL);
- }
- }
+ s390_handle_wait(cpu);
r = EXCP_HALTED;
break;
case ICPT_CPU_STOP:
- if (s390_cpu_set_state(CPU_STATE_STOPPED, cpu) == 0) {
- qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
- }
- if (cpu->env.sigp_order == SIGP_STOP_STORE_STATUS) {
- kvm_s390_store_status(cpu, KVM_S390_STORE_STATUS_DEF_ADDR,
- true);
- }
- cpu->env.sigp_order = 0;
+ do_stop_interrupt(&cpu->env);
r = EXCP_HALTED;
break;
case ICPT_OPEREXC:
struct kvm_run *run = cs->kvm_run;
int ret;
- cpu_synchronize_state(cs);
-
- ret = ioinst_handle_tsch(cpu, cpu->env.regs[1], run->s390_tsch.ipb);
+ ret = ioinst_handle_tsch(cpu, cpu->env.regs[1], run->s390_tsch.ipb,
+ RA_IGNORED);
if (ret < 0) {
/*
* Failure.
* If an I/O interrupt had been dequeued, we have to reinject it.
*/
if (run->s390_tsch.dequeued) {
- kvm_s390_io_interrupt(run->s390_tsch.subchannel_id,
- run->s390_tsch.subchannel_nr,
- run->s390_tsch.io_int_parm,
- run->s390_tsch.io_int_word);
+ s390_io_interrupt(run->s390_tsch.subchannel_id,
+ run->s390_tsch.subchannel_nr,
+ run->s390_tsch.io_int_parm,
+ run->s390_tsch.io_int_word);
}
ret = 0;
}
static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar)
{
- struct sysib_322 sysib;
+ SysIB_322 sysib;
int del;
if (s390_cpu_virt_mem_read(cpu, addr, ar, &sysib, sizeof(sysib))) {
qemu_mutex_lock_iothread();
+ kvm_cpu_synchronize_state(cs);
+
switch (run->exit_reason) {
case KVM_EXIT_S390_SIEIC:
ret = handle_intercept(cpu);
return true;
}
-void kvm_s390_io_interrupt(uint16_t subchannel_id,
- uint16_t subchannel_nr, uint32_t io_int_parm,
- uint32_t io_int_word)
-{
- struct kvm_s390_irq irq = {
- .u.io.subchannel_id = subchannel_id,
- .u.io.subchannel_nr = subchannel_nr,
- .u.io.io_int_parm = io_int_parm,
- .u.io.io_int_word = io_int_word,
- };
-
- if (io_int_word & IO_INT_WORD_AI) {
- irq.type = KVM_S390_INT_IO(1, 0, 0, 0);
- } else {
- irq.type = KVM_S390_INT_IO(0, (subchannel_id & 0xff00) >> 8,
- (subchannel_id & 0x0006),
- subchannel_nr);
- }
- kvm_s390_floating_interrupt(&irq);
-}
-
-static uint64_t build_channel_report_mcic(void)
-{
- uint64_t mcic;
-
- /* subclass: indicate channel report pending */
- mcic = MCIC_SC_CP |
- /* subclass modifiers: none */
- /* storage errors: none */
- /* validity bits: no damage */
- MCIC_VB_WP | MCIC_VB_MS | MCIC_VB_PM | MCIC_VB_IA | MCIC_VB_FP |
- MCIC_VB_GR | MCIC_VB_CR | MCIC_VB_ST | MCIC_VB_AR | MCIC_VB_PR |
- MCIC_VB_FC | MCIC_VB_CT | MCIC_VB_CC;
- if (s390_has_feat(S390_FEAT_VECTOR)) {
- mcic |= MCIC_VB_VR;
- }
- if (s390_has_feat(S390_FEAT_GUARDED_STORAGE)) {
- mcic |= MCIC_VB_GS;
- }
- return mcic;
-}
-
-void kvm_s390_crw_mchk(void)
-{
- struct kvm_s390_irq irq = {
- .type = KVM_S390_MCHK,
- .u.mchk.cr14 = 1 << 28,
- .u.mchk.mcic = build_channel_report_mcic(),
- };
- kvm_s390_floating_interrupt(&irq);
-}
-
void kvm_s390_enable_css_support(S390CPU *cpu)
{
int r;
return kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick);
}
-int kvm_s390_get_memslot_count(void)
-{
- return kvm_check_extension(kvm_state, KVM_CAP_NR_MEMSLOTS);
-}
-
int kvm_s390_get_ri(void)
{
return cap_ri;
}
switch (cpu_state) {
- case CPU_STATE_STOPPED:
+ case S390_CPU_STATE_STOPPED:
mp_state.mp_state = KVM_MP_STATE_STOPPED;
break;
- case CPU_STATE_CHECK_STOP:
+ case S390_CPU_STATE_CHECK_STOP:
mp_state.mp_state = KVM_MP_STATE_CHECK_STOP;
break;
- case CPU_STATE_OPERATING:
+ case S390_CPU_STATE_OPERATING:
mp_state.mp_state = KVM_MP_STATE_OPERATING;
break;
- case CPU_STATE_LOAD:
+ case S390_CPU_STATE_LOAD:
mp_state.mp_state = KVM_MP_STATE_LOAD;
break;
default:
void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu)
{
- struct kvm_s390_irq_state irq_state;
+ struct kvm_s390_irq_state irq_state = {
+ .buf = (uint64_t) cpu->irqstate,
+ .len = VCPU_IRQ_BUF_SIZE,
+ };
CPUState *cs = CPU(cpu);
int32_t bytes;
return;
}
- irq_state.buf = (uint64_t) cpu->irqstate;
- irq_state.len = VCPU_IRQ_BUF_SIZE;
-
bytes = kvm_vcpu_ioctl(cs, KVM_S390_GET_IRQ_STATE, &irq_state);
if (bytes < 0) {
cpu->irqstate_saved_size = 0;
int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu)
{
CPUState *cs = CPU(cpu);
- struct kvm_s390_irq_state irq_state;
+ struct kvm_s390_irq_state irq_state = {
+ .buf = (uint64_t) cpu->irqstate,
+ .len = cpu->irqstate_saved_size,
+ };
int r;
if (cpu->irqstate_saved_size == 0) {
return -ENOSYS;
}
- irq_state.buf = (uint64_t) cpu->irqstate;
- irq_state.len = cpu->irqstate_saved_size;
-
r = kvm_vcpu_ioctl(cs, KVM_S390_SET_IRQ_STATE, &irq_state);
if (r) {
error_report("Setting interrupt state failed %d", r);
return;
}
+ /* PTFF subfunctions might be indicated although kernel support missing */
+ if (!test_bit(S390_FEAT_MULTIPLE_EPOCH, model->features)) {
+ clear_bit(S390_FEAT_PTFF_QSIE, model->features);
+ clear_bit(S390_FEAT_PTFF_QTOUE, model->features);
+ clear_bit(S390_FEAT_PTFF_STOE, model->features);
+ clear_bit(S390_FEAT_PTFF_STOUE, model->features);
+ }
+
/* with cpu model support, CMM is only indicated if really available */
if (kvm_s390_cmma_available()) {
set_bit(S390_FEAT_CMM, model->features);
clear_bit(S390_FEAT_CMM_NT, model->features);
}
+ /* bpb needs kernel support for migration, VSIE and reset */
+ if (!kvm_check_extension(kvm_state, KVM_CAP_S390_BPB)) {
+ clear_bit(S390_FEAT_BPB, model->features);
+ }
+
/* We emulate a zPCI bus and AEN, therefore we don't need HW support */
if (pci_available) {
set_bit(S390_FEAT_ZPCI, model->features);
kvm_s390_enable_cmma();
}
}
+
+void kvm_s390_restart_interrupt(S390CPU *cpu)
+{
+ struct kvm_s390_irq irq = {
+ .type = KVM_S390_RESTART,
+ };
+
+ kvm_s390_vcpu_interrupt(cpu, &irq);
+}
+
+void kvm_s390_stop_interrupt(S390CPU *cpu)
+{
+ struct kvm_s390_irq irq = {
+ .type = KVM_S390_SIGP_STOP,
+ };
+
+ kvm_s390_vcpu_interrupt(cpu, &irq);
+}