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