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::IrqChip;
15 use devices::IrqEventSource;
16 use devices::ProxyDevice;
17 use devices::VfioPlatformDevice;
18 use libc::sched_getcpu;
19 use minijail::Minijail;
20 use resources::AllocOptions;
21 use resources::SystemAllocator;
22 use sync::Mutex;
23
24 use crate::DeviceRegistrationError;
25 use crate::MsrValueFrom;
26
27 impl MsrValueFrom {
28 /// Get the physical(host) CPU id from MsrValueFrom type.
get_cpu_id(&self) -> usize29 pub fn get_cpu_id(&self) -> usize {
30 match self {
31 MsrValueFrom::RWFromCPU0 => 0,
32 MsrValueFrom::RWFromRunningCPU => {
33 // Safe because the host supports this sys call.
34 (unsafe { sched_getcpu() }) as usize
35 }
36 }
37 }
38 }
39
40 /// Adds goldfish battery and returns the platform needed resources including
41 /// its AML data and mmio base address
42 ///
43 /// # Arguments
44 ///
45 /// * `amls` - the vector to put the goldfish battery AML
46 /// * `battery_jail` - used when sandbox is enabled
47 /// * `mmio_bus` - bus to add the devices to
48 /// * `irq_chip` - the IrqChip object for registering irq events
49 /// * `irq_num` - assigned interrupt to use
50 /// * `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: Option<&swap::SwapController>, ) -> Result<(Tube, u64), DeviceRegistrationError>51 pub fn add_goldfish_battery(
52 amls: &mut Vec<u8>,
53 battery_jail: Option<Minijail>,
54 mmio_bus: &Bus,
55 irq_chip: &mut dyn IrqChip,
56 irq_num: u32,
57 resources: &mut SystemAllocator,
58 #[cfg(feature = "swap")] swap_controller: Option<&swap::SwapController>,
59 ) -> Result<(Tube, u64), DeviceRegistrationError> {
60 let alloc = resources.get_anon_alloc();
61 let mmio_base = resources
62 .allocate_mmio(
63 devices::bat::GOLDFISHBAT_MMIO_LEN,
64 alloc,
65 "GoldfishBattery".to_string(),
66 AllocOptions::new().align(devices::bat::GOLDFISHBAT_MMIO_LEN),
67 )
68 .map_err(DeviceRegistrationError::AllocateIoResource)?;
69
70 let (control_tube, response_tube) =
71 Tube::pair().map_err(DeviceRegistrationError::CreateTube)?;
72
73 #[cfg(feature = "power-monitor-powerd")]
74 let create_monitor = Some(Box::new(power_monitor::powerd::DBusMonitor::connect)
75 as Box<dyn power_monitor::CreatePowerMonitorFn>);
76
77 #[cfg(not(feature = "power-monitor-powerd"))]
78 let create_monitor = None;
79
80 let irq_evt = devices::IrqLevelEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
81
82 let goldfish_bat = devices::GoldfishBattery::new(
83 mmio_base,
84 irq_num,
85 irq_evt
86 .try_clone()
87 .map_err(DeviceRegistrationError::EventClone)?,
88 response_tube,
89 create_monitor,
90 )
91 .map_err(DeviceRegistrationError::RegisterBattery)?;
92 goldfish_bat.to_aml_bytes(amls);
93
94 irq_chip
95 .register_level_irq_event(
96 irq_num,
97 &irq_evt,
98 IrqEventSource::from_device(&goldfish_bat),
99 )
100 .map_err(DeviceRegistrationError::RegisterIrqfd)?;
101
102 match battery_jail {
103 #[cfg(not(windows))]
104 Some(jail) => {
105 let mut keep_rds = goldfish_bat.keep_rds();
106 syslog::push_descriptors(&mut keep_rds);
107 cros_tracing::push_descriptors!(&mut keep_rds);
108 mmio_bus
109 .insert(
110 Arc::new(Mutex::new(
111 ProxyDevice::new(
112 goldfish_bat,
113 jail,
114 keep_rds,
115 #[cfg(feature = "swap")]
116 swap_controller,
117 )
118 .map_err(DeviceRegistrationError::ProxyDeviceCreation)?,
119 )),
120 mmio_base,
121 devices::bat::GOLDFISHBAT_MMIO_LEN,
122 )
123 .map_err(DeviceRegistrationError::MmioInsert)?;
124 }
125 #[cfg(windows)]
126 Some(_) => {}
127 None => {
128 mmio_bus
129 .insert(
130 Arc::new(Mutex::new(goldfish_bat)),
131 mmio_base,
132 devices::bat::GOLDFISHBAT_MMIO_LEN,
133 )
134 .map_err(DeviceRegistrationError::MmioInsert)?;
135 }
136 }
137
138 Ok((control_tube, mmio_base))
139 }
140
141 /// Creates a platform device for use by this Vm.
142 #[cfg(unix)]
generate_platform_bus( devices: Vec<(VfioPlatformDevice, Option<Minijail>)>, irq_chip: &mut dyn IrqChip, mmio_bus: &Bus, resources: &mut SystemAllocator, #[cfg(feature = "swap")] swap_controller: Option<&swap::SwapController>, ) -> Result<(Vec<Arc<Mutex<dyn BusDevice>>>, BTreeMap<u32, String>), DeviceRegistrationError>143 pub fn generate_platform_bus(
144 devices: Vec<(VfioPlatformDevice, Option<Minijail>)>,
145 irq_chip: &mut dyn IrqChip,
146 mmio_bus: &Bus,
147 resources: &mut SystemAllocator,
148 #[cfg(feature = "swap")] swap_controller: Option<&swap::SwapController>,
149 ) -> Result<(Vec<Arc<Mutex<dyn BusDevice>>>, BTreeMap<u32, String>), DeviceRegistrationError> {
150 let mut platform_devices = Vec::new();
151 let mut pid_labels = BTreeMap::new();
152
153 // Allocate ranges that may need to be in the Platform MMIO region (MmioType::Platform).
154 for (mut device, jail) in devices.into_iter() {
155 let ranges = device
156 .allocate_regions(resources)
157 .map_err(DeviceRegistrationError::AllocateIoResource)?;
158
159 let mut keep_rds = device.keep_rds();
160 syslog::push_descriptors(&mut keep_rds);
161 cros_tracing::push_descriptors!(&mut keep_rds);
162
163 let irqs = device
164 .get_platform_irqs()
165 .map_err(DeviceRegistrationError::AllocateIrqResource)?;
166 for irq in irqs.into_iter() {
167 let irq_num = resources
168 .allocate_irq()
169 .ok_or(DeviceRegistrationError::AllocateIrq)?;
170
171 if device.irq_is_automask(&irq) {
172 let irq_evt =
173 devices::IrqLevelEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
174 irq_chip
175 .register_level_irq_event(
176 irq_num,
177 &irq_evt,
178 IrqEventSource::from_device(&device),
179 )
180 .map_err(DeviceRegistrationError::RegisterIrqfd)?;
181 device
182 .assign_level_platform_irq(&irq_evt, irq.index)
183 .map_err(DeviceRegistrationError::SetupVfioPlatformIrq)?;
184 keep_rds.extend(irq_evt.as_raw_descriptors());
185 } else {
186 let irq_evt =
187 devices::IrqEdgeEvent::new().map_err(DeviceRegistrationError::EventCreate)?;
188 irq_chip
189 .register_edge_irq_event(
190 irq_num,
191 &irq_evt,
192 IrqEventSource::from_device(&device),
193 )
194 .map_err(DeviceRegistrationError::RegisterIrqfd)?;
195 device
196 .assign_edge_platform_irq(&irq_evt, irq.index)
197 .map_err(DeviceRegistrationError::SetupVfioPlatformIrq)?;
198 keep_rds.extend(irq_evt.as_raw_descriptors());
199 }
200 }
201
202 let arced_dev: Arc<Mutex<dyn BusDevice>> = if let Some(jail) = jail {
203 let proxy = ProxyDevice::new(
204 device,
205 jail,
206 keep_rds,
207 #[cfg(feature = "swap")]
208 swap_controller,
209 )
210 .map_err(DeviceRegistrationError::ProxyDeviceCreation)?;
211 pid_labels.insert(proxy.pid() as u32, proxy.debug_label());
212 Arc::new(Mutex::new(proxy))
213 } else {
214 device.on_sandboxed();
215 Arc::new(Mutex::new(device))
216 };
217 platform_devices.push(arced_dev.clone());
218 for range in &ranges {
219 mmio_bus
220 .insert(arced_dev.clone(), range.0, range.1)
221 .map_err(DeviceRegistrationError::MmioInsert)?;
222 }
223 }
224 Ok((platform_devices, pid_labels))
225 }
226