xref: /qemu/hw/s390x/s390-hypercall.c (revision 513823e7521a09ed7ad1e32e6454bac3b2cbf52d)
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 
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 
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 
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 
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