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 #[cfg(feature = "direct")]
7 use std::fs;
8 #[cfg(feature = "direct")]
9 use std::io::Error as IoError;
10 #[cfg(feature = "direct")]
11 use std::path::PathBuf;
12 use std::str::FromStr;
13 use std::sync::Arc;
14
15 use acpi_tables::aml;
16 use acpi_tables::aml::Aml;
17 use anyhow::Context;
18 use base::custom_serde::serialize_arc_mutex;
19 use base::error;
20 use base::warn;
21 use base::Error as SysError;
22 use base::Event;
23 use base::EventToken;
24 use base::SendTube;
25 use base::VmEventType;
26 use base::WaitContext;
27 use base::WorkerThread;
28 use serde::Deserialize;
29 use serde::Serialize;
30 use sync::Mutex;
31 use thiserror::Error;
32 use vm_control::GpeNotify;
33 use vm_control::PmResource;
34 use vm_control::PmeNotify;
35
36 use crate::ac_adapter::AcAdapter;
37 use crate::pci::CrosvmDeviceId;
38 use crate::BusAccessInfo;
39 use crate::BusDevice;
40 use crate::BusResumeDevice;
41 use crate::DeviceId;
42 use crate::IrqLevelEvent;
43 use crate::Suspendable;
44
45 #[derive(Error, Debug)]
46 pub enum ACPIPMError {
47 /// Creating WaitContext failed.
48 #[error("failed to create wait context: {0}")]
49 CreateWaitContext(SysError),
50 /// Error while waiting for events.
51 #[error("failed to wait for events: {0}")]
52 WaitError(SysError),
53 #[error("Did not find group_id corresponding to acpi_mc_group")]
54 AcpiMcGroupError,
55 #[error("Failed to create and bind NETLINK_GENERIC socket for acpi_mc_group: {0}")]
56 AcpiEventSockError(base::Error),
57 #[error("GPE {0} is out of bound")]
58 GpeOutOfBound(u32),
59 }
60
61 #[derive(Debug, Copy, Clone, Serialize, Deserialize)]
62 pub enum ACPIPMFixedEvent {
63 GlobalLock,
64 PowerButton,
65 SleepButton,
66 RTC,
67 }
68
69 #[derive(Serialize, Deserialize, Clone)]
70 pub(crate) struct Pm1Resource {
71 pub(crate) status: u16,
72 enable: u16,
73 control: u16,
74 }
75
76 #[derive(Serialize, Deserialize, Clone)]
77 pub(crate) struct GpeResource {
78 pub(crate) status: [u8; ACPIPM_RESOURCE_GPE0_BLK_LEN as usize / 2],
79 enable: [u8; ACPIPM_RESOURCE_GPE0_BLK_LEN as usize / 2],
80 #[serde(skip_serializing, skip_deserializing)]
81 pub(crate) gpe_notify: BTreeMap<u32, Vec<Arc<Mutex<dyn GpeNotify>>>>,
82 }
83
84 #[derive(Serialize, Deserialize, Clone)]
85 pub(crate) struct PciResource {
86 #[serde(skip_serializing, skip_deserializing)]
87 pub(crate) pme_notify: BTreeMap<u8, Vec<Arc<Mutex<dyn PmeNotify>>>>,
88 }
89
90 #[cfg(feature = "direct")]
91 struct DirectGpe {
92 num: u32,
93 path: PathBuf,
94 ready: bool,
95 enabled: bool,
96 }
97
98 #[cfg(feature = "direct")]
99 struct DirectFixedEvent {
100 evt: ACPIPMFixedEvent,
101 bitshift: u16,
102 path: PathBuf,
103 enabled: bool,
104 }
105
106 /// ACPI PM resource for handling OS suspend/resume request
107 #[allow(dead_code)]
108 #[derive(Serialize)]
109 pub struct ACPIPMResource {
110 // This is SCI interrupt that will be raised in the VM.
111 #[serde(skip_serializing)]
112 sci_evt: IrqLevelEvent,
113 // This is the host SCI that is being handled by crosvm.
114 #[cfg(feature = "direct")]
115 #[serde(skip_serializing)]
116 sci_direct_evt: Option<IrqLevelEvent>,
117 #[cfg(feature = "direct")]
118 #[serde(skip_serializing)]
119 direct_gpe: Vec<DirectGpe>,
120 #[cfg(feature = "direct")]
121 #[serde(skip_serializing)]
122 direct_fixed_evts: Vec<DirectFixedEvent>,
123 #[serde(skip_serializing)]
124 worker_thread: Option<WorkerThread<()>>,
125 #[serde(skip_serializing)]
126 suspend_evt: Event,
127 #[serde(skip_serializing)]
128 exit_evt_wrtube: SendTube,
129 #[serde(serialize_with = "serialize_arc_mutex")]
130 pm1: Arc<Mutex<Pm1Resource>>,
131 #[serde(serialize_with = "serialize_arc_mutex")]
132 gpe0: Arc<Mutex<GpeResource>>,
133 #[serde(serialize_with = "serialize_arc_mutex")]
134 pci: Arc<Mutex<PciResource>>,
135 #[serde(skip_serializing)]
136 acdc: Option<Arc<Mutex<AcAdapter>>>,
137 }
138
139 #[derive(Deserialize)]
140 struct ACPIPMResrourceSerializable {
141 pm1: Pm1Resource,
142 gpe0: GpeResource,
143 }
144
145 impl ACPIPMResource {
146 /// Constructs ACPI Power Management Resouce.
147 ///
148 /// `direct_evt_info` - tuple of:
149 /// 1. host SCI trigger and resample events
150 /// 2. list of direct GPEs
151 /// 3. list of direct fixed events
152 #[allow(dead_code)]
new( sci_evt: IrqLevelEvent, #[cfg(feature = "direct")] direct_evt_info: Option<( IrqLevelEvent, &[u32], &[ACPIPMFixedEvent], )>, suspend_evt: Event, exit_evt_wrtube: SendTube, acdc: Option<Arc<Mutex<AcAdapter>>>, ) -> ACPIPMResource153 pub fn new(
154 sci_evt: IrqLevelEvent,
155 #[cfg(feature = "direct")] direct_evt_info: Option<(
156 IrqLevelEvent,
157 &[u32],
158 &[ACPIPMFixedEvent],
159 )>,
160 suspend_evt: Event,
161 exit_evt_wrtube: SendTube,
162 acdc: Option<Arc<Mutex<AcAdapter>>>,
163 ) -> ACPIPMResource {
164 let pm1 = Pm1Resource {
165 status: 0,
166 enable: 0,
167 control: 0,
168 };
169 let gpe0 = GpeResource {
170 status: Default::default(),
171 enable: Default::default(),
172 gpe_notify: BTreeMap::new(),
173 };
174 let pci = PciResource {
175 pme_notify: BTreeMap::new(),
176 };
177
178 #[cfg(feature = "direct")]
179 let (sci_direct_evt, direct_gpe, direct_fixed_evts) = if let Some(info) = direct_evt_info {
180 let (evt, gpes, fixed_evts) = info;
181 let gpe_vec = gpes.iter().map(|gpe| DirectGpe::new(*gpe)).collect();
182 let fixed_evt_vec = fixed_evts
183 .iter()
184 .map(|evt| DirectFixedEvent::new(*evt))
185 .collect();
186 (Some(evt), gpe_vec, fixed_evt_vec)
187 } else {
188 (None, Vec::new(), Vec::new())
189 };
190
191 ACPIPMResource {
192 sci_evt,
193 #[cfg(feature = "direct")]
194 sci_direct_evt,
195 #[cfg(feature = "direct")]
196 direct_gpe,
197 #[cfg(feature = "direct")]
198 direct_fixed_evts,
199 worker_thread: None,
200 suspend_evt,
201 exit_evt_wrtube,
202 pm1: Arc::new(Mutex::new(pm1)),
203 gpe0: Arc::new(Mutex::new(gpe0)),
204 pci: Arc::new(Mutex::new(pci)),
205 acdc,
206 }
207 }
208
start(&mut self)209 pub fn start(&mut self) {
210 let sci_evt = self.sci_evt.try_clone().expect("failed to clone event");
211 let pm1 = self.pm1.clone();
212 let gpe0 = self.gpe0.clone();
213 let acdc = self.acdc.clone();
214
215 #[cfg(feature = "direct")]
216 let sci_direct_evt = self.sci_direct_evt.take();
217
218 #[cfg(feature = "direct")]
219 // ACPI event listener is currently used only for notifying gpe_notify
220 // notifiers when a GPE is fired in the host. For direct forwarded GPEs,
221 // we notify gpe_notify in a different way, ensuring that the notifier
222 // completes synchronously before we inject the GPE into the guest.
223 // So tell ACPI event listener to ignore direct GPEs.
224 let acpi_event_ignored_gpe = self.direct_gpe.iter().map(|gpe| gpe.num).collect();
225
226 #[cfg(not(feature = "direct"))]
227 let acpi_event_ignored_gpe = Vec::new();
228
229 self.worker_thread = Some(WorkerThread::start("ACPI PM worker", move |kill_evt| {
230 if let Err(e) = run_worker(
231 sci_evt,
232 kill_evt,
233 pm1,
234 gpe0,
235 acpi_event_ignored_gpe,
236 #[cfg(feature = "direct")]
237 sci_direct_evt,
238 acdc,
239 ) {
240 error!("{}", e);
241 }
242 }));
243 }
244 }
245
246 impl Suspendable for ACPIPMResource {
snapshot(&self) -> anyhow::Result<serde_json::Value>247 fn snapshot(&self) -> anyhow::Result<serde_json::Value> {
248 serde_json::to_value(self)
249 .with_context(|| format!("error serializing {}", self.debug_label()))
250 }
251
restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>252 fn restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
253 let acpi_snapshot: ACPIPMResrourceSerializable = serde_json::from_value(data)
254 .with_context(|| format!("error deserializing {}", self.debug_label()))?;
255 {
256 let mut pm1 = self.pm1.lock();
257 *pm1 = acpi_snapshot.pm1;
258 }
259 {
260 let mut gpe0 = self.gpe0.lock();
261 gpe0.status = acpi_snapshot.gpe0.status;
262 gpe0.enable = acpi_snapshot.gpe0.enable;
263 }
264 Ok(())
265 }
266
sleep(&mut self) -> anyhow::Result<()>267 fn sleep(&mut self) -> anyhow::Result<()> {
268 if let Some(worker_thread) = self.worker_thread.take() {
269 worker_thread.stop();
270 }
271 Ok(())
272 }
273
wake(&mut self) -> anyhow::Result<()>274 fn wake(&mut self) -> anyhow::Result<()> {
275 self.start();
276 Ok(())
277 }
278 }
279
run_worker( sci_evt: IrqLevelEvent, kill_evt: Event, pm1: Arc<Mutex<Pm1Resource>>, gpe0: Arc<Mutex<GpeResource>>, acpi_event_ignored_gpe: Vec<u32>, #[cfg(feature = "direct")] sci_direct_evt: Option<IrqLevelEvent>, arced_ac_adapter: Option<Arc<Mutex<AcAdapter>>>, ) -> Result<(), ACPIPMError>280 fn run_worker(
281 sci_evt: IrqLevelEvent,
282 kill_evt: Event,
283 pm1: Arc<Mutex<Pm1Resource>>,
284 gpe0: Arc<Mutex<GpeResource>>,
285 acpi_event_ignored_gpe: Vec<u32>,
286 #[cfg(feature = "direct")] sci_direct_evt: Option<IrqLevelEvent>,
287 arced_ac_adapter: Option<Arc<Mutex<AcAdapter>>>,
288 ) -> Result<(), ACPIPMError> {
289 let acpi_event_sock = crate::sys::get_acpi_event_sock()?;
290 #[derive(EventToken)]
291 enum Token {
292 AcpiEvent,
293 InterruptResample,
294 #[cfg(feature = "direct")]
295 InterruptTriggerDirect,
296 Kill,
297 }
298
299 let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
300 (sci_evt.get_resample(), Token::InterruptResample),
301 (&kill_evt, Token::Kill),
302 ])
303 .map_err(ACPIPMError::CreateWaitContext)?;
304 if let Some(acpi_event_sock) = &acpi_event_sock {
305 wait_ctx
306 .add(acpi_event_sock, Token::AcpiEvent)
307 .map_err(ACPIPMError::CreateWaitContext)?;
308 }
309
310 #[cfg(feature = "direct")]
311 if let Some(ref evt) = sci_direct_evt {
312 wait_ctx
313 .add(evt.get_trigger(), Token::InterruptTriggerDirect)
314 .map_err(ACPIPMError::CreateWaitContext)?;
315 }
316
317 #[cfg(feature = "direct")]
318 let mut pending_sci_direct: Option<&IrqLevelEvent> = None;
319
320 loop {
321 let events = wait_ctx.wait().map_err(ACPIPMError::WaitError)?;
322 for event in events.iter().filter(|e| e.is_readable) {
323 match event.token {
324 Token::AcpiEvent => {
325 crate::sys::acpi_event_run(
326 &sci_evt,
327 &acpi_event_sock,
328 &gpe0,
329 &acpi_event_ignored_gpe,
330 &arced_ac_adapter,
331 );
332 }
333 Token::InterruptResample => {
334 sci_evt.clear_resample();
335
336 #[cfg(feature = "direct")]
337 if let Some(evt) = pending_sci_direct.take() {
338 if let Err(e) = evt.trigger_resample() {
339 error!("ACPIPM: failed to resample sci event: {}", e);
340 }
341 }
342
343 // Re-trigger SCI if PM1 or GPE status is still not cleared.
344 pm1.lock().trigger_sci(&sci_evt);
345 gpe0.lock().trigger_sci(&sci_evt);
346 }
347 #[cfg(feature = "direct")]
348 Token::InterruptTriggerDirect => {
349 if let Some(ref evt) = sci_direct_evt {
350 evt.clear_trigger();
351
352 for (gpe, devs) in &gpe0.lock().gpe_notify {
353 if DirectGpe::is_gpe_trigger(*gpe).unwrap_or(false) {
354 for dev in devs {
355 dev.lock().notify();
356 }
357 }
358 }
359
360 if let Err(e) = sci_evt.trigger() {
361 error!("ACPIPM: failed to trigger sci event: {}", e);
362 }
363 pending_sci_direct = Some(evt);
364 }
365 }
366 Token::Kill => return Ok(()),
367 }
368 }
369 }
370 }
371
372 impl Pm1Resource {
trigger_sci(&self, sci_evt: &IrqLevelEvent)373 fn trigger_sci(&self, sci_evt: &IrqLevelEvent) {
374 if self.status & self.enable & ACPIPMFixedEvent::bitmask_all() != 0 {
375 if let Err(e) = sci_evt.trigger() {
376 error!("ACPIPM: failed to trigger sci event for pm1: {}", e);
377 }
378 }
379 }
380 }
381
382 impl GpeResource {
trigger_sci(&self, sci_evt: &IrqLevelEvent)383 pub fn trigger_sci(&self, sci_evt: &IrqLevelEvent) {
384 if (0..self.status.len()).any(|i| self.status[i] & self.enable[i] != 0) {
385 if let Err(e) = sci_evt.trigger() {
386 error!("ACPIPM: failed to trigger sci event for gpe: {}", e);
387 }
388 }
389 }
390
set_active(&mut self, gpe: u32) -> Result<(), ACPIPMError>391 pub fn set_active(&mut self, gpe: u32) -> Result<(), ACPIPMError> {
392 if let Some(status_byte) = self.status.get_mut(gpe as usize / 8) {
393 *status_byte |= 1 << (gpe % 8);
394 } else {
395 return Err(ACPIPMError::GpeOutOfBound(gpe));
396 }
397 Ok(())
398 }
399 }
400
401 #[cfg(feature = "direct")]
402 impl DirectGpe {
new(gpe: u32) -> DirectGpe403 fn new(gpe: u32) -> DirectGpe {
404 DirectGpe {
405 num: gpe,
406 path: PathBuf::from("/sys/firmware/acpi/interrupts").join(format!("gpe{:02X}", gpe)),
407 ready: false,
408 enabled: false,
409 }
410 }
411
is_status_set(&self) -> Result<bool, IoError>412 fn is_status_set(&self) -> Result<bool, IoError> {
413 match fs::read_to_string(&self.path) {
414 Err(e) => {
415 error!("ACPIPM: failed to read gpe {} STS: {}", self.num, e);
416 Err(e)
417 }
418 Ok(s) => Ok(s.split_whitespace().any(|s| s == "STS")),
419 }
420 }
421
is_enabled(&self) -> Result<bool, IoError>422 fn is_enabled(&self) -> Result<bool, IoError> {
423 match fs::read_to_string(&self.path) {
424 Err(e) => {
425 error!("ACPIPM: failed to read gpe {} EN: {}", self.num, e);
426 Err(e)
427 }
428 Ok(s) => Ok(s.split_whitespace().any(|s| s == "EN")),
429 }
430 }
431
clear(&self)432 fn clear(&self) {
433 if !self.is_status_set().unwrap_or(false) {
434 // Just to avoid harmless error messages due to clearing an already cleared GPE.
435 return;
436 }
437
438 if let Err(e) = fs::write(&self.path, "clear\n") {
439 error!("ACPIPM: failed to clear gpe {}: {}", self.num, e);
440 }
441 }
442
enable(&mut self)443 fn enable(&mut self) {
444 if self.enabled {
445 // Just to avoid harmless error messages due to enabling an already enabled GPE.
446 return;
447 }
448
449 if !self.ready {
450 // The GPE is being enabled for the first time.
451 // Use "enable" to ensure the ACPICA's reference count for this GPE is > 0.
452 match fs::write(&self.path, "enable\n") {
453 Err(e) => error!("ACPIPM: failed to enable gpe {}: {}", self.num, e),
454 Ok(()) => {
455 self.ready = true;
456 self.enabled = true;
457 }
458 }
459 } else {
460 // Use "unmask" instead of "enable", to bypass ACPICA's reference counting.
461 match fs::write(&self.path, "unmask\n") {
462 Err(e) => error!("ACPIPM: failed to unmask gpe {}: {}", self.num, e),
463 Ok(()) => {
464 self.enabled = true;
465 }
466 }
467 }
468 }
469
disable(&mut self)470 fn disable(&mut self) {
471 if !self.enabled {
472 // Just to avoid harmless error messages due to disabling an already disabled GPE.
473 return;
474 }
475
476 // Use "mask" instead of "disable", to bypass ACPICA's reference counting.
477 match fs::write(&self.path, "mask\n") {
478 Err(e) => error!("ACPIPM: failed to mask gpe {}: {}", self.num, e),
479 Ok(()) => {
480 self.enabled = false;
481 }
482 }
483 }
484
is_gpe_trigger(gpe: u32) -> Result<bool, IoError>485 fn is_gpe_trigger(gpe: u32) -> Result<bool, IoError> {
486 let path = PathBuf::from("/sys/firmware/acpi/interrupts").join(format!("gpe{:02X}", gpe));
487 let s = fs::read_to_string(&path)?;
488 let mut enable = false;
489 let mut status = false;
490 for itr in s.split_whitespace() {
491 match itr {
492 "EN" => enable = true,
493 "STS" => status = true,
494 _ => (),
495 }
496 }
497
498 Ok(enable && status)
499 }
500 }
501
502 #[cfg(feature = "direct")]
503 impl DirectFixedEvent {
new(evt: ACPIPMFixedEvent) -> DirectFixedEvent504 fn new(evt: ACPIPMFixedEvent) -> DirectFixedEvent {
505 DirectFixedEvent {
506 evt,
507 bitshift: evt.bitshift(),
508 path: PathBuf::from("/sys/firmware/acpi/interrupts").join(match evt {
509 ACPIPMFixedEvent::GlobalLock => "ff_gbl_lock",
510 ACPIPMFixedEvent::PowerButton => "ff_pwr_btn",
511 ACPIPMFixedEvent::SleepButton => "ff_slp_btn",
512 ACPIPMFixedEvent::RTC => "ff_rt_clk",
513 }),
514 enabled: false,
515 }
516 }
517
is_status_set(&self) -> Result<bool, IoError>518 fn is_status_set(&self) -> Result<bool, IoError> {
519 match fs::read_to_string(&self.path) {
520 Err(e) => {
521 error!("ACPIPM: failed to read {:?} event STS: {}", self.evt, e);
522 Err(e)
523 }
524 Ok(s) => Ok(s.split_whitespace().any(|s| s == "STS")),
525 }
526 }
527
is_enabled(&self) -> Result<bool, IoError>528 fn is_enabled(&self) -> Result<bool, IoError> {
529 match fs::read_to_string(&self.path) {
530 Err(e) => {
531 error!("ACPIPM: failed to read {:?} event EN: {}", self.evt, e);
532 Err(e)
533 }
534 Ok(s) => Ok(s.split_whitespace().any(|s| s == "EN")),
535 }
536 }
537
clear(&self)538 fn clear(&self) {
539 if !self.is_status_set().unwrap_or(false) {
540 // Just to avoid harmless error messages due to clearing an already cleared event.
541 return;
542 }
543
544 if let Err(e) = fs::write(&self.path, "clear\n") {
545 error!("ACPIPM: failed to clear {:?} event: {}", self.evt, e);
546 }
547 }
548
enable(&mut self)549 fn enable(&mut self) {
550 if self.enabled {
551 // Just to avoid harmless error messages due to enabling an already enabled event.
552 return;
553 }
554
555 match fs::write(&self.path, "enable\n") {
556 Err(e) => error!("ACPIPM: failed to enable {:?} event: {}", self.evt, e),
557 Ok(()) => {
558 self.enabled = true;
559 }
560 }
561 }
562
disable(&mut self)563 fn disable(&mut self) {
564 if !self.enabled {
565 // Just to avoid harmless error messages due to disabling an already disabled event.
566 return;
567 }
568
569 match fs::write(&self.path, "disable\n") {
570 Err(e) => error!("ACPIPM: failed to disable {:?} event: {}", self.evt, e),
571 Ok(()) => {
572 self.enabled = false;
573 }
574 }
575 }
576 }
577
578 /// the ACPI PM register length.
579 pub const ACPIPM_RESOURCE_EVENTBLK_LEN: u8 = 4;
580 pub const ACPIPM_RESOURCE_CONTROLBLK_LEN: u8 = 2;
581 pub const ACPIPM_RESOURCE_GPE0_BLK_LEN: u8 = 64;
582 pub const ACPIPM_RESOURCE_LEN: u8 = ACPIPM_RESOURCE_EVENTBLK_LEN + 4 + ACPIPM_RESOURCE_GPE0_BLK_LEN;
583
584 // Should be in sync with gpe_allocator range
585 pub const ACPIPM_GPE_MAX: u16 = ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2 * 8 - 1;
586
587 /// ACPI PM register value definitions
588
589 /// 4.8.4.1.1 PM1 Status Registers, ACPI Spec Version 6.4
590 /// Register Location: <PM1a_EVT_BLK / PM1b_EVT_BLK> System I/O or Memory Space (defined in FADT)
591 /// Size: PM1_EVT_LEN / 2 (defined in FADT)
592 const PM1_STATUS: u16 = 0;
593
594 /// 4.8.4.1.2 PM1Enable Registers, ACPI Spec Version 6.4
595 /// Register Location: <<PM1a_EVT_BLK / PM1b_EVT_BLK> + PM1_EVT_LEN / 2 System I/O or Memory Space
596 /// (defined in FADT)
597 /// Size: PM1_EVT_LEN / 2 (defined in FADT)
598 const PM1_ENABLE: u16 = PM1_STATUS + (ACPIPM_RESOURCE_EVENTBLK_LEN as u16 / 2);
599
600 /// 4.8.4.2.1 PM1 Control Registers, ACPI Spec Version 6.4
601 /// Register Location: <PM1a_CNT_BLK / PM1b_CNT_BLK> System I/O or Memory Space (defined in FADT)
602 /// Size: PM1_CNT_LEN (defined in FADT)
603 const PM1_CONTROL: u16 = PM1_STATUS + ACPIPM_RESOURCE_EVENTBLK_LEN as u16;
604
605 /// 4.8.5.1 General-Purpose Event Register Blocks, ACPI Spec Version 6.4
606 /// - Each register block contains two registers: an enable and a status register.
607 /// - Each register block is 32-bit aligned.
608 /// - Each register in the block is accessed as a byte.
609
610 /// 4.8.5.1.1 General-Purpose Event 0 Register Block, ACPI Spec Version 6.4
611 /// This register block consists of two registers: The GPE0_STS and the GPE0_EN registers. Each
612 /// register’s length is defined to be half the length of the GPE0 register block, and is described
613 /// in the ACPI FADT’s GPE0_BLK and GPE0_BLK_LEN operators.
614
615 /// 4.8.5.1.1.1 General-Purpose Event 0 Status Register, ACPI Spec Version 6.4
616 /// Register Location: <GPE0_STS> System I/O or System Memory Space (defined in FADT)
617 /// Size: GPE0_BLK_LEN/2 (defined in FADT)
618 const GPE0_STATUS: u16 = PM1_STATUS + ACPIPM_RESOURCE_EVENTBLK_LEN as u16 + 4; // ensure alignment
619
620 /// 4.8.5.1.1.2 General-Purpose Event 0 Enable Register, ACPI Spec Version 6.4
621 /// Register Location: <GPE0_EN> System I/O or System Memory Space (defined in FADT)
622 /// Size: GPE0_BLK_LEN/2 (defined in FADT)
623 const GPE0_ENABLE: u16 = GPE0_STATUS + (ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2);
624
625 /// 4.8.4.1.1, 4.8.4.1.2 Fixed event bits in both PM1 Status and PM1 Enable registers.
626 const BITSHIFT_PM1_GBL: u16 = 5;
627 const BITSHIFT_PM1_PWRBTN: u16 = 8;
628 const BITSHIFT_PM1_SLPBTN: u16 = 9;
629 const BITSHIFT_PM1_RTC: u16 = 10;
630
631 const BITMASK_PM1CNT_SLEEP_ENABLE: u16 = 0x2000;
632 const BITMASK_PM1CNT_WAKE_STATUS: u16 = 0x8000;
633
634 #[cfg(not(feature = "direct"))]
635 const BITMASK_PM1CNT_SLEEP_TYPE: u16 = 0x1C00;
636 #[cfg(not(feature = "direct"))]
637 const SLEEP_TYPE_S1: u16 = 1 << 10;
638 #[cfg(not(feature = "direct"))]
639 const SLEEP_TYPE_S5: u16 = 0 << 10;
640
641 impl ACPIPMFixedEvent {
bitshift(self) -> u16642 fn bitshift(self) -> u16 {
643 match self {
644 ACPIPMFixedEvent::GlobalLock => BITSHIFT_PM1_GBL,
645 ACPIPMFixedEvent::PowerButton => BITSHIFT_PM1_PWRBTN,
646 ACPIPMFixedEvent::SleepButton => BITSHIFT_PM1_SLPBTN,
647 ACPIPMFixedEvent::RTC => BITSHIFT_PM1_RTC,
648 }
649 }
650
bitmask(self) -> u16651 pub(crate) fn bitmask(self) -> u16 {
652 1 << self.bitshift()
653 }
654
bitmask_all() -> u16655 fn bitmask_all() -> u16 {
656 (1 << BITSHIFT_PM1_GBL)
657 | (1 << BITSHIFT_PM1_PWRBTN)
658 | (1 << BITSHIFT_PM1_SLPBTN)
659 | (1 << BITSHIFT_PM1_RTC)
660 }
661 }
662
663 impl FromStr for ACPIPMFixedEvent {
664 type Err = &'static str;
665
from_str(s: &str) -> Result<Self, Self::Err>666 fn from_str(s: &str) -> Result<Self, Self::Err> {
667 match s {
668 "gbllock" => Ok(ACPIPMFixedEvent::GlobalLock),
669 "powerbtn" => Ok(ACPIPMFixedEvent::PowerButton),
670 "sleepbtn" => Ok(ACPIPMFixedEvent::SleepButton),
671 "rtc" => Ok(ACPIPMFixedEvent::RTC),
672 _ => Err("unknown event, must be: gbllock|powerbtn|sleepbtn|rtc"),
673 }
674 }
675 }
676
677 impl PmResource for ACPIPMResource {
pwrbtn_evt(&mut self)678 fn pwrbtn_evt(&mut self) {
679 let mut pm1 = self.pm1.lock();
680
681 pm1.status |= ACPIPMFixedEvent::PowerButton.bitmask();
682 pm1.trigger_sci(&self.sci_evt);
683 }
684
slpbtn_evt(&mut self)685 fn slpbtn_evt(&mut self) {
686 let mut pm1 = self.pm1.lock();
687
688 pm1.status |= ACPIPMFixedEvent::SleepButton.bitmask();
689 pm1.trigger_sci(&self.sci_evt);
690 }
691
rtc_evt(&mut self)692 fn rtc_evt(&mut self) {
693 let mut pm1 = self.pm1.lock();
694
695 pm1.status |= ACPIPMFixedEvent::RTC.bitmask();
696 pm1.trigger_sci(&self.sci_evt);
697 }
698
gpe_evt(&mut self, gpe: u32)699 fn gpe_evt(&mut self, gpe: u32) {
700 let mut gpe0 = self.gpe0.lock();
701
702 match gpe0.set_active(gpe) {
703 Ok(_) => gpe0.trigger_sci(&self.sci_evt),
704 Err(e) => error!("{}", e),
705 }
706 }
707
pme_evt(&mut self, requester_id: u16)708 fn pme_evt(&mut self, requester_id: u16) {
709 let bus = ((requester_id >> 8) & 0xFF) as u8;
710 let mut pci = self.pci.lock();
711 if let Some(root_ports) = pci.pme_notify.get_mut(&bus) {
712 for root_port in root_ports {
713 root_port.lock().notify(requester_id);
714 }
715 }
716 }
717
register_gpe_notify_dev(&mut self, gpe: u32, notify_dev: Arc<Mutex<dyn GpeNotify>>)718 fn register_gpe_notify_dev(&mut self, gpe: u32, notify_dev: Arc<Mutex<dyn GpeNotify>>) {
719 let mut gpe0 = self.gpe0.lock();
720 match gpe0.gpe_notify.get_mut(&gpe) {
721 Some(v) => v.push(notify_dev),
722 None => {
723 gpe0.gpe_notify.insert(gpe, vec![notify_dev]);
724 }
725 }
726 }
727
register_pme_notify_dev(&mut self, bus: u8, notify_dev: Arc<Mutex<dyn PmeNotify>>)728 fn register_pme_notify_dev(&mut self, bus: u8, notify_dev: Arc<Mutex<dyn PmeNotify>>) {
729 let mut pci = self.pci.lock();
730 match pci.pme_notify.get_mut(&bus) {
731 Some(v) => v.push(notify_dev),
732 None => {
733 pci.pme_notify.insert(bus, vec![notify_dev]);
734 }
735 }
736 }
737 }
738
739 const PM1_STATUS_LAST: u16 = PM1_STATUS + (ACPIPM_RESOURCE_EVENTBLK_LEN as u16 / 2) - 1;
740 const PM1_ENABLE_LAST: u16 = PM1_ENABLE + (ACPIPM_RESOURCE_EVENTBLK_LEN as u16 / 2) - 1;
741 const PM1_CONTROL_LAST: u16 = PM1_CONTROL + ACPIPM_RESOURCE_CONTROLBLK_LEN as u16 - 1;
742 const GPE0_STATUS_LAST: u16 = GPE0_STATUS + (ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2) - 1;
743 const GPE0_ENABLE_LAST: u16 = GPE0_ENABLE + (ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2) - 1;
744
745 impl BusDevice for ACPIPMResource {
device_id(&self) -> DeviceId746 fn device_id(&self) -> DeviceId {
747 CrosvmDeviceId::ACPIPMResource.into()
748 }
749
debug_label(&self) -> String750 fn debug_label(&self) -> String {
751 "ACPIPMResource".to_owned()
752 }
753
read(&mut self, info: BusAccessInfo, data: &mut [u8])754 fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
755 match info.offset as u16 {
756 // Accesses to the PM1 registers are done through byte or word accesses
757 PM1_STATUS..=PM1_STATUS_LAST => {
758 if data.len() > std::mem::size_of::<u16>()
759 || info.offset + data.len() as u64 > (PM1_STATUS_LAST + 1).into()
760 {
761 warn!("ACPIPM: bad read size: {}", data.len());
762 return;
763 }
764 let offset = (info.offset - PM1_STATUS as u64) as usize;
765
766 let v = self.pm1.lock().status.to_ne_bytes();
767 for (i, j) in (offset..offset + data.len()).enumerate() {
768 data[i] = v[j];
769
770 #[cfg(feature = "direct")]
771 for evt in self
772 .direct_fixed_evts
773 .iter()
774 .filter(|evt| evt.bitshift / 8 == j as u16)
775 {
776 data[i] &= !(1 << (evt.bitshift % 8));
777 if evt.is_status_set().unwrap_or(false) {
778 data[i] |= 1 << (evt.bitshift % 8);
779 }
780 }
781 }
782 }
783 PM1_ENABLE..=PM1_ENABLE_LAST => {
784 if data.len() > std::mem::size_of::<u16>()
785 || info.offset + data.len() as u64 > (PM1_ENABLE_LAST + 1).into()
786 {
787 warn!("ACPIPM: bad read size: {}", data.len());
788 return;
789 }
790 let offset = (info.offset - PM1_ENABLE as u64) as usize;
791
792 let v = self.pm1.lock().enable.to_ne_bytes();
793 for (i, j) in (offset..offset + data.len()).enumerate() {
794 data[i] = v[j];
795
796 #[cfg(feature = "direct")]
797 for evt in self
798 .direct_fixed_evts
799 .iter()
800 .filter(|evt| evt.bitshift / 8 == j as u16)
801 {
802 data[i] &= !(1 << (evt.bitshift % 8));
803 if evt.is_enabled().unwrap_or(false) {
804 data[i] |= 1 << (evt.bitshift % 8);
805 }
806 }
807 }
808 }
809 PM1_CONTROL..=PM1_CONTROL_LAST => {
810 if data.len() > std::mem::size_of::<u16>()
811 || info.offset + data.len() as u64 > (PM1_CONTROL_LAST + 1).into()
812 {
813 warn!("ACPIPM: bad read size: {}", data.len());
814 return;
815 }
816 let offset = (info.offset - PM1_CONTROL as u64) as usize;
817 data.copy_from_slice(
818 &self.pm1.lock().control.to_ne_bytes()[offset..offset + data.len()],
819 );
820 }
821 // OSPM accesses GPE registers through byte accesses (regardless of their length)
822 GPE0_STATUS..=GPE0_STATUS_LAST => {
823 if data.len() > std::mem::size_of::<u8>()
824 || info.offset + data.len() as u64 > (GPE0_STATUS_LAST + 1).into()
825 {
826 warn!("ACPIPM: bad read size: {}", data.len());
827 return;
828 }
829 let offset = (info.offset - GPE0_STATUS as u64) as usize;
830 data[0] = self.gpe0.lock().status[offset];
831
832 #[cfg(feature = "direct")]
833 for gpe in self
834 .direct_gpe
835 .iter()
836 .filter(|gpe| gpe.num / 8 == offset as u32)
837 {
838 data[0] &= !(1 << (gpe.num % 8));
839 if gpe.is_status_set().unwrap_or(false) {
840 data[0] |= 1 << (gpe.num % 8);
841 }
842 }
843 }
844 GPE0_ENABLE..=GPE0_ENABLE_LAST => {
845 if data.len() > std::mem::size_of::<u8>()
846 || info.offset + data.len() as u64 > (GPE0_ENABLE_LAST + 1).into()
847 {
848 warn!("ACPIPM: bad read size: {}", data.len());
849 return;
850 }
851 let offset = (info.offset - GPE0_ENABLE as u64) as usize;
852 data[0] = self.gpe0.lock().enable[offset];
853
854 #[cfg(feature = "direct")]
855 for gpe in self
856 .direct_gpe
857 .iter()
858 .filter(|gpe| gpe.num / 8 == offset as u32)
859 {
860 data[0] &= !(1 << (gpe.num % 8));
861 if gpe.is_enabled().unwrap_or(false) {
862 data[0] |= 1 << (gpe.num % 8);
863 }
864 }
865 }
866 _ => {
867 warn!("ACPIPM: Bad read from {}", info);
868 }
869 }
870 }
871
write(&mut self, info: BusAccessInfo, data: &[u8])872 fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
873 match info.offset as u16 {
874 // Accesses to the PM1 registers are done through byte or word accesses
875 PM1_STATUS..=PM1_STATUS_LAST => {
876 if data.len() > std::mem::size_of::<u16>()
877 || info.offset + data.len() as u64 > (PM1_STATUS_LAST + 1).into()
878 {
879 warn!("ACPIPM: bad write size: {}", data.len());
880 return;
881 }
882 let offset = (info.offset - PM1_STATUS as u64) as usize;
883
884 let mut pm1 = self.pm1.lock();
885 let mut v = pm1.status.to_ne_bytes();
886 for (i, j) in (offset..offset + data.len()).enumerate() {
887 #[cfg(feature = "direct")]
888 for evt in self
889 .direct_fixed_evts
890 .iter()
891 .filter(|evt| evt.bitshift / 8 == j as u16)
892 {
893 if data[i] & (1 << (evt.bitshift % 8)) != 0 {
894 evt.clear();
895 }
896 }
897
898 v[j] &= !data[i];
899 }
900 pm1.status = u16::from_ne_bytes(v);
901 }
902 PM1_ENABLE..=PM1_ENABLE_LAST => {
903 if data.len() > std::mem::size_of::<u16>()
904 || info.offset + data.len() as u64 > (PM1_ENABLE_LAST + 1).into()
905 {
906 warn!("ACPIPM: bad write size: {}", data.len());
907 return;
908 }
909 let offset = (info.offset - PM1_ENABLE as u64) as usize;
910
911 let mut pm1 = self.pm1.lock();
912 let mut v = pm1.enable.to_ne_bytes();
913 for (i, j) in (offset..offset + data.len()).enumerate() {
914 #[cfg(feature = "direct")]
915 for evt in self
916 .direct_fixed_evts
917 .iter_mut()
918 .filter(|evt| evt.bitshift / 8 == j as u16)
919 {
920 if data[i] & (1 << (evt.bitshift % 8)) != 0 {
921 evt.enable();
922 } else {
923 evt.disable();
924 }
925 }
926
927 v[j] = data[i];
928 }
929 pm1.enable = u16::from_ne_bytes(v);
930 pm1.trigger_sci(&self.sci_evt);
931 }
932 PM1_CONTROL..=PM1_CONTROL_LAST => {
933 if data.len() > std::mem::size_of::<u16>()
934 || info.offset + data.len() as u64 > (PM1_CONTROL_LAST + 1).into()
935 {
936 warn!("ACPIPM: bad write size: {}", data.len());
937 return;
938 }
939 let offset = (info.offset - PM1_CONTROL as u64) as usize;
940
941 let mut pm1 = self.pm1.lock();
942
943 let mut v = pm1.control.to_ne_bytes();
944 for (i, j) in (offset..offset + data.len()).enumerate() {
945 v[j] = data[i];
946 }
947 let val = u16::from_ne_bytes(v);
948
949 // SLP_EN is a write-only bit and reads to it always return a zero
950 if (val & BITMASK_PM1CNT_SLEEP_ENABLE) != 0 {
951 // only support S5 in direct mode
952 #[cfg(feature = "direct")]
953 if let Err(e) = self.exit_evt_wrtube.send::<VmEventType>(&VmEventType::Exit) {
954 error!("ACPIPM: failed to trigger exit event: {}", e);
955 }
956 #[cfg(not(feature = "direct"))]
957 match val & BITMASK_PM1CNT_SLEEP_TYPE {
958 SLEEP_TYPE_S1 => {
959 if let Err(e) = self.suspend_evt.signal() {
960 error!("ACPIPM: failed to trigger suspend event: {}", e);
961 }
962 }
963 SLEEP_TYPE_S5 => {
964 if let Err(e) =
965 self.exit_evt_wrtube.send::<VmEventType>(&VmEventType::Exit)
966 {
967 error!("ACPIPM: failed to trigger exit event: {}", e);
968 }
969 }
970 _ => error!(
971 "ACPIPM: unknown SLP_TYP written: {}",
972 (val & BITMASK_PM1CNT_SLEEP_TYPE) >> 10
973 ),
974 }
975 }
976 pm1.control = val & !BITMASK_PM1CNT_SLEEP_ENABLE;
977 }
978 // OSPM accesses GPE registers through byte accesses (regardless of their length)
979 GPE0_STATUS..=GPE0_STATUS_LAST => {
980 if data.len() > std::mem::size_of::<u8>()
981 || info.offset + data.len() as u64 > (GPE0_STATUS_LAST + 1).into()
982 {
983 warn!("ACPIPM: bad write size: {}", data.len());
984 return;
985 }
986 let offset = (info.offset - GPE0_STATUS as u64) as usize;
987
988 #[cfg(feature = "direct")]
989 for gpe in self
990 .direct_gpe
991 .iter()
992 .filter(|gpe| gpe.num / 8 == offset as u32)
993 {
994 if data[0] & (1 << (gpe.num % 8)) != 0 {
995 gpe.clear();
996 }
997 }
998
999 self.gpe0.lock().status[offset] &= !data[0];
1000 }
1001 GPE0_ENABLE..=GPE0_ENABLE_LAST => {
1002 if data.len() > std::mem::size_of::<u8>()
1003 || info.offset + data.len() as u64 > (GPE0_ENABLE_LAST + 1).into()
1004 {
1005 warn!("ACPIPM: bad write size: {}", data.len());
1006 return;
1007 }
1008 let offset = (info.offset - GPE0_ENABLE as u64) as usize;
1009
1010 #[cfg(feature = "direct")]
1011 for gpe in self
1012 .direct_gpe
1013 .iter_mut()
1014 .filter(|gpe| gpe.num / 8 == offset as u32)
1015 {
1016 if data[0] & (1 << (gpe.num % 8)) != 0 {
1017 gpe.enable();
1018 } else {
1019 gpe.disable();
1020 }
1021 }
1022
1023 let mut gpe = self.gpe0.lock();
1024 gpe.enable[offset] = data[0];
1025 gpe.trigger_sci(&self.sci_evt);
1026 }
1027 _ => {
1028 warn!("ACPIPM: Bad write to {}", info);
1029 }
1030 };
1031 }
1032 }
1033
1034 impl BusResumeDevice for ACPIPMResource {
resume_imminent(&mut self)1035 fn resume_imminent(&mut self) {
1036 self.pm1.lock().status |= BITMASK_PM1CNT_WAKE_STATUS;
1037 }
1038 }
1039
1040 impl Aml for ACPIPMResource {
to_aml_bytes(&self, bytes: &mut Vec<u8>)1041 fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
1042 // S1
1043 aml::Name::new(
1044 "_S1_".into(),
1045 &aml::Package::new(vec![&aml::ONE, &aml::ONE, &aml::ZERO, &aml::ZERO]),
1046 )
1047 .to_aml_bytes(bytes);
1048
1049 // S5
1050 aml::Name::new(
1051 "_S5_".into(),
1052 &aml::Package::new(vec![&aml::ZERO, &aml::ZERO, &aml::ZERO, &aml::ZERO]),
1053 )
1054 .to_aml_bytes(bytes);
1055 }
1056 }
1057
1058 #[cfg(test)]
1059 mod tests {
1060 use base::SendTube;
1061 use base::Tube;
1062
1063 use super::*;
1064 use crate::suspendable_tests;
1065
get_evt_tube() -> SendTube1066 fn get_evt_tube() -> SendTube {
1067 let (vm_evt_wrtube, _) = Tube::directional_pair().unwrap();
1068 vm_evt_wrtube
1069 }
1070
get_irq_evt() -> IrqLevelEvent1071 fn get_irq_evt() -> IrqLevelEvent {
1072 match crate::IrqLevelEvent::new() {
1073 Ok(evt) => evt,
1074 Err(e) => panic!(
1075 "failed to create irqlevelevt: {} - panic. Can't test ACPI",
1076 e
1077 ),
1078 }
1079 }
1080
modify_device(acpi: &mut ACPIPMResource)1081 fn modify_device(acpi: &mut ACPIPMResource) {
1082 {
1083 let mut pm1 = acpi.pm1.lock();
1084 pm1.enable += 1;
1085 }
1086 }
1087
1088 suspendable_tests!(
1089 acpi,
1090 ACPIPMResource::new(
1091 get_irq_evt(),
1092 #[cfg(feature = "direct")]
1093 None,
1094 Event::new().unwrap(),
1095 get_evt_tube(),
1096 None,
1097 ),
1098 modify_device
1099 );
1100 }
1101