Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/arch/src/sys/linux.rs
5394 views
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::warn;
11
use base::AsRawDescriptors;
12
use base::Tube;
13
use devices::Bus;
14
use devices::BusDevice;
15
use devices::DevicePowerManager;
16
use devices::IommuDevType;
17
use devices::IrqChip;
18
use devices::IrqEventSource;
19
use devices::ProxyDevice;
20
use devices::VfioPlatformDevice;
21
use hypervisor::ProtectionType;
22
use hypervisor::Vm;
23
use minijail::Minijail;
24
use resources::AllocOptions;
25
use resources::SystemAllocator;
26
use sync::Mutex;
27
28
use crate::DeviceRegistrationError;
29
30
/// Adds goldfish battery and returns the platform needed resources including
31
/// its AML data and mmio base address
32
///
33
/// # Arguments
34
///
35
/// * `amls` - the vector to put the goldfish battery AML
36
/// * `battery_jail` - used when sandbox is enabled
37
/// * `mmio_bus` - bus to add the devices to
38
/// * `irq_chip` - the IrqChip object for registering irq events
39
/// * `irq_num` - assigned interrupt to use
40
/// * `resources` - the SystemAllocator to allocate IO and MMIO for acpi
41
pub 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
139
pub struct PlatformBusResources {
140
pub dt_symbol: String, // DT symbol (label) assigned to the device
141
pub regions: Vec<(u64, u64)>, // (start address, size)
142
pub irqs: Vec<(u32, u32)>, // (IRQ number, flags)
143
pub iommus: Vec<(IommuDevType, Option<u32>, Vec<u32>)>, // (IOMMU type, IOMMU identifier, IDs)
144
pub requires_power_domain: bool,
145
}
146
147
impl 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
/// Creates a platform device for use by this Vm.
163
#[cfg(any(target_os = "android", target_os = "linux"))]
164
pub 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
// Allocate ranges that may need to be in the Platform MMIO region (MmioType::Platform).
186
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 guest memory is private, don't wait for the first access to mmap the device.
197
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
// We currently only support one IOMMU per VFIO device.
253
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
// As we currently restrict one device per vPD and to simplify having a PD ID
288
// which the VMM, hypervisor, and guest recognize, refer to a PD using the base
289
// of the MMIO of the device it contains.
290
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
}
302
303