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