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::IrqChip;
17use devices::IrqEventSource;
18use devices::PlatformBusResources;
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: &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
139#[cfg(any(target_os = "android", target_os = "linux"))]
141pub fn generate_platform_bus(
142 devices: Vec<(VfioPlatformDevice, Option<Minijail>)>,
143 irq_chip: &dyn IrqChip,
144 mmio_bus: &Bus,
145 resources: &mut SystemAllocator,
146 vm: &dyn Vm,
147 #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
148 dev_pm: &mut Option<DevicePowerManager>,
149 protection_type: ProtectionType,
150) -> Result<
151 (
152 Vec<Arc<Mutex<dyn BusDevice>>>,
153 BTreeMap<u32, String>,
154 Vec<PlatformBusResources>,
155 ),
156 DeviceRegistrationError,
157> {
158 let mut platform_devices = Vec::new();
159 let mut pid_labels = BTreeMap::new();
160 let mut bus_dev_resources = vec![];
161
162 for (mut device, jail) in devices.into_iter() {
164 let dt_symbol = device
165 .dt_symbol()
166 .ok_or(DeviceRegistrationError::MissingDeviceTreeSymbol)?
167 .to_owned();
168 let mut device_resources = PlatformBusResources::new(dt_symbol);
169 let ranges = device
170 .allocate_regions(resources)
171 .map_err(DeviceRegistrationError::AllocateIoResource)?;
172
173 if protection_type.isolates_memory() {
175 device.regions_mmap_early(vm);
176 }
177
178 let mut keep_rds = device.keep_rds();
179 syslog::push_descriptors(&mut keep_rds);
180 cros_tracing::push_descriptors!(&mut keep_rds);
181 metrics::push_descriptors(&mut keep_rds);
182
183 let irqs = device
184 .get_platform_irqs()
185 .map_err(DeviceRegistrationError::AllocateIrqResource)?;
186 for irq in irqs.into_iter() {
187 let irq_num = resources
188 .allocate_irq()
189 .ok_or(DeviceRegistrationError::AllocateIrq)?;
190
191 if device.irq_is_automask(&irq) {
192 let irq_evt =
193 devices::IrqLevelEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
194 irq_chip
195 .register_level_irq_event(
196 irq_num,
197 &irq_evt,
198 IrqEventSource::from_device(&device),
199 )
200 .map_err(DeviceRegistrationError::RegisterIrqfd)?;
201 device
202 .assign_level_platform_irq(&irq_evt, irq.index)
203 .map_err(DeviceRegistrationError::SetupVfioPlatformIrq)?;
204 keep_rds.extend(irq_evt.as_raw_descriptors());
205 device_resources
206 .irqs
207 .push((irq_num, PlatformBusResources::IRQ_TRIGGER_LEVEL));
208 } else {
209 let irq_evt =
210 devices::IrqEdgeEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
211 irq_chip
212 .register_edge_irq_event(
213 irq_num,
214 &irq_evt,
215 IrqEventSource::from_device(&device),
216 )
217 .map_err(DeviceRegistrationError::RegisterIrqfd)?;
218 device
219 .assign_edge_platform_irq(&irq_evt, irq.index)
220 .map_err(DeviceRegistrationError::SetupVfioPlatformIrq)?;
221 keep_rds.extend(irq_evt.as_raw_descriptors());
222 device_resources
223 .irqs
224 .push((irq_num, PlatformBusResources::IRQ_TRIGGER_EDGE));
225 }
226 }
227
228 if let Some((iommu_type, id, vsids)) = device.iommu() {
229 device_resources
231 .iommus
232 .push((iommu_type, id, vsids.to_vec()));
233 }
234
235 let arced_dev: Arc<Mutex<dyn BusDevice>> = if let Some(jail) = jail {
236 let proxy = ProxyDevice::new(
237 device,
238 jail,
239 keep_rds,
240 #[cfg(feature = "swap")]
241 swap_controller,
242 )
243 .map_err(DeviceRegistrationError::ProxyDeviceCreation)?;
244 pid_labels.insert(proxy.pid() as u32, proxy.debug_label());
245 Arc::new(Mutex::new(proxy))
246 } else {
247 device.on_sandboxed();
248 Arc::new(Mutex::new(device))
249 };
250 platform_devices.push(arced_dev.clone());
251 for range in &ranges {
252 mmio_bus
253 .insert(arced_dev.clone(), range.0, range.1)
254 .map_err(DeviceRegistrationError::MmioInsert)?;
255 device_resources.regions.push((range.0, range.1));
256 }
257
258 if let Some(ref mut pm) = dev_pm {
259 let supports_power_management = arced_dev.lock().supports_power_management();
260 match supports_power_management {
261 Err(e) => warn!("Error while detecting PM support, ignoring: {e:#}"),
262 Ok(false) => {}
263 Ok(true) => {
264 let domain_id = ranges.first().unwrap().0.try_into().unwrap();
268 pm.attach(arced_dev.clone(), domain_id)
269 .map_err(DeviceRegistrationError::AttachDevicePowerDomain)?;
270 device_resources.requires_power_domain = true;
271 }
272 }
273 }
274
275 bus_dev_resources.push(device_resources);
276 }
277 Ok((platform_devices, pid_labels, bus_dev_resources))
278}