Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/pmc_virt.rs
5392 views
1
// Copyright 2023 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 std::sync::Arc;
6
7
use acpi_tables::aml;
8
use acpi_tables::aml::Aml;
9
use base::warn;
10
use sync::Condvar;
11
use sync::Mutex;
12
use vm_control::DeviceId;
13
use vm_control::PlatformDeviceId;
14
15
use crate::BusAccessInfo;
16
use crate::BusDevice;
17
use crate::Suspendable;
18
19
/// PMC Virt MMIO offset
20
const PMC_RESERVED1: u32 = 0;
21
const _PMC_RESERVED2: u32 = 0x4;
22
const _PMC_RESERVED3: u32 = 0x8;
23
const _PMC_RESERVED4: u32 = 0xc;
24
25
pub const VPMC_VIRT_MMIO_SIZE: u64 = 0x10;
26
27
pub struct VirtualPmc {
28
mmio_base: u64,
29
guest_suspended_cvar: Arc<(Mutex<bool>, Condvar)>,
30
}
31
32
impl VirtualPmc {
33
pub fn new(mmio_base: u64, guest_suspended_cvar: Arc<(Mutex<bool>, Condvar)>) -> Self {
34
VirtualPmc {
35
mmio_base,
36
guest_suspended_cvar,
37
}
38
}
39
}
40
41
fn handle_s2idle_request(guest_suspended_cvar: &Arc<(Mutex<bool>, Condvar)>) {
42
// Wake up blocked thread on condvar, which is awaiting non-privileged guest suspension to
43
// finish.
44
let (lock, cvar) = &**guest_suspended_cvar;
45
let mut guest_suspended = lock.lock();
46
*guest_suspended = true;
47
48
cvar.notify_one();
49
}
50
51
impl BusDevice for VirtualPmc {
52
fn device_id(&self) -> DeviceId {
53
PlatformDeviceId::VirtualPmc.into()
54
}
55
fn debug_label(&self) -> String {
56
"PmcVirt".to_owned()
57
}
58
59
fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
60
if data.len() != std::mem::size_of::<u32>() {
61
warn!(
62
"{}: unsupported read length {}, only support 4bytes read",
63
self.debug_label(),
64
data.len()
65
);
66
return;
67
}
68
69
warn!("{}: unsupported read address {}", self.debug_label(), info);
70
}
71
72
fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
73
if data.len() != std::mem::size_of::<u32>() {
74
warn!(
75
"{}: unsupported write length {}, only support 4bytes write",
76
self.debug_label(),
77
data.len()
78
);
79
return;
80
}
81
82
match info.offset as u32 {
83
PMC_RESERVED1 => {
84
handle_s2idle_request(&self.guest_suspended_cvar);
85
}
86
_ => {
87
warn!("{}: Bad write to address {}", self.debug_label(), info);
88
}
89
};
90
}
91
}
92
93
impl Aml for VirtualPmc {
94
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
95
let vpmc_uuid = "9ea49ba3-434a-49a6-be30-37cc55c4d397";
96
aml::Device::new(
97
"VPMC".into(),
98
vec![
99
&aml::Name::new("_CID".into(), &aml::EISAName::new("PNP0D80")),
100
&aml::Name::new("_HID".into(), &"HYPE0001"),
101
&aml::Name::new("UUID".into(), &aml::Uuid::new(vpmc_uuid)),
102
&aml::OpRegion::new(
103
"VREG".into(),
104
aml::OpRegionSpace::SystemMemory,
105
&self.mmio_base,
106
&(16_u32),
107
),
108
&aml::Field::new(
109
"VREG".into(),
110
aml::FieldAccessType::DWord,
111
aml::FieldLockRule::Lock,
112
aml::FieldUpdateRule::Preserve,
113
vec![aml::FieldEntry::Named(*b"RSV1", 32)],
114
),
115
&aml::Method::new(
116
"_DSM".into(),
117
4,
118
true,
119
vec![
120
&aml::If::new(
121
&aml::Equal::new(&aml::Arg(0), &aml::Name::new_field_name("UUID")),
122
vec![
123
&aml::If::new(
124
&aml::Equal::new(&aml::Arg(2), &aml::ZERO),
125
vec![&aml::Return::new(&aml::BufferData::new(vec![3]))],
126
),
127
&aml::If::new(
128
&aml::Equal::new(&aml::Arg(2), &aml::ONE),
129
vec![&aml::Store::new(
130
&aml::Name::new_field_name("RSV1"),
131
&0x3_usize,
132
)],
133
),
134
],
135
),
136
&aml::Return::new(&aml::BufferData::new(vec![3])),
137
],
138
),
139
],
140
)
141
.to_aml_bytes(bytes);
142
}
143
}
144
145
impl Suspendable for VirtualPmc {}
146
147