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 set_power_state(&self, domain_id: usize, power_level: usize) -> anyhow::Result<()> {
34 match power_level {
35 0 => self.manager.lock().power_off(domain_id)?,
36 _ => self.manager.lock().power_on(domain_id)?,
37 };
38 Ok(())
39 }
40}
41
42impl BusDevice for HvcDevicePowerManager {
43 fn device_id(&self) -> DeviceId {
44 PlatformDeviceId::HvcDevicePowerManager.into()
45 }
46
47 fn debug_label(&self) -> String {
48 "HvcDevicePowerManager".to_owned()
49 }
50
51 fn handle_hypercall(&self, abi: &mut HypercallAbi) -> anyhow::Result<()> {
52 match abi.hypercall_id() as u32 {
53 Self::HVC_FUNCTION_ID => {
54 let domain_id = *abi.get_argument(0).unwrap();
55 let power_level = *abi.get_argument(1).unwrap();
56
57 let ok_or_err = self
58 .set_power_state(domain_id, power_level)
59 .with_context(|| {
60 format!(
61 "HvcDevicePowerManager::handle_hypercall({domain_id}, {power_level})"
62 )
63 });
64
65 let r0 = if ok_or_err.is_ok() {
66 0 } else {
68 -3i64 as _ };
70
71 abi.set_results(&[r0, 0, 0, 0]);
72
73 ok_or_err
74 }
75 fid => bail!("HvcDevicePowerManager: Call {fid:#x} is not implemented"),
76 }
77 }
78
79 fn read(&mut self, _info: BusAccessInfo, _data: &mut [u8]) {
80 unimplemented!("HvcDevicePowerManager: read not supported");
81 }
82
83 fn write(&mut self, _info: BusAccessInfo, _data: &[u8]) {
84 unimplemented!("HvcDevicePowerManager: write not supported");
85 }
86}
87
88impl BusDeviceSync for HvcDevicePowerManager {
89 fn read(&self, _info: BusAccessInfo, _data: &mut [u8]) {
90 unimplemented!("HvcDevicePowerManager: read not supported");
91 }
92
93 fn write(&self, _info: BusAccessInfo, _data: &[u8]) {
94 unimplemented!("HvcDevicePowerManager: write not supported");
95 }
96}
97
98impl Suspendable for HvcDevicePowerManager {}