1 //! Hypercalls for x86-64 pKVM.
2
3 use core::arch::asm;
4 use zerocopy::{FromBytes, Immutable, IntoBytes};
5
6 /// This CPUID returns the signature and should be used to determine if VM is running under pKVM,
7 /// KVM or not. See the Linux header `arch/x86/include/uapi/asm/kvm_para.h`.
8 const KVM_CPUID_SIGNATURE: u32 = 0x40000000;
9
10 // See `include/uapi/linux/kvm_para.h`. (These hypercalls numbers can change depending on the
11 // 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;
15
16 /// The maximum number of bytes that can be read or written by a single IO hypercall.
17 const HYP_IO_MAX: usize = 8;
18
19 /// Gets the signature CPU ID.
cpuid_signature() -> [u8; 4]20 pub fn cpuid_signature() -> [u8; 4] {
21 let signature: u32;
22 unsafe {
23 // The argument for cpuid is passed via rax and in case of KVM_CPUID_SIGNATURE returned via
24 // rbx, rcx and rdx. Ideally using a named argument in inline asm for rbx would be more
25 // straightforward, but when "rbx" is directly used LLVM complains that it is used
26 // internally.
27 //
28 // Therefore use r8 instead and push rbx to the stack before making cpuid call, store
29 // rbx content to r8 as use it as inline asm output and pop the rbx.
30 asm!(
31 "push rbx",
32 "cpuid",
33 "mov r8, rbx",
34 "pop rbx",
35 in("eax") KVM_CPUID_SIGNATURE,
36 out("r8") signature,
37 out("rcx") _,
38 out("rdx") _,
39 );
40 };
41 signature.to_le_bytes()
42 }
43
44 /// Asks the hypervisor to perform an IO read at the given physical address.
hyp_io_read(address: usize, size: usize) -> u6445 pub fn hyp_io_read(address: usize, size: usize) -> u64 {
46 // Arguments for vmcall are passed via rax, rbx, rcx and rdx. Ideally using a named argument in
47 // the inline asm for rbx would be more straightforward, but when "rbx" is used directly LLVM
48 // complains that it is used internally.
49 //
50 // Therefore use r8 temporary, push rbx to the stack, perform proper call and pop rbx
51 // again
52 let data;
53 unsafe {
54 asm!(
55 "push rbx",
56 "mov rbx, r8",
57 "vmcall",
58 "pop rbx",
59 inout("rax") u64::from(PKVM_GHC_IOREAD) => data,
60 in("r8") address,
61 in("rcx") size,
62 );
63 }
64 data
65 }
66
67 /// Asks the hypervisor to perform an IO write at the given physical address.
hyp_io_write(address: usize, size: usize, data: u64)68 pub fn hyp_io_write(address: usize, size: usize, data: u64) {
69 unsafe {
70 // Arguments for vmcall are passed via rax, rbx, rcx and rdx. Ideally using a named argument
71 // in the inline asm for rbx would be more straightforward but when "rbx" is used directly
72 // 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
75 // again
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 }
87 }
88
89 /// A region of physical address space which may be accessed by IO read and/or write hypercalls.
90 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
91 pub struct HypIoRegion {
92 /// The physical address of the start of the IO region.
93 pub paddr: usize,
94 /// The size of the IO region in bytes.
95 pub size: usize,
96 }
97
98 impl HypIoRegion {
read<T: FromBytes>(self, offset: usize) -> T99 pub fn read<T: FromBytes>(self, offset: usize) -> T {
100 assert!(offset + size_of::<T>() <= self.size);
101 assert!(size_of::<T>() <= HYP_IO_MAX);
102
103 let data = hyp_io_read(self.paddr + offset, size_of::<T>());
104 T::read_from_prefix(data.as_bytes()).unwrap().0
105 }
106
write<T: IntoBytes + Immutable>(self, offset: usize, value: T)107 pub fn write<T: IntoBytes + Immutable>(self, offset: usize, value: T) {
108 assert!(offset + size_of::<T>() <= self.size);
109 assert!(size_of::<T>() <= HYP_IO_MAX);
110
111 let mut data = 0;
112 data.as_mut_bytes()[..size_of::<T>()].copy_from_slice(value.as_bytes());
113 hyp_io_write(self.paddr + offset, size_of::<T>(), data);
114 }
115 }
116