12040f414SThomas Huth // SPDX-License-Identifier: GPL-2.0
22040f414SThomas Huth /*
32040f414SThomas Huth * ucall support. A ucall is a "hypercall to userspace".
42040f414SThomas Huth *
52040f414SThomas Huth * Copyright (C) 2018, Red Hat, Inc.
62040f414SThomas Huth */
72040f414SThomas Huth #include "kvm_util.h"
82040f414SThomas Huth
92040f414SThomas Huth #define UCALL_PIO_PORT ((uint16_t)0x1000)
102040f414SThomas Huth
ucall_arch_do_ucall(vm_vaddr_t uc)1170466381SSean Christopherson void ucall_arch_do_ucall(vm_vaddr_t uc)
122040f414SThomas Huth {
13*6783ca41SSean Christopherson /*
14*6783ca41SSean Christopherson * FIXME: Revert this hack (the entire commit that added it) once nVMX
15*6783ca41SSean Christopherson * preserves L2 GPRs across a nested VM-Exit. If a ucall from L2, e.g.
16*6783ca41SSean Christopherson * to do a GUEST_SYNC(), lands the vCPU in L1, any and all GPRs can be
17*6783ca41SSean Christopherson * clobbered by L1. Save and restore non-volatile GPRs (clobbering RBP
18*6783ca41SSean Christopherson * in particular is problematic) along with RDX and RDI (which are
19*6783ca41SSean Christopherson * inputs), and clobber volatile GPRs. *sigh*
20*6783ca41SSean Christopherson */
21*6783ca41SSean Christopherson #define HORRIFIC_L2_UCALL_CLOBBER_HACK \
22*6783ca41SSean Christopherson "rcx", "rsi", "r8", "r9", "r10", "r11"
23*6783ca41SSean Christopherson
24*6783ca41SSean Christopherson asm volatile("push %%rbp\n\t"
25*6783ca41SSean Christopherson "push %%r15\n\t"
26*6783ca41SSean Christopherson "push %%r14\n\t"
27*6783ca41SSean Christopherson "push %%r13\n\t"
28*6783ca41SSean Christopherson "push %%r12\n\t"
29*6783ca41SSean Christopherson "push %%rbx\n\t"
30*6783ca41SSean Christopherson "push %%rdx\n\t"
31*6783ca41SSean Christopherson "push %%rdi\n\t"
32*6783ca41SSean Christopherson "in %[port], %%al\n\t"
33*6783ca41SSean Christopherson "pop %%rdi\n\t"
34*6783ca41SSean Christopherson "pop %%rdx\n\t"
35*6783ca41SSean Christopherson "pop %%rbx\n\t"
36*6783ca41SSean Christopherson "pop %%r12\n\t"
37*6783ca41SSean Christopherson "pop %%r13\n\t"
38*6783ca41SSean Christopherson "pop %%r14\n\t"
39*6783ca41SSean Christopherson "pop %%r15\n\t"
40*6783ca41SSean Christopherson "pop %%rbp\n\t"
41*6783ca41SSean Christopherson : : [port] "d" (UCALL_PIO_PORT), "D" (uc) : "rax", "memory",
42*6783ca41SSean Christopherson HORRIFIC_L2_UCALL_CLOBBER_HACK);
432040f414SThomas Huth }
442040f414SThomas Huth
ucall_arch_get_ucall(struct kvm_vcpu * vcpu)45ef38871eSSean Christopherson void *ucall_arch_get_ucall(struct kvm_vcpu *vcpu)
462040f414SThomas Huth {
47768e9a61SSean Christopherson struct kvm_run *run = vcpu->run;
4885f2a432SAaron Lewis
492040f414SThomas Huth if (run->exit_reason == KVM_EXIT_IO && run->io.port == UCALL_PIO_PORT) {
502040f414SThomas Huth struct kvm_regs regs;
512040f414SThomas Huth
52768e9a61SSean Christopherson vcpu_regs_get(vcpu, ®s);
53426729b2SPeter Gonda return (void *)regs.rdi;
542040f414SThomas Huth }
55ef38871eSSean Christopherson return NULL;
562040f414SThomas Huth }
57