1 // Copyright 2022 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::collections::BTreeMap;
6 use std::sync::Arc;
7
8 use acpi_tables::aml::Aml;
9 use base::syslog;
10 use base::AsRawDescriptors;
11 use base::Tube;
12 use devices::Bus;
13 use devices::BusDevice;
14 use devices::IommuDevType;
15 use devices::IrqChip;
16 use devices::IrqEventSource;
17 use devices::ProxyDevice;
18 use devices::VfioPlatformDevice;
19 use hypervisor::ProtectionType;
20 use hypervisor::Vm;
21 use minijail::Minijail;
22 use resources::AllocOptions;
23 use resources::SystemAllocator;
24 use sync::Mutex;
25
26 use crate::DeviceRegistrationError;
27
28 /// Adds goldfish battery and returns the platform needed resources including
29 /// its AML data and mmio base address
30 ///
31 /// # Arguments
32 ///
33 /// * `amls` - the vector to put the goldfish battery AML
34 /// * `battery_jail` - used when sandbox is enabled
35 /// * `mmio_bus` - bus to add the devices to
36 /// * `irq_chip` - the IrqChip object for registering irq events
37 /// * `irq_num` - assigned interrupt to use
38 /// * `resources` - the SystemAllocator to allocate IO and MMIO for acpi
add_goldfish_battery( amls: &mut Vec<u8>, battery_jail: Option<Minijail>, mmio_bus: &Bus, irq_chip: &mut dyn IrqChip, irq_num: u32, resources: &mut SystemAllocator, #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>, ) -> Result<(Tube, u64), DeviceRegistrationError>39 pub fn add_goldfish_battery(
40 amls: &mut Vec<u8>,
41 battery_jail: Option<Minijail>,
42 mmio_bus: &Bus,
43 irq_chip: &mut dyn IrqChip,
44 irq_num: u32,
45 resources: &mut SystemAllocator,
46 #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
47 ) -> Result<(Tube, u64), DeviceRegistrationError> {
48 let alloc = resources.get_anon_alloc();
49 let mmio_base = resources
50 .allocate_mmio(
51 devices::bat::GOLDFISHBAT_MMIO_LEN,
52 alloc,
53 "GoldfishBattery".to_string(),
54 AllocOptions::new().align(devices::bat::GOLDFISHBAT_MMIO_LEN),
55 )
56 .map_err(DeviceRegistrationError::AllocateIoResource)?;
57
58 let (control_tube, response_tube) =
59 Tube::pair().map_err(DeviceRegistrationError::CreateTube)?;
60
61 #[cfg(feature = "power-monitor-powerd")]
62 let (create_monitor, create_client) = (
63 Some(
64 Box::new(power_monitor::powerd::monitor::DBusMonitor::connect)
65 as Box<dyn power_monitor::CreatePowerMonitorFn>,
66 ),
67 Some(Box::new(power_monitor::powerd::client::DBusClient::connect)
68 as Box<dyn power_monitor::CreatePowerClientFn>),
69 );
70
71 #[cfg(not(feature = "power-monitor-powerd"))]
72 let (create_monitor, create_client) = (None, None);
73
74 let irq_evt = devices::IrqLevelEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
75
76 let goldfish_bat = devices::GoldfishBattery::new(
77 mmio_base,
78 irq_num,
79 irq_evt
80 .try_clone()
81 .map_err(DeviceRegistrationError::EventClone)?,
82 response_tube,
83 create_monitor,
84 create_client,
85 )
86 .map_err(DeviceRegistrationError::RegisterBattery)?;
87 goldfish_bat.to_aml_bytes(amls);
88
89 irq_chip
90 .register_level_irq_event(
91 irq_num,
92 &irq_evt,
93 IrqEventSource::from_device(&goldfish_bat),
94 )
95 .map_err(DeviceRegistrationError::RegisterIrqfd)?;
96
97 match battery_jail {
98 #[cfg(not(windows))]
99 Some(jail) => {
100 let mut keep_rds = goldfish_bat.keep_rds();
101 syslog::push_descriptors(&mut keep_rds);
102 cros_tracing::push_descriptors!(&mut keep_rds);
103 metrics::push_descriptors(&mut keep_rds);
104 mmio_bus
105 .insert(
106 Arc::new(Mutex::new(
107 ProxyDevice::new(
108 goldfish_bat,
109 jail,
110 keep_rds,
111 #[cfg(feature = "swap")]
112 swap_controller,
113 )
114 .map_err(DeviceRegistrationError::ProxyDeviceCreation)?,
115 )),
116 mmio_base,
117 devices::bat::GOLDFISHBAT_MMIO_LEN,
118 )
119 .map_err(DeviceRegistrationError::MmioInsert)?;
120 }
121 #[cfg(windows)]
122 Some(_) => {}
123 None => {
124 mmio_bus
125 .insert(
126 Arc::new(Mutex::new(goldfish_bat)),
127 mmio_base,
128 devices::bat::GOLDFISHBAT_MMIO_LEN,
129 )
130 .map_err(DeviceRegistrationError::MmioInsert)?;
131 }
132 }
133
134 Ok((control_tube, mmio_base))
135 }
136
137 pub struct PlatformBusResources {
138 pub dt_symbol: String, // DT symbol (label) assigned to the device
139 pub regions: Vec<(u64, u64)>, // (start address, size)
140 pub irqs: Vec<(u32, u32)>, // (IRQ number, flags)
141 pub iommus: Vec<(IommuDevType, Option<u32>, Vec<u32>)>, // (IOMMU type, IOMMU identifier, IDs)
142 }
143
144 impl PlatformBusResources {
145 const IRQ_TRIGGER_EDGE: u32 = 1;
146 const IRQ_TRIGGER_LEVEL: u32 = 4;
147
new(symbol: String) -> Self148 fn new(symbol: String) -> Self {
149 Self {
150 dt_symbol: symbol,
151 regions: vec![],
152 irqs: vec![],
153 iommus: vec![],
154 }
155 }
156 }
157
158 /// Creates a platform device for use by this Vm.
159 #[cfg(any(target_os = "android", target_os = "linux"))]
generate_platform_bus( devices: Vec<(VfioPlatformDevice, Option<Minijail>)>, irq_chip: &mut dyn IrqChip, mmio_bus: &Bus, resources: &mut SystemAllocator, vm: &mut impl Vm, #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>, protection_type: ProtectionType, ) -> Result< ( Vec<Arc<Mutex<dyn BusDevice>>>, BTreeMap<u32, String>, Vec<PlatformBusResources>, ), DeviceRegistrationError, >160 pub fn generate_platform_bus(
161 devices: Vec<(VfioPlatformDevice, Option<Minijail>)>,
162 irq_chip: &mut dyn IrqChip,
163 mmio_bus: &Bus,
164 resources: &mut SystemAllocator,
165 vm: &mut impl Vm,
166 #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
167 protection_type: ProtectionType,
168 ) -> Result<
169 (
170 Vec<Arc<Mutex<dyn BusDevice>>>,
171 BTreeMap<u32, String>,
172 Vec<PlatformBusResources>,
173 ),
174 DeviceRegistrationError,
175 > {
176 let mut platform_devices = Vec::new();
177 let mut pid_labels = BTreeMap::new();
178 let mut bus_dev_resources = vec![];
179
180 // Allocate ranges that may need to be in the Platform MMIO region (MmioType::Platform).
181 for (mut device, jail) in devices.into_iter() {
182 let dt_symbol = device
183 .dt_symbol()
184 .ok_or(DeviceRegistrationError::MissingDeviceTreeSymbol)?
185 .to_owned();
186 let mut device_resources = PlatformBusResources::new(dt_symbol);
187 let ranges = device
188 .allocate_regions(resources)
189 .map_err(DeviceRegistrationError::AllocateIoResource)?;
190
191 // If guest memory is private, don't wait for the first access to mmap the device.
192 if protection_type.isolates_memory() {
193 device.regions_mmap_early(vm);
194 }
195
196 let mut keep_rds = device.keep_rds();
197 syslog::push_descriptors(&mut keep_rds);
198 cros_tracing::push_descriptors!(&mut keep_rds);
199 metrics::push_descriptors(&mut keep_rds);
200
201 let irqs = device
202 .get_platform_irqs()
203 .map_err(DeviceRegistrationError::AllocateIrqResource)?;
204 for irq in irqs.into_iter() {
205 let irq_num = resources
206 .allocate_irq()
207 .ok_or(DeviceRegistrationError::AllocateIrq)?;
208
209 if device.irq_is_automask(&irq) {
210 let irq_evt =
211 devices::IrqLevelEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
212 irq_chip
213 .register_level_irq_event(
214 irq_num,
215 &irq_evt,
216 IrqEventSource::from_device(&device),
217 )
218 .map_err(DeviceRegistrationError::RegisterIrqfd)?;
219 device
220 .assign_level_platform_irq(&irq_evt, irq.index)
221 .map_err(DeviceRegistrationError::SetupVfioPlatformIrq)?;
222 keep_rds.extend(irq_evt.as_raw_descriptors());
223 device_resources
224 .irqs
225 .push((irq_num, PlatformBusResources::IRQ_TRIGGER_LEVEL));
226 } else {
227 let irq_evt =
228 devices::IrqEdgeEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
229 irq_chip
230 .register_edge_irq_event(
231 irq_num,
232 &irq_evt,
233 IrqEventSource::from_device(&device),
234 )
235 .map_err(DeviceRegistrationError::RegisterIrqfd)?;
236 device
237 .assign_edge_platform_irq(&irq_evt, irq.index)
238 .map_err(DeviceRegistrationError::SetupVfioPlatformIrq)?;
239 keep_rds.extend(irq_evt.as_raw_descriptors());
240 device_resources
241 .irqs
242 .push((irq_num, PlatformBusResources::IRQ_TRIGGER_EDGE));
243 }
244 }
245
246 if let Some((iommu_type, id, vsids)) = device.iommu() {
247 // We currently only support one IOMMU per VFIO device.
248 device_resources
249 .iommus
250 .push((iommu_type, id, vsids.to_vec()));
251 }
252
253 let arced_dev: Arc<Mutex<dyn BusDevice>> = if let Some(jail) = jail {
254 let proxy = ProxyDevice::new(
255 device,
256 jail,
257 keep_rds,
258 #[cfg(feature = "swap")]
259 swap_controller,
260 )
261 .map_err(DeviceRegistrationError::ProxyDeviceCreation)?;
262 pid_labels.insert(proxy.pid() as u32, proxy.debug_label());
263 Arc::new(Mutex::new(proxy))
264 } else {
265 device.on_sandboxed();
266 Arc::new(Mutex::new(device))
267 };
268 platform_devices.push(arced_dev.clone());
269 for range in &ranges {
270 mmio_bus
271 .insert(arced_dev.clone(), range.0, range.1)
272 .map_err(DeviceRegistrationError::MmioInsert)?;
273 device_resources.regions.push((range.0, range.1));
274 }
275 bus_dev_resources.push(device_resources);
276 }
277 Ok((platform_devices, pid_labels, bus_dev_resources))
278 }
279