vmm_core/
vmotherboard_adapter.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Glue code to adapt OpenVMM-specific platform APIs to the types/traits
5//! required by `vmotherboard`.
6
7use crate::partition_unit::Halt;
8use crate::synic::SynicPorts;
9use hvdef::Vtl;
10use std::sync::Arc;
11use virt::VpIndex;
12use virt::io::CpuIo;
13use vmm_core_defs::HaltReason;
14use vmotherboard::Chipset;
15
16#[expect(missing_docs)]
17#[derive(Clone)]
18pub struct ChipsetPlusSynic {
19    pub synic_ports: Arc<SynicPorts>,
20    pub chipset: Arc<Chipset>,
21    fatal_policy: FatalErrorPolicy,
22}
23
24#[derive(Clone)]
25pub enum FatalErrorPolicy {
26    /// Panic the process, running the given closure immediately before panicking.
27    Panic(Arc<dyn Fn() + Send + Sync>),
28    /// Convert the failure to a debugger break, and send the error over the
29    /// given channel.
30    DebugBreak(mesh::Sender<Box<dyn std::error::Error + Send + Sync>>),
31}
32
33impl ChipsetPlusSynic {
34    #[expect(missing_docs)]
35    pub fn new(
36        synic_ports: Arc<SynicPorts>,
37        chipset: Arc<Chipset>,
38        fatal_policy: FatalErrorPolicy,
39    ) -> Self {
40        Self {
41            synic_ports,
42            chipset,
43            fatal_policy,
44        }
45    }
46}
47
48impl CpuIo for ChipsetPlusSynic {
49    fn is_mmio(&self, address: u64) -> bool {
50        self.chipset.is_mmio(address)
51    }
52
53    fn acknowledge_pic_interrupt(&self) -> Option<u8> {
54        self.chipset.acknowledge_pic_interrupt()
55    }
56
57    fn handle_eoi(&self, irq: u32) {
58        self.chipset.handle_eoi(irq)
59    }
60
61    fn signal_synic_event(&self, vtl: Vtl, connection_id: u32, flag: u16) -> hvdef::HvResult<()> {
62        self.synic_ports.on_signal_event(vtl, connection_id, flag)
63    }
64
65    fn post_synic_message(
66        &self,
67        vtl: Vtl,
68        connection_id: u32,
69        secure: bool,
70        message: &[u8],
71    ) -> hvdef::HvResult<()> {
72        self.synic_ports
73            .on_post_message(vtl, connection_id, secure, message)
74    }
75
76    fn read_mmio(&self, vp: VpIndex, address: u64, data: &mut [u8]) -> impl Future<Output = ()> {
77        self.chipset.mmio_read(vp.index(), address, data)
78    }
79
80    fn write_mmio(&self, vp: VpIndex, address: u64, data: &[u8]) -> impl Future<Output = ()> {
81        self.chipset.mmio_write(vp.index(), address, data)
82    }
83
84    fn read_io(&self, vp: VpIndex, port: u16, data: &mut [u8]) -> impl Future<Output = ()> {
85        self.chipset.io_read(vp.index(), port, data)
86    }
87
88    fn write_io(&self, vp: VpIndex, port: u16, data: &[u8]) -> impl Future<Output = ()> {
89        self.chipset.io_write(vp.index(), port, data)
90    }
91
92    #[track_caller]
93    fn fatal_error(&self, error: Box<dyn std::error::Error + Send + Sync>) -> virt::VpHaltReason {
94        tracing::error!(
95            err = error.as_ref() as &dyn std::error::Error,
96            "fatal error"
97        );
98        match &self.fatal_policy {
99            FatalErrorPolicy::Panic(prep) => {
100                prep();
101                panic!("fatal error: {}", error)
102            }
103            FatalErrorPolicy::DebugBreak(channel) => {
104                channel.send(error);
105                virt::VpHaltReason::SingleStep
106            }
107        }
108    }
109}
110
111impl vmotherboard::PowerEventHandler for Halt {
112    fn on_power_event(&self, evt: vmotherboard::PowerEvent) {
113        let reason = match evt {
114            vmotherboard::PowerEvent::PowerOff => HaltReason::PowerOff,
115            vmotherboard::PowerEvent::Reset => HaltReason::Reset,
116            vmotherboard::PowerEvent::Hibernate => HaltReason::Hibernate,
117        };
118        self.halt(reason)
119    }
120}
121
122impl vmotherboard::DebugEventHandler for Halt {
123    fn on_debug_break(&self, vp: Option<u32>) {
124        self.halt(HaltReason::DebugBreak { vp })
125    }
126}