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 "cpu.h"
14 #include "hw/s390x/s390-virtio-ccw.h"
15 #include "hw/s390x/s390-hypercall.h"
16 #include "hw/s390x/ioinst.h"
17 #include "hw/s390x/css.h"
18 #include "virtio-ccw.h"
19
handle_virtio_notify(uint64_t mem)20 static int handle_virtio_notify(uint64_t mem)
21 {
22 MachineState *ms = MACHINE(qdev_get_machine());
23
24 if (mem < ms->ram_size) {
25 /* Early printk */
26 return 0;
27 }
28 return -EINVAL;
29 }
30
handle_virtio_ccw_notify(uint64_t subch_id,uint64_t data)31 static int handle_virtio_ccw_notify(uint64_t subch_id, uint64_t data)
32 {
33 SubchDev *sch;
34 VirtIODevice *vdev;
35 int cssid, ssid, schid, m;
36 uint16_t vq_idx = data;
37
38 if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid)) {
39 return -EINVAL;
40 }
41 sch = css_find_subch(m, cssid, ssid, schid);
42 if (!sch || !css_subch_visible(sch)) {
43 return -EINVAL;
44 }
45
46 vdev = virtio_ccw_get_vdev(sch);
47 if (vq_idx >= VIRTIO_QUEUE_MAX || !virtio_queue_get_num(vdev, vq_idx)) {
48 return -EINVAL;
49 }
50
51 if (virtio_vdev_has_feature(vdev, VIRTIO_F_NOTIFICATION_DATA)) {
52 virtio_queue_set_shadow_avail_idx(virtio_get_queue(vdev, vq_idx),
53 (data >> 16) & 0xFFFF);
54 }
55
56 virtio_queue_notify(vdev, vq_idx);
57 return 0;
58 }
59
handle_storage_limit(void)60 static uint64_t handle_storage_limit(void)
61 {
62 S390CcwMachineState *s390ms = S390_CCW_MACHINE(qdev_get_machine());
63
64 return s390_get_memory_limit(s390ms) - 1;
65 }
66
handle_diag_500(S390CPU * cpu,uintptr_t ra)67 void handle_diag_500(S390CPU *cpu, uintptr_t ra)
68 {
69 CPUS390XState *env = &cpu->env;
70 const uint64_t subcode = env->regs[1];
71
72 switch (subcode) {
73 case DIAG500_VIRTIO_NOTIFY:
74 env->regs[2] = handle_virtio_notify(env->regs[2]);
75 break;
76 case DIAG500_VIRTIO_CCW_NOTIFY:
77 env->regs[2] = handle_virtio_ccw_notify(env->regs[2], env->regs[3]);
78 break;
79 case DIAG500_STORAGE_LIMIT:
80 env->regs[2] = handle_storage_limit();
81 break;
82 default:
83 s390_program_interrupt(env, PGM_SPECIFICATION, ra);
84 }
85 }
86