devices/
acpi.rs

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
5use 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    /// 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("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    // For each triggered GPE, a vector of events to check when resampling
88    // sci_evt. If any events are un-signaled, then sci_evt should be re-asserted.
89    #[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/// ACPI PM resource for handling OS suspend/resume request
108#[allow(dead_code)]
109#[derive(Serialize)]
110pub struct ACPIPMResource {
111    // This is SCI interrupt that will be raised in the VM.
112    #[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    /// Constructs ACPI Power Management Resouce.
136    #[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                    // Re-trigger SCI if PM1 or GPE status is still not cleared.
248                    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
320/// the ACPI PM register length.
321pub 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
326// Should be in sync with gpe_allocator range
327pub const ACPIPM_GPE_MAX: u16 = ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2 * 8 - 1;
328
329// ACPI PM register value definitions
330
331/// Section 4.8.4.1.1 PM1 Status Registers, ACPI Spec Version 6.4
332/// Register Location: <PM1a_EVT_BLK / PM1b_EVT_BLK> System I/O or Memory Space (defined in FADT)
333/// Size: PM1_EVT_LEN / 2 (defined in FADT)
334const PM1_STATUS: u16 = 0;
335
336/// Section 4.8.4.1.2 PM1Enable Registers, ACPI Spec Version 6.4
337/// Register Location: <<PM1a_EVT_BLK / PM1b_EVT_BLK> + PM1_EVT_LEN / 2 System I/O or Memory Space
338/// (defined in FADT)
339/// Size: PM1_EVT_LEN / 2 (defined in FADT)
340const PM1_ENABLE: u16 = PM1_STATUS + (ACPIPM_RESOURCE_EVENTBLK_LEN as u16 / 2);
341
342/// Section 4.8.4.2.1 PM1 Control Registers, ACPI Spec Version 6.4
343/// Register Location: <PM1a_CNT_BLK / PM1b_CNT_BLK> System I/O or Memory Space (defined in FADT)
344/// Size: PM1_CNT_LEN (defined in FADT)
345const PM1_CONTROL: u16 = PM1_STATUS + ACPIPM_RESOURCE_EVENTBLK_LEN as u16;
346
347/// Section 4.8.5.1 General-Purpose Event Register Blocks, ACPI Spec Version 6.4
348/// - Each register block contains two registers: an enable and a status register.
349/// - Each register block is 32-bit aligned.
350/// - Each register in the block is accessed as a byte.
351///
352/// Section 4.8.5.1.1 General-Purpose Event 0 Register Block, ACPI Spec Version 6.4
353/// This register block consists of two registers: The GPE0_STS and the GPE0_EN registers. Each
354/// register’s length is defined to be half the length of the GPE0 register block, and is described
355/// in the ACPI FADT’s GPE0_BLK and GPE0_BLK_LEN operators.
356///
357/// Section 4.8.5.1.1.1 General-Purpose Event 0 Status Register, ACPI Spec Version 6.4
358/// Register Location: <GPE0_STS> System I/O or System Memory Space (defined in FADT)
359/// Size: GPE0_BLK_LEN/2 (defined in FADT)
360const GPE0_STATUS: u16 = PM1_STATUS + ACPIPM_RESOURCE_EVENTBLK_LEN as u16 + 4; // ensure alignment
361
362/// Section 4.8.5.1.1.2 General-Purpose Event 0 Enable Register, ACPI Spec Version 6.4
363/// Register Location: <GPE0_EN> System I/O or System Memory Space (defined in FADT)
364/// Size: GPE0_BLK_LEN/2 (defined in FADT)
365const GPE0_ENABLE: u16 = GPE0_STATUS + (ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2);
366
367/// Section 4.8.4.1.1, 4.8.4.1.2 Fixed event bits in both PM1 Status and PM1 Enable registers.
368const 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            // Accesses to the PM1 registers are done through byte or word accesses
494            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            // OSPM accesses GPE registers through byte accesses (regardless of their length)
535            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            // Accesses to the PM1 registers are done through byte or word accesses
564            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                // SLP_EN is a write-only bit and reads to it always return a zero
615                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                // Re-trigger PM & GPEs in case there is a pending wakeup that should
638                // override us just having gone to sleep.
639                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            // OSPM accesses GPE registers through byte accesses (regardless of their length)
645            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        // S1
685        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        // S5
692        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}