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