• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium OS Authors. All rights reserved.
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 crate::{BusAccessInfo, BusDevice, BusResumeDevice, IrqLevelEvent};
6 use acpi_tables::{aml, aml::Aml};
7 use base::{error, info, warn, Error as SysError, Event, PollToken, WaitContext};
8 use base::{AcpiNotifyEvent, NetlinkGenericSocket};
9 use std::collections::BTreeMap;
10 use std::sync::Arc;
11 use std::thread;
12 use sync::Mutex;
13 use thiserror::Error;
14 use vm_control::{GpeNotify, PmResource};
15 
16 #[cfg(feature = "direct")]
17 use {std::fs, std::io::Error as IoError, std::path::PathBuf};
18 
19 #[derive(Error, Debug)]
20 pub enum ACPIPMError {
21     /// Creating WaitContext failed.
22     #[error("failed to create wait context: {0}")]
23     CreateWaitContext(SysError),
24     /// Error while waiting for events.
25     #[error("failed to wait for events: {0}")]
26     WaitError(SysError),
27     #[error("Did not find group_id corresponding to acpi_mc_group")]
28     AcpiMcGroupError,
29     #[error("Failed to create and bind NETLINK_GENERIC socket for acpi_mc_group: {0}")]
30     AcpiEventSockError(base::Error),
31 }
32 
33 struct Pm1Resource {
34     status: u16,
35     enable: u16,
36     control: u16,
37 }
38 
39 struct GpeResource {
40     status: [u8; ACPIPM_RESOURCE_GPE0_BLK_LEN as usize / 2],
41     enable: [u8; ACPIPM_RESOURCE_GPE0_BLK_LEN as usize / 2],
42     gpe_notify: BTreeMap<u32, Vec<Arc<Mutex<dyn GpeNotify>>>>,
43 }
44 
45 #[cfg(feature = "direct")]
46 struct DirectGpe {
47     num: u32,
48     path: PathBuf,
49     ready: bool,
50     enabled: bool,
51 }
52 
53 /// ACPI PM resource for handling OS suspend/resume request
54 #[allow(dead_code)]
55 pub struct ACPIPMResource {
56     // This is SCI interrupt that will be raised in the VM.
57     sci_evt: IrqLevelEvent,
58     // This is the host SCI that is being handled by crosvm.
59     #[cfg(feature = "direct")]
60     sci_direct_evt: Option<IrqLevelEvent>,
61     #[cfg(feature = "direct")]
62     direct_gpe: Vec<DirectGpe>,
63     kill_evt: Option<Event>,
64     worker_thread: Option<thread::JoinHandle<()>>,
65     suspend_evt: Event,
66     exit_evt: Event,
67     pm1: Arc<Mutex<Pm1Resource>>,
68     gpe0: Arc<Mutex<GpeResource>>,
69 }
70 
71 impl ACPIPMResource {
72     /// Constructs ACPI Power Management Resouce.
73     ///
74     /// `direct_gpe_info` - tuple of host SCI trigger and resample events, and list of direct GPEs
75     #[allow(dead_code)]
new( sci_evt: IrqLevelEvent, #[cfg(feature = "direct")] direct_gpe_info: Option<(IrqLevelEvent, &[u32])>, suspend_evt: Event, exit_evt: Event, ) -> ACPIPMResource76     pub fn new(
77         sci_evt: IrqLevelEvent,
78         #[cfg(feature = "direct")] direct_gpe_info: Option<(IrqLevelEvent, &[u32])>,
79         suspend_evt: Event,
80         exit_evt: Event,
81     ) -> ACPIPMResource {
82         let pm1 = Pm1Resource {
83             status: 0,
84             enable: 0,
85             control: 0,
86         };
87         let gpe0 = GpeResource {
88             status: Default::default(),
89             enable: Default::default(),
90             gpe_notify: BTreeMap::new(),
91         };
92 
93         #[cfg(feature = "direct")]
94         let (sci_direct_evt, direct_gpe) = if let Some(info) = direct_gpe_info {
95             let (evt, gpes) = info;
96             let gpe_vec = gpes.iter().map(|gpe| DirectGpe::new(*gpe)).collect();
97             (Some(evt), gpe_vec)
98         } else {
99             (None, Vec::new())
100         };
101 
102         ACPIPMResource {
103             sci_evt,
104             #[cfg(feature = "direct")]
105             sci_direct_evt,
106             #[cfg(feature = "direct")]
107             direct_gpe,
108             kill_evt: None,
109             worker_thread: None,
110             suspend_evt,
111             exit_evt,
112             pm1: Arc::new(Mutex::new(pm1)),
113             gpe0: Arc::new(Mutex::new(gpe0)),
114         }
115     }
116 
start(&mut self)117     pub fn start(&mut self) {
118         let (self_kill_evt, kill_evt) = match Event::new().and_then(|e| Ok((e.try_clone()?, e))) {
119             Ok(v) => v,
120             Err(e) => {
121                 error!("failed to create kill Event pair: {}", e);
122                 return;
123             }
124         };
125         self.kill_evt = Some(self_kill_evt);
126 
127         let sci_evt = self.sci_evt.try_clone().expect("failed to clone event");
128         let pm1 = self.pm1.clone();
129         let gpe0 = self.gpe0.clone();
130 
131         #[cfg(feature = "direct")]
132         let sci_direct_evt = self.sci_direct_evt.take();
133 
134         #[cfg(feature = "direct")]
135         // Direct GPEs are forwarded via direct SCI forwarding,
136         // not via ACPI netlink events.
137         let acpi_event_ignored_gpe = self.direct_gpe.iter().map(|gpe| gpe.num).collect();
138 
139         #[cfg(not(feature = "direct"))]
140         let acpi_event_ignored_gpe = Vec::new();
141 
142         let worker_result = thread::Builder::new()
143             .name("ACPI PM worker".to_string())
144             .spawn(move || {
145                 if let Err(e) = run_worker(
146                     sci_evt,
147                     kill_evt,
148                     pm1,
149                     gpe0,
150                     acpi_event_ignored_gpe,
151                     #[cfg(feature = "direct")]
152                     sci_direct_evt,
153                 ) {
154                     error!("{}", e);
155                 }
156             });
157 
158         match worker_result {
159             Err(e) => error!("failed to spawn ACPI PM worker thread: {}", e),
160             Ok(join_handle) => self.worker_thread = Some(join_handle),
161         }
162     }
163 }
164 
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>, ) -> Result<(), ACPIPMError>165 fn run_worker(
166     sci_evt: IrqLevelEvent,
167     kill_evt: Event,
168     pm1: Arc<Mutex<Pm1Resource>>,
169     gpe0: Arc<Mutex<GpeResource>>,
170     acpi_event_ignored_gpe: Vec<u32>,
171     #[cfg(feature = "direct")] sci_direct_evt: Option<IrqLevelEvent>,
172 ) -> Result<(), ACPIPMError> {
173     // Get group id corresponding to acpi_mc_group of acpi_event family
174     let nl_groups: u32;
175     match get_acpi_event_group() {
176         Some(group) if group > 0 => {
177             nl_groups = 1 << (group - 1);
178             info!("Listening on acpi_mc_group of acpi_event family");
179         }
180         _ => {
181             return Err(ACPIPMError::AcpiMcGroupError);
182         }
183     }
184 
185     let acpi_event_sock = match NetlinkGenericSocket::new(nl_groups) {
186         Ok(acpi_sock) => acpi_sock,
187         Err(e) => {
188             return Err(ACPIPMError::AcpiEventSockError(e));
189         }
190     };
191 
192     #[derive(PollToken)]
193     enum Token {
194         AcpiEvent,
195         InterruptResample,
196         #[cfg(feature = "direct")]
197         InterruptTriggerDirect,
198         Kill,
199     }
200 
201     let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
202         (&acpi_event_sock, Token::AcpiEvent),
203         (sci_evt.get_resample(), Token::InterruptResample),
204         (&kill_evt, Token::Kill),
205     ])
206     .map_err(ACPIPMError::CreateWaitContext)?;
207 
208     #[cfg(feature = "direct")]
209     if let Some(ref evt) = sci_direct_evt {
210         wait_ctx
211             .add(evt.get_trigger(), Token::InterruptTriggerDirect)
212             .map_err(ACPIPMError::CreateWaitContext)?;
213     }
214 
215     #[cfg(feature = "direct")]
216     let mut pending_sci_direct: Option<&IrqLevelEvent> = None;
217 
218     loop {
219         let events = wait_ctx.wait().map_err(ACPIPMError::WaitError)?;
220         for event in events.iter().filter(|e| e.is_readable) {
221             match event.token {
222                 Token::AcpiEvent => {
223                     acpi_event_run(
224                         &acpi_event_sock,
225                         &gpe0,
226                         &pm1,
227                         &sci_evt,
228                         &acpi_event_ignored_gpe,
229                     );
230                 }
231                 Token::InterruptResample => {
232                     sci_evt.clear_resample();
233 
234                     #[cfg(feature = "direct")]
235                     if let Some(evt) = pending_sci_direct.take() {
236                         if let Err(e) = evt.trigger_resample() {
237                             error!("ACPIPM: failed to resample sci event: {}", e);
238                         }
239                     }
240 
241                     // Re-trigger SCI if PM1 or GPE status is still not cleared.
242                     pm1.lock().trigger_sci(&sci_evt);
243                     gpe0.lock().trigger_sci(&sci_evt);
244                 }
245                 #[cfg(feature = "direct")]
246                 Token::InterruptTriggerDirect => {
247                     if let Some(ref evt) = sci_direct_evt {
248                         evt.clear_trigger();
249 
250                         for (gpe, devs) in &gpe0.lock().gpe_notify {
251                             if DirectGpe::is_gpe_trigger(*gpe).unwrap_or(false) {
252                                 for dev in devs {
253                                     dev.lock().notify();
254                                 }
255                             }
256                         }
257 
258                         if let Err(e) = sci_evt.trigger() {
259                             error!("ACPIPM: failed to trigger sci event: {}", e);
260                         }
261                         pending_sci_direct = Some(evt);
262                     }
263                 }
264                 Token::Kill => return Ok(()),
265             }
266         }
267     }
268 }
269 
acpi_event_handle_gpe( gpe_number: u32, _type: u32, gpe0: &Arc<Mutex<GpeResource>>, sci_evt: &IrqLevelEvent, ignored_gpe: &[u32], )270 fn acpi_event_handle_gpe(
271     gpe_number: u32,
272     _type: u32,
273     gpe0: &Arc<Mutex<GpeResource>>,
274     sci_evt: &IrqLevelEvent,
275     ignored_gpe: &[u32],
276 ) {
277     // If gpe event, emulate GPE and trigger SCI
278     if _type == 0 && gpe_number < 256 && !ignored_gpe.contains(&gpe_number) {
279         let mut gpe0 = gpe0.lock();
280         let byte = gpe_number as usize / 8;
281 
282         if byte >= gpe0.status.len() {
283             error!("gpe_evt: GPE register {} does not exist", byte);
284             return;
285         }
286         gpe0.status[byte] |= 1 << (gpe_number % 8);
287         gpe0.trigger_sci(sci_evt);
288     }
289 }
290 
291 const ACPI_BUTTON_NOTIFY_STATUS: u32 = 0x80;
292 
acpi_event_handle_power_button( acpi_event: AcpiNotifyEvent, pm1: &Arc<Mutex<Pm1Resource>>, sci_evt: &IrqLevelEvent, )293 fn acpi_event_handle_power_button(
294     acpi_event: AcpiNotifyEvent,
295     pm1: &Arc<Mutex<Pm1Resource>>,
296     sci_evt: &IrqLevelEvent,
297 ) {
298     // If received power button event, emulate PM/PWRBTN_STS and trigger SCI
299     if acpi_event._type == ACPI_BUTTON_NOTIFY_STATUS && acpi_event.bus_id.contains("LNXPWRBN") {
300         let mut pm1 = pm1.lock();
301 
302         pm1.status |= BITMASK_PM1STS_PWRBTN_STS;
303         pm1.trigger_sci(sci_evt);
304     }
305 }
306 
get_acpi_event_group() -> Option<u32>307 fn get_acpi_event_group() -> Option<u32> {
308     // Create netlink generic socket which will be used to query about given family name
309     let netlink_ctrl_sock = match NetlinkGenericSocket::new(0) {
310         Ok(sock) => sock,
311         Err(e) => {
312             error!("netlink generic socket creation error: {}", e);
313             return None;
314         }
315     };
316 
317     let nlmsg_family_response = netlink_ctrl_sock
318         .family_name_query("acpi_event".to_string())
319         .unwrap();
320     return nlmsg_family_response.get_multicast_group_id("acpi_mc_group".to_string());
321 }
322 
acpi_event_run( acpi_event_sock: &NetlinkGenericSocket, gpe0: &Arc<Mutex<GpeResource>>, pm1: &Arc<Mutex<Pm1Resource>>, sci_evt: &IrqLevelEvent, ignored_gpe: &[u32], )323 fn acpi_event_run(
324     acpi_event_sock: &NetlinkGenericSocket,
325     gpe0: &Arc<Mutex<GpeResource>>,
326     pm1: &Arc<Mutex<Pm1Resource>>,
327     sci_evt: &IrqLevelEvent,
328     ignored_gpe: &[u32],
329 ) {
330     let nl_msg = match acpi_event_sock.recv() {
331         Ok(msg) => msg,
332         Err(e) => {
333             error!("recv returned with error {}", e);
334             return;
335         }
336     };
337 
338     for netlink_message in nl_msg.iter() {
339         let acpi_event = match AcpiNotifyEvent::new(netlink_message) {
340             Ok(evt) => evt,
341             Err(e) => {
342                 error!("Received netlink message is not an acpi_event, error {}", e);
343                 continue;
344             }
345         };
346         match acpi_event.device_class.as_str() {
347             "gpe" => {
348                 acpi_event_handle_gpe(
349                     acpi_event.data,
350                     acpi_event._type,
351                     gpe0,
352                     sci_evt,
353                     ignored_gpe,
354                 );
355             }
356             "button/power" => acpi_event_handle_power_button(acpi_event, pm1, sci_evt),
357             c => warn!("unknown acpi event {}", c),
358         };
359     }
360 }
361 
362 impl Drop for ACPIPMResource {
drop(&mut self)363     fn drop(&mut self) {
364         if let Some(kill_evt) = self.kill_evt.take() {
365             let _ = kill_evt.write(1);
366         }
367 
368         if let Some(worker_thread) = self.worker_thread.take() {
369             let _ = worker_thread.join();
370         }
371     }
372 }
373 
374 impl Pm1Resource {
trigger_sci(&self, sci_evt: &IrqLevelEvent)375     fn trigger_sci(&self, sci_evt: &IrqLevelEvent) {
376         if self.status
377             & self.enable
378             & (BITMASK_PM1EN_GBL_EN
379                 | BITMASK_PM1EN_PWRBTN_EN
380                 | BITMASK_PM1EN_SLPBTN_EN
381                 | BITMASK_PM1EN_RTC_EN)
382             != 0
383         {
384             if let Err(e) = sci_evt.trigger() {
385                 error!("ACPIPM: failed to trigger sci event for pm1: {}", e);
386             }
387         }
388     }
389 }
390 
391 impl GpeResource {
trigger_sci(&self, sci_evt: &IrqLevelEvent)392     fn trigger_sci(&self, sci_evt: &IrqLevelEvent) {
393         let mut trigger = false;
394         for i in 0..self.status.len() {
395             let gpes = self.status[i] & self.enable[i];
396             if gpes == 0 {
397                 continue;
398             }
399 
400             for j in 0..8 {
401                 if gpes & (1 << j) == 0 {
402                     continue;
403                 }
404 
405                 let gpe_num: u32 = i as u32 * 8 + j;
406                 if let Some(notify_devs) = self.gpe_notify.get(&gpe_num) {
407                     for notify_dev in notify_devs.iter() {
408                         notify_dev.lock().notify();
409                     }
410                 }
411             }
412             trigger = true;
413         }
414 
415         if trigger {
416             if let Err(e) = sci_evt.trigger() {
417                 error!("ACPIPM: failed to trigger sci event for gpe: {}", e);
418             }
419         }
420     }
421 }
422 
423 #[cfg(feature = "direct")]
424 impl DirectGpe {
new(gpe: u32) -> DirectGpe425     fn new(gpe: u32) -> DirectGpe {
426         DirectGpe {
427             num: gpe,
428             path: PathBuf::from("/sys/firmware/acpi/interrupts").join(format!("gpe{:02X}", gpe)),
429             ready: false,
430             enabled: false,
431         }
432     }
433 
is_status_set(&self) -> Result<bool, IoError>434     fn is_status_set(&self) -> Result<bool, IoError> {
435         match fs::read_to_string(&self.path) {
436             Err(e) => {
437                 error!("ACPIPM: failed to read gpe {} STS: {}", self.num, e);
438                 Err(e)
439             }
440             Ok(s) => Ok(s.split_whitespace().any(|s| s == "STS")),
441         }
442     }
443 
is_enabled(&self) -> Result<bool, IoError>444     fn is_enabled(&self) -> Result<bool, IoError> {
445         match fs::read_to_string(&self.path) {
446             Err(e) => {
447                 error!("ACPIPM: failed to read gpe {} EN: {}", self.num, e);
448                 Err(e)
449             }
450             Ok(s) => Ok(s.split_whitespace().any(|s| s == "EN")),
451         }
452     }
453 
clear(&self)454     fn clear(&self) {
455         if !self.is_status_set().unwrap_or(false) {
456             // Just to avoid harmless error messages due to clearing an already cleared GPE.
457             return;
458         }
459 
460         if let Err(e) = fs::write(&self.path, "clear\n") {
461             error!("ACPIPM: failed to clear gpe {}: {}", self.num, e);
462         }
463     }
464 
enable(&mut self)465     fn enable(&mut self) {
466         if self.enabled {
467             // Just to avoid harmless error messages due to enabling an already enabled GPE.
468             return;
469         }
470 
471         if !self.ready {
472             // The GPE is being enabled for the first time.
473             // Use "enable" to ensure the ACPICA's reference count for this GPE is > 0.
474             match fs::write(&self.path, "enable\n") {
475                 Err(e) => error!("ACPIPM: failed to enable gpe {}: {}", self.num, e),
476                 Ok(()) => {
477                     self.ready = true;
478                     self.enabled = true;
479                 }
480             }
481         } else {
482             // Use "unmask" instead of "enable", to bypass ACPICA's reference counting.
483             match fs::write(&self.path, "unmask\n") {
484                 Err(e) => error!("ACPIPM: failed to unmask gpe {}: {}", self.num, e),
485                 Ok(()) => {
486                     self.enabled = true;
487                 }
488             }
489         }
490     }
491 
disable(&mut self)492     fn disable(&mut self) {
493         if !self.enabled {
494             // Just to avoid harmless error messages due to disabling an already disabled GPE.
495             return;
496         }
497 
498         // Use "mask" instead of "disable", to bypass ACPICA's reference counting.
499         match fs::write(&self.path, "mask\n") {
500             Err(e) => error!("ACPIPM: failed to mask gpe {}: {}", self.num, e),
501             Ok(()) => {
502                 self.enabled = false;
503             }
504         }
505     }
506 
is_gpe_trigger(gpe: u32) -> Result<bool, IoError>507     fn is_gpe_trigger(gpe: u32) -> Result<bool, IoError> {
508         let path = PathBuf::from("/sys/firmware/acpi/interrupts").join(format!("gpe{:02X}", gpe));
509         let s = fs::read_to_string(&path)?;
510         let mut enable = false;
511         let mut status = false;
512         for itr in s.split_whitespace() {
513             match itr {
514                 "EN" => enable = true,
515                 "STS" => status = true,
516                 _ => (),
517             }
518         }
519 
520         Ok(enable && status)
521     }
522 }
523 
524 /// the ACPI PM register length.
525 pub const ACPIPM_RESOURCE_EVENTBLK_LEN: u8 = 4;
526 pub const ACPIPM_RESOURCE_CONTROLBLK_LEN: u8 = 2;
527 pub const ACPIPM_RESOURCE_GPE0_BLK_LEN: u8 = 64;
528 pub const ACPIPM_RESOURCE_LEN: u8 = ACPIPM_RESOURCE_EVENTBLK_LEN + 4 + ACPIPM_RESOURCE_GPE0_BLK_LEN;
529 
530 /// ACPI PM register value definitions
531 
532 /// 4.8.4.1.1 PM1 Status Registers, ACPI Spec Version 6.4
533 /// Register Location: <PM1a_EVT_BLK / PM1b_EVT_BLK> System I/O or Memory Space (defined in FADT)
534 /// Size: PM1_EVT_LEN / 2 (defined in FADT)
535 const PM1_STATUS: u16 = 0;
536 
537 /// 4.8.4.1.2 PM1Enable Registers, ACPI Spec Version 6.4
538 /// Register Location: <<PM1a_EVT_BLK / PM1b_EVT_BLK> + PM1_EVT_LEN / 2 System I/O or Memory Space
539 /// (defined in FADT)
540 /// Size: PM1_EVT_LEN / 2 (defined in FADT)
541 const PM1_ENABLE: u16 = PM1_STATUS + (ACPIPM_RESOURCE_EVENTBLK_LEN as u16 / 2);
542 
543 /// 4.8.4.2.1 PM1 Control Registers, ACPI Spec Version 6.4
544 /// Register Location: <PM1a_CNT_BLK / PM1b_CNT_BLK> System I/O or Memory Space (defined in FADT)
545 /// Size: PM1_CNT_LEN (defined in FADT)
546 const PM1_CONTROL: u16 = PM1_STATUS + ACPIPM_RESOURCE_EVENTBLK_LEN as u16;
547 
548 /// 4.8.5.1 General-Purpose Event Register Blocks, ACPI Spec Version 6.4
549 /// - Each register block contains two registers: an enable and a status register.
550 /// - Each register block is 32-bit aligned.
551 /// - Each register in the block is accessed as a byte.
552 
553 /// 4.8.5.1.1 General-Purpose Event 0 Register Block, ACPI Spec Version 6.4
554 /// This register block consists of two registers: The GPE0_STS and the GPE0_EN registers. Each
555 /// register’s length is defined to be half the length of the GPE0 register block, and is described
556 /// in the ACPI FADT’s GPE0_BLK and GPE0_BLK_LEN operators.
557 
558 /// 4.8.5.1.1.1 General-Purpose Event 0 Status Register, ACPI Spec Version 6.4
559 /// Register Location: <GPE0_STS> System I/O or System Memory Space (defined in FADT)
560 /// Size: GPE0_BLK_LEN/2 (defined in FADT)
561 const GPE0_STATUS: u16 = PM1_STATUS + ACPIPM_RESOURCE_EVENTBLK_LEN as u16 + 4; // ensure alignment
562 
563 /// 4.8.5.1.1.2 General-Purpose Event 0 Enable Register, ACPI Spec Version 6.4
564 /// Register Location: <GPE0_EN> System I/O or System Memory Space (defined in FADT)
565 /// Size: GPE0_BLK_LEN/2 (defined in FADT)
566 const GPE0_ENABLE: u16 = GPE0_STATUS + (ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2);
567 
568 const BITMASK_PM1STS_PWRBTN_STS: u16 = 1 << 8;
569 const BITMASK_PM1EN_GBL_EN: u16 = 1 << 5;
570 const BITMASK_PM1EN_PWRBTN_EN: u16 = 1 << 8;
571 const BITMASK_PM1EN_SLPBTN_EN: u16 = 1 << 9;
572 const BITMASK_PM1EN_RTC_EN: u16 = 1 << 10;
573 const BITMASK_PM1CNT_SLEEP_ENABLE: u16 = 0x2000;
574 const BITMASK_PM1CNT_WAKE_STATUS: u16 = 0x8000;
575 
576 #[cfg(not(feature = "direct"))]
577 const BITMASK_PM1CNT_SLEEP_TYPE: u16 = 0x1C00;
578 #[cfg(not(feature = "direct"))]
579 const SLEEP_TYPE_S1: u16 = 1 << 10;
580 #[cfg(not(feature = "direct"))]
581 const SLEEP_TYPE_S5: u16 = 0 << 10;
582 
583 impl PmResource for ACPIPMResource {
pwrbtn_evt(&mut self)584     fn pwrbtn_evt(&mut self) {
585         let mut pm1 = self.pm1.lock();
586 
587         pm1.status |= BITMASK_PM1STS_PWRBTN_STS;
588         pm1.trigger_sci(&self.sci_evt);
589     }
590 
gpe_evt(&mut self, gpe: u32)591     fn gpe_evt(&mut self, gpe: u32) {
592         let mut gpe0 = self.gpe0.lock();
593 
594         let byte = gpe as usize / 8;
595         if byte >= gpe0.status.len() {
596             error!("gpe_evt: GPE register {} does not exist", byte);
597             return;
598         }
599         gpe0.status[byte] |= 1 << (gpe % 8);
600         gpe0.trigger_sci(&self.sci_evt);
601     }
602 
register_gpe_notify_dev(&mut self, gpe: u32, notify_dev: Arc<Mutex<dyn GpeNotify>>)603     fn register_gpe_notify_dev(&mut self, gpe: u32, notify_dev: Arc<Mutex<dyn GpeNotify>>) {
604         let mut gpe0 = self.gpe0.lock();
605         match gpe0.gpe_notify.get_mut(&gpe) {
606             Some(v) => v.push(notify_dev),
607             None => {
608                 gpe0.gpe_notify.insert(gpe, vec![notify_dev]);
609             }
610         }
611     }
612 }
613 
614 const PM1_STATUS_LAST: u16 = PM1_STATUS + (ACPIPM_RESOURCE_EVENTBLK_LEN as u16 / 2) - 1;
615 const PM1_ENABLE_LAST: u16 = PM1_ENABLE + (ACPIPM_RESOURCE_EVENTBLK_LEN as u16 / 2) - 1;
616 const PM1_CONTROL_LAST: u16 = PM1_CONTROL + ACPIPM_RESOURCE_CONTROLBLK_LEN as u16 - 1;
617 const GPE0_STATUS_LAST: u16 = GPE0_STATUS + (ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2) - 1;
618 const GPE0_ENABLE_LAST: u16 = GPE0_ENABLE + (ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2) - 1;
619 
620 impl BusDevice for ACPIPMResource {
debug_label(&self) -> String621     fn debug_label(&self) -> String {
622         "ACPIPMResource".to_owned()
623     }
624 
read(&mut self, info: BusAccessInfo, data: &mut [u8])625     fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
626         match info.offset as u16 {
627             // Accesses to the PM1 registers are done through byte or word accesses
628             PM1_STATUS..=PM1_STATUS_LAST => {
629                 if data.len() > std::mem::size_of::<u16>()
630                     || info.offset + data.len() as u64 > (PM1_STATUS_LAST + 1).into()
631                 {
632                     warn!("ACPIPM: bad read size: {}", data.len());
633                     return;
634                 }
635                 let offset = (info.offset - PM1_STATUS as u64) as usize;
636                 data.copy_from_slice(
637                     &self.pm1.lock().status.to_ne_bytes()[offset..offset + data.len()],
638                 );
639             }
640             PM1_ENABLE..=PM1_ENABLE_LAST => {
641                 if data.len() > std::mem::size_of::<u16>()
642                     || info.offset + data.len() as u64 > (PM1_ENABLE_LAST + 1).into()
643                 {
644                     warn!("ACPIPM: bad read size: {}", data.len());
645                     return;
646                 }
647                 let offset = (info.offset - PM1_ENABLE as u64) as usize;
648                 data.copy_from_slice(
649                     &self.pm1.lock().enable.to_ne_bytes()[offset..offset + data.len()],
650                 );
651             }
652             PM1_CONTROL..=PM1_CONTROL_LAST => {
653                 if data.len() > std::mem::size_of::<u16>()
654                     || info.offset + data.len() as u64 > (PM1_CONTROL_LAST + 1).into()
655                 {
656                     warn!("ACPIPM: bad read size: {}", data.len());
657                     return;
658                 }
659                 let offset = (info.offset - PM1_CONTROL as u64) as usize;
660                 data.copy_from_slice(
661                     &self.pm1.lock().control.to_ne_bytes()[offset..offset + data.len()],
662                 );
663             }
664             // OSPM accesses GPE registers through byte accesses (regardless of their length)
665             GPE0_STATUS..=GPE0_STATUS_LAST => {
666                 if data.len() > std::mem::size_of::<u8>()
667                     || info.offset + data.len() as u64 > (GPE0_STATUS_LAST + 1).into()
668                 {
669                     warn!("ACPIPM: bad read size: {}", data.len());
670                     return;
671                 }
672                 let offset = (info.offset - GPE0_STATUS as u64) as usize;
673                 data[0] = self.gpe0.lock().status[offset];
674 
675                 #[cfg(feature = "direct")]
676                 for gpe in self
677                     .direct_gpe
678                     .iter()
679                     .filter(|gpe| gpe.num / 8 == offset as u32)
680                 {
681                     data[0] &= !(1 << (gpe.num % 8));
682                     if gpe.is_status_set().unwrap_or(false) {
683                         data[0] |= 1 << (gpe.num % 8);
684                     }
685                 }
686             }
687             GPE0_ENABLE..=GPE0_ENABLE_LAST => {
688                 if data.len() > std::mem::size_of::<u8>()
689                     || info.offset + data.len() as u64 > (GPE0_ENABLE_LAST + 1).into()
690                 {
691                     warn!("ACPIPM: bad read size: {}", data.len());
692                     return;
693                 }
694                 let offset = (info.offset - GPE0_ENABLE as u64) as usize;
695                 data[0] = self.gpe0.lock().enable[offset];
696 
697                 #[cfg(feature = "direct")]
698                 for gpe in self
699                     .direct_gpe
700                     .iter()
701                     .filter(|gpe| gpe.num / 8 == offset as u32)
702                 {
703                     data[0] &= !(1 << (gpe.num % 8));
704                     if gpe.is_enabled().unwrap_or(false) {
705                         data[0] |= 1 << (gpe.num % 8);
706                     }
707                 }
708             }
709             _ => {
710                 warn!("ACPIPM: Bad read from {}", info);
711             }
712         }
713     }
714 
write(&mut self, info: BusAccessInfo, data: &[u8])715     fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
716         match info.offset as u16 {
717             // Accesses to the PM1 registers are done through byte or word accesses
718             PM1_STATUS..=PM1_STATUS_LAST => {
719                 if data.len() > std::mem::size_of::<u16>()
720                     || info.offset + data.len() as u64 > (PM1_STATUS_LAST + 1).into()
721                 {
722                     warn!("ACPIPM: bad write size: {}", data.len());
723                     return;
724                 }
725                 let offset = (info.offset - PM1_STATUS as u64) as usize;
726 
727                 let mut pm1 = self.pm1.lock();
728                 let mut v = pm1.status.to_ne_bytes();
729                 for (i, j) in (offset..offset + data.len()).enumerate() {
730                     v[j] &= !data[i];
731                 }
732                 pm1.status = u16::from_ne_bytes(v);
733             }
734             PM1_ENABLE..=PM1_ENABLE_LAST => {
735                 if data.len() > std::mem::size_of::<u16>()
736                     || info.offset + data.len() as u64 > (PM1_ENABLE_LAST + 1).into()
737                 {
738                     warn!("ACPIPM: bad write size: {}", data.len());
739                     return;
740                 }
741                 let offset = (info.offset - PM1_ENABLE as u64) as usize;
742 
743                 let mut pm1 = self.pm1.lock();
744                 let mut v = pm1.enable.to_ne_bytes();
745                 for (i, j) in (offset..offset + data.len()).enumerate() {
746                     v[j] = data[i];
747                 }
748                 pm1.enable = u16::from_ne_bytes(v);
749                 pm1.trigger_sci(&self.sci_evt);
750             }
751             PM1_CONTROL..=PM1_CONTROL_LAST => {
752                 if data.len() > std::mem::size_of::<u16>()
753                     || info.offset + data.len() as u64 > (PM1_CONTROL_LAST + 1).into()
754                 {
755                     warn!("ACPIPM: bad write size: {}", data.len());
756                     return;
757                 }
758                 let offset = (info.offset - PM1_CONTROL as u64) as usize;
759 
760                 let mut pm1 = self.pm1.lock();
761 
762                 let mut v = pm1.control.to_ne_bytes();
763                 for (i, j) in (offset..offset + data.len()).enumerate() {
764                     v[j] = data[i];
765                 }
766                 let val = u16::from_ne_bytes(v);
767 
768                 // SLP_EN is a write-only bit and reads to it always return a zero
769                 if (val & BITMASK_PM1CNT_SLEEP_ENABLE) != 0 {
770                     // only support S5 in direct mode
771                     #[cfg(feature = "direct")]
772                     if let Err(e) = self.exit_evt.write(1) {
773                         error!("ACPIPM: failed to trigger exit event: {}", e);
774                     }
775                     #[cfg(not(feature = "direct"))]
776                     match val & BITMASK_PM1CNT_SLEEP_TYPE {
777                         SLEEP_TYPE_S1 => {
778                             if let Err(e) = self.suspend_evt.write(1) {
779                                 error!("ACPIPM: failed to trigger suspend event: {}", e);
780                             }
781                         }
782                         SLEEP_TYPE_S5 => {
783                             if let Err(e) = self.exit_evt.write(1) {
784                                 error!("ACPIPM: failed to trigger exit event: {}", e);
785                             }
786                         }
787                         _ => error!(
788                             "ACPIPM: unknown SLP_TYP written: {}",
789                             (val & BITMASK_PM1CNT_SLEEP_TYPE) >> 10
790                         ),
791                     }
792                 }
793                 pm1.control = val & !BITMASK_PM1CNT_SLEEP_ENABLE;
794             }
795             // OSPM accesses GPE registers through byte accesses (regardless of their length)
796             GPE0_STATUS..=GPE0_STATUS_LAST => {
797                 if data.len() > std::mem::size_of::<u8>()
798                     || info.offset + data.len() as u64 > (GPE0_STATUS_LAST + 1).into()
799                 {
800                     warn!("ACPIPM: bad write size: {}", data.len());
801                     return;
802                 }
803                 let offset = (info.offset - GPE0_STATUS as u64) as usize;
804 
805                 #[cfg(feature = "direct")]
806                 for gpe in self
807                     .direct_gpe
808                     .iter()
809                     .filter(|gpe| gpe.num / 8 == offset as u32)
810                 {
811                     if data[0] & (1 << (gpe.num % 8)) != 0 {
812                         gpe.clear();
813                     }
814                 }
815 
816                 self.gpe0.lock().status[offset] &= !data[0];
817             }
818             GPE0_ENABLE..=GPE0_ENABLE_LAST => {
819                 if data.len() > std::mem::size_of::<u8>()
820                     || info.offset + data.len() as u64 > (GPE0_ENABLE_LAST + 1).into()
821                 {
822                     warn!("ACPIPM: bad write size: {}", data.len());
823                     return;
824                 }
825                 let offset = (info.offset - GPE0_ENABLE as u64) as usize;
826 
827                 #[cfg(feature = "direct")]
828                 for gpe in self
829                     .direct_gpe
830                     .iter_mut()
831                     .filter(|gpe| gpe.num / 8 == offset as u32)
832                 {
833                     if data[0] & (1 << (gpe.num % 8)) != 0 {
834                         gpe.enable();
835                     } else {
836                         gpe.disable();
837                     }
838                 }
839 
840                 let mut gpe = self.gpe0.lock();
841                 gpe.enable[offset] = data[0];
842                 gpe.trigger_sci(&self.sci_evt);
843             }
844             _ => {
845                 warn!("ACPIPM: Bad write to {}", info);
846             }
847         };
848     }
849 }
850 
851 impl BusResumeDevice for ACPIPMResource {
resume_imminent(&mut self)852     fn resume_imminent(&mut self) {
853         self.pm1.lock().status |= BITMASK_PM1CNT_WAKE_STATUS;
854     }
855 }
856 
857 impl Aml for ACPIPMResource {
to_aml_bytes(&self, bytes: &mut Vec<u8>)858     fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
859         // S1
860         aml::Name::new(
861             "_S1_".into(),
862             &aml::Package::new(vec![&aml::ONE, &aml::ONE, &aml::ZERO, &aml::ZERO]),
863         )
864         .to_aml_bytes(bytes);
865 
866         // S5
867         aml::Name::new(
868             "_S5_".into(),
869             &aml::Package::new(vec![&aml::ZERO, &aml::ZERO, &aml::ZERO, &aml::ZERO]),
870         )
871         .to_aml_bytes(bytes);
872     }
873 }
874