#include <asm/ptrace.h>
#include "qemu-common.h"
+#include "qemu/error-report.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
#define PRIV_E3_MPCIFC 0xd0
#define PRIV_E3_STPCIFC 0xd4
+#define DIAG_TIMEREVENT 0x288
#define DIAG_IPL 0x308
#define DIAG_KVM_HYPERCALL 0x500
#define DIAG_KVM_BREAKPOINT 0x501
}
kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0);
+ kvm_vm_enable_cap(s, KVM_CAP_S390_VECTOR_REGISTERS, 0);
kvm_vm_enable_cap(s, KVM_CAP_S390_USER_STSI, 0);
return 0;
}
}
- /* Floating point */
- for (i = 0; i < 16; i++) {
- fpu.fprs[i] = env->fregs[i].ll;
- }
- fpu.fpc = env->fpc;
+ if (can_sync_regs(cs, KVM_SYNC_VRS)) {
+ for (i = 0; i < 32; i++) {
+ cs->kvm_run->s.regs.vrs[i][0] = env->vregs[i][0].ll;
+ cs->kvm_run->s.regs.vrs[i][1] = env->vregs[i][1].ll;
+ }
+ cs->kvm_run->s.regs.fpc = env->fpc;
+ cs->kvm_run->kvm_dirty_regs |= KVM_SYNC_VRS;
+ } else {
+ /* Floating point */
+ for (i = 0; i < 16; i++) {
+ fpu.fprs[i] = get_freg(env, i)->ll;
+ }
+ fpu.fpc = env->fpc;
- r = kvm_vcpu_ioctl(cs, KVM_SET_FPU, &fpu);
- if (r < 0) {
- return r;
+ r = kvm_vcpu_ioctl(cs, KVM_SET_FPU, &fpu);
+ if (r < 0) {
+ return r;
+ }
}
/* Do we need to save more than that? */
}
}
- /* Floating point */
- r = kvm_vcpu_ioctl(cs, KVM_GET_FPU, &fpu);
- if (r < 0) {
- return r;
- }
- for (i = 0; i < 16; i++) {
- env->fregs[i].ll = fpu.fprs[i];
+ /* Floating point and vector registers */
+ if (can_sync_regs(cs, KVM_SYNC_VRS)) {
+ for (i = 0; i < 32; i++) {
+ env->vregs[i][0].ll = cs->kvm_run->s.regs.vrs[i][0];
+ env->vregs[i][1].ll = cs->kvm_run->s.regs.vrs[i][1];
+ }
+ env->fpc = cs->kvm_run->s.regs.fpc;
+ } else {
+ r = kvm_vcpu_ioctl(cs, KVM_GET_FPU, &fpu);
+ if (r < 0) {
+ return r;
+ }
+ for (i = 0; i < 16; i++) {
+ get_freg(env, i)->ll = fpu.fprs[i];
+ }
+ env->fpc = fpu.fpc;
}
- env->fpc = fpu.fpc;
/* The prefix */
if (can_sync_regs(cs, KVM_SYNC_PREFIX)) {
return ret;
}
+static void kvm_handle_diag_288(S390CPU *cpu, struct kvm_run *run)
+{
+ 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);
+ if (rc) {
+ enter_pgmcheck(cpu, PGM_SPECIFICATION);
+ }
+}
+
static void kvm_handle_diag_308(S390CPU *cpu, struct kvm_run *run)
{
uint64_t r1, r3;
*/
func_code = decode_basedisp_rs(&cpu->env, ipb, NULL) & DIAG_KVM_CODE_MASK;
switch (func_code) {
+ case DIAG_TIMEREVENT:
+ kvm_handle_diag_288(cpu, run);
+ break;
case DIAG_IPL:
kvm_handle_diag_308(cpu, run);
break;
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
+#define ADTL_SAVE_AREA_SIZE 1024
+static int kvm_s390_store_adtl_status(S390CPU *cpu, hwaddr addr)
+{
+ void *mem;
+ hwaddr len = ADTL_SAVE_AREA_SIZE;
+
+ mem = cpu_physical_memory_map(addr, &len, 1);
+ if (!mem) {
+ return -EFAULT;
+ }
+ if (len != ADTL_SAVE_AREA_SIZE) {
+ cpu_physical_memory_unmap(mem, len, 1, 0);
+ return -EFAULT;
+ }
+
+ memcpy(mem, &cpu->env.vregs, 512);
+
+ 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 (store_arch) {
cpu_physical_memory_write(offsetof(LowCore, ar_access_id), &ar_id, 1);
}
- memcpy(mem, &cpu->env.fregs, 128);
+ for (i = 0; i < 16; ++i) {
+ *((uint64 *)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);
si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
+static void sigp_store_adtl_status(void *arg)
+{
+ SigpInfo *si = arg;
+
+ if (!kvm_check_extension(kvm_state, KVM_CAP_S390_VECTOR_REGISTERS)) {
+ set_sigp_status(si, SIGP_STAT_INVALID_ORDER);
+ return;
+ }
+
+ /* cpu has to be stopped */
+ if (s390_cpu_get_state(si->cpu) != CPU_STATE_STOPPED) {
+ set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
+ return;
+ }
+
+ /* parameter must be aligned to 1024-byte boundary */
+ if (si->param & 0x3ff) {
+ set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
+ return;
+ }
+
+ cpu_synchronize_state(CPU(si->cpu));
+
+ if (kvm_s390_store_adtl_status(si->cpu, si->param)) {
+ set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
+ return;
+ }
+ si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
+}
+
static void sigp_restart(void *arg)
{
SigpInfo *si = arg;
case SIGP_STORE_STATUS_ADDR:
run_on_cpu(CPU(dst_cpu), sigp_store_status_at_address, &si);
break;
+ case SIGP_STORE_ADTL_STATUS:
+ run_on_cpu(CPU(dst_cpu), sigp_store_adtl_status, &si);
+ break;
case SIGP_SET_PREFIX:
run_on_cpu(CPU(dst_cpu), sigp_set_prefix, &si);
break;
struct kvm_s390_irq_state irq_state;
int r;
+ if (cpu->irqstate_saved_size == 0) {
+ return 0;
+ }
+
if (!kvm_check_extension(kvm_state, KVM_CAP_S390_IRQ_STATE)) {
return -ENOSYS;
}
- if (cpu->irqstate_saved_size == 0) {
- return 0;
- }
irq_state.buf = (uint64_t) cpu->irqstate;
irq_state.len = cpu->irqstate_saved_size;
route->u.adapter.adapter_id = pbdev->routes.adapter.adapter_id;
return 0;
}
+
+int kvm_arch_msi_data_to_gsi(uint32_t data)
+{
+ abort();
+}