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, &regs);
53426729b2SPeter Gonda 		return (void *)regs.rdi;
542040f414SThomas Huth 	}
55ef38871eSSean Christopherson 	return NULL;
562040f414SThomas Huth }
57