mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-12-01 04:28:48 +00:00
sys_util: add acpi event support
The acpi events are netlink generic based messages, used by kernel to notify about various ACPI related events (in fact, the "acpi_event" is one of registered by the kernel generic netlink family). This commit adds support for de-capsulating and parsing acpi events from the netlink generic message. BUG=b:197247746 TEST=Build crosvm-direct and listen on acpi events, parse and use them [above done with additional WIP patches but without acpi_event.rs modification] Change-Id: I1671d95b1bca1fbd31ba042eac49f5d2d99cb92a Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3407320 Reviewed-by: Dmitry Torokhov <dtor@chromium.org> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Grzegorz Jaszczyk <jaszczyk@google.com>
This commit is contained in:
parent
7d7fb7c567
commit
1f4e67e324
3 changed files with 130 additions and 0 deletions
109
common/sys_util/src/acpi_event.rs
Normal file
109
common/sys_util/src/acpi_event.rs
Normal file
|
@ -0,0 +1,109 @@
|
|||
// Copyright 2022 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::str;
|
||||
|
||||
use crate::netlink::*;
|
||||
use thiserror::Error;
|
||||
|
||||
use data_model::DataInit;
|
||||
|
||||
const ACPI_EVENT_SIZE: usize = std::mem::size_of::<AcpiGenlEvent>();
|
||||
const GENL_HDRLEN: usize = std::mem::size_of::<GenlMsgHdr>();
|
||||
const NLA_HDRLEN: usize = std::mem::size_of::<NlAttr>();
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum AcpiEventError {
|
||||
#[error("GenmsghdrCmd or NlAttrType inappropriate for acpi event")]
|
||||
TypeAttrMissmatch,
|
||||
#[error("Something goes wrong: msg_len {0} is not correct")]
|
||||
InvalidMsgLen(usize),
|
||||
}
|
||||
type Result<T> = std::result::Result<T, AcpiEventError>;
|
||||
|
||||
/// attributes of AcpiGenlFamily
|
||||
#[allow(dead_code)]
|
||||
enum NlAttrType {
|
||||
AcpiGenlAttrUnspec,
|
||||
AcpiGenlAttrEvent, // acpi_event (needed by user space)
|
||||
AcpiGenlAttrMax,
|
||||
}
|
||||
|
||||
/// commands supported by the AcpiGenlFamily
|
||||
#[allow(dead_code)]
|
||||
enum GenmsghdrCmd {
|
||||
AcpiGenlCmdUnspec,
|
||||
AcpiGenlCmdEvent, // kernel->user notifications for acpi_events
|
||||
AcpiGenlCmdMax,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
struct AcpiGenlEvent {
|
||||
device_class: [::std::os::raw::c_char; 20usize],
|
||||
bus_id: [::std::os::raw::c_char; 15usize],
|
||||
_type: u32,
|
||||
data: u32,
|
||||
}
|
||||
unsafe impl DataInit for AcpiGenlEvent {}
|
||||
|
||||
pub struct AcpiNotifyEvent {
|
||||
pub device_class: String,
|
||||
pub bus_id: String,
|
||||
pub _type: u32,
|
||||
pub data: u32,
|
||||
}
|
||||
|
||||
impl AcpiNotifyEvent {
|
||||
/// Create acpi event by decapsulating it from NetlinkMessage.
|
||||
pub fn new(netlink_message: NetlinkMessage) -> Result<Self> {
|
||||
let msg_len = netlink_message.data.len();
|
||||
if msg_len != GENL_HDRLEN + NLA_HDRLEN + ACPI_EVENT_SIZE {
|
||||
return Err(AcpiEventError::InvalidMsgLen(msg_len));
|
||||
}
|
||||
|
||||
let genl_hdr = GenlMsgHdr::from_slice(&netlink_message.data[..GENL_HDRLEN])
|
||||
.expect("unable to get GenlMsgHdr from slice");
|
||||
|
||||
let nlattr_end = GENL_HDRLEN + NLA_HDRLEN;
|
||||
let nl_attr = NlAttr::from_slice(&netlink_message.data[GENL_HDRLEN..nlattr_end])
|
||||
.expect("unable to get NlAttr from slice");
|
||||
|
||||
// Sanity check that the headers have correct for acpi event `cmd` and `_type`
|
||||
if genl_hdr.cmd != GenmsghdrCmd::AcpiGenlCmdEvent as u8
|
||||
|| nl_attr._type != NlAttrType::AcpiGenlAttrEvent as u16
|
||||
{
|
||||
return Err(AcpiEventError::TypeAttrMissmatch);
|
||||
}
|
||||
|
||||
let acpi_event = AcpiGenlEvent::from_slice(&netlink_message.data[nlattr_end..msg_len])
|
||||
.expect("unable to get AcpiGenlEvent from slice");
|
||||
|
||||
// The raw::c_char is either i8 or u8 which is known portability issue:
|
||||
// https://github.com/rust-lang/rust/issues/79089,
|
||||
// before using device_class further cast it to u8.
|
||||
let device_class: &[u8; 20usize] =
|
||||
unsafe { ::std::mem::transmute(&acpi_event.device_class) };
|
||||
let bus_id: &[u8; 15usize] = unsafe { ::std::mem::transmute(&acpi_event.bus_id) };
|
||||
|
||||
Ok(AcpiNotifyEvent {
|
||||
device_class: strip_padding(device_class).to_owned(),
|
||||
bus_id: strip_padding(bus_id).to_owned(),
|
||||
_type: acpi_event._type,
|
||||
data: acpi_event.data,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Like `CStr::from_bytes_with_nul` but strips any bytes starting from first '\0'-byte and
|
||||
// returns &str. Panics if `b` doesn't contain any '\0' bytes.
|
||||
fn strip_padding(b: &[u8]) -> &str {
|
||||
// It would be nice if we could use memchr here but that's locked behind an unstable gate.
|
||||
let pos = b
|
||||
.iter()
|
||||
.position(|&c| c == 0)
|
||||
.expect("`b` doesn't contain any nul bytes");
|
||||
|
||||
str::from_utf8(&b[..pos]).unwrap()
|
||||
}
|
|
@ -19,6 +19,7 @@ pub mod handle_eintr;
|
|||
pub mod ioctl;
|
||||
#[macro_use]
|
||||
pub mod syslog;
|
||||
mod acpi_event;
|
||||
mod capabilities;
|
||||
mod clock;
|
||||
mod descriptor;
|
||||
|
@ -51,6 +52,7 @@ mod timerfd;
|
|||
pub mod vsock;
|
||||
mod write_zeroes;
|
||||
|
||||
pub use crate::acpi_event::*;
|
||||
pub use crate::alloc::LayoutAllocation;
|
||||
pub use crate::capabilities::drop_capabilities;
|
||||
pub use crate::clock::{Clock, FakeClock};
|
||||
|
|
|
@ -23,6 +23,25 @@ struct NlMsgHdr {
|
|||
}
|
||||
unsafe impl DataInit for NlMsgHdr {}
|
||||
|
||||
/// Netlink attribute struct, can be used by netlink consumer
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct NlAttr {
|
||||
pub len: u16,
|
||||
pub _type: u16,
|
||||
}
|
||||
unsafe impl DataInit for NlAttr {}
|
||||
|
||||
/// Generic netlink header struct, can be used by netlink consumer
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct GenlMsgHdr {
|
||||
pub cmd: u8,
|
||||
pub version: u8,
|
||||
pub reserved: u16,
|
||||
}
|
||||
unsafe impl DataInit for GenlMsgHdr {}
|
||||
|
||||
/// A single netlink message, including its header and data.
|
||||
pub struct NetlinkMessage<'a> {
|
||||
pub _type: u16,
|
||||
|
|
Loading…
Reference in a new issue