1use std::collections::BTreeMap;
6use std::str::FromStr;
7use std::sync::Arc;
8use std::time::Duration;
9
10use acpi_tables::aml;
11use acpi_tables::aml::Aml;
12use anyhow::bail;
13use anyhow::Context;
14use base::custom_serde::serialize_arc_mutex;
15use base::error;
16use base::warn;
17use base::Error as SysError;
18use base::Event;
19use base::EventToken;
20use base::EventWaitResult;
21use base::SendTube;
22use base::Tube;
23use base::VmEventType;
24use base::WaitContext;
25use base::WorkerThread;
26use serde::Deserialize;
27use serde::Serialize;
28use snapshot::AnySnapshot;
29use sync::Mutex;
30use thiserror::Error;
31use vm_control::DeviceId;
32use vm_control::PlatformDeviceId;
33use vm_control::PmResource;
34use vm_control::PmeNotify;
35use vm_control::VmRequest;
36use vm_control::VmResponse;
37
38use crate::pci::pm::PmConfig;
39use crate::BusAccessInfo;
40use crate::BusDevice;
41use crate::BusResumeDevice;
42use crate::IrqLevelEvent;
43use crate::Suspendable;
44
45#[derive(Error, Debug)]
46pub enum ACPIPMError {
47 #[error("failed to create wait context: {0}")]
49 CreateWaitContext(SysError),
50 #[error("failed to wait for events: {0}")]
52 WaitError(SysError),
53 #[error("GPE {0} is out of bound")]
54 GpeOutOfBound(u32),
55}
56
57#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
58pub enum ACPIPMFixedEvent {
59 GlobalLock,
60 PowerButton,
61 SleepButton,
62 RTC,
63}
64
65#[derive(Serialize)]
66pub(crate) struct Pm1Resource {
67 pub(crate) status: u16,
68 enable: u16,
69 control: u16,
70 #[serde(skip_serializing)]
71 suspend_tube: Arc<Mutex<SendTube>>,
72 #[serde(skip_serializing)]
73 rtc_clear_evt: Option<Event>,
74}
75
76#[derive(Deserialize)]
77struct Pm1ResourceSerializable {
78 status: u16,
79 enable: u16,
80 control: u16,
81}
82
83#[derive(Serialize)]
84pub(crate) struct GpeResource {
85 pub(crate) status: [u8; ACPIPM_RESOURCE_GPE0_BLK_LEN as usize / 2],
86 enable: [u8; ACPIPM_RESOURCE_GPE0_BLK_LEN as usize / 2],
87 #[serde(skip_serializing)]
90 pending_clear_evts: BTreeMap<u32, Vec<Event>>,
91 #[serde(skip_serializing)]
92 suspend_tube: Arc<Mutex<SendTube>>,
93}
94
95#[derive(Deserialize)]
96struct GpeResourceSerializable {
97 status: [u8; ACPIPM_RESOURCE_GPE0_BLK_LEN as usize / 2],
98 enable: [u8; ACPIPM_RESOURCE_GPE0_BLK_LEN as usize / 2],
99}
100
101#[derive(Serialize, Deserialize, Clone)]
102pub(crate) struct PciResource {
103 #[serde(skip_serializing, skip_deserializing)]
104 pub(crate) pme_notify: BTreeMap<u8, Vec<Arc<Mutex<dyn PmeNotify>>>>,
105}
106
107#[allow(dead_code)]
109#[derive(Serialize)]
110pub struct ACPIPMResource {
111 #[serde(skip_serializing)]
113 sci_evt: IrqLevelEvent,
114 #[serde(skip_serializing)]
115 worker_thread: Option<WorkerThread<()>>,
116 #[serde(skip_serializing)]
117 suspend_tube: Arc<Mutex<SendTube>>,
118 #[serde(skip_serializing)]
119 exit_evt_wrtube: SendTube,
120 #[serde(serialize_with = "serialize_arc_mutex")]
121 pm1: Arc<Mutex<Pm1Resource>>,
122 #[serde(serialize_with = "serialize_arc_mutex")]
123 gpe0: Arc<Mutex<GpeResource>>,
124 #[serde(serialize_with = "serialize_arc_mutex")]
125 pci: Arc<Mutex<PciResource>>,
126}
127
128#[derive(Deserialize)]
129struct ACPIPMResrourceSerializable {
130 pm1: Pm1ResourceSerializable,
131 gpe0: GpeResourceSerializable,
132}
133
134impl ACPIPMResource {
135 #[allow(dead_code)]
137 pub fn new(
138 sci_evt: IrqLevelEvent,
139 suspend_tube: Arc<Mutex<SendTube>>,
140 exit_evt_wrtube: SendTube,
141 ) -> ACPIPMResource {
142 let pm1 = Pm1Resource {
143 status: 0,
144 enable: 0,
145 control: 0,
146 suspend_tube: suspend_tube.clone(),
147 rtc_clear_evt: None,
148 };
149 let gpe0 = GpeResource {
150 status: Default::default(),
151 enable: Default::default(),
152 pending_clear_evts: BTreeMap::new(),
153 suspend_tube: suspend_tube.clone(),
154 };
155 let pci = PciResource {
156 pme_notify: BTreeMap::new(),
157 };
158
159 ACPIPMResource {
160 sci_evt,
161 worker_thread: None,
162 suspend_tube,
163 exit_evt_wrtube,
164 pm1: Arc::new(Mutex::new(pm1)),
165 gpe0: Arc::new(Mutex::new(gpe0)),
166 pci: Arc::new(Mutex::new(pci)),
167 }
168 }
169
170 pub fn start(&mut self) {
171 let sci_evt = self.sci_evt.try_clone().expect("failed to clone event");
172 let pm1 = self.pm1.clone();
173 let gpe0 = self.gpe0.clone();
174
175 self.worker_thread = Some(WorkerThread::start("ACPI PM worker", move |kill_evt| {
176 if let Err(e) = run_worker(sci_evt, kill_evt, pm1, gpe0) {
177 error!("{}", e);
178 }
179 }));
180 }
181}
182
183impl Suspendable for ACPIPMResource {
184 fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
185 if !self.gpe0.lock().pending_clear_evts.is_empty() {
186 bail!("ACPIPMResource is busy");
187 }
188 AnySnapshot::to_any(&self)
189 .with_context(|| format!("error serializing {}", self.debug_label()))
190 }
191
192 fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
193 let acpi_snapshot: ACPIPMResrourceSerializable = AnySnapshot::from_any(data)
194 .with_context(|| format!("error deserializing {}", self.debug_label()))?;
195 {
196 let mut pm1 = self.pm1.lock();
197 pm1.status = acpi_snapshot.pm1.status;
198 pm1.enable = acpi_snapshot.pm1.enable;
199 pm1.control = acpi_snapshot.pm1.control;
200 }
201 {
202 let mut gpe0 = self.gpe0.lock();
203 gpe0.status = acpi_snapshot.gpe0.status;
204 gpe0.enable = acpi_snapshot.gpe0.enable;
205 }
206 Ok(())
207 }
208
209 fn sleep(&mut self) -> anyhow::Result<()> {
210 if let Some(worker_thread) = self.worker_thread.take() {
211 worker_thread.stop();
212 }
213 Ok(())
214 }
215
216 fn wake(&mut self) -> anyhow::Result<()> {
217 self.start();
218 Ok(())
219 }
220}
221
222fn run_worker(
223 sci_evt: IrqLevelEvent,
224 kill_evt: Event,
225 pm1: Arc<Mutex<Pm1Resource>>,
226 gpe0: Arc<Mutex<GpeResource>>,
227) -> Result<(), ACPIPMError> {
228 #[derive(EventToken)]
229 enum Token {
230 InterruptResample,
231 Kill,
232 }
233
234 let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
235 (sci_evt.get_resample(), Token::InterruptResample),
236 (&kill_evt, Token::Kill),
237 ])
238 .map_err(ACPIPMError::CreateWaitContext)?;
239
240 loop {
241 let events = wait_ctx.wait().map_err(ACPIPMError::WaitError)?;
242 for event in events.iter().filter(|e| e.is_readable) {
243 match event.token {
244 Token::InterruptResample => {
245 sci_evt.clear_resample();
246
247 pm1.lock().resample_clear_evts_and_trigger(&sci_evt);
249 gpe0.lock().resample_clear_evts_and_trigger(&sci_evt);
250 }
251 Token::Kill => return Ok(()),
252 }
253 }
254 }
255}
256
257impl Pm1Resource {
258 fn trigger_sci(&self, sci_evt: &IrqLevelEvent) {
259 if self.status & self.enable & ACPIPMFixedEvent::bitmask_all() != 0 {
260 if let Err(e) = sci_evt.trigger() {
261 error!("ACPIPM: failed to trigger sci event for pm1: {}", e);
262 }
263 if let Err(e) = self.suspend_tube.lock().send(&false) {
264 error!("ACPIPM: failed to trigger wake event: {}", e);
265 }
266 }
267 }
268
269 fn resample_clear_evts_and_trigger(&mut self, sci_evt: &IrqLevelEvent) {
270 if let Some(clear_evt) = self.rtc_clear_evt.take() {
271 if clear_evt.wait_timeout(Duration::ZERO) == Ok(EventWaitResult::TimedOut) {
272 self.rtc_clear_evt = Some(clear_evt);
273 self.status |= ACPIPMFixedEvent::RTC.bitmask();
274 }
275 }
276 self.trigger_sci(sci_evt);
277 }
278}
279
280impl GpeResource {
281 pub fn trigger_sci(&self, sci_evt: &IrqLevelEvent) {
282 if (0..self.status.len()).any(|i| self.status[i] & self.enable[i] != 0) {
283 if let Err(e) = sci_evt.trigger() {
284 error!("ACPIPM: failed to trigger sci event for gpe: {}", e);
285 }
286 if let Err(e) = self.suspend_tube.lock().send(&false) {
287 error!("ACPIPM: failed to trigger wake event: {}", e);
288 }
289 }
290 }
291
292 pub fn set_active(&mut self, gpe: u32) -> Result<(), ACPIPMError> {
293 if let Some(status_byte) = self.status.get_mut(gpe as usize / 8) {
294 *status_byte |= 1 << (gpe % 8);
295 } else {
296 return Err(ACPIPMError::GpeOutOfBound(gpe));
297 }
298 Ok(())
299 }
300
301 pub fn resample_clear_evts_and_trigger(&mut self, sci_evt: &IrqLevelEvent) {
302 let mut retained = Vec::new();
303 self.pending_clear_evts.retain(|gpe, clear_evts| {
304 clear_evts.retain(|clear_evt| {
305 clear_evt.wait_timeout(Duration::ZERO) == Ok(EventWaitResult::TimedOut)
306 });
307 if !clear_evts.is_empty() {
308 retained.push(*gpe);
309 }
310 !clear_evts.is_empty()
311 });
312 for gpe in retained.into_iter() {
313 self.set_active(gpe).expect("bad gpe index");
314 }
315
316 self.trigger_sci(sci_evt);
317 }
318}
319
320pub const ACPIPM_RESOURCE_EVENTBLK_LEN: u8 = 4;
322pub const ACPIPM_RESOURCE_CONTROLBLK_LEN: u8 = 2;
323pub const ACPIPM_RESOURCE_GPE0_BLK_LEN: u8 = 64;
324pub const ACPIPM_RESOURCE_LEN: u8 = ACPIPM_RESOURCE_EVENTBLK_LEN + 4 + ACPIPM_RESOURCE_GPE0_BLK_LEN;
325
326pub const ACPIPM_GPE_MAX: u16 = ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2 * 8 - 1;
328
329const PM1_STATUS: u16 = 0;
335
336const PM1_ENABLE: u16 = PM1_STATUS + (ACPIPM_RESOURCE_EVENTBLK_LEN as u16 / 2);
341
342const PM1_CONTROL: u16 = PM1_STATUS + ACPIPM_RESOURCE_EVENTBLK_LEN as u16;
346
347const GPE0_STATUS: u16 = PM1_STATUS + ACPIPM_RESOURCE_EVENTBLK_LEN as u16 + 4; const GPE0_ENABLE: u16 = GPE0_STATUS + (ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2);
366
367const BITSHIFT_PM1_GBL: u16 = 5;
369const BITSHIFT_PM1_PWRBTN: u16 = 8;
370const BITSHIFT_PM1_SLPBTN: u16 = 9;
371const BITSHIFT_PM1_RTC: u16 = 10;
372
373const BITMASK_PM1CNT_SLEEP_ENABLE: u16 = 0x2000;
374const BITMASK_PM1CNT_WAKE_STATUS: u16 = 0x8000;
375
376const BITMASK_PM1CNT_SLEEP_TYPE: u16 = 0x1C00;
377const SLEEP_TYPE_S1: u16 = 1 << 10;
378const SLEEP_TYPE_S5: u16 = 0 << 10;
379
380impl ACPIPMFixedEvent {
381 fn bitshift(self) -> u16 {
382 match self {
383 ACPIPMFixedEvent::GlobalLock => BITSHIFT_PM1_GBL,
384 ACPIPMFixedEvent::PowerButton => BITSHIFT_PM1_PWRBTN,
385 ACPIPMFixedEvent::SleepButton => BITSHIFT_PM1_SLPBTN,
386 ACPIPMFixedEvent::RTC => BITSHIFT_PM1_RTC,
387 }
388 }
389
390 pub(crate) fn bitmask(self) -> u16 {
391 1 << self.bitshift()
392 }
393
394 fn bitmask_all() -> u16 {
395 (1 << BITSHIFT_PM1_GBL)
396 | (1 << BITSHIFT_PM1_PWRBTN)
397 | (1 << BITSHIFT_PM1_SLPBTN)
398 | (1 << BITSHIFT_PM1_RTC)
399 }
400}
401
402impl FromStr for ACPIPMFixedEvent {
403 type Err = &'static str;
404
405 fn from_str(s: &str) -> Result<Self, Self::Err> {
406 match s {
407 "gbllock" => Ok(ACPIPMFixedEvent::GlobalLock),
408 "powerbtn" => Ok(ACPIPMFixedEvent::PowerButton),
409 "sleepbtn" => Ok(ACPIPMFixedEvent::SleepButton),
410 "rtc" => Ok(ACPIPMFixedEvent::RTC),
411 _ => Err("unknown event, must be: gbllock|powerbtn|sleepbtn|rtc"),
412 }
413 }
414}
415
416impl PmResource for ACPIPMResource {
417 fn pwrbtn_evt(&mut self) {
418 let mut pm1 = self.pm1.lock();
419
420 pm1.status |= ACPIPMFixedEvent::PowerButton.bitmask();
421 pm1.trigger_sci(&self.sci_evt);
422 }
423
424 fn slpbtn_evt(&mut self) {
425 let mut pm1 = self.pm1.lock();
426
427 pm1.status |= ACPIPMFixedEvent::SleepButton.bitmask();
428 pm1.trigger_sci(&self.sci_evt);
429 }
430
431 fn rtc_evt(&mut self, clear_evt: Event) {
432 let mut pm1 = self.pm1.lock();
433
434 pm1.rtc_clear_evt = Some(clear_evt);
435 pm1.status |= ACPIPMFixedEvent::RTC.bitmask();
436 pm1.trigger_sci(&self.sci_evt);
437 }
438
439 fn gpe_evt(&mut self, gpe: u32, clear_evt: Option<Event>) {
440 let mut gpe0 = self.gpe0.lock();
441 match gpe0.set_active(gpe) {
442 Ok(_) => {
443 if let Some(clear_evt) = clear_evt {
444 gpe0.pending_clear_evts
445 .entry(gpe)
446 .or_default()
447 .push(clear_evt);
448 }
449 gpe0.trigger_sci(&self.sci_evt)
450 }
451 Err(e) => error!("{}", e),
452 }
453 }
454
455 fn pme_evt(&mut self, requester_id: u16) {
456 let bus = ((requester_id >> 8) & 0xFF) as u8;
457 let mut pci = self.pci.lock();
458 if let Some(root_ports) = pci.pme_notify.get_mut(&bus) {
459 for root_port in root_ports {
460 root_port.lock().notify(requester_id);
461 }
462 }
463 }
464
465 fn register_pme_notify_dev(&mut self, bus: u8, notify_dev: Arc<Mutex<dyn PmeNotify>>) {
466 let mut pci = self.pci.lock();
467 match pci.pme_notify.get_mut(&bus) {
468 Some(v) => v.push(notify_dev),
469 None => {
470 pci.pme_notify.insert(bus, vec![notify_dev]);
471 }
472 }
473 }
474}
475
476const PM1_STATUS_LAST: u16 = PM1_STATUS + (ACPIPM_RESOURCE_EVENTBLK_LEN as u16 / 2) - 1;
477const PM1_ENABLE_LAST: u16 = PM1_ENABLE + (ACPIPM_RESOURCE_EVENTBLK_LEN as u16 / 2) - 1;
478const PM1_CONTROL_LAST: u16 = PM1_CONTROL + ACPIPM_RESOURCE_CONTROLBLK_LEN as u16 - 1;
479const GPE0_STATUS_LAST: u16 = GPE0_STATUS + (ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2) - 1;
480const GPE0_ENABLE_LAST: u16 = GPE0_ENABLE + (ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2) - 1;
481
482impl BusDevice for ACPIPMResource {
483 fn device_id(&self) -> DeviceId {
484 PlatformDeviceId::ACPIPMResource.into()
485 }
486
487 fn debug_label(&self) -> String {
488 "ACPIPMResource".to_owned()
489 }
490
491 fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
492 match info.offset as u16 {
493 PM1_STATUS..=PM1_STATUS_LAST => {
495 if data.len() > std::mem::size_of::<u16>()
496 || info.offset + data.len() as u64 > (PM1_STATUS_LAST + 1).into()
497 {
498 warn!("ACPIPM: bad read size: {}", data.len());
499 return;
500 }
501 let offset = (info.offset - PM1_STATUS as u64) as usize;
502
503 let v = self.pm1.lock().status.to_ne_bytes();
504 for (i, j) in (offset..offset + data.len()).enumerate() {
505 data[i] = v[j];
506 }
507 }
508 PM1_ENABLE..=PM1_ENABLE_LAST => {
509 if data.len() > std::mem::size_of::<u16>()
510 || info.offset + data.len() as u64 > (PM1_ENABLE_LAST + 1).into()
511 {
512 warn!("ACPIPM: bad read size: {}", data.len());
513 return;
514 }
515 let offset = (info.offset - PM1_ENABLE as u64) as usize;
516
517 let v = self.pm1.lock().enable.to_ne_bytes();
518 for (i, j) in (offset..offset + data.len()).enumerate() {
519 data[i] = v[j];
520 }
521 }
522 PM1_CONTROL..=PM1_CONTROL_LAST => {
523 if data.len() > std::mem::size_of::<u16>()
524 || info.offset + data.len() as u64 > (PM1_CONTROL_LAST + 1).into()
525 {
526 warn!("ACPIPM: bad read size: {}", data.len());
527 return;
528 }
529 let offset = (info.offset - PM1_CONTROL as u64) as usize;
530 data.copy_from_slice(
531 &self.pm1.lock().control.to_ne_bytes()[offset..offset + data.len()],
532 );
533 }
534 GPE0_STATUS..=GPE0_STATUS_LAST => {
536 if data.len() > std::mem::size_of::<u8>()
537 || info.offset + data.len() as u64 > (GPE0_STATUS_LAST + 1).into()
538 {
539 warn!("ACPIPM: bad read size: {}", data.len());
540 return;
541 }
542 let offset = (info.offset - GPE0_STATUS as u64) as usize;
543 data[0] = self.gpe0.lock().status[offset];
544 }
545 GPE0_ENABLE..=GPE0_ENABLE_LAST => {
546 if data.len() > std::mem::size_of::<u8>()
547 || info.offset + data.len() as u64 > (GPE0_ENABLE_LAST + 1).into()
548 {
549 warn!("ACPIPM: bad read size: {}", data.len());
550 return;
551 }
552 let offset = (info.offset - GPE0_ENABLE as u64) as usize;
553 data[0] = self.gpe0.lock().enable[offset];
554 }
555 _ => {
556 warn!("ACPIPM: Bad read from {}", info);
557 }
558 }
559 }
560
561 fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
562 match info.offset as u16 {
563 PM1_STATUS..=PM1_STATUS_LAST => {
565 if data.len() > std::mem::size_of::<u16>()
566 || info.offset + data.len() as u64 > (PM1_STATUS_LAST + 1).into()
567 {
568 warn!("ACPIPM: bad write size: {}", data.len());
569 return;
570 }
571 let offset = (info.offset - PM1_STATUS as u64) as usize;
572
573 let mut pm1 = self.pm1.lock();
574 let mut v = pm1.status.to_ne_bytes();
575 for (i, j) in (offset..offset + data.len()).enumerate() {
576 v[j] &= !data[i];
577 }
578 pm1.status = u16::from_ne_bytes(v);
579 }
580 PM1_ENABLE..=PM1_ENABLE_LAST => {
581 if data.len() > std::mem::size_of::<u16>()
582 || info.offset + data.len() as u64 > (PM1_ENABLE_LAST + 1).into()
583 {
584 warn!("ACPIPM: bad write size: {}", data.len());
585 return;
586 }
587 let offset = (info.offset - PM1_ENABLE as u64) as usize;
588
589 let mut pm1 = self.pm1.lock();
590 let mut v = pm1.enable.to_ne_bytes();
591 for (i, j) in (offset..offset + data.len()).enumerate() {
592 v[j] = data[i];
593 }
594 pm1.enable = u16::from_ne_bytes(v);
595 pm1.resample_clear_evts_and_trigger(&self.sci_evt);
596 }
597 PM1_CONTROL..=PM1_CONTROL_LAST => {
598 if data.len() > std::mem::size_of::<u16>()
599 || info.offset + data.len() as u64 > (PM1_CONTROL_LAST + 1).into()
600 {
601 warn!("ACPIPM: bad write size: {}", data.len());
602 return;
603 }
604 let offset = (info.offset - PM1_CONTROL as u64) as usize;
605
606 let mut pm1 = self.pm1.lock();
607
608 let mut v = pm1.control.to_ne_bytes();
609 for (i, j) in (offset..offset + data.len()).enumerate() {
610 v[j] = data[i];
611 }
612 let val = u16::from_ne_bytes(v);
613
614 if (val & BITMASK_PM1CNT_SLEEP_ENABLE) != 0 {
616 match val & BITMASK_PM1CNT_SLEEP_TYPE {
617 SLEEP_TYPE_S1 => {
618 if let Err(e) = self.suspend_tube.lock().send(&true) {
619 error!("ACPIPM: failed to trigger suspend event: {}", e);
620 }
621 }
622 SLEEP_TYPE_S5 => {
623 if let Err(e) =
624 self.exit_evt_wrtube.send::<VmEventType>(&VmEventType::Exit)
625 {
626 error!("ACPIPM: failed to trigger exit event: {}", e);
627 }
628 }
629 _ => error!(
630 "ACPIPM: unknown SLP_TYP written: {}",
631 (val & BITMASK_PM1CNT_SLEEP_TYPE) >> 10
632 ),
633 }
634 }
635 pm1.control = val & !BITMASK_PM1CNT_SLEEP_ENABLE;
636
637 pm1.resample_clear_evts_and_trigger(&self.sci_evt);
640 self.gpe0
641 .lock()
642 .resample_clear_evts_and_trigger(&self.sci_evt);
643 }
644 GPE0_STATUS..=GPE0_STATUS_LAST => {
646 if data.len() > std::mem::size_of::<u8>()
647 || info.offset + data.len() as u64 > (GPE0_STATUS_LAST + 1).into()
648 {
649 warn!("ACPIPM: bad write size: {}", data.len());
650 return;
651 }
652 let offset = (info.offset - GPE0_STATUS as u64) as usize;
653 self.gpe0.lock().status[offset] &= !data[0];
654 }
655 GPE0_ENABLE..=GPE0_ENABLE_LAST => {
656 if data.len() > std::mem::size_of::<u8>()
657 || info.offset + data.len() as u64 > (GPE0_ENABLE_LAST + 1).into()
658 {
659 warn!("ACPIPM: bad write size: {}", data.len());
660 return;
661 }
662 let offset = (info.offset - GPE0_ENABLE as u64) as usize;
663 let mut gpe = self.gpe0.lock();
664 if gpe.enable[offset] != data[0] {
665 gpe.enable[offset] = data[0];
666 gpe.resample_clear_evts_and_trigger(&self.sci_evt);
667 }
668 }
669 _ => {
670 warn!("ACPIPM: Bad write to {}", info);
671 }
672 };
673 }
674}
675
676impl BusResumeDevice for ACPIPMResource {
677 fn resume_imminent(&mut self) {
678 self.pm1.lock().status |= BITMASK_PM1CNT_WAKE_STATUS;
679 }
680}
681
682impl Aml for ACPIPMResource {
683 fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
684 aml::Name::new(
686 "_S1_".into(),
687 &aml::Package::new(vec![&aml::ONE, &aml::ONE, &aml::ZERO, &aml::ZERO]),
688 )
689 .to_aml_bytes(bytes);
690
691 aml::Name::new(
693 "_S5_".into(),
694 &aml::Package::new(vec![&aml::ZERO, &aml::ZERO, &aml::ZERO, &aml::ZERO]),
695 )
696 .to_aml_bytes(bytes);
697 }
698}
699
700pub const PM_WAKEUP_GPIO: u32 = 0;
701
702pub struct PmWakeupEvent {
703 vm_control_tube: Arc<Mutex<Tube>>,
704 pm_config: Arc<Mutex<PmConfig>>,
705}
706
707impl PmWakeupEvent {
708 pub fn new(vm_control_tube: Arc<Mutex<Tube>>, pm_config: Arc<Mutex<PmConfig>>) -> Self {
709 Self {
710 vm_control_tube,
711 pm_config,
712 }
713 }
714
715 pub fn trigger_wakeup(&self) -> anyhow::Result<Option<Event>> {
716 if self.pm_config.lock().should_trigger_pme() {
717 let event = Event::new().context("failed to create clear event")?;
718 let tube = self.vm_control_tube.lock();
719 tube.send(&VmRequest::Gpe {
720 gpe: PM_WAKEUP_GPIO,
721 clear_evt: Some(event.try_clone().context("failed to clone clear event")?),
722 })
723 .context("failed to send pme")?;
724 match tube.recv::<VmResponse>() {
725 Ok(VmResponse::Ok) => Ok(Some(event)),
726 e => bail!("pme failure {:?}", e),
727 }
728 } else {
729 Ok(None)
730 }
731 }
732}
733
734#[cfg(test)]
735mod tests {
736 use base::Tube;
737
738 use super::*;
739 use crate::suspendable_tests;
740
741 fn get_send_tube() -> SendTube {
742 Tube::directional_pair().unwrap().0
743 }
744
745 fn get_irq_evt() -> IrqLevelEvent {
746 match crate::IrqLevelEvent::new() {
747 Ok(evt) => evt,
748 Err(e) => panic!("failed to create irqlevelevt: {e} - panic. Can't test ACPI"),
749 }
750 }
751
752 fn modify_device(acpi: &mut ACPIPMResource) {
753 {
754 let mut pm1 = acpi.pm1.lock();
755 pm1.enable += 1;
756 }
757 }
758
759 suspendable_tests!(
760 acpi,
761 ACPIPMResource::new(
762 get_irq_evt(),
763 Arc::new(Mutex::new(get_send_tube())),
764 get_send_tube(),
765 ),
766 modify_device
767 );
768}