1 // Copyright 2020 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 use std::sync::Arc;
6
7 use acpi_tables::aml;
8 use acpi_tables::aml::Aml;
9 use anyhow::bail;
10 use anyhow::Context;
11 use base::error;
12 use base::warn;
13 use base::AsRawDescriptor;
14 use base::Event;
15 use base::EventToken;
16 use base::RawDescriptor;
17 use base::Tube;
18 use base::WaitContext;
19 use base::WorkerThread;
20 use power_monitor::BatteryStatus;
21 use power_monitor::CreatePowerClientFn;
22 use power_monitor::CreatePowerMonitorFn;
23 use remain::sorted;
24 use serde::Deserialize;
25 use serde::Serialize;
26 use sync::Mutex;
27 use thiserror::Error;
28 use vm_control::BatConfig;
29 use vm_control::BatControlCommand;
30 use vm_control::BatControlResult;
31
32 use crate::pci::CrosvmDeviceId;
33 use crate::BusAccessInfo;
34 use crate::BusDevice;
35 use crate::DeviceId;
36 use crate::IrqLevelEvent;
37 use crate::Suspendable;
38
39 /// Errors for battery devices.
40 #[sorted]
41 #[derive(Error, Debug)]
42 pub enum BatteryError {
43 #[error("Non 32-bit mmio address space")]
44 Non32BitMmioAddress,
45 }
46
47 type Result<T> = std::result::Result<T, BatteryError>;
48
49 /// the GoldFish Battery MMIO length.
50 pub const GOLDFISHBAT_MMIO_LEN: u64 = 0x1000;
51
52 #[derive(Clone, Serialize, Deserialize)]
53 struct GoldfishBatteryState {
54 // interrupt state
55 int_status: u32,
56 int_enable: u32,
57 // AC state
58 ac_online: u32,
59 // Battery state
60 status: u32,
61 health: u32,
62 present: u32,
63 capacity: u32,
64 voltage: u32,
65 current: u32,
66 charge_counter: u32,
67 charge_full: u32,
68 initialized: bool,
69 }
70
71 macro_rules! create_battery_func {
72 // $property: the battery property which is going to be modified.
73 // $int: the interrupt status which is going to be set to notify the guest.
74 ($fn:ident, $property:ident, $int:ident) => {
75 pub(crate) fn $fn(&mut self, value: u32) -> bool {
76 let old = std::mem::replace(&mut self.$property, value);
77 old != self.$property && self.set_int_status($int)
78 }
79 };
80 }
81
82 impl GoldfishBatteryState {
set_int_status(&mut self, mask: u32) -> bool83 fn set_int_status(&mut self, mask: u32) -> bool {
84 if ((self.int_enable & mask) != 0) && ((self.int_status & mask) == 0) {
85 self.int_status |= mask;
86 return true;
87 }
88 false
89 }
90
int_status(&self) -> u3291 fn int_status(&self) -> u32 {
92 self.int_status
93 }
94
95 create_battery_func!(set_ac_online, ac_online, AC_STATUS_CHANGED);
96
97 create_battery_func!(set_status, status, BATTERY_STATUS_CHANGED);
98
99 create_battery_func!(set_health, health, BATTERY_STATUS_CHANGED);
100
101 create_battery_func!(set_present, present, BATTERY_STATUS_CHANGED);
102
103 create_battery_func!(set_capacity, capacity, BATTERY_STATUS_CHANGED);
104
105 create_battery_func!(set_voltage, voltage, BATTERY_STATUS_CHANGED);
106
107 create_battery_func!(set_current, current, BATTERY_STATUS_CHANGED);
108
109 create_battery_func!(set_charge_counter, charge_counter, BATTERY_STATUS_CHANGED);
110
111 create_battery_func!(set_charge_full, charge_full, BATTERY_STATUS_CHANGED);
112 }
113
114 /// GoldFish Battery state
115 pub struct GoldfishBattery {
116 state: Arc<Mutex<GoldfishBatteryState>>,
117 mmio_base: u32,
118 irq_num: u32,
119 irq_evt: IrqLevelEvent,
120 activated: bool,
121 monitor_thread: Option<WorkerThread<()>>,
122 tube: Option<Tube>,
123 create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>,
124 create_powerd_client: Option<Box<dyn CreatePowerClientFn>>,
125 // battery_config is used for goldfish battery to report fake battery to the guest.
126 battery_config: Arc<Mutex<BatConfig>>,
127 }
128
129 #[derive(Serialize, Deserialize)]
130 struct GoldfishBatterySnapshot {
131 state: GoldfishBatteryState,
132 mmio_base: u32,
133 irq_num: u32,
134 activated: bool,
135 }
136
137 /// Goldfish Battery MMIO offset
138 const BATTERY_INT_STATUS: u32 = 0;
139 const BATTERY_INT_ENABLE: u32 = 0x4;
140 const BATTERY_AC_ONLINE: u32 = 0x8;
141 const BATTERY_STATUS: u32 = 0xC;
142 const BATTERY_HEALTH: u32 = 0x10;
143 const BATTERY_PRESENT: u32 = 0x14;
144 const BATTERY_CAPACITY: u32 = 0x18;
145 const BATTERY_VOLTAGE: u32 = 0x1C;
146 const BATTERY_TEMP: u32 = 0x20;
147 const BATTERY_CHARGE_COUNTER: u32 = 0x24;
148 const BATTERY_VOLTAGE_MAX: u32 = 0x28;
149 const BATTERY_CURRENT_MAX: u32 = 0x2C;
150 const BATTERY_CURRENT_NOW: u32 = 0x30;
151 const BATTERY_CURRENT_AVG: u32 = 0x34;
152 const BATTERY_CHARGE_FULL_UAH: u32 = 0x38;
153 const BATTERY_CYCLE_COUNT: u32 = 0x40;
154
155 /// Goldfish Battery interrupt bits
156 const BATTERY_STATUS_CHANGED: u32 = 1 << 0;
157 const AC_STATUS_CHANGED: u32 = 1 << 1;
158 const BATTERY_INT_MASK: u32 = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED;
159
160 /// Goldfish Battery status
161 const BATTERY_STATUS_VAL_UNKNOWN: u32 = 0;
162 const BATTERY_STATUS_VAL_CHARGING: u32 = 1;
163 const BATTERY_STATUS_VAL_DISCHARGING: u32 = 2;
164 const BATTERY_STATUS_VAL_NOT_CHARGING: u32 = 3;
165
166 /// Goldfish Battery health
167 const BATTERY_HEALTH_VAL_UNKNOWN: u32 = 0;
168
169 // Goldfish ac online status
170 const AC_ONLINE_VAL_OFFLINE: u32 = 0;
171
172 #[derive(EventToken)]
173 pub(crate) enum Token {
174 Commands,
175 Resample,
176 Kill,
177 Monitor,
178 }
179
command_monitor( tube: Tube, irq_evt: IrqLevelEvent, kill_evt: Event, state: Arc<Mutex<GoldfishBatteryState>>, create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>, battery_config: Arc<Mutex<BatConfig>>, )180 fn command_monitor(
181 tube: Tube,
182 irq_evt: IrqLevelEvent,
183 kill_evt: Event,
184 state: Arc<Mutex<GoldfishBatteryState>>,
185 create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>,
186 battery_config: Arc<Mutex<BatConfig>>,
187 ) {
188 let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
189 (&tube, Token::Commands),
190 (irq_evt.get_resample(), Token::Resample),
191 (&kill_evt, Token::Kill),
192 ]) {
193 Ok(pc) => pc,
194 Err(e) => {
195 error!("failed to build WaitContext: {}", e);
196 return;
197 }
198 };
199
200 let mut power_monitor = match create_power_monitor {
201 Some(f) => match f() {
202 Ok(p) => match wait_ctx.add(p.get_read_notifier(), Token::Monitor) {
203 Ok(()) => Some(p),
204 Err(e) => {
205 error!("failed to add power monitor to poll context: {}", e);
206 None
207 }
208 },
209 Err(e) => {
210 error!("failed to create power monitor: {}", e);
211 None
212 }
213 },
214 None => None,
215 };
216
217 'poll: loop {
218 let events = match wait_ctx.wait() {
219 Ok(v) => v,
220 Err(e) => {
221 error!("error while polling for events: {}", e);
222 break;
223 }
224 };
225
226 for event in events.iter().filter(|e| e.is_readable) {
227 match event.token {
228 Token::Commands => {
229 let req = match tube.recv() {
230 Ok(req) => req,
231 Err(e) => {
232 error!("failed to receive request: {}", e);
233 continue;
234 }
235 };
236
237 let mut bat_config = battery_config.lock();
238 let mut bat_state = state.lock();
239 let inject_irq = match req {
240 BatControlCommand::SetStatus(status) => bat_state.set_status(status.into()),
241 BatControlCommand::SetHealth(health) => bat_state.set_health(health.into()),
242 BatControlCommand::SetPresent(present) => {
243 let v = present != 0;
244 bat_state.set_present(v.into())
245 }
246 BatControlCommand::SetCapacity(capacity) => {
247 let v = std::cmp::min(capacity, 100);
248 bat_state.set_capacity(v)
249 }
250 BatControlCommand::SetACOnline(ac_online) => {
251 let v = ac_online != 0;
252 bat_state.set_ac_online(v.into())
253 }
254 BatControlCommand::SetFakeBatConfig(max_capacity) => {
255 let max_capacity = std::cmp::min(max_capacity, 100);
256 *bat_config = BatConfig::Fake { max_capacity };
257 true
258 }
259 BatControlCommand::CancelFakeConfig => {
260 *bat_config = BatConfig::Real;
261 true
262 }
263 };
264
265 if inject_irq {
266 let _ = irq_evt.trigger();
267 }
268
269 if let Err(e) = tube.send(&BatControlResult::Ok) {
270 error!("failed to send response: {}", e);
271 }
272 }
273
274 Token::Monitor => {
275 // Safe because power_monitor must be populated if Token::Monitor is triggered.
276 let power_monitor = power_monitor.as_mut().unwrap();
277
278 let data = match power_monitor.read_message() {
279 Ok(Some(d)) => d,
280 Ok(None) => continue,
281 Err(e) => {
282 error!("failed to read new power data: {}", e);
283 continue;
284 }
285 };
286
287 let mut bat_state = state.lock();
288
289 // Each set_* function called below returns true when interrupt bits
290 // (*_STATUS_CHANGED) changed. If `inject_irq` is true after we attempt to
291 // update each field, inject an interrupt.
292 let mut inject_irq = bat_state.set_ac_online(data.ac_online.into());
293
294 match data.battery {
295 Some(battery_data) => {
296 inject_irq |= bat_state.set_capacity(battery_data.percent);
297 let battery_status = match battery_data.status {
298 BatteryStatus::Unknown => BATTERY_STATUS_VAL_UNKNOWN,
299 BatteryStatus::Charging => BATTERY_STATUS_VAL_CHARGING,
300 BatteryStatus::Discharging => BATTERY_STATUS_VAL_DISCHARGING,
301 BatteryStatus::NotCharging => BATTERY_STATUS_VAL_NOT_CHARGING,
302 };
303 inject_irq |= bat_state.set_status(battery_status);
304 inject_irq |= bat_state.set_voltage(battery_data.voltage);
305 inject_irq |= bat_state.set_current(battery_data.current);
306 inject_irq |= bat_state.set_charge_counter(battery_data.charge_counter);
307 inject_irq |= bat_state.set_charge_full(battery_data.charge_full);
308 }
309 None => {
310 inject_irq |= bat_state.set_present(0);
311 }
312 }
313
314 if inject_irq {
315 let _ = irq_evt.trigger();
316 }
317 }
318
319 Token::Resample => {
320 irq_evt.clear_resample();
321 if state.lock().int_status() != 0 {
322 let _ = irq_evt.trigger();
323 }
324 }
325
326 Token::Kill => break 'poll,
327 }
328 }
329 }
330 }
331
332 impl GoldfishBattery {
333 /// Create GoldfishBattery device model
334 ///
335 /// * `mmio_base` - The 32-bit mmio base address.
336 /// * `irq_num` - The corresponding interrupt number of the irq_evt which will be put into the
337 /// ACPI DSDT.
338 /// * `irq_evt` - The interrupt event used to notify driver about the battery properties
339 /// changing.
340 /// * `socket` - Battery control socket
new( mmio_base: u64, irq_num: u32, irq_evt: IrqLevelEvent, tube: Tube, create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>, create_powerd_client: Option<Box<dyn CreatePowerClientFn>>, ) -> Result<Self>341 pub fn new(
342 mmio_base: u64,
343 irq_num: u32,
344 irq_evt: IrqLevelEvent,
345 tube: Tube,
346 create_power_monitor: Option<Box<dyn CreatePowerMonitorFn>>,
347 create_powerd_client: Option<Box<dyn CreatePowerClientFn>>,
348 ) -> Result<Self> {
349 if mmio_base + GOLDFISHBAT_MMIO_LEN - 1 > u32::MAX as u64 {
350 return Err(BatteryError::Non32BitMmioAddress);
351 }
352 let state = Arc::new(Mutex::new(GoldfishBatteryState {
353 capacity: 50,
354 health: BATTERY_HEALTH_VAL_UNKNOWN,
355 present: 1,
356 status: BATTERY_STATUS_VAL_UNKNOWN,
357 ac_online: 1,
358 int_enable: 0,
359 int_status: 0,
360 voltage: 0,
361 current: 0,
362 charge_counter: 0,
363 charge_full: 0,
364 initialized: false,
365 }));
366
367 let battery_config = Arc::new(Mutex::new(BatConfig::default()));
368
369 Ok(GoldfishBattery {
370 state,
371 mmio_base: mmio_base as u32,
372 irq_num,
373 irq_evt,
374 activated: false,
375 monitor_thread: None,
376 tube: Some(tube),
377 create_power_monitor,
378 create_powerd_client,
379 battery_config,
380 })
381 }
382
383 /// return the descriptors used by this device
keep_rds(&self) -> Vec<RawDescriptor>384 pub fn keep_rds(&self) -> Vec<RawDescriptor> {
385 let mut rds = vec![
386 self.irq_evt.get_trigger().as_raw_descriptor(),
387 self.irq_evt.get_resample().as_raw_descriptor(),
388 ];
389
390 if let Some(tube) = &self.tube {
391 rds.push(tube.as_raw_descriptor());
392 }
393
394 rds
395 }
396
397 /// start a monitor thread to monitor the events from host
start_monitor(&mut self)398 fn start_monitor(&mut self) {
399 if self.activated {
400 return;
401 }
402
403 if let Some(tube) = self.tube.take() {
404 let irq_evt = self.irq_evt.try_clone().unwrap();
405 let bat_state = self.state.clone();
406 let create_monitor_fn = self.create_power_monitor.take();
407 let battery_config = self.battery_config.clone();
408 self.monitor_thread = Some(WorkerThread::start(self.debug_label(), move |kill_evt| {
409 command_monitor(
410 tube,
411 irq_evt,
412 kill_evt,
413 bat_state,
414 create_monitor_fn,
415 battery_config,
416 )
417 }));
418 self.activated = true;
419 }
420 }
421
initialize_battery_state(&mut self) -> anyhow::Result<()>422 fn initialize_battery_state(&mut self) -> anyhow::Result<()> {
423 let mut power_client = match &self.create_powerd_client {
424 Some(f) => match f() {
425 Ok(c) => c,
426 Err(e) => bail!("failed to connect to the powerd: {:#}", e),
427 },
428 None => return Ok(()),
429 };
430 match power_client.get_power_data() {
431 Ok(data) => {
432 let mut bat_state = self.state.lock();
433 bat_state.set_ac_online(data.ac_online.into());
434
435 match data.battery {
436 Some(battery_data) => {
437 bat_state.set_capacity(battery_data.percent);
438 let battery_status = match battery_data.status {
439 BatteryStatus::Unknown => BATTERY_STATUS_VAL_UNKNOWN,
440 BatteryStatus::Charging => BATTERY_STATUS_VAL_CHARGING,
441 BatteryStatus::Discharging => BATTERY_STATUS_VAL_DISCHARGING,
442 BatteryStatus::NotCharging => BATTERY_STATUS_VAL_NOT_CHARGING,
443 };
444 bat_state.set_status(battery_status);
445 bat_state.set_voltage(battery_data.voltage);
446 bat_state.set_current(battery_data.current);
447 bat_state.set_charge_counter(battery_data.charge_counter);
448 bat_state.set_charge_full(battery_data.charge_full);
449 }
450 None => {
451 bat_state.set_present(0);
452 }
453 }
454 Ok(())
455 }
456 Err(e) => {
457 bail!("failed to get response from powerd: {:#}", e);
458 }
459 }
460 }
461 }
462
463 impl Drop for GoldfishBattery {
drop(&mut self)464 fn drop(&mut self) {
465 if let Err(e) = self.sleep() {
466 error!("{}", e);
467 };
468 }
469 }
470
471 impl BusDevice for GoldfishBattery {
device_id(&self) -> DeviceId472 fn device_id(&self) -> DeviceId {
473 CrosvmDeviceId::GoldfishBattery.into()
474 }
475
debug_label(&self) -> String476 fn debug_label(&self) -> String {
477 "GoldfishBattery".to_owned()
478 }
479
read(&mut self, info: BusAccessInfo, data: &mut [u8])480 fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
481 if data.len() != std::mem::size_of::<u32>() {
482 warn!(
483 "{}: unsupported read length {}, only support 4bytes read",
484 self.debug_label(),
485 data.len()
486 );
487 return;
488 }
489
490 // Before first read, we try to ask powerd the actual power data to initialize `self.state`.
491 if !self.state.lock().initialized {
492 match self.initialize_battery_state() {
493 Ok(()) => self.state.lock().initialized = true,
494 Err(e) => {
495 error!(
496 "{}: failed to get power data and update: {:#}",
497 self.debug_label(),
498 e
499 );
500 }
501 }
502 }
503
504 let val = match info.offset as u32 {
505 BATTERY_INT_STATUS => {
506 // read to clear the interrupt status
507 std::mem::replace(&mut self.state.lock().int_status, 0)
508 }
509 BATTERY_INT_ENABLE => self.state.lock().int_enable,
510 BATTERY_AC_ONLINE => match *self.battery_config.lock() {
511 BatConfig::Real => self.state.lock().ac_online,
512 BatConfig::Fake { max_capacity: _ } => AC_ONLINE_VAL_OFFLINE,
513 },
514 BATTERY_STATUS => match *self.battery_config.lock() {
515 BatConfig::Real => self.state.lock().status,
516 BatConfig::Fake { max_capacity: _ } => BATTERY_STATUS_VAL_DISCHARGING,
517 },
518 BATTERY_HEALTH => self.state.lock().health,
519 BATTERY_PRESENT => self.state.lock().present,
520 BATTERY_CAPACITY => {
521 let max_capacity = match *self.battery_config.lock() {
522 BatConfig::Real => 100,
523 BatConfig::Fake { max_capacity } => max_capacity,
524 };
525 std::cmp::min(max_capacity, self.state.lock().capacity)
526 }
527 BATTERY_VOLTAGE => self.state.lock().voltage,
528 BATTERY_TEMP => 0,
529 BATTERY_CHARGE_COUNTER => self.state.lock().charge_counter,
530 BATTERY_VOLTAGE_MAX => 0,
531 BATTERY_CURRENT_MAX => 0,
532 BATTERY_CURRENT_NOW => self.state.lock().current,
533 BATTERY_CURRENT_AVG => 0,
534 BATTERY_CHARGE_FULL_UAH => self.state.lock().charge_full,
535 BATTERY_CYCLE_COUNT => 0,
536 _ => {
537 warn!("{}: unsupported read address {}", self.debug_label(), info);
538 return;
539 }
540 };
541
542 let val_arr = val.to_ne_bytes();
543 data.copy_from_slice(&val_arr);
544 }
545
write(&mut self, info: BusAccessInfo, data: &[u8])546 fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
547 if data.len() != std::mem::size_of::<u32>() {
548 warn!(
549 "{}: unsupported write length {}, only support 4bytes write",
550 self.debug_label(),
551 data.len()
552 );
553 return;
554 }
555
556 let mut val_arr = u32::to_ne_bytes(0u32);
557 val_arr.copy_from_slice(data);
558 let val = u32::from_ne_bytes(val_arr);
559
560 match info.offset as u32 {
561 BATTERY_INT_ENABLE => {
562 self.state.lock().int_enable = val;
563 if (val & BATTERY_INT_MASK) != 0 && !self.activated {
564 self.start_monitor();
565 }
566 }
567 _ => {
568 warn!("{}: Bad write to address {}", self.debug_label(), info);
569 }
570 };
571 }
572 }
573
574 impl Aml for GoldfishBattery {
to_aml_bytes(&self, bytes: &mut Vec<u8>)575 fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
576 aml::Device::new(
577 "GFBY".into(),
578 vec![
579 &aml::Name::new("_HID".into(), &"GFSH0001"),
580 &aml::Name::new(
581 "_CRS".into(),
582 &aml::ResourceTemplate::new(vec![
583 &aml::Memory32Fixed::new(true, self.mmio_base, GOLDFISHBAT_MMIO_LEN as u32),
584 &aml::Interrupt::new(true, false, false, true, self.irq_num),
585 ]),
586 ),
587 ],
588 )
589 .to_aml_bytes(bytes);
590 }
591 }
592
593 impl Suspendable for GoldfishBattery {
sleep(&mut self) -> anyhow::Result<()>594 fn sleep(&mut self) -> anyhow::Result<()> {
595 if let Some(thread) = self.monitor_thread.take() {
596 thread.stop();
597 }
598 Ok(())
599 }
600
wake(&mut self) -> anyhow::Result<()>601 fn wake(&mut self) -> anyhow::Result<()> {
602 if self.activated {
603 // Set activated to false for start_monitor to start monitoring again.
604 self.activated = false;
605 self.start_monitor();
606 }
607 Ok(())
608 }
609
snapshot(&mut self) -> anyhow::Result<serde_json::Value>610 fn snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
611 serde_json::to_value(GoldfishBatterySnapshot {
612 state: self.state.lock().clone(),
613 mmio_base: self.mmio_base,
614 irq_num: self.irq_num,
615 activated: self.activated,
616 })
617 .context("failed to snapshot GoldfishBattery")
618 }
619
restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>620 fn restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
621 let deser: GoldfishBatterySnapshot =
622 serde_json::from_value(data).context("failed to deserialize GoldfishBattery")?;
623 {
624 let mut locked_state = self.state.lock();
625 *locked_state = deser.state;
626 }
627 self.mmio_base = deser.mmio_base;
628 self.irq_num = deser.irq_num;
629 self.activated = deser.activated;
630 Ok(())
631 }
632 }
633
634 #[cfg(test)]
635 mod tests {
636 use super::*;
637 use crate::suspendable_tests;
638
modify_device(battery: &mut GoldfishBattery)639 fn modify_device(battery: &mut GoldfishBattery) {
640 let mut state = battery.state.lock();
641 state.set_capacity(70);
642 }
643
644 suspendable_tests! {
645 battery, GoldfishBattery::new(
646 0,
647 0,
648 IrqLevelEvent::new().unwrap(),
649 Tube::pair().unwrap().1,
650 None,
651 None,
652 ).unwrap(),
653 modify_device
654 }
655 }
656