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 std::sync::Arc;
9use virt::VpIndex;
10use virt::io::CpuIo;
11use vmm_core_defs::HaltReason;
12use vmotherboard::Chipset;
13
14/// This struct adds the necessary `CpuIo` implementation to a `Chipset`, so it
15/// can be used directly in the VP dispatch loop and passed to the processor
16/// implementations.
17#[derive(Clone)]
18pub struct AdaptedChipset {
19    pub chipset: Arc<Chipset>,
20    fatal_policy: FatalErrorPolicy,
21}
22
23#[derive(Clone)]
24pub enum FatalErrorPolicy {
25    /// Panic the process, running the given closure immediately before panicking.
26    Panic(Arc<dyn Fn() + Send + Sync>),
27    /// Convert the failure to a debugger break, and send the error over the
28    /// given channel.
29    DebugBreak(mesh::Sender<Box<dyn std::error::Error + Send + Sync>>),
30}
31
32impl AdaptedChipset {
33    /// Create a new `AdaptedChipset` from a `Chipset` and a `FatalErrorPolicy`.
34    pub fn new(chipset: Arc<Chipset>, fatal_policy: FatalErrorPolicy) -> Self {
35        Self {
36            chipset,
37            fatal_policy,
38        }
39    }
40}
41
42impl CpuIo for AdaptedChipset {
43    fn is_mmio(&self, address: u64) -> bool {
44        self.chipset.is_mmio(address)
45    }
46
47    fn acknowledge_pic_interrupt(&self) -> Option<u8> {
48        self.chipset.acknowledge_pic_interrupt()
49    }
50
51    fn handle_eoi(&self, irq: u32) {
52        self.chipset.handle_eoi(irq)
53    }
54
55    fn read_mmio(&self, vp: VpIndex, address: u64, data: &mut [u8]) -> impl Future<Output = ()> {
56        self.chipset.mmio_read(vp.index(), address, data)
57    }
58
59    fn write_mmio(&self, vp: VpIndex, address: u64, data: &[u8]) -> impl Future<Output = ()> {
60        self.chipset.mmio_write(vp.index(), address, data)
61    }
62
63    fn read_io(&self, vp: VpIndex, port: u16, data: &mut [u8]) -> impl Future<Output = ()> {
64        self.chipset.io_read(vp.index(), port, data)
65    }
66
67    fn write_io(&self, vp: VpIndex, port: u16, data: &[u8]) -> impl Future<Output = ()> {
68        self.chipset.io_write(vp.index(), port, data)
69    }
70
71    #[track_caller]
72    fn fatal_error(&self, error: Box<dyn std::error::Error + Send + Sync>) -> virt::VpHaltReason {
73        tracing::error!(
74            err = error.as_ref() as &dyn std::error::Error,
75            "fatal error"
76        );
77        match &self.fatal_policy {
78            FatalErrorPolicy::Panic(prep) => {
79                prep();
80                panic!("fatal error: {}", error)
81            }
82            FatalErrorPolicy::DebugBreak(channel) => {
83                channel.send(error);
84                virt::VpHaltReason::SingleStep
85            }
86        }
87    }
88}
89
90impl vmotherboard::PowerEventHandler for Halt {
91    fn on_power_event(&self, evt: vmotherboard::PowerEvent) {
92        let reason = match evt {
93            vmotherboard::PowerEvent::PowerOff => HaltReason::PowerOff,
94            vmotherboard::PowerEvent::Reset => HaltReason::Reset,
95            vmotherboard::PowerEvent::Hibernate => HaltReason::Hibernate,
96        };
97        self.halt(reason)
98    }
99}
100
101impl vmotherboard::DebugEventHandler for Halt {
102    fn on_debug_break(&self, vp: Option<u32>) {
103        self.halt(HaltReason::DebugBreak { vp })
104    }
105}