Skip to content

Commit

Permalink
Move pKVM hypercalls to a submodule.
Browse files Browse the repository at this point in the history
  • Loading branch information
qwandor committed Dec 4, 2024
1 parent 27e705b commit 64abe3d
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 81 deletions.
84 changes: 3 additions & 81 deletions src/transport/x86_64.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! x86-64 specific transports.
mod hypercalls;

use super::{
pci::{
bus::{Cam, ConfigurationAccess, DeviceFunction, PciRoot, PCI_CAP_ID_VNDR},
Expand All @@ -14,19 +16,9 @@ use crate::{
hal::{Hal, PhysAddr},
Error,
};
use core::arch::asm;
use hypercalls::{cpuid_signature, hyp_io_read, hyp_io_write};
use zerocopy::{FromBytes, Immutable, IntoBytes};

/// This CPUID returns the signature and should be used to determine if VM is running under pKVM,
/// KVM or not. See the Linux header `arch/x86/include/uapi/asm/kvm_para.h`.
const KVM_CPUID_SIGNATURE: u32 = 0x40000000;

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

const PKVM_SIGNATURE: &[u8] = b"PKVM";

/// The maximum number of bytes that can be read or written by a single IO hypercall.
Expand Down Expand Up @@ -365,76 +357,6 @@ fn get_bar_region<H: Hal, T, C: ConfigurationAccess>(
})
}

/// Gets the signature CPU ID.
fn cpuid_signature() -> [u8; 4] {
let signature: u32;
unsafe {
// The argument for cpuid is passed via rax and in case of KVM_CPUID_SIGNATURE returned via
// rbx, rcx and rdx. Ideally using a named argument in inline asm for rbx would be more
// straightforward, but when "rbx" is directly used LLVM complains that it is used
// internally.
//
// Therefore use r8 instead and push rbx to the stack before making cpuid call, store
// rbx content to r8 as use it as inline asm output and pop the rbx.
asm!(
"push rbx",
"cpuid",
"mov r8, rbx",
"pop rbx",
in("eax") KVM_CPUID_SIGNATURE,
out("r8") signature,
out("rcx") _,
out("rdx") _,
);
};
signature.to_le_bytes()
}

/// Asks the hypervisor to perform an IO read at the given physical address.
fn hyp_io_read(address: usize, size: usize) -> u64 {
// Arguments for vmcall are passed via rax, rbx, rcx and rdx. Ideally using a named argument in
// the inline asm for rbx would be more straightforward, but when "rbx" is used directly LLVM
// complains that it is used internally.
//
// Therefore use r8 temporary, push rbx to the stack, perform proper call and pop rbx
// again
let data;
unsafe {
asm!(
"push rbx",
"mov rbx, r8",
"vmcall",
"pop rbx",
inout("rax") u64::from(PKVM_GHC_IOREAD) => data,
in("r8") address,
in("rcx") size,
);
}
data
}

/// Asks the hypervisor to perform an IO write at the given physical address.
fn hyp_io_write(address: usize, size: usize, data: u64) {
unsafe {
// Arguments for vmcall are passed via rax, rbx, rcx and rdx. Ideally using a named argument
// in the inline asm for rbx would be more straightforward but when "rbx" is used directly
// used LLVM complains that it is used internally.
//
// Therefore use r8 temporary, push rbx to the stack, perform proper call and pop rbx
// again
asm!(
"push rbx",
"mov rbx, r8",
"vmcall",
"pop rbx",
in("rax") PKVM_GHC_IOWRITE,
in("r8") address,
in("rcx") size,
in("rdx") data,
);
}
}

/// A region of physical address space which may be accessed by IO read and/or write hypercalls.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct HypIoRegion {
Expand Down
83 changes: 83 additions & 0 deletions src/transport/x86_64/hypercalls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//! Hypercalls for x86-64 pKVM.
use core::arch::asm;

/// This CPUID returns the signature and should be used to determine if VM is running under pKVM,
/// KVM or not. See the Linux header `arch/x86/include/uapi/asm/kvm_para.h`.
const KVM_CPUID_SIGNATURE: u32 = 0x40000000;

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

/// Gets the signature CPU ID.
pub fn cpuid_signature() -> [u8; 4] {
let signature: u32;
unsafe {
// The argument for cpuid is passed via rax and in case of KVM_CPUID_SIGNATURE returned via
// rbx, rcx and rdx. Ideally using a named argument in inline asm for rbx would be more
// straightforward, but when "rbx" is directly used LLVM complains that it is used
// internally.
//
// Therefore use r8 instead and push rbx to the stack before making cpuid call, store
// rbx content to r8 as use it as inline asm output and pop the rbx.
asm!(
"push rbx",
"cpuid",
"mov r8, rbx",
"pop rbx",
in("eax") KVM_CPUID_SIGNATURE,
out("r8") signature,
out("rcx") _,
out("rdx") _,
);
};
signature.to_le_bytes()
}

/// Asks the hypervisor to perform an IO read at the given physical address.
pub fn hyp_io_read(address: usize, size: usize) -> u64 {
// Arguments for vmcall are passed via rax, rbx, rcx and rdx. Ideally using a named argument in
// the inline asm for rbx would be more straightforward, but when "rbx" is used directly LLVM
// complains that it is used internally.
//
// Therefore use r8 temporary, push rbx to the stack, perform proper call and pop rbx
// again
let data;
unsafe {
asm!(
"push rbx",
"mov rbx, r8",
"vmcall",
"pop rbx",
inout("rax") u64::from(PKVM_GHC_IOREAD) => data,
in("r8") address,
in("rcx") size,
);
}
data
}

/// Asks the hypervisor to perform an IO write at the given physical address.
pub fn hyp_io_write(address: usize, size: usize, data: u64) {
unsafe {
// Arguments for vmcall are passed via rax, rbx, rcx and rdx. Ideally using a named argument
// in the inline asm for rbx would be more straightforward but when "rbx" is used directly
// used LLVM complains that it is used internally.
//
// Therefore use r8 temporary, push rbx to the stack, perform proper call and pop rbx
// again
asm!(
"push rbx",
"mov rbx, r8",
"vmcall",
"pop rbx",
in("rax") PKVM_GHC_IOWRITE,
in("r8") address,
in("rcx") size,
in("rdx") data,
);
}
}

0 comments on commit 64abe3d

Please sign in to comment.