• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = Some(Box::new(power_monitor::powerd::DBusMonitor::connect)
63         as Box<dyn power_monitor::CreatePowerMonitorFn>);
64 
65     #[cfg(not(feature = "power-monitor-powerd"))]
66     let create_monitor = None;
67 
68     let irq_evt = devices::IrqLevelEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
69 
70     let goldfish_bat = devices::GoldfishBattery::new(
71         mmio_base,
72         irq_num,
73         irq_evt
74             .try_clone()
75             .map_err(DeviceRegistrationError::EventClone)?,
76         response_tube,
77         create_monitor,
78     )
79     .map_err(DeviceRegistrationError::RegisterBattery)?;
80     goldfish_bat.to_aml_bytes(amls);
81 
82     irq_chip
83         .register_level_irq_event(
84             irq_num,
85             &irq_evt,
86             IrqEventSource::from_device(&goldfish_bat),
87         )
88         .map_err(DeviceRegistrationError::RegisterIrqfd)?;
89 
90     match battery_jail {
91         #[cfg(not(windows))]
92         Some(jail) => {
93             let mut keep_rds = goldfish_bat.keep_rds();
94             syslog::push_descriptors(&mut keep_rds);
95             cros_tracing::push_descriptors!(&mut keep_rds);
96             metrics::push_descriptors(&mut keep_rds);
97             mmio_bus
98                 .insert(
99                     Arc::new(Mutex::new(
100                         ProxyDevice::new(
101                             goldfish_bat,
102                             jail,
103                             keep_rds,
104                             #[cfg(feature = "swap")]
105                             swap_controller,
106                         )
107                         .map_err(DeviceRegistrationError::ProxyDeviceCreation)?,
108                     )),
109                     mmio_base,
110                     devices::bat::GOLDFISHBAT_MMIO_LEN,
111                 )
112                 .map_err(DeviceRegistrationError::MmioInsert)?;
113         }
114         #[cfg(windows)]
115         Some(_) => {}
116         None => {
117             mmio_bus
118                 .insert(
119                     Arc::new(Mutex::new(goldfish_bat)),
120                     mmio_base,
121                     devices::bat::GOLDFISHBAT_MMIO_LEN,
122                 )
123                 .map_err(DeviceRegistrationError::MmioInsert)?;
124         }
125     }
126 
127     Ok((control_tube, mmio_base))
128 }
129 
130 pub struct PlatformBusResources {
131     pub dt_symbol: String,        // DT symbol (label) assigned to the device
132     pub regions: Vec<(u64, u64)>, // (start address, size)
133     pub irqs: Vec<(u32, u32)>,    // (IRQ number, flags)
134     pub iommus: Vec<(IommuDevType, Option<u32>, Vec<u32>)>, // (IOMMU type, IOMMU identifier, IDs)
135 }
136 
137 impl PlatformBusResources {
138     const IRQ_TRIGGER_EDGE: u32 = 1;
139     const IRQ_TRIGGER_LEVEL: u32 = 4;
140 
new(symbol: String) -> Self141     fn new(symbol: String) -> Self {
142         Self {
143             dt_symbol: symbol,
144             regions: vec![],
145             irqs: vec![],
146             iommus: vec![],
147         }
148     }
149 }
150 
151 /// Creates a platform device for use by this Vm.
152 #[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, >153 pub fn generate_platform_bus(
154     devices: Vec<(VfioPlatformDevice, Option<Minijail>)>,
155     irq_chip: &mut dyn IrqChip,
156     mmio_bus: &Bus,
157     resources: &mut SystemAllocator,
158     vm: &mut impl Vm,
159     #[cfg(feature = "swap")] swap_controller: &mut Option<swap::SwapController>,
160     protection_type: ProtectionType,
161 ) -> Result<
162     (
163         Vec<Arc<Mutex<dyn BusDevice>>>,
164         BTreeMap<u32, String>,
165         Vec<PlatformBusResources>,
166     ),
167     DeviceRegistrationError,
168 > {
169     let mut platform_devices = Vec::new();
170     let mut pid_labels = BTreeMap::new();
171     let mut bus_dev_resources = vec![];
172 
173     // Allocate ranges that may need to be in the Platform MMIO region (MmioType::Platform).
174     for (mut device, jail) in devices.into_iter() {
175         let dt_symbol = device
176             .dt_symbol()
177             .ok_or(DeviceRegistrationError::MissingDeviceTreeSymbol)?
178             .to_owned();
179         let mut device_resources = PlatformBusResources::new(dt_symbol);
180         let ranges = device
181             .allocate_regions(resources)
182             .map_err(DeviceRegistrationError::AllocateIoResource)?;
183 
184         // If guest memory is private, don't wait for the first access to mmap the device.
185         if protection_type.isolates_memory() {
186             device.regions_mmap_early(vm);
187         }
188 
189         let mut keep_rds = device.keep_rds();
190         syslog::push_descriptors(&mut keep_rds);
191         cros_tracing::push_descriptors!(&mut keep_rds);
192         metrics::push_descriptors(&mut keep_rds);
193 
194         let irqs = device
195             .get_platform_irqs()
196             .map_err(DeviceRegistrationError::AllocateIrqResource)?;
197         for irq in irqs.into_iter() {
198             let irq_num = resources
199                 .allocate_irq()
200                 .ok_or(DeviceRegistrationError::AllocateIrq)?;
201 
202             if device.irq_is_automask(&irq) {
203                 let irq_evt =
204                     devices::IrqLevelEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
205                 irq_chip
206                     .register_level_irq_event(
207                         irq_num,
208                         &irq_evt,
209                         IrqEventSource::from_device(&device),
210                     )
211                     .map_err(DeviceRegistrationError::RegisterIrqfd)?;
212                 device
213                     .assign_level_platform_irq(&irq_evt, irq.index)
214                     .map_err(DeviceRegistrationError::SetupVfioPlatformIrq)?;
215                 keep_rds.extend(irq_evt.as_raw_descriptors());
216                 device_resources
217                     .irqs
218                     .push((irq_num, PlatformBusResources::IRQ_TRIGGER_LEVEL));
219             } else {
220                 let irq_evt =
221                     devices::IrqEdgeEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
222                 irq_chip
223                     .register_edge_irq_event(
224                         irq_num,
225                         &irq_evt,
226                         IrqEventSource::from_device(&device),
227                     )
228                     .map_err(DeviceRegistrationError::RegisterIrqfd)?;
229                 device
230                     .assign_edge_platform_irq(&irq_evt, irq.index)
231                     .map_err(DeviceRegistrationError::SetupVfioPlatformIrq)?;
232                 keep_rds.extend(irq_evt.as_raw_descriptors());
233                 device_resources
234                     .irqs
235                     .push((irq_num, PlatformBusResources::IRQ_TRIGGER_EDGE));
236             }
237         }
238 
239         if let Some((iommu_type, id, vsids)) = device.iommu() {
240             // We currently only support one IOMMU per VFIO device.
241             device_resources
242                 .iommus
243                 .push((iommu_type, id, vsids.to_vec()));
244         }
245 
246         let arced_dev: Arc<Mutex<dyn BusDevice>> = if let Some(jail) = jail {
247             let proxy = ProxyDevice::new(
248                 device,
249                 jail,
250                 keep_rds,
251                 #[cfg(feature = "swap")]
252                 swap_controller,
253             )
254             .map_err(DeviceRegistrationError::ProxyDeviceCreation)?;
255             pid_labels.insert(proxy.pid() as u32, proxy.debug_label());
256             Arc::new(Mutex::new(proxy))
257         } else {
258             device.on_sandboxed();
259             Arc::new(Mutex::new(device))
260         };
261         platform_devices.push(arced_dev.clone());
262         for range in &ranges {
263             mmio_bus
264                 .insert(arced_dev.clone(), range.0, range.1)
265                 .map_err(DeviceRegistrationError::MmioInsert)?;
266             device_resources.regions.push((range.0, range.1));
267         }
268         bus_dev_resources.push(device_resources);
269     }
270     Ok((platform_devices, pid_labels, bus_dev_resources))
271 }
272