1use anyhow::bail;
6use anyhow::Context;
7use hypervisor::HypercallAbi;
8use sync::Mutex;
9use vm_control::DeviceId;
10use vm_control::PlatformDeviceId;
11
12use crate::BusAccessInfo;
13use crate::BusDevice;
14use crate::BusDeviceSync;
15use crate::DevicePowerManager;
16use crate::Suspendable;
17
18pub struct HvcDevicePowerManager {
20 manager: Mutex<DevicePowerManager>,
21}
22
23impl HvcDevicePowerManager {
24 pub const HVC_FUNCTION_ID: u32 = 0xc600003c;
25
26 pub fn new(manager: DevicePowerManager) -> Self {
28 Self {
29 manager: Mutex::new(manager),
30 }
31 }
32
33 fn handle(&self, abi: &HypercallAbi) -> anyhow::Result<()> {
34 let call = DeviceManagerHypercall::new(abi)
35 .with_context(|| format!("Invalid HvcDevicePowerManager call: {abi:?}"))?;
36 match call {
37 DeviceManagerHypercall::PowerOff(d) => self.manager.lock().power_off(d),
38 DeviceManagerHypercall::PowerOn(d) => self.manager.lock().power_on(d),
39 }
40 .with_context(|| format!("HvcDevicePowerManager::handle({call:?})"))
41 }
42}
43
44impl BusDevice for HvcDevicePowerManager {
45 fn device_id(&self) -> DeviceId {
46 PlatformDeviceId::HvcDevicePowerManager.into()
47 }
48
49 fn debug_label(&self) -> String {
50 "HvcDevicePowerManager".to_owned()
51 }
52
53 fn handle_hypercall(&self, abi: &mut HypercallAbi) -> anyhow::Result<()> {
54 match abi.hypercall_id() as u32 {
55 Self::HVC_FUNCTION_ID => {
56 let ok_or_err = self.handle(abi);
57 let r0 = if ok_or_err.is_ok() {
58 0 } else {
60 -3i64 as _ };
62
63 abi.set_results(&[r0, 0, 0, 0]);
64
65 ok_or_err
66 }
67 fid => bail!("HvcDevicePowerManager: Call {fid:#x} is not implemented"),
68 }
69 }
70
71 fn read(&mut self, _info: BusAccessInfo, _data: &mut [u8]) {
72 unimplemented!("HvcDevicePowerManager: read not supported");
73 }
74
75 fn write(&mut self, _info: BusAccessInfo, _data: &[u8]) {
76 unimplemented!("HvcDevicePowerManager: write not supported");
77 }
78}
79
80impl BusDeviceSync for HvcDevicePowerManager {
81 fn read(&self, _info: BusAccessInfo, _data: &mut [u8]) {
82 unimplemented!("HvcDevicePowerManager: read not supported");
83 }
84
85 fn write(&self, _info: BusAccessInfo, _data: &[u8]) {
86 unimplemented!("HvcDevicePowerManager: write not supported");
87 }
88}
89
90impl Suspendable for HvcDevicePowerManager {}
91
92#[derive(Debug)]
93enum DeviceManagerHypercall {
94 PowerOff(usize),
95 PowerOn(usize),
96}
97
98impl DeviceManagerHypercall {
99 fn new(abi: &HypercallAbi) -> Option<Self> {
100 let func = *abi.get_argument(0).unwrap();
101 let arg0 = *abi.get_argument(1).unwrap();
102
103 match func {
104 0 => Some(Self::PowerOff(arg0)),
105 1 => Some(Self::PowerOn(arg0)),
106 _ => None,
107 }
108 }
109}