master
c 99 lines 2.91 KB
Raw
1 /*
2 * Support for QEMU/KVM hypercalls on s390
3 *
4 * Copyright 2012 IBM Corp.
5 * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
6 *
7 * This work is licensed under the terms of the GNU GPL, version 2 or (at
8 * your option) any later version. See the COPYING file in the top-level
9 * directory.
10 */
11
12 #include "qemu/osdep.h"
13 #include "qemu/error-report.h"
14 #include "target/s390x/cpu.h"
15 #include "hw/s390x/s390-virtio-ccw.h"
16 #include "hw/s390x/s390-hypercall.h"
17 #include "hw/s390x/ioinst.h"
18 #include "hw/s390x/css.h"
19 #include "virtio-ccw.h"
20
21 static int handle_virtio_notify(uint64_t mem)
22 {
23 MachineState *ms = MACHINE(qdev_get_machine());
24
25 if (mem < ms->ram_size) {
26 /* Early printk */
27 return 0;
28 }
29 return -EINVAL;
30 }
31
32 static int handle_virtio_ccw_notify(uint64_t subch_id, uint64_t data)
33 {
34 SubchDev *sch;
35 VirtIODevice *vdev;
36 int cssid, ssid, schid, m;
37 uint16_t vq_idx = data;
38
39 if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid)) {
40 return -EINVAL;
41 }
42 sch = css_find_subch(m, cssid, ssid, schid);
43 if (!sch || !css_subch_visible(sch)) {
44 return -EINVAL;
45 }
46 if (sch->id.cu_type != VIRTIO_CCW_CU_TYPE) {
47 /*
48 * This might happen in nested setups: If the L1 host defined the
49 * L2 guest with a virtio device (e.g. virtio-keyboard), and the
50 * L2 guest passes this device through to the L3 guest, the L3 guest
51 * might send virtio notifications to the QEMU in L2 for that device.
52 * But since the QEMU in L2 defined this device as vfio-ccw, it's not
53 * a VirtIODevice that we can handle here!
54 */
55 warn_report_once("Got virtio notification for unsupported device "
56 "on subchannel %02x.%1x.%04x!", cssid, ssid, schid);
57 return -EINVAL;
58 }
59
60 vdev = virtio_ccw_get_vdev(sch);
61 if (vq_idx >= VIRTIO_QUEUE_MAX || !virtio_queue_get_num(vdev, vq_idx)) {
62 return -EINVAL;
63 }
64
65 if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFICATION_DATA)) {
66 virtio_queue_set_shadow_avail_idx(virtio_get_queue(vdev, vq_idx),
67 (data >> 16) & 0xFFFF);
68 }
69
70 virtio_queue_notify(vdev, vq_idx);
71 return 0;
72 }
73
74 static uint64_t handle_storage_limit(void)
75 {
76 S390CcwMachineState *s390ms = S390_CCW_MACHINE(qdev_get_machine());
77
78 return s390_get_memory_limit(s390ms) - 1;
79 }
80
81 void handle_diag_500(S390CPU *cpu, uintptr_t ra)
82 {
83 CPUS390XState *env = &cpu->env;
84 const uint64_t subcode = env->regs[1];
85
86 switch (subcode) {
87 case DIAG500_VIRTIO_NOTIFY:
88 env->regs[2] = handle_virtio_notify(env->regs[2]);
89 break;
90 case DIAG500_VIRTIO_CCW_NOTIFY:
91 env->regs[2] = handle_virtio_ccw_notify(env->regs[2], env->regs[3]);
92 break;
93 case DIAG500_STORAGE_LIMIT:
94 env->regs[2] = handle_storage_limit();
95 break;
96 default:
97 s390_program_interrupt(env, PGM_SPECIFICATION, ra);
98 }
99 }