aboutsummaryrefslogtreecommitdiff
path: root/hw/s390x/s390-hypercall.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/s390x/s390-hypercall.c')
-rw-r--r--hw/s390x/s390-hypercall.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/hw/s390x/s390-hypercall.c b/hw/s390x/s390-hypercall.c
new file mode 100644
index 0000000..ac1b08b
--- /dev/null
+++ b/hw/s390x/s390-hypercall.c
@@ -0,0 +1,85 @@
+/*
+ * Support for QEMU/KVM hypercalls on s390
+ *
+ * Copyright 2012 IBM Corp.
+ * Author(s): Cornelia Huck <cornelia.huck@de.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
+ * directory.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "hw/s390x/s390-virtio-ccw.h"
+#include "hw/s390x/s390-hypercall.h"
+#include "hw/s390x/ioinst.h"
+#include "hw/s390x/css.h"
+#include "virtio-ccw.h"
+
+static int handle_virtio_notify(uint64_t mem)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+
+ if (mem < ms->ram_size) {
+ /* Early printk */
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int handle_virtio_ccw_notify(uint64_t subch_id, uint64_t data)
+{
+ SubchDev *sch;
+ VirtIODevice *vdev;
+ int cssid, ssid, schid, m;
+ uint16_t vq_idx = data;
+
+ if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid)) {
+ return -EINVAL;
+ }
+ sch = css_find_subch(m, cssid, ssid, schid);
+ if (!sch || !css_subch_visible(sch)) {
+ return -EINVAL;
+ }
+
+ vdev = virtio_ccw_get_vdev(sch);
+ if (vq_idx >= VIRTIO_QUEUE_MAX || !virtio_queue_get_num(vdev, vq_idx)) {
+ return -EINVAL;
+ }
+
+ if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFICATION_DATA)) {
+ virtio_queue_set_shadow_avail_idx(virtio_get_queue(vdev, vq_idx),
+ (data >> 16) & 0xFFFF);
+ }
+
+ virtio_queue_notify(vdev, vq_idx);
+ return 0;
+}
+
+static uint64_t handle_storage_limit(void)
+{
+ S390CcwMachineState *s390ms = S390_CCW_MACHINE(qdev_get_machine());
+
+ return s390_get_memory_limit(s390ms) - 1;
+}
+
+void handle_diag_500(S390CPU *cpu, uintptr_t ra)
+{
+ CPUS390XState *env = &cpu->env;
+ const uint64_t subcode = env->regs[1];
+
+ switch (subcode) {
+ case DIAG500_VIRTIO_NOTIFY:
+ env->regs[2] = handle_virtio_notify(env->regs[2]);
+ break;
+ case DIAG500_VIRTIO_CCW_NOTIFY:
+ env->regs[2] = handle_virtio_ccw_notify(env->regs[2], env->regs[3]);
+ break;
+ case DIAG500_STORAGE_LIMIT:
+ env->regs[2] = handle_storage_limit();
+ break;
+ default:
+ s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+ }
+}