Skip to content

Commit 2e0beb3

Browse files
authored
Merge pull request #210 from jaszczyk-grzegorz/hypercall-improvements
Improve pKVM hypercalls
2 parents 3967727 + 2e7b9ce commit 2e0beb3

File tree

1 file changed

+46
-35
lines changed

1 file changed

+46
-35
lines changed

src/transport/x86_64/hypercalls.rs

Lines changed: 46 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ const KVM_CPUID_SIGNATURE: u32 = 0x40000000;
99

1010
// See `include/uapi/linux/kvm_para.h`. (These hypercalls numbers can change depending on the
1111
// upstream progress.)
12-
const KVM_HC_PKVM_OP: u32 = 20;
13-
const PKVM_GHC_IOREAD: u32 = KVM_HC_PKVM_OP + 3;
14-
const PKVM_GHC_IOWRITE: u32 = KVM_HC_PKVM_OP + 4;
12+
const KVM_HC_PKVM_OP: u64 = 20;
13+
const PKVM_GHC_IOREAD: u64 = KVM_HC_PKVM_OP + 3;
14+
const PKVM_GHC_IOWRITE: u64 = KVM_HC_PKVM_OP + 4;
1515

1616
/// The maximum number of bytes that can be read or written by a single IO hypercall.
1717
const HYP_IO_MAX: usize = 8;
@@ -42,48 +42,59 @@ pub fn cpuid_signature() -> [u8; 4] {
4242
signature.to_le_bytes()
4343
}
4444

45-
/// Asks the hypervisor to perform an IO read at the given physical address.
46-
pub fn hyp_io_read(address: u64, size: usize) -> u64 {
47-
let data;
45+
fn __vmcall_impl(hypcall: u64, a1: u64, a2: u64, a3: u64, a4: u64) -> u64 {
46+
let ret: u64;
4847

49-
// SAFETY: Assembly call. Arguments for vmcall are passed via rax, rbx, rcx and rdx. Ideally
50-
// using a named argument in the inline asm for rbx would be more straightforward, but when
51-
// "rbx" is used directly LLVM complains that it is used internally.
48+
// SAFETY: Assembly call. Arguments for vmcall are passed via rax, rbx, rcx, rdx and rsi.
49+
// Ideally using a named argument in the inline asm for rbx would be more straightforward,
50+
// but when "rbx" is used directly LLVM complains that it is used internally.
5251
//
53-
// Therefore use r8 temporary, push rbx to the stack, perform proper call and pop rbx again.
52+
// Therefore use temp register to store rbx content and restore it back afterwards.
5453
unsafe {
5554
asm!(
56-
"push rbx",
57-
"mov rbx, r8",
55+
"xchg %rbx, {0:r}",
5856
"vmcall",
59-
"pop rbx",
60-
inout("rax") u64::from(PKVM_GHC_IOREAD) => data,
61-
in("r8") address,
62-
in("rcx") size,
57+
"xchg %rbx, {0:r}",
58+
in(reg) a1,
59+
inout("rax") hypcall => ret,
60+
in("rcx") a2,
61+
in("rdx") a3,
62+
in("rsi") a4,
63+
options(att_syntax)
6364
);
64-
}
65-
data
65+
};
66+
ret
67+
}
68+
69+
// This block uses inline assembly to perform a vmcall, interacting directly with the hypervisor.
70+
// The pKVM hypervisor can share RAX/RBX/RCX/RDX/RSI with pKVM host during hypercall
71+
// handling.
72+
macro_rules! vmcall {
73+
($hypcall:expr) => {
74+
__vmcall_impl($hypcall, 0, 0, 0, 0)
75+
};
76+
($hypcall:expr, $a1:expr) => {
77+
__vmcall_impl($hypcall, $a1, 0, 0, 0)
78+
};
79+
($hypcall:expr, $a1:expr, $a2:expr) => {
80+
__vmcall_impl($hypcall, $a1, $a2, 0, 0)
81+
};
82+
($hypcall:expr, $a1:expr, $a2:expr, $a3:expr) => {
83+
__vmcall_impl($hypcall, $a1, $a2, $a3, 0)
84+
};
85+
($hypcall:expr, $a1:expr, $a2:expr, $a3:expr, $a4:expr) => {
86+
__vmcall_impl($hypcall, $a1, $a2, $a3, $a4)
87+
};
88+
}
89+
90+
/// Asks the hypervisor to perform an IO read at the given physical address.
91+
pub fn hyp_io_read(address: u64, size: usize) -> u64 {
92+
vmcall!(PKVM_GHC_IOREAD, address, size as u64)
6693
}
6794

6895
/// Asks the hypervisor to perform an IO write at the given physical address.
6996
pub fn hyp_io_write(address: u64, size: usize, data: u64) {
70-
// SAFETY: Assembly call. Arguments for vmcall are passed via rax, rbx, rcx and rdx. Ideally
71-
// using a named argument in the inline asm for rbx would be more straightforward but when
72-
// "rbx" is used directly used LLVM complains that it is used internally.
73-
//
74-
// Therefore use r8 temporary, push rbx to the stack, perform proper call and pop rbx again.
75-
unsafe {
76-
asm!(
77-
"push rbx",
78-
"mov rbx, r8",
79-
"vmcall",
80-
"pop rbx",
81-
in("rax") PKVM_GHC_IOWRITE,
82-
in("r8") address,
83-
in("rcx") size,
84-
in("rdx") data,
85-
);
86-
}
97+
vmcall!(PKVM_GHC_IOWRITE, address, size as u64, data);
8798
}
8899

89100
/// A region of physical address space which may be accessed by IO read and/or write hypercalls.

0 commit comments

Comments
 (0)