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