Skip to main content

hyperlight_common/
outb.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2025 The Hyperlight Authors.
3
4use core::convert::TryFrom;
5
6use anyhow::{Error, anyhow};
7
8/// Exception codes for the x86 architecture.
9/// These are helpful to identify the type of exception that occurred
10/// together with OutBAction::Abort.
11#[repr(u8)]
12#[derive(Debug, Clone, Copy)]
13pub enum Exception {
14    DivideByZero = 0,
15    Debug = 1,
16    NonMaskableInterrupt = 2,
17    Breakpoint = 3,
18    Overflow = 4,
19    BoundRangeExceeded = 5,
20    InvalidOpcode = 6,
21    DeviceNotAvailable = 7,
22    DoubleFault = 8,
23    CoprocessorSegmentOverrun = 9,
24    InvalidTSS = 10,
25    SegmentNotPresent = 11,
26    StackSegmentFault = 12,
27    GeneralProtectionFault = 13,
28    PageFault = 14,
29    Reserved = 15,
30    X87FloatingPointException = 16,
31    AlignmentCheck = 17,
32    MachineCheck = 18,
33    SIMDFloatingPointException = 19,
34    VirtualizationException = 20,
35    SecurityException = 30,
36    NoException = 0xFF,
37}
38
39impl TryFrom<u8> for Exception {
40    type Error = Error;
41
42    fn try_from(value: u8) -> Result<Self, Self::Error> {
43        use Exception::*;
44        let exception = match value {
45            0 => DivideByZero,
46            1 => Debug,
47            2 => NonMaskableInterrupt,
48            3 => Breakpoint,
49            4 => Overflow,
50            5 => BoundRangeExceeded,
51            6 => InvalidOpcode,
52            7 => DeviceNotAvailable,
53            8 => DoubleFault,
54            9 => CoprocessorSegmentOverrun,
55            10 => InvalidTSS,
56            11 => SegmentNotPresent,
57            12 => StackSegmentFault,
58            13 => GeneralProtectionFault,
59            14 => PageFault,
60            15 => Reserved,
61            16 => X87FloatingPointException,
62            17 => AlignmentCheck,
63            18 => MachineCheck,
64            19 => SIMDFloatingPointException,
65            20 => VirtualizationException,
66            30 => SecurityException,
67            0xFF => NoException,
68            _ => return Err(anyhow!("Unknown exception code: {:#x}", value)),
69        };
70
71        Ok(exception)
72    }
73}
74
75/// Supported actions when issuing an OUTB actions by Hyperlight.
76/// These are handled by the sandbox-level outb dispatcher.
77/// - Log: for logging,
78/// - CallFunction: makes a call to a host function,
79/// - Abort: aborts the execution of the guest,
80/// - DebugPrint: prints a message to the host
81/// - TraceBatch: reports a batch of spans and events from the guest
82/// - TraceMemoryAlloc: records memory allocation events
83/// - TraceMemoryFree: records memory deallocation events
84pub enum OutBAction {
85    Log = 99,
86    CallFunction = 101,
87    Abort = 102,
88    DebugPrint = 103,
89    #[cfg(feature = "trace_guest")]
90    TraceBatch = 104,
91    #[cfg(feature = "mem_profile")]
92    TraceMemoryAlloc = 105,
93    #[cfg(feature = "mem_profile")]
94    TraceMemoryFree = 106,
95}
96
97/// IO-port actions intercepted at the hypervisor level (in `run_vcpu`)
98/// before they ever reach the sandbox outb handler.  These are split
99/// from [`OutBAction`] so the outb handler does not need unreachable
100/// match arms for ports it can never see.
101pub enum VmAction {
102    /// IO port for PV timer configuration. The guest writes a 32-bit
103    /// LE value representing the desired timer period in microseconds.
104    /// A value of 0 disables the timer.
105    PvTimerConfig = 107,
106    /// IO port the guest writes to signal "I'm done" to the host.
107    /// This replaces the `hlt` instruction for halt signaling so that
108    /// KVM's in-kernel LAPIC (which absorbs HLT exits) does not interfere
109    /// with hyperlight's halt-based guest-host protocol.
110    Halt = 108,
111}
112
113impl TryFrom<u16> for OutBAction {
114    type Error = anyhow::Error;
115    fn try_from(val: u16) -> anyhow::Result<Self> {
116        match val {
117            99 => Ok(OutBAction::Log),
118            101 => Ok(OutBAction::CallFunction),
119            102 => Ok(OutBAction::Abort),
120            103 => Ok(OutBAction::DebugPrint),
121            #[cfg(feature = "trace_guest")]
122            104 => Ok(OutBAction::TraceBatch),
123            #[cfg(feature = "mem_profile")]
124            105 => Ok(OutBAction::TraceMemoryAlloc),
125            #[cfg(feature = "mem_profile")]
126            106 => Ok(OutBAction::TraceMemoryFree),
127            _ => Err(anyhow::anyhow!("Invalid OutBAction value: {}", val)),
128        }
129    }
130}
131
132impl TryFrom<u16> for VmAction {
133    type Error = anyhow::Error;
134    fn try_from(val: u16) -> anyhow::Result<Self> {
135        match val {
136            107 => Ok(VmAction::PvTimerConfig),
137            108 => Ok(VmAction::Halt),
138            _ => Err(anyhow::anyhow!("Invalid VmAction value: {}", val)),
139        }
140    }
141}