summaryrefslogtreecommitdiffstats
path: root/target/s390x/kvm.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/s390x/kvm.c')
-rw-r--r--target/s390x/kvm.c79
1 files changed, 72 insertions, 7 deletions
diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c
index 7f7ebab842..69881a0da0 100644
--- a/target/s390x/kvm.c
+++ b/target/s390x/kvm.c
@@ -50,6 +50,7 @@
#include "exec/memattrs.h"
#include "hw/s390x/s390-virtio-ccw.h"
#include "hw/s390x/s390-virtio-hcall.h"
+#include "hw/s390x/pv.h"
#ifndef DEBUG_KVM
#define DEBUG_KVM 0
@@ -115,6 +116,8 @@
#define ICPT_CPU_STOP 0x28
#define ICPT_OPEREXC 0x2c
#define ICPT_IO 0x40
+#define ICPT_PV_INSTR 0x68
+#define ICPT_PV_INSTR_NOTIFICATION 0x6c
#define NR_LOCAL_IRQS 32
/*
@@ -152,6 +155,7 @@ static int cap_ri;
static int cap_gs;
static int cap_hpage_1m;
static int cap_vcpu_resets;
+static int cap_protected;
static int active_cmma;
@@ -321,6 +325,11 @@ void kvm_s390_set_max_pagesize(uint64_t pagesize, Error **errp)
cap_hpage_1m = 1;
}
+int kvm_s390_get_hpage_1m(void)
+{
+ return cap_hpage_1m;
+}
+
static void ccw_machine_class_foreach(ObjectClass *oc, void *opaque)
{
MachineClass *mc = MACHINE_CLASS(oc);
@@ -344,6 +353,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
cap_mem_op = kvm_check_extension(s, KVM_CAP_S390_MEM_OP);
cap_s390_irq = kvm_check_extension(s, KVM_CAP_S390_INJECT_IRQ);
cap_vcpu_resets = kvm_check_extension(s, KVM_CAP_S390_VCPU_RESETS);
+ cap_protected = kvm_check_extension(s, KVM_CAP_S390_PROTECTED);
if (!kvm_check_extension(s, KVM_CAP_S390_GMAP)
|| !kvm_check_extension(s, KVM_CAP_S390_COW)) {
@@ -844,6 +854,30 @@ int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf,
return ret;
}
+int kvm_s390_mem_op_pv(S390CPU *cpu, uint64_t offset, void *hostbuf,
+ int len, bool is_write)
+{
+ struct kvm_s390_mem_op mem_op = {
+ .sida_offset = offset,
+ .size = len,
+ .op = is_write ? KVM_S390_MEMOP_SIDA_WRITE
+ : KVM_S390_MEMOP_SIDA_READ,
+ .buf = (uint64_t)hostbuf,
+ };
+ int ret;
+
+ if (!cap_mem_op || !cap_protected) {
+ return -ENOSYS;
+ }
+
+ ret = kvm_vcpu_ioctl(CPU(cpu), KVM_S390_MEM_OP, &mem_op);
+ if (ret < 0) {
+ error_report("KVM_S390_MEM_OP failed: %s", strerror(-ret));
+ abort();
+ }
+ return ret;
+}
+
/*
* Legacy layout for s390:
* Older S390 KVM requires the topmost vma of the RAM to be
@@ -1199,12 +1233,27 @@ static void kvm_sclp_service_call(S390CPU *cpu, struct kvm_run *run,
sccb = env->regs[ipbh0 & 0xf];
code = env->regs[(ipbh0 & 0xf0) >> 4];
- r = sclp_service_call(env, sccb, code);
- if (r < 0) {
- kvm_s390_program_interrupt(cpu, -r);
- return;
+ switch (run->s390_sieic.icptcode) {
+ case ICPT_PV_INSTR_NOTIFICATION:
+ g_assert(s390_is_pv());
+ /* The notification intercepts are currently handled by KVM */
+ error_report("unexpected SCLP PV notification");
+ exit(1);
+ break;
+ case ICPT_PV_INSTR:
+ g_assert(s390_is_pv());
+ sclp_service_call_protected(env, sccb, code);
+ /* Setting the CC is done by the Ultravisor. */
+ break;
+ case ICPT_INSTRUCTION:
+ g_assert(!s390_is_pv());
+ r = sclp_service_call(env, sccb, code);
+ if (r < 0) {
+ kvm_s390_program_interrupt(cpu, -r);
+ return;
+ }
+ setcc(cpu, r);
}
- setcc(cpu, r);
}
static int handle_b2(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
@@ -1693,6 +1742,8 @@ static int handle_intercept(S390CPU *cpu)
(long)cs->kvm_run->psw_addr);
switch (icpt_code) {
case ICPT_INSTRUCTION:
+ case ICPT_PV_INSTR:
+ case ICPT_PV_INSTR_NOTIFICATION:
r = handle_instruction(cpu, run);
break;
case ICPT_PROGRAM:
@@ -1773,7 +1824,9 @@ static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar)
SysIB_322 sysib;
int del, i;
- if (s390_cpu_virt_mem_read(cpu, addr, ar, &sysib, sizeof(sysib))) {
+ if (s390_is_pv()) {
+ s390_cpu_pv_mem_read(cpu, 0, &sysib, sizeof(sysib));
+ } else if (s390_cpu_virt_mem_read(cpu, addr, ar, &sysib, sizeof(sysib))) {
return;
}
/* Shift the stack of Extended Names to prepare for our own data */
@@ -1826,7 +1879,11 @@ static void insert_stsi_3_2_2(S390CPU *cpu, __u64 addr, uint8_t ar)
/* Insert UUID */
memcpy(sysib.vm[0].uuid, &qemu_uuid, sizeof(sysib.vm[0].uuid));
- s390_cpu_virt_mem_write(cpu, addr, ar, &sysib, sizeof(sysib));
+ if (s390_is_pv()) {
+ s390_cpu_pv_mem_write(cpu, 0, &sysib, sizeof(sysib));
+ } else {
+ s390_cpu_virt_mem_write(cpu, addr, ar, &sysib, sizeof(sysib));
+ }
}
static int handle_stsi(S390CPU *cpu)
@@ -2368,6 +2425,14 @@ void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp)
clear_bit(S390_FEAT_BPB, model->features);
}
+ /*
+ * If we have support for protected virtualization, indicate
+ * the protected virtualization IPL unpack facility.
+ */
+ if (cap_protected) {
+ set_bit(S390_FEAT_UNPACK, model->features);
+ }
+
/* We emulate a zPCI bus and AEN, therefore we don't need HW support */
set_bit(S390_FEAT_ZPCI, model->features);
set_bit(S390_FEAT_ADAPTER_EVENT_NOTIFICATION, model->features);