Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/acpi.rs
5392 views
1
// Copyright 2019 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::collections::BTreeMap;
6
use std::str::FromStr;
7
use std::sync::Arc;
8
use std::time::Duration;
9
10
use acpi_tables::aml;
11
use acpi_tables::aml::Aml;
12
use anyhow::bail;
13
use anyhow::Context;
14
use base::custom_serde::serialize_arc_mutex;
15
use base::error;
16
use base::warn;
17
use base::Error as SysError;
18
use base::Event;
19
use base::EventToken;
20
use base::EventWaitResult;
21
use base::SendTube;
22
use base::Tube;
23
use base::VmEventType;
24
use base::WaitContext;
25
use base::WorkerThread;
26
use serde::Deserialize;
27
use serde::Serialize;
28
use snapshot::AnySnapshot;
29
use sync::Mutex;
30
use thiserror::Error;
31
use vm_control::DeviceId;
32
use vm_control::GpeNotify;
33
use vm_control::PlatformDeviceId;
34
use vm_control::PmResource;
35
use vm_control::PmeNotify;
36
use vm_control::VmRequest;
37
use vm_control::VmResponse;
38
39
use crate::ac_adapter::AcAdapter;
40
use crate::pci::pm::PmConfig;
41
use crate::BusAccessInfo;
42
use crate::BusDevice;
43
use crate::BusResumeDevice;
44
use crate::IrqLevelEvent;
45
use crate::Suspendable;
46
47
#[derive(Error, Debug)]
48
pub enum ACPIPMError {
49
/// Creating WaitContext failed.
50
#[error("failed to create wait context: {0}")]
51
CreateWaitContext(SysError),
52
/// Error while waiting for events.
53
#[error("failed to wait for events: {0}")]
54
WaitError(SysError),
55
#[error("Did not find group_id corresponding to acpi_mc_group")]
56
AcpiMcGroupError,
57
#[error("Failed to create and bind NETLINK_GENERIC socket for acpi_mc_group: {0}")]
58
AcpiEventSockError(base::Error),
59
#[error("GPE {0} is out of bound")]
60
GpeOutOfBound(u32),
61
}
62
63
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
64
pub enum ACPIPMFixedEvent {
65
GlobalLock,
66
PowerButton,
67
SleepButton,
68
RTC,
69
}
70
71
#[derive(Serialize)]
72
pub(crate) struct Pm1Resource {
73
pub(crate) status: u16,
74
enable: u16,
75
control: u16,
76
#[serde(skip_serializing)]
77
suspend_tube: Arc<Mutex<SendTube>>,
78
#[serde(skip_serializing)]
79
rtc_clear_evt: Option<Event>,
80
}
81
82
#[derive(Deserialize)]
83
struct Pm1ResourceSerializable {
84
status: u16,
85
enable: u16,
86
control: u16,
87
}
88
89
#[derive(Serialize)]
90
pub(crate) struct GpeResource {
91
pub(crate) status: [u8; ACPIPM_RESOURCE_GPE0_BLK_LEN as usize / 2],
92
enable: [u8; ACPIPM_RESOURCE_GPE0_BLK_LEN as usize / 2],
93
#[serde(skip_serializing)]
94
pub(crate) gpe_notify: BTreeMap<u32, Vec<Arc<Mutex<dyn GpeNotify>>>>,
95
// For each triggered GPE, a vector of events to check when resampling
96
// sci_evt. If any events are un-signaled, then sci_evt should be re-asserted.
97
#[serde(skip_serializing)]
98
pending_clear_evts: BTreeMap<u32, Vec<Event>>,
99
#[serde(skip_serializing)]
100
suspend_tube: Arc<Mutex<SendTube>>,
101
}
102
103
#[derive(Deserialize)]
104
struct GpeResourceSerializable {
105
status: [u8; ACPIPM_RESOURCE_GPE0_BLK_LEN as usize / 2],
106
enable: [u8; ACPIPM_RESOURCE_GPE0_BLK_LEN as usize / 2],
107
}
108
109
#[derive(Serialize, Deserialize, Clone)]
110
pub(crate) struct PciResource {
111
#[serde(skip_serializing, skip_deserializing)]
112
pub(crate) pme_notify: BTreeMap<u8, Vec<Arc<Mutex<dyn PmeNotify>>>>,
113
}
114
115
/// ACPI PM resource for handling OS suspend/resume request
116
#[allow(dead_code)]
117
#[derive(Serialize)]
118
pub struct ACPIPMResource {
119
// This is SCI interrupt that will be raised in the VM.
120
#[serde(skip_serializing)]
121
sci_evt: IrqLevelEvent,
122
#[serde(skip_serializing)]
123
worker_thread: Option<WorkerThread<()>>,
124
#[serde(skip_serializing)]
125
suspend_tube: Arc<Mutex<SendTube>>,
126
#[serde(skip_serializing)]
127
exit_evt_wrtube: SendTube,
128
#[serde(serialize_with = "serialize_arc_mutex")]
129
pm1: Arc<Mutex<Pm1Resource>>,
130
#[serde(serialize_with = "serialize_arc_mutex")]
131
gpe0: Arc<Mutex<GpeResource>>,
132
#[serde(serialize_with = "serialize_arc_mutex")]
133
pci: Arc<Mutex<PciResource>>,
134
#[serde(skip_serializing)]
135
acdc: Option<Arc<Mutex<AcAdapter>>>,
136
}
137
138
#[derive(Deserialize)]
139
struct ACPIPMResrourceSerializable {
140
pm1: Pm1ResourceSerializable,
141
gpe0: GpeResourceSerializable,
142
}
143
144
impl ACPIPMResource {
145
/// Constructs ACPI Power Management Resouce.
146
#[allow(dead_code)]
147
pub fn new(
148
sci_evt: IrqLevelEvent,
149
suspend_tube: Arc<Mutex<SendTube>>,
150
exit_evt_wrtube: SendTube,
151
acdc: Option<Arc<Mutex<AcAdapter>>>,
152
) -> ACPIPMResource {
153
let pm1 = Pm1Resource {
154
status: 0,
155
enable: 0,
156
control: 0,
157
suspend_tube: suspend_tube.clone(),
158
rtc_clear_evt: None,
159
};
160
let gpe0 = GpeResource {
161
status: Default::default(),
162
enable: Default::default(),
163
gpe_notify: BTreeMap::new(),
164
pending_clear_evts: BTreeMap::new(),
165
suspend_tube: suspend_tube.clone(),
166
};
167
let pci = PciResource {
168
pme_notify: BTreeMap::new(),
169
};
170
171
ACPIPMResource {
172
sci_evt,
173
worker_thread: None,
174
suspend_tube,
175
exit_evt_wrtube,
176
pm1: Arc::new(Mutex::new(pm1)),
177
gpe0: Arc::new(Mutex::new(gpe0)),
178
pci: Arc::new(Mutex::new(pci)),
179
acdc,
180
}
181
}
182
183
pub fn start(&mut self) {
184
let sci_evt = self.sci_evt.try_clone().expect("failed to clone event");
185
let pm1 = self.pm1.clone();
186
let gpe0 = self.gpe0.clone();
187
let acdc = self.acdc.clone();
188
189
let acpi_event_ignored_gpe = Vec::new();
190
191
self.worker_thread = Some(WorkerThread::start("ACPI PM worker", move |kill_evt| {
192
if let Err(e) = run_worker(sci_evt, kill_evt, pm1, gpe0, acpi_event_ignored_gpe, acdc) {
193
error!("{}", e);
194
}
195
}));
196
}
197
}
198
199
impl Suspendable for ACPIPMResource {
200
fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
201
if !self.gpe0.lock().pending_clear_evts.is_empty() {
202
bail!("ACPIPMResource is busy");
203
}
204
AnySnapshot::to_any(&self)
205
.with_context(|| format!("error serializing {}", self.debug_label()))
206
}
207
208
fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
209
let acpi_snapshot: ACPIPMResrourceSerializable = AnySnapshot::from_any(data)
210
.with_context(|| format!("error deserializing {}", self.debug_label()))?;
211
{
212
let mut pm1 = self.pm1.lock();
213
pm1.status = acpi_snapshot.pm1.status;
214
pm1.enable = acpi_snapshot.pm1.enable;
215
pm1.control = acpi_snapshot.pm1.control;
216
}
217
{
218
let mut gpe0 = self.gpe0.lock();
219
gpe0.status = acpi_snapshot.gpe0.status;
220
gpe0.enable = acpi_snapshot.gpe0.enable;
221
}
222
Ok(())
223
}
224
225
fn sleep(&mut self) -> anyhow::Result<()> {
226
if let Some(worker_thread) = self.worker_thread.take() {
227
worker_thread.stop();
228
}
229
Ok(())
230
}
231
232
fn wake(&mut self) -> anyhow::Result<()> {
233
self.start();
234
Ok(())
235
}
236
}
237
238
fn run_worker(
239
sci_evt: IrqLevelEvent,
240
kill_evt: Event,
241
pm1: Arc<Mutex<Pm1Resource>>,
242
gpe0: Arc<Mutex<GpeResource>>,
243
acpi_event_ignored_gpe: Vec<u32>,
244
arced_ac_adapter: Option<Arc<Mutex<AcAdapter>>>,
245
) -> Result<(), ACPIPMError> {
246
let acpi_event_sock = crate::sys::get_acpi_event_sock()?;
247
#[derive(EventToken)]
248
enum Token {
249
AcpiEvent,
250
InterruptResample,
251
Kill,
252
}
253
254
let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
255
(sci_evt.get_resample(), Token::InterruptResample),
256
(&kill_evt, Token::Kill),
257
])
258
.map_err(ACPIPMError::CreateWaitContext)?;
259
if let Some(acpi_event_sock) = &acpi_event_sock {
260
wait_ctx
261
.add(acpi_event_sock, Token::AcpiEvent)
262
.map_err(ACPIPMError::CreateWaitContext)?;
263
}
264
265
loop {
266
let events = wait_ctx.wait().map_err(ACPIPMError::WaitError)?;
267
for event in events.iter().filter(|e| e.is_readable) {
268
match event.token {
269
Token::AcpiEvent => {
270
crate::sys::acpi_event_run(
271
&sci_evt,
272
&acpi_event_sock,
273
&gpe0,
274
&acpi_event_ignored_gpe,
275
&arced_ac_adapter,
276
);
277
}
278
Token::InterruptResample => {
279
sci_evt.clear_resample();
280
281
// Re-trigger SCI if PM1 or GPE status is still not cleared.
282
pm1.lock().resample_clear_evts_and_trigger(&sci_evt);
283
gpe0.lock().resample_clear_evts_and_trigger(&sci_evt);
284
}
285
Token::Kill => return Ok(()),
286
}
287
}
288
}
289
}
290
291
impl Pm1Resource {
292
fn trigger_sci(&self, sci_evt: &IrqLevelEvent) {
293
if self.status & self.enable & ACPIPMFixedEvent::bitmask_all() != 0 {
294
if let Err(e) = sci_evt.trigger() {
295
error!("ACPIPM: failed to trigger sci event for pm1: {}", e);
296
}
297
if let Err(e) = self.suspend_tube.lock().send(&false) {
298
error!("ACPIPM: failed to trigger wake event: {}", e);
299
}
300
}
301
}
302
303
fn resample_clear_evts_and_trigger(&mut self, sci_evt: &IrqLevelEvent) {
304
if let Some(clear_evt) = self.rtc_clear_evt.take() {
305
if clear_evt.wait_timeout(Duration::ZERO) == Ok(EventWaitResult::TimedOut) {
306
self.rtc_clear_evt = Some(clear_evt);
307
self.status |= ACPIPMFixedEvent::RTC.bitmask();
308
}
309
}
310
self.trigger_sci(sci_evt);
311
}
312
}
313
314
impl GpeResource {
315
pub fn trigger_sci(&self, sci_evt: &IrqLevelEvent) {
316
if (0..self.status.len()).any(|i| self.status[i] & self.enable[i] != 0) {
317
if let Err(e) = sci_evt.trigger() {
318
error!("ACPIPM: failed to trigger sci event for gpe: {}", e);
319
}
320
if let Err(e) = self.suspend_tube.lock().send(&false) {
321
error!("ACPIPM: failed to trigger wake event: {}", e);
322
}
323
}
324
}
325
326
pub fn set_active(&mut self, gpe: u32) -> Result<(), ACPIPMError> {
327
if let Some(status_byte) = self.status.get_mut(gpe as usize / 8) {
328
*status_byte |= 1 << (gpe % 8);
329
} else {
330
return Err(ACPIPMError::GpeOutOfBound(gpe));
331
}
332
Ok(())
333
}
334
335
pub fn resample_clear_evts_and_trigger(&mut self, sci_evt: &IrqLevelEvent) {
336
let mut retained = Vec::new();
337
self.pending_clear_evts.retain(|gpe, clear_evts| {
338
clear_evts.retain(|clear_evt| {
339
clear_evt.wait_timeout(Duration::ZERO) == Ok(EventWaitResult::TimedOut)
340
});
341
if !clear_evts.is_empty() {
342
retained.push(*gpe);
343
}
344
!clear_evts.is_empty()
345
});
346
for gpe in retained.into_iter() {
347
self.set_active(gpe).expect("bad gpe index");
348
}
349
350
self.trigger_sci(sci_evt);
351
}
352
}
353
354
/// the ACPI PM register length.
355
pub const ACPIPM_RESOURCE_EVENTBLK_LEN: u8 = 4;
356
pub const ACPIPM_RESOURCE_CONTROLBLK_LEN: u8 = 2;
357
pub const ACPIPM_RESOURCE_GPE0_BLK_LEN: u8 = 64;
358
pub const ACPIPM_RESOURCE_LEN: u8 = ACPIPM_RESOURCE_EVENTBLK_LEN + 4 + ACPIPM_RESOURCE_GPE0_BLK_LEN;
359
360
// Should be in sync with gpe_allocator range
361
pub const ACPIPM_GPE_MAX: u16 = ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2 * 8 - 1;
362
363
// ACPI PM register value definitions
364
365
/// Section 4.8.4.1.1 PM1 Status Registers, ACPI Spec Version 6.4
366
/// Register Location: <PM1a_EVT_BLK / PM1b_EVT_BLK> System I/O or Memory Space (defined in FADT)
367
/// Size: PM1_EVT_LEN / 2 (defined in FADT)
368
const PM1_STATUS: u16 = 0;
369
370
/// Section 4.8.4.1.2 PM1Enable Registers, ACPI Spec Version 6.4
371
/// Register Location: <<PM1a_EVT_BLK / PM1b_EVT_BLK> + PM1_EVT_LEN / 2 System I/O or Memory Space
372
/// (defined in FADT)
373
/// Size: PM1_EVT_LEN / 2 (defined in FADT)
374
const PM1_ENABLE: u16 = PM1_STATUS + (ACPIPM_RESOURCE_EVENTBLK_LEN as u16 / 2);
375
376
/// Section 4.8.4.2.1 PM1 Control Registers, ACPI Spec Version 6.4
377
/// Register Location: <PM1a_CNT_BLK / PM1b_CNT_BLK> System I/O or Memory Space (defined in FADT)
378
/// Size: PM1_CNT_LEN (defined in FADT)
379
const PM1_CONTROL: u16 = PM1_STATUS + ACPIPM_RESOURCE_EVENTBLK_LEN as u16;
380
381
/// Section 4.8.5.1 General-Purpose Event Register Blocks, ACPI Spec Version 6.4
382
/// - Each register block contains two registers: an enable and a status register.
383
/// - Each register block is 32-bit aligned.
384
/// - Each register in the block is accessed as a byte.
385
///
386
/// Section 4.8.5.1.1 General-Purpose Event 0 Register Block, ACPI Spec Version 6.4
387
/// This register block consists of two registers: The GPE0_STS and the GPE0_EN registers. Each
388
/// register’s length is defined to be half the length of the GPE0 register block, and is described
389
/// in the ACPI FADT’s GPE0_BLK and GPE0_BLK_LEN operators.
390
///
391
/// Section 4.8.5.1.1.1 General-Purpose Event 0 Status Register, ACPI Spec Version 6.4
392
/// Register Location: <GPE0_STS> System I/O or System Memory Space (defined in FADT)
393
/// Size: GPE0_BLK_LEN/2 (defined in FADT)
394
const GPE0_STATUS: u16 = PM1_STATUS + ACPIPM_RESOURCE_EVENTBLK_LEN as u16 + 4; // ensure alignment
395
396
/// Section 4.8.5.1.1.2 General-Purpose Event 0 Enable Register, ACPI Spec Version 6.4
397
/// Register Location: <GPE0_EN> System I/O or System Memory Space (defined in FADT)
398
/// Size: GPE0_BLK_LEN/2 (defined in FADT)
399
const GPE0_ENABLE: u16 = GPE0_STATUS + (ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2);
400
401
/// Section 4.8.4.1.1, 4.8.4.1.2 Fixed event bits in both PM1 Status and PM1 Enable registers.
402
const BITSHIFT_PM1_GBL: u16 = 5;
403
const BITSHIFT_PM1_PWRBTN: u16 = 8;
404
const BITSHIFT_PM1_SLPBTN: u16 = 9;
405
const BITSHIFT_PM1_RTC: u16 = 10;
406
407
const BITMASK_PM1CNT_SLEEP_ENABLE: u16 = 0x2000;
408
const BITMASK_PM1CNT_WAKE_STATUS: u16 = 0x8000;
409
410
const BITMASK_PM1CNT_SLEEP_TYPE: u16 = 0x1C00;
411
const SLEEP_TYPE_S1: u16 = 1 << 10;
412
const SLEEP_TYPE_S5: u16 = 0 << 10;
413
414
impl ACPIPMFixedEvent {
415
fn bitshift(self) -> u16 {
416
match self {
417
ACPIPMFixedEvent::GlobalLock => BITSHIFT_PM1_GBL,
418
ACPIPMFixedEvent::PowerButton => BITSHIFT_PM1_PWRBTN,
419
ACPIPMFixedEvent::SleepButton => BITSHIFT_PM1_SLPBTN,
420
ACPIPMFixedEvent::RTC => BITSHIFT_PM1_RTC,
421
}
422
}
423
424
pub(crate) fn bitmask(self) -> u16 {
425
1 << self.bitshift()
426
}
427
428
fn bitmask_all() -> u16 {
429
(1 << BITSHIFT_PM1_GBL)
430
| (1 << BITSHIFT_PM1_PWRBTN)
431
| (1 << BITSHIFT_PM1_SLPBTN)
432
| (1 << BITSHIFT_PM1_RTC)
433
}
434
}
435
436
impl FromStr for ACPIPMFixedEvent {
437
type Err = &'static str;
438
439
fn from_str(s: &str) -> Result<Self, Self::Err> {
440
match s {
441
"gbllock" => Ok(ACPIPMFixedEvent::GlobalLock),
442
"powerbtn" => Ok(ACPIPMFixedEvent::PowerButton),
443
"sleepbtn" => Ok(ACPIPMFixedEvent::SleepButton),
444
"rtc" => Ok(ACPIPMFixedEvent::RTC),
445
_ => Err("unknown event, must be: gbllock|powerbtn|sleepbtn|rtc"),
446
}
447
}
448
}
449
450
impl PmResource for ACPIPMResource {
451
fn pwrbtn_evt(&mut self) {
452
let mut pm1 = self.pm1.lock();
453
454
pm1.status |= ACPIPMFixedEvent::PowerButton.bitmask();
455
pm1.trigger_sci(&self.sci_evt);
456
}
457
458
fn slpbtn_evt(&mut self) {
459
let mut pm1 = self.pm1.lock();
460
461
pm1.status |= ACPIPMFixedEvent::SleepButton.bitmask();
462
pm1.trigger_sci(&self.sci_evt);
463
}
464
465
fn rtc_evt(&mut self, clear_evt: Event) {
466
let mut pm1 = self.pm1.lock();
467
468
pm1.rtc_clear_evt = Some(clear_evt);
469
pm1.status |= ACPIPMFixedEvent::RTC.bitmask();
470
pm1.trigger_sci(&self.sci_evt);
471
}
472
473
fn gpe_evt(&mut self, gpe: u32, clear_evt: Option<Event>) {
474
let mut gpe0 = self.gpe0.lock();
475
match gpe0.set_active(gpe) {
476
Ok(_) => {
477
if let Some(clear_evt) = clear_evt {
478
gpe0.pending_clear_evts
479
.entry(gpe)
480
.or_default()
481
.push(clear_evt);
482
}
483
gpe0.trigger_sci(&self.sci_evt)
484
}
485
Err(e) => error!("{}", e),
486
}
487
}
488
489
fn pme_evt(&mut self, requester_id: u16) {
490
let bus = ((requester_id >> 8) & 0xFF) as u8;
491
let mut pci = self.pci.lock();
492
if let Some(root_ports) = pci.pme_notify.get_mut(&bus) {
493
for root_port in root_ports {
494
root_port.lock().notify(requester_id);
495
}
496
}
497
}
498
499
fn register_gpe_notify_dev(&mut self, gpe: u32, notify_dev: Arc<Mutex<dyn GpeNotify>>) {
500
let mut gpe0 = self.gpe0.lock();
501
match gpe0.gpe_notify.get_mut(&gpe) {
502
Some(v) => v.push(notify_dev),
503
None => {
504
gpe0.gpe_notify.insert(gpe, vec![notify_dev]);
505
}
506
}
507
}
508
509
fn register_pme_notify_dev(&mut self, bus: u8, notify_dev: Arc<Mutex<dyn PmeNotify>>) {
510
let mut pci = self.pci.lock();
511
match pci.pme_notify.get_mut(&bus) {
512
Some(v) => v.push(notify_dev),
513
None => {
514
pci.pme_notify.insert(bus, vec![notify_dev]);
515
}
516
}
517
}
518
}
519
520
const PM1_STATUS_LAST: u16 = PM1_STATUS + (ACPIPM_RESOURCE_EVENTBLK_LEN as u16 / 2) - 1;
521
const PM1_ENABLE_LAST: u16 = PM1_ENABLE + (ACPIPM_RESOURCE_EVENTBLK_LEN as u16 / 2) - 1;
522
const PM1_CONTROL_LAST: u16 = PM1_CONTROL + ACPIPM_RESOURCE_CONTROLBLK_LEN as u16 - 1;
523
const GPE0_STATUS_LAST: u16 = GPE0_STATUS + (ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2) - 1;
524
const GPE0_ENABLE_LAST: u16 = GPE0_ENABLE + (ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2) - 1;
525
526
impl BusDevice for ACPIPMResource {
527
fn device_id(&self) -> DeviceId {
528
PlatformDeviceId::ACPIPMResource.into()
529
}
530
531
fn debug_label(&self) -> String {
532
"ACPIPMResource".to_owned()
533
}
534
535
fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
536
match info.offset as u16 {
537
// Accesses to the PM1 registers are done through byte or word accesses
538
PM1_STATUS..=PM1_STATUS_LAST => {
539
if data.len() > std::mem::size_of::<u16>()
540
|| info.offset + data.len() as u64 > (PM1_STATUS_LAST + 1).into()
541
{
542
warn!("ACPIPM: bad read size: {}", data.len());
543
return;
544
}
545
let offset = (info.offset - PM1_STATUS as u64) as usize;
546
547
let v = self.pm1.lock().status.to_ne_bytes();
548
for (i, j) in (offset..offset + data.len()).enumerate() {
549
data[i] = v[j];
550
}
551
}
552
PM1_ENABLE..=PM1_ENABLE_LAST => {
553
if data.len() > std::mem::size_of::<u16>()
554
|| info.offset + data.len() as u64 > (PM1_ENABLE_LAST + 1).into()
555
{
556
warn!("ACPIPM: bad read size: {}", data.len());
557
return;
558
}
559
let offset = (info.offset - PM1_ENABLE as u64) as usize;
560
561
let v = self.pm1.lock().enable.to_ne_bytes();
562
for (i, j) in (offset..offset + data.len()).enumerate() {
563
data[i] = v[j];
564
}
565
}
566
PM1_CONTROL..=PM1_CONTROL_LAST => {
567
if data.len() > std::mem::size_of::<u16>()
568
|| info.offset + data.len() as u64 > (PM1_CONTROL_LAST + 1).into()
569
{
570
warn!("ACPIPM: bad read size: {}", data.len());
571
return;
572
}
573
let offset = (info.offset - PM1_CONTROL as u64) as usize;
574
data.copy_from_slice(
575
&self.pm1.lock().control.to_ne_bytes()[offset..offset + data.len()],
576
);
577
}
578
// OSPM accesses GPE registers through byte accesses (regardless of their length)
579
GPE0_STATUS..=GPE0_STATUS_LAST => {
580
if data.len() > std::mem::size_of::<u8>()
581
|| info.offset + data.len() as u64 > (GPE0_STATUS_LAST + 1).into()
582
{
583
warn!("ACPIPM: bad read size: {}", data.len());
584
return;
585
}
586
let offset = (info.offset - GPE0_STATUS as u64) as usize;
587
data[0] = self.gpe0.lock().status[offset];
588
}
589
GPE0_ENABLE..=GPE0_ENABLE_LAST => {
590
if data.len() > std::mem::size_of::<u8>()
591
|| info.offset + data.len() as u64 > (GPE0_ENABLE_LAST + 1).into()
592
{
593
warn!("ACPIPM: bad read size: {}", data.len());
594
return;
595
}
596
let offset = (info.offset - GPE0_ENABLE as u64) as usize;
597
data[0] = self.gpe0.lock().enable[offset];
598
}
599
_ => {
600
warn!("ACPIPM: Bad read from {}", info);
601
}
602
}
603
}
604
605
fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
606
match info.offset as u16 {
607
// Accesses to the PM1 registers are done through byte or word accesses
608
PM1_STATUS..=PM1_STATUS_LAST => {
609
if data.len() > std::mem::size_of::<u16>()
610
|| info.offset + data.len() as u64 > (PM1_STATUS_LAST + 1).into()
611
{
612
warn!("ACPIPM: bad write size: {}", data.len());
613
return;
614
}
615
let offset = (info.offset - PM1_STATUS as u64) as usize;
616
617
let mut pm1 = self.pm1.lock();
618
let mut v = pm1.status.to_ne_bytes();
619
for (i, j) in (offset..offset + data.len()).enumerate() {
620
v[j] &= !data[i];
621
}
622
pm1.status = u16::from_ne_bytes(v);
623
}
624
PM1_ENABLE..=PM1_ENABLE_LAST => {
625
if data.len() > std::mem::size_of::<u16>()
626
|| info.offset + data.len() as u64 > (PM1_ENABLE_LAST + 1).into()
627
{
628
warn!("ACPIPM: bad write size: {}", data.len());
629
return;
630
}
631
let offset = (info.offset - PM1_ENABLE as u64) as usize;
632
633
let mut pm1 = self.pm1.lock();
634
let mut v = pm1.enable.to_ne_bytes();
635
for (i, j) in (offset..offset + data.len()).enumerate() {
636
v[j] = data[i];
637
}
638
pm1.enable = u16::from_ne_bytes(v);
639
pm1.resample_clear_evts_and_trigger(&self.sci_evt);
640
}
641
PM1_CONTROL..=PM1_CONTROL_LAST => {
642
if data.len() > std::mem::size_of::<u16>()
643
|| info.offset + data.len() as u64 > (PM1_CONTROL_LAST + 1).into()
644
{
645
warn!("ACPIPM: bad write size: {}", data.len());
646
return;
647
}
648
let offset = (info.offset - PM1_CONTROL as u64) as usize;
649
650
let mut pm1 = self.pm1.lock();
651
652
let mut v = pm1.control.to_ne_bytes();
653
for (i, j) in (offset..offset + data.len()).enumerate() {
654
v[j] = data[i];
655
}
656
let val = u16::from_ne_bytes(v);
657
658
// SLP_EN is a write-only bit and reads to it always return a zero
659
if (val & BITMASK_PM1CNT_SLEEP_ENABLE) != 0 {
660
match val & BITMASK_PM1CNT_SLEEP_TYPE {
661
SLEEP_TYPE_S1 => {
662
if let Err(e) = self.suspend_tube.lock().send(&true) {
663
error!("ACPIPM: failed to trigger suspend event: {}", e);
664
}
665
}
666
SLEEP_TYPE_S5 => {
667
if let Err(e) =
668
self.exit_evt_wrtube.send::<VmEventType>(&VmEventType::Exit)
669
{
670
error!("ACPIPM: failed to trigger exit event: {}", e);
671
}
672
}
673
_ => error!(
674
"ACPIPM: unknown SLP_TYP written: {}",
675
(val & BITMASK_PM1CNT_SLEEP_TYPE) >> 10
676
),
677
}
678
}
679
pm1.control = val & !BITMASK_PM1CNT_SLEEP_ENABLE;
680
681
// Re-trigger PM & GPEs in case there is a pending wakeup that should
682
// override us just having gone to sleep.
683
pm1.resample_clear_evts_and_trigger(&self.sci_evt);
684
self.gpe0
685
.lock()
686
.resample_clear_evts_and_trigger(&self.sci_evt);
687
}
688
// OSPM accesses GPE registers through byte accesses (regardless of their length)
689
GPE0_STATUS..=GPE0_STATUS_LAST => {
690
if data.len() > std::mem::size_of::<u8>()
691
|| info.offset + data.len() as u64 > (GPE0_STATUS_LAST + 1).into()
692
{
693
warn!("ACPIPM: bad write size: {}", data.len());
694
return;
695
}
696
let offset = (info.offset - GPE0_STATUS as u64) as usize;
697
self.gpe0.lock().status[offset] &= !data[0];
698
}
699
GPE0_ENABLE..=GPE0_ENABLE_LAST => {
700
if data.len() > std::mem::size_of::<u8>()
701
|| info.offset + data.len() as u64 > (GPE0_ENABLE_LAST + 1).into()
702
{
703
warn!("ACPIPM: bad write size: {}", data.len());
704
return;
705
}
706
let offset = (info.offset - GPE0_ENABLE as u64) as usize;
707
let mut gpe = self.gpe0.lock();
708
if gpe.enable[offset] != data[0] {
709
gpe.enable[offset] = data[0];
710
gpe.resample_clear_evts_and_trigger(&self.sci_evt);
711
}
712
}
713
_ => {
714
warn!("ACPIPM: Bad write to {}", info);
715
}
716
};
717
}
718
}
719
720
impl BusResumeDevice for ACPIPMResource {
721
fn resume_imminent(&mut self) {
722
self.pm1.lock().status |= BITMASK_PM1CNT_WAKE_STATUS;
723
}
724
}
725
726
impl Aml for ACPIPMResource {
727
fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
728
// S1
729
aml::Name::new(
730
"_S1_".into(),
731
&aml::Package::new(vec![&aml::ONE, &aml::ONE, &aml::ZERO, &aml::ZERO]),
732
)
733
.to_aml_bytes(bytes);
734
735
// S5
736
aml::Name::new(
737
"_S5_".into(),
738
&aml::Package::new(vec![&aml::ZERO, &aml::ZERO, &aml::ZERO, &aml::ZERO]),
739
)
740
.to_aml_bytes(bytes);
741
}
742
}
743
744
pub const PM_WAKEUP_GPIO: u32 = 0;
745
746
pub struct PmWakeupEvent {
747
vm_control_tube: Arc<Mutex<Tube>>,
748
pm_config: Arc<Mutex<PmConfig>>,
749
}
750
751
impl PmWakeupEvent {
752
pub fn new(vm_control_tube: Arc<Mutex<Tube>>, pm_config: Arc<Mutex<PmConfig>>) -> Self {
753
Self {
754
vm_control_tube,
755
pm_config,
756
}
757
}
758
759
pub fn trigger_wakeup(&self) -> anyhow::Result<Option<Event>> {
760
if self.pm_config.lock().should_trigger_pme() {
761
let event = Event::new().context("failed to create clear event")?;
762
let tube = self.vm_control_tube.lock();
763
tube.send(&VmRequest::Gpe {
764
gpe: PM_WAKEUP_GPIO,
765
clear_evt: Some(event.try_clone().context("failed to clone clear event")?),
766
})
767
.context("failed to send pme")?;
768
match tube.recv::<VmResponse>() {
769
Ok(VmResponse::Ok) => Ok(Some(event)),
770
e => bail!("pme failure {:?}", e),
771
}
772
} else {
773
Ok(None)
774
}
775
}
776
}
777
778
#[cfg(test)]
779
mod tests {
780
use base::Tube;
781
782
use super::*;
783
use crate::suspendable_tests;
784
785
fn get_send_tube() -> SendTube {
786
Tube::directional_pair().unwrap().0
787
}
788
789
fn get_irq_evt() -> IrqLevelEvent {
790
match crate::IrqLevelEvent::new() {
791
Ok(evt) => evt,
792
Err(e) => panic!("failed to create irqlevelevt: {e} - panic. Can't test ACPI"),
793
}
794
}
795
796
fn modify_device(acpi: &mut ACPIPMResource) {
797
{
798
let mut pm1 = acpi.pm1.lock();
799
pm1.enable += 1;
800
}
801
}
802
803
suspendable_tests!(
804
acpi,
805
ACPIPMResource::new(
806
get_irq_evt(),
807
Arc::new(Mutex::new(get_send_tube())),
808
get_send_tube(),
809
None,
810
),
811
modify_device
812
);
813
}
814
815