vmm/devices/acpi/
vmgenid.rs1use std::convert::Infallible;
5
6use acpi_tables::{Aml, aml};
7use aws_lc_rs::error::Unspecified as RandError;
8use aws_lc_rs::rand;
9use log::{debug, error};
10use serde::{Deserialize, Serialize};
11use vm_memory::{GuestAddress, GuestMemoryError};
12use vm_superio::Trigger;
13use vmm_sys_util::eventfd::EventFd;
14
15use super::super::legacy::EventFdTrigger;
16use crate::snapshot::Persist;
17use crate::vstate::memory::{Bytes, GuestMemoryMmap};
18use crate::vstate::resources::ResourceAllocator;
19
20pub const VMGENID_MEM_SIZE: u64 = 16;
22
23#[derive(Debug)]
32pub struct VmGenId {
33 pub gen_id: u128,
35 pub interrupt_evt: EventFdTrigger,
37 pub guest_address: GuestAddress,
39 pub gsi: u32,
41}
42
43impl VmGenId {
44 pub fn from_parts(guest_address: GuestAddress, gsi: u32) -> Self {
47 debug!(
48 "vmgenid: building VMGenID device. Address: {:#010x}. IRQ: {}",
49 guest_address.0, gsi
50 );
51 let interrupt_evt = EventFdTrigger::new(
52 EventFd::new(libc::EFD_NONBLOCK)
53 .expect("vmgenid: Could not create EventFd for VMGenID device"),
54 );
55 let gen_id = Self::make_genid();
56
57 Self {
58 gen_id,
59 interrupt_evt,
60 guest_address,
61 gsi,
62 }
63 }
64
65 pub fn new(resource_allocator: &mut ResourceAllocator) -> Self {
69 let gsi = resource_allocator
70 .allocate_gsi_legacy(1)
71 .expect("vmgenid: Could not allocate GSI for VMGenID");
72 let addr = resource_allocator
74 .allocate_system_memory(VMGENID_MEM_SIZE, 8, vm_allocator::AllocPolicy::LastMatch)
75 .expect("vmgenid: Could not allocate guest RAM for VMGenID");
76
77 Self::from_parts(GuestAddress(addr), gsi[0])
78 }
79
80 fn make_genid() -> u128 {
82 let mut gen_id_bytes = [0u8; 16];
83 rand::fill(&mut gen_id_bytes).expect("vmgenid: could not create new generation ID");
84 u128::from_le_bytes(gen_id_bytes)
85 }
86
87 pub fn notify_guest(&mut self) -> Result<(), std::io::Error> {
92 self.interrupt_evt
93 .trigger()
94 .inspect_err(|err| error!("vmgenid: could not send guest notification: {err}"))?;
95 debug!("vmgenid: notifying guest about new generation ID");
96 Ok(())
97 }
98
99 pub fn activate(&self, mem: &GuestMemoryMmap) -> Result<(), GuestMemoryError> {
101 debug!(
102 "vmgenid: writing new generation ID to guest: {:#034x}",
103 self.gen_id
104 );
105 mem.write_slice(&self.gen_id.to_le_bytes(), self.guest_address)
106 .inspect_err(|err| error!("vmgenid: could not write generation ID to guest: {err}"))?;
107
108 Ok(())
109 }
110}
111
112#[derive(Default, Debug, Clone, Serialize, Deserialize)]
115pub struct VMGenIDState {
116 pub gsi: u32,
118 pub addr: u64,
120}
121
122impl<'a> Persist<'a> for VmGenId {
123 type State = VMGenIDState;
124 type ConstructorArgs = ();
125 type Error = Infallible;
126
127 fn save(&self) -> Self::State {
128 VMGenIDState {
129 gsi: self.gsi,
130 addr: self.guest_address.0,
131 }
132 }
133
134 fn restore(_: Self::ConstructorArgs, state: &Self::State) -> Result<Self, Self::Error> {
135 Ok(Self::from_parts(GuestAddress(state.addr), state.gsi))
136 }
137}
138
139impl Aml for VmGenId {
140 fn append_aml_bytes(&self, v: &mut Vec<u8>) -> Result<(), aml::AmlError> {
141 #[allow(clippy::cast_possible_truncation)]
142 let addr_low = self.guest_address.0 as u32;
143 let addr_high = (self.guest_address.0 >> 32) as u32;
144 aml::Device::new(
145 "_SB_.VGEN".try_into()?,
146 vec![
147 &aml::Name::new("_HID".try_into()?, &"FCVMGID")?,
148 &aml::Name::new("_CID".try_into()?, &"VM_Gen_Counter")?,
149 &aml::Name::new("_DDN".try_into()?, &"VM_Gen_Counter")?,
150 &aml::Name::new(
151 "ADDR".try_into()?,
152 &aml::Package::new(vec![&addr_low, &addr_high]),
153 )?,
154 ],
155 )
156 .append_aml_bytes(v)
157 }
158}