1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * ucall support. A ucall is a "hypercall to userspace". 4 * 5 * Copyright (C) 2019 Red Hat, Inc. 6 */ 7 #include "kvm_util.h" 8 9 void ucall_init(struct kvm_vm *vm, void *arg) 10 { 11 } 12 13 void ucall_uninit(struct kvm_vm *vm) 14 { 15 } 16 17 void ucall(uint64_t cmd, int nargs, ...) 18 { 19 struct ucall uc = { 20 .cmd = cmd, 21 }; 22 va_list va; 23 int i; 24 25 nargs = nargs <= UCALL_MAX_ARGS ? nargs : UCALL_MAX_ARGS; 26 27 va_start(va, nargs); 28 for (i = 0; i < nargs; ++i) 29 uc.args[i] = va_arg(va, uint64_t); 30 va_end(va); 31 32 /* Exit via DIAGNOSE 0x501 (normally used for breakpoints) */ 33 asm volatile ("diag 0,%0,0x501" : : "a"(&uc) : "memory"); 34 } 35 36 uint64_t get_ucall(struct kvm_vm *vm, uint32_t vcpu_id, struct ucall *uc) 37 { 38 struct kvm_run *run = vcpu_state(vm, vcpu_id); 39 struct ucall ucall = {}; 40 41 if (uc) 42 memset(uc, 0, sizeof(*uc)); 43 44 if (run->exit_reason == KVM_EXIT_S390_SIEIC && 45 run->s390_sieic.icptcode == 4 && 46 (run->s390_sieic.ipa >> 8) == 0x83 && /* 0x83 means DIAGNOSE */ 47 (run->s390_sieic.ipb >> 16) == 0x501) { 48 int reg = run->s390_sieic.ipa & 0xf; 49 50 memcpy(&ucall, addr_gva2hva(vm, run->s.regs.gprs[reg]), 51 sizeof(ucall)); 52 53 vcpu_run_complete_io(vm, vcpu_id); 54 if (uc) 55 memcpy(uc, &ucall, sizeof(ucall)); 56 } 57 58 return ucall.cmd; 59 } 60