Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * ucall support. A ucall is a "hypercall to userspace".
0004  *
0005  * Copyright (C) 2018, Red Hat, Inc.
0006  */
0007 #include "kvm_util.h"
0008 
0009 #define UCALL_PIO_PORT ((uint16_t)0x1000)
0010 
0011 void ucall_init(struct kvm_vm *vm, void *arg)
0012 {
0013 }
0014 
0015 void ucall_uninit(struct kvm_vm *vm)
0016 {
0017 }
0018 
0019 void ucall(uint64_t cmd, int nargs, ...)
0020 {
0021     struct ucall uc = {
0022         .cmd = cmd,
0023     };
0024     va_list va;
0025     int i;
0026 
0027     nargs = min(nargs, UCALL_MAX_ARGS);
0028 
0029     va_start(va, nargs);
0030     for (i = 0; i < nargs; ++i)
0031         uc.args[i] = va_arg(va, uint64_t);
0032     va_end(va);
0033 
0034     asm volatile("in %[port], %%al"
0035         : : [port] "d" (UCALL_PIO_PORT), "D" (&uc) : "rax", "memory");
0036 }
0037 
0038 uint64_t get_ucall(struct kvm_vcpu *vcpu, struct ucall *uc)
0039 {
0040     struct kvm_run *run = vcpu->run;
0041     struct ucall ucall = {};
0042 
0043     if (uc)
0044         memset(uc, 0, sizeof(*uc));
0045 
0046     if (run->exit_reason == KVM_EXIT_IO && run->io.port == UCALL_PIO_PORT) {
0047         struct kvm_regs regs;
0048 
0049         vcpu_regs_get(vcpu, &regs);
0050         memcpy(&ucall, addr_gva2hva(vcpu->vm, (vm_vaddr_t)regs.rdi),
0051                sizeof(ucall));
0052 
0053         vcpu_run_complete_io(vcpu);
0054         if (uc)
0055             memcpy(uc, &ucall, sizeof(ucall));
0056     }
0057 
0058     return ucall.cmd;
0059 }