1use std::collections::BTreeMap;
6use std::sync::Arc;
7
8use acpi_tables::aml::Aml;
9use base::syslog;
10use base::warn;
11use base::AsRawDescriptors;
12use base::Tube;
13use devices::Bus;
14use devices::BusDevice;
15use devices::DevicePowerManager;
16use devices::IommuDevType;
17use devices::IrqChip;
18use devices::IrqEventSource;
19use devices::ProxyDevice;
20use devices::VfioPlatformDevice;
21use hypervisor::ProtectionType;
22use hypervisor::Vm;
23use minijail::Minijail;
24use resources::AllocOptions;
25use resources::SystemAllocator;
26use sync::Mutex;
27
28use crate::DeviceRegistrationError;
29
30pub fn add_goldfish_battery(
42 amls: &mut Vec<u8>,
43 battery_jail: Option<Minijail>,
44 mmio_bus: &Bus,
45 irq_chip: &mut dyn IrqChip,
46 irq_num: u32,
47 resources: &mut SystemAllocator,
48 #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
49) -> Result<(Tube, u64), DeviceRegistrationError> {
50 let alloc = resources.get_anon_alloc();
51 let mmio_base = resources
52 .allocate_mmio(
53 devices::bat::GOLDFISHBAT_MMIO_LEN,
54 alloc,
55 "GoldfishBattery".to_string(),
56 AllocOptions::new().align(devices::bat::GOLDFISHBAT_MMIO_LEN),
57 )
58 .map_err(DeviceRegistrationError::AllocateIoResource)?;
59
60 let (control_tube, response_tube) =
61 Tube::pair().map_err(DeviceRegistrationError::CreateTube)?;
62
63 #[cfg(feature = "power-monitor-powerd")]
64 let (create_monitor, create_client) = (
65 Some(
66 Box::new(power_monitor::powerd::monitor::DBusMonitor::connect)
67 as Box<dyn power_monitor::CreatePowerMonitorFn>,
68 ),
69 Some(Box::new(power_monitor::powerd::client::DBusClient::connect)
70 as Box<dyn power_monitor::CreatePowerClientFn>),
71 );
72
73 #[cfg(not(feature = "power-monitor-powerd"))]
74 let (create_monitor, create_client) = (None, None);
75
76 let irq_evt = devices::IrqLevelEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
77
78 let goldfish_bat = devices::GoldfishBattery::new(
79 mmio_base,
80 irq_num,
81 irq_evt
82 .try_clone()
83 .map_err(DeviceRegistrationError::EventClone)?,
84 response_tube,
85 create_monitor,
86 create_client,
87 )
88 .map_err(DeviceRegistrationError::RegisterBattery)?;
89 goldfish_bat.to_aml_bytes(amls);
90
91 irq_chip
92 .register_level_irq_event(
93 irq_num,
94 &irq_evt,
95 IrqEventSource::from_device(&goldfish_bat),
96 )
97 .map_err(DeviceRegistrationError::RegisterIrqfd)?;
98
99 match battery_jail {
100 #[cfg(not(windows))]
101 Some(jail) => {
102 let mut keep_rds = goldfish_bat.keep_rds();
103 syslog::push_descriptors(&mut keep_rds);
104 cros_tracing::push_descriptors!(&mut keep_rds);
105 metrics::push_descriptors(&mut keep_rds);
106 mmio_bus
107 .insert(
108 Arc::new(Mutex::new(
109 ProxyDevice::new(
110 goldfish_bat,
111 jail,
112 keep_rds,
113 #[cfg(feature = "swap")]
114 swap_controller,
115 )
116 .map_err(DeviceRegistrationError::ProxyDeviceCreation)?,
117 )),
118 mmio_base,
119 devices::bat::GOLDFISHBAT_MMIO_LEN,
120 )
121 .map_err(DeviceRegistrationError::MmioInsert)?;
122 }
123 #[cfg(windows)]
124 Some(_) => {}
125 None => {
126 mmio_bus
127 .insert(
128 Arc::new(Mutex::new(goldfish_bat)),
129 mmio_base,
130 devices::bat::GOLDFISHBAT_MMIO_LEN,
131 )
132 .map_err(DeviceRegistrationError::MmioInsert)?;
133 }
134 }
135
136 Ok((control_tube, mmio_base))
137}
138
139pub struct PlatformBusResources {
140 pub dt_symbol: String, pub regions: Vec<(u64, u64)>, pub irqs: Vec<(u32, u32)>, pub iommus: Vec<(IommuDevType, Option<u32>, Vec<u32>)>, pub requires_power_domain: bool,
145}
146
147impl PlatformBusResources {
148 const IRQ_TRIGGER_EDGE: u32 = 1;
149 const IRQ_TRIGGER_LEVEL: u32 = 4;
150
151 fn new(symbol: String) -> Self {
152 Self {
153 dt_symbol: symbol,
154 regions: vec![],
155 irqs: vec![],
156 iommus: vec![],
157 requires_power_domain: false,
158 }
159 }
160}
161
162#[cfg(any(target_os = "android", target_os = "linux"))]
164pub fn generate_platform_bus(
165 devices: Vec<(VfioPlatformDevice, Option<Minijail>)>,
166 irq_chip: &mut dyn IrqChip,
167 mmio_bus: &Bus,
168 resources: &mut SystemAllocator,
169 vm: &mut impl Vm,
170 #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
171 dev_pm: &mut Option<DevicePowerManager>,
172 protection_type: ProtectionType,
173) -> Result<
174 (
175 Vec<Arc<Mutex<dyn BusDevice>>>,
176 BTreeMap<u32, String>,
177 Vec<PlatformBusResources>,
178 ),
179 DeviceRegistrationError,
180> {
181 let mut platform_devices = Vec::new();
182 let mut pid_labels = BTreeMap::new();
183 let mut bus_dev_resources = vec![];
184
185 for (mut device, jail) in devices.into_iter() {
187 let dt_symbol = device
188 .dt_symbol()
189 .ok_or(DeviceRegistrationError::MissingDeviceTreeSymbol)?
190 .to_owned();
191 let mut device_resources = PlatformBusResources::new(dt_symbol);
192 let ranges = device
193 .allocate_regions(resources)
194 .map_err(DeviceRegistrationError::AllocateIoResource)?;
195
196 if protection_type.isolates_memory() {
198 device.regions_mmap_early(vm);
199 }
200
201 let mut keep_rds = device.keep_rds();
202 syslog::push_descriptors(&mut keep_rds);
203 cros_tracing::push_descriptors!(&mut keep_rds);
204 metrics::push_descriptors(&mut keep_rds);
205
206 let irqs = device
207 .get_platform_irqs()
208 .map_err(DeviceRegistrationError::AllocateIrqResource)?;
209 for irq in irqs.into_iter() {
210 let irq_num = resources
211 .allocate_irq()
212 .ok_or(DeviceRegistrationError::AllocateIrq)?;
213
214 if device.irq_is_automask(&irq) {
215 let irq_evt =
216 devices::IrqLevelEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
217 irq_chip
218 .register_level_irq_event(
219 irq_num,
220 &irq_evt,
221 IrqEventSource::from_device(&device),
222 )
223 .map_err(DeviceRegistrationError::RegisterIrqfd)?;
224 device
225 .assign_level_platform_irq(&irq_evt, irq.index)
226 .map_err(DeviceRegistrationError::SetupVfioPlatformIrq)?;
227 keep_rds.extend(irq_evt.as_raw_descriptors());
228 device_resources
229 .irqs
230 .push((irq_num, PlatformBusResources::IRQ_TRIGGER_LEVEL));
231 } else {
232 let irq_evt =
233 devices::IrqEdgeEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
234 irq_chip
235 .register_edge_irq_event(
236 irq_num,
237 &irq_evt,
238 IrqEventSource::from_device(&device),
239 )
240 .map_err(DeviceRegistrationError::RegisterIrqfd)?;
241 device
242 .assign_edge_platform_irq(&irq_evt, irq.index)
243 .map_err(DeviceRegistrationError::SetupVfioPlatformIrq)?;
244 keep_rds.extend(irq_evt.as_raw_descriptors());
245 device_resources
246 .irqs
247 .push((irq_num, PlatformBusResources::IRQ_TRIGGER_EDGE));
248 }
249 }
250
251 if let Some((iommu_type, id, vsids)) = device.iommu() {
252 device_resources
254 .iommus
255 .push((iommu_type, id, vsids.to_vec()));
256 }
257
258 let arced_dev: Arc<Mutex<dyn BusDevice>> = if let Some(jail) = jail {
259 let proxy = ProxyDevice::new(
260 device,
261 jail,
262 keep_rds,
263 #[cfg(feature = "swap")]
264 swap_controller,
265 )
266 .map_err(DeviceRegistrationError::ProxyDeviceCreation)?;
267 pid_labels.insert(proxy.pid() as u32, proxy.debug_label());
268 Arc::new(Mutex::new(proxy))
269 } else {
270 device.on_sandboxed();
271 Arc::new(Mutex::new(device))
272 };
273 platform_devices.push(arced_dev.clone());
274 for range in &ranges {
275 mmio_bus
276 .insert(arced_dev.clone(), range.0, range.1)
277 .map_err(DeviceRegistrationError::MmioInsert)?;
278 device_resources.regions.push((range.0, range.1));
279 }
280
281 if let Some(ref mut pm) = dev_pm {
282 let supports_power_management = arced_dev.lock().supports_power_management();
283 match supports_power_management {
284 Err(e) => warn!("Error while detecting PM support, ignoring: {e:#}"),
285 Ok(false) => {}
286 Ok(true) => {
287 let domain_id = ranges.first().unwrap().0.try_into().unwrap();
291 pm.attach(arced_dev.clone(), domain_id)
292 .map_err(DeviceRegistrationError::AttachDevicePowerDomain)?;
293 device_resources.requires_power_domain = true;
294 }
295 }
296 }
297
298 bus_dev_resources.push(device_resources);
299 }
300 Ok((platform_devices, pid_labels, bus_dev_resources))
301}