Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/power/hvc.rs
5394 views
1
// Copyright 2026 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
use anyhow::bail;
6
use anyhow::Context;
7
use hypervisor::HypercallAbi;
8
use sync::Mutex;
9
use vm_control::DeviceId;
10
use vm_control::PlatformDeviceId;
11
12
use crate::BusAccessInfo;
13
use crate::BusDevice;
14
use crate::BusDeviceSync;
15
use crate::DevicePowerManager;
16
use crate::Suspendable;
17
18
/// Back-end for pKVM-enabled power management, intended for physical assigned devices.
19
pub struct HvcDevicePowerManager {
20
manager: Mutex<DevicePowerManager>,
21
}
22
23
impl HvcDevicePowerManager {
24
pub const HVC_FUNCTION_ID: u32 = 0xc600003c;
25
26
/// Takes ownership of the abstract `DevicePowerManager`, as a `HvcDevicePowerManager`.
27
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
44
impl 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 // SMCCC_SUCCESS
59
} else {
60
-3i64 as _ // SMCCC_INVALID_PARAMETER
61
};
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
80
impl 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
90
impl Suspendable for HvcDevicePowerManager {}
91
92
#[derive(Debug)]
93
enum DeviceManagerHypercall {
94
PowerOff(usize),
95
PowerOn(usize),
96
}
97
98
impl 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
}
110
111