microsoft/openvmm

Public

mirrored fromhttps://github.com/microsoft/openvmmAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
e8c4f2e8ffc1914ac7dab5e566370609f1f37cd7

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

openhcl/minimal_rt/src/enlightened_panic.rs

80lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Enlightened panic for a Hyper-V guest.
5
6//! Hyper-V guests may choose to report a crash to the Hyper-V host
7//! via a set of MSRs (x64) or synthetic crash registers on ARM.
8//! The registers carry crash-specific information and may optionally
9//! include a message buffer.
10
11use crate::arch::write_crash_reg;
12use arrayvec::ArrayString;
13use core::fmt::Write;
14use core::sync::atomic::AtomicBool;
15use core::sync::atomic::Ordering::Relaxed;
16use hvdef::GuestCrashCtl;
17
18// This is chosen to identify the boot shim as a pre-OS environment
19const PRE_OS_ID: u8 = 5;
20
21static CAN_REPORT_MSG: AtomicBool = AtomicBool::new(false);
22
23fn report_raw(msg: &[u8], msg_pa: Option<usize>) {
24 // Before using the guest crash MSRs, could check
25 // if these are supported. Here, we don't do that
26 // as the intention is to fault anyways.
27
28 let crash_ctl = GuestCrashCtl::new()
29 .with_pre_os_id(PRE_OS_ID)
30 .with_no_crash_dump(true)
31 .with_crash_message(!msg.is_empty())
32 .with_crash_notify(true);
33
34 // SAFETY: Using the contract established in the Hyper-V TLFS.
35 unsafe {
36 write_crash_reg(0, u64::from_le_bytes(*b"BOOTSHIM"));
37 write_crash_reg(1, u64::from_be_bytes(*b"IGVMBOOT"));
38 write_crash_reg(2, u64::MAX);
39
40 match (msg, msg_pa) {
41 (msg @ [_, ..], Some(msg_pa)) => {
42 // There is a non-empty message and a valid physical address.
43 write_crash_reg(3, msg_pa as u64);
44 write_crash_reg(4, msg.len() as u64);
45 }
46 _ => {
47 write_crash_reg(3, 0);
48 write_crash_reg(4, 0);
49 }
50 }
51
52 // Report crash to Hyper-V
53 write_crash_reg(5, crash_ctl.into());
54 }
55}
56
57/// Reports the panic.
58///
59/// `stack_va_to_pa` takes an object on the stack and returns its physical address.
60pub fn report(
61 panic: &core::panic::PanicInfo<'_>,
62 mut stack_va_to_pa: impl FnMut(*const ()) -> Option<usize>,
63) {
64 let mut panic_buffer = ArrayString::<512>::new();
65 if CAN_REPORT_MSG.load(Relaxed) {
66 let _ = write!(panic_buffer, "{}", panic);
67 }
68 report_raw(
69 panic_buffer.as_ref().as_bytes(),
70 stack_va_to_pa(panic_buffer.as_bytes().as_ptr().cast()),
71 );
72}
73
74/// Enables writing the enlightened panic message.
75///
76/// If this is not called, then [`report`] will just report that a panic occurred
77/// and not include the panic message.
78pub fn enable_enlightened_panic() {
79 CAN_REPORT_MSG.store(true, Relaxed);
80}
81