openhcl_boot/arch/x86_64/
hypercall.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use core::ptr::addr_of;
5use hvdef::HV_PAGE_SIZE;
6use hvdef::hypercall::HvGuestOsMicrosoft;
7use minimal_rt::arch::hypercall::HYPERCALL_PAGE;
8use minimal_rt::arch::msr::read_msr;
9use minimal_rt::arch::msr::write_msr;
10
11fn report_os_id(guest_os_id: HvGuestOsMicrosoft) {
12    // SAFETY: Using the contract established in the Hyper-V TLFS.
13    unsafe {
14        write_msr(hvdef::HV_X64_MSR_GUEST_OS_ID, guest_os_id.into());
15    };
16}
17
18/// Writes an MSR to tell the hypervisor where the hypercall page is
19fn write_hypercall_msr(enable: bool) {
20    // SAFETY: Using the contract established in the Hyper-V TLFS.
21    let hypercall_contents = hvdef::hypercall::MsrHypercallContents::from(unsafe {
22        read_msr(hvdef::HV_X64_MSR_HYPERCALL)
23    });
24
25    let hypercall_page_num = addr_of!(HYPERCALL_PAGE) as u64 / HV_PAGE_SIZE;
26
27    assert!(
28        !enable || !hypercall_contents.enable(),
29        "{:?}",
30        hypercall_contents
31    );
32    let new_hv_contents = hypercall_contents.with_enable(enable).with_gpn(if enable {
33        hypercall_page_num
34    } else {
35        0
36    });
37
38    // SAFETY: Using the contract established in the Hyper-V TLFS.
39    unsafe { write_msr(hvdef::HV_X64_MSR_HYPERCALL, new_hv_contents.into()) };
40}
41
42/// Has to be called before using hypercalls.
43pub(crate) fn initialize(guest_os_id: HvGuestOsMicrosoft) {
44    // TODO: For now, we are assuming we are running under a Microsoft hypervisor, so there is
45    // no need to check any cpuid leaves.
46    report_os_id(guest_os_id);
47    write_hypercall_msr(true);
48}
49
50/// Call before jumping to kernel.
51pub(crate) fn uninitialize() {
52    write_hypercall_msr(false);
53    report_os_id(0.into());
54}