1use std::cmp::Ordering;
9use std::collections::BTreeMap;
10use std::collections::HashMap;
11use std::collections::VecDeque;
12use std::sync::mpsc;
13use std::sync::Arc;
14
15use anyhow::anyhow;
16use anyhow::bail;
17use anyhow::Context;
18use anyhow::Error;
19use arch::RunnableLinuxVm;
20use base::AsRawDescriptor;
21use base::Event;
22use base::EventToken;
23use base::RawDescriptor;
24use base::WaitContext;
25use base::WorkerThread;
26use devices::BusDevice;
27use devices::HotPlugBus;
28use devices::HotPlugKey;
29use devices::IrqEventSource;
30use devices::IrqLevelEvent;
31use devices::PciAddress;
32use devices::PciInterruptPin;
33use devices::PciRootCommand;
34use devices::ResourceCarrier;
35use log::error;
36use resources::SystemAllocator;
37#[cfg(feature = "swap")]
38use swap::SwapDeviceHelper;
39use sync::Mutex;
40use vm_memory::GuestMemory;
41
42use crate::crosvm::sys::linux::JailWarden;
43use crate::crosvm::sys::linux::JailWardenImpl;
44use crate::crosvm::sys::linux::PermissiveJailWarden;
45use crate::Config;
46
47pub type Result<T> = std::result::Result<T, Error>;
48
49pub struct PciHotPlugManager {
51 port_stubs: BTreeMap<PciAddress, PortManagerStub>,
53 bus_address_map: BTreeMap<u8, PciAddress>,
55 jail_warden: Box<dyn JailWarden>,
57 worker_client: Option<WorkerClient>,
59}
60
61struct WorkerClient {
63 control_evt: Event,
65 command_sender: mpsc::Sender<WorkerCommand>,
67 response_receiver: mpsc::Receiver<WorkerResponse>,
69 _worker_thread: WorkerThread<()>,
70}
71
72impl WorkerClient {
73 fn new(rootbus_controller: mpsc::Sender<PciRootCommand>) -> Result<Self> {
75 let (command_sender, command_receiver) = mpsc::channel();
76 let (response_sender, response_receiver) = mpsc::channel();
77 let control_evt = Event::new()?;
78 let control_evt_cpy = control_evt.try_clone()?;
79 let worker_thread = WorkerThread::start("pcihp_mgr_workr", move |kill_evt| {
80 if let Err(e) = PciHotPlugWorker::new(
81 rootbus_controller,
82 command_receiver,
83 response_sender,
84 control_evt_cpy,
85 &kill_evt,
86 )
87 .and_then(move |mut worker| worker.run(kill_evt))
88 {
89 error!("PciHotPlugManager worker failed: {e:#}");
90 }
91 });
92 Ok(WorkerClient {
93 control_evt,
94 command_sender,
95 response_receiver,
96 _worker_thread: worker_thread,
97 })
98 }
99
100 fn send_worker_command(&self, command: WorkerCommand) -> Result<WorkerResponse> {
102 self.command_sender.send(command)?;
103 self.control_evt.signal()?;
104 Ok(self.response_receiver.recv()?)
105 }
106}
107
108struct PortManagerStub {
110 downstream_bus: u8,
112 devices: HashMap<PciAddress, RecoverableResource>,
115}
116
117struct RecoverableResource {
119 irq_num: u32,
120 irq_evt: IrqLevelEvent,
121}
122
123enum WorkerCommand {
125 AddPort(PciAddress, PortWorkerStub),
127 GetPortState(PciAddress),
129 GetEmptyPort,
131 SignalHotPlug(SignalHotPlugCommand),
133 SignalHotUnplug(PciAddress),
135}
136
137#[derive(Clone)]
138struct GuestDeviceStub {
139 pci_addr: PciAddress,
140 key: HotPlugKey,
141 device: Arc<Mutex<dyn BusDevice>>,
142}
143
144#[derive(Clone)]
145struct SignalHotPlugCommand {
146 upstream_address: PciAddress,
148 guest_devices: Vec<GuestDeviceStub>,
150}
151
152impl SignalHotPlugCommand {
153 fn new(upstream_address: PciAddress, guest_devices: Vec<GuestDeviceStub>) -> Result<Self> {
154 if guest_devices.is_empty() {
155 bail!("No guest devices");
156 }
157 Ok(Self {
158 upstream_address,
159 guest_devices,
160 })
161 }
162}
163
164#[derive(Clone)]
166struct PortWorkerStub {
167 base_address: PciAddress,
169 attached_devices: Vec<PciAddress>,
171 devices_to_add: VecDeque<Vec<GuestDeviceStub>>,
173 port: Arc<Mutex<dyn HotPlugBus>>,
175}
176
177impl PortWorkerStub {
178 fn new(port: Arc<Mutex<dyn HotPlugBus>>, downstream_bus: u8) -> Result<Self> {
179 let base_address = PciAddress::new(0, downstream_bus.into(), 0, 0)?;
180 Ok(Self {
181 base_address,
182 devices_to_add: VecDeque::new(),
183 attached_devices: Vec::new(),
184 port,
185 })
186 }
187
188 fn add_hotplug_devices(&mut self, devices: Vec<GuestDeviceStub>) -> Result<()> {
189 if devices.is_empty() {
190 bail!("No guest devices");
191 }
192 self.devices_to_add.push_back(devices);
193 Ok(())
194 }
195
196 fn cancel_queued_add(&mut self) -> Result<()> {
197 self.devices_to_add
198 .pop_back()
199 .context("No guest device add queued")?;
200 Ok(())
201 }
202
203 fn send_hot_plug_signal(
204 &mut self,
205 rootbus_controller: &mpsc::Sender<PciRootCommand>,
206 ) -> Result<Event> {
207 let mut port_lock = self.port.lock();
208 let devices = self
209 .devices_to_add
210 .pop_front()
211 .context("Missing devices to add")?;
212 for device in devices {
213 rootbus_controller.send(PciRootCommand::Add(device.pci_addr, device.device))?;
214 self.attached_devices.push(device.pci_addr);
215 port_lock.add_hotplug_device(device.key, device.pci_addr);
216 }
217 port_lock
218 .hot_plug(self.base_address)?
219 .context("hotplug bus does not support command complete notification")
220 }
221
222 fn send_hot_unplug_signal(
223 &mut self,
224 rootbus_controller: &mpsc::Sender<PciRootCommand>,
225 ) -> Result<Event> {
226 for pci_addr in self.attached_devices.drain(..) {
227 rootbus_controller.send(PciRootCommand::Remove(pci_addr))?;
228 }
229 self.port
230 .lock()
231 .hot_unplug(self.base_address)?
232 .context("hotplug bus does not support command complete notification")
233 }
234}
235
236#[derive(Debug)]
238enum WorkerResponse {
239 AddPortOk,
241 GetEmptyPortOk(PciAddress),
243 GetPortStateOk(PortState),
246 SignalOk,
248 InvalidCommand(Error),
250}
251
252impl PartialEq for WorkerResponse {
253 fn eq(&self, other: &Self) -> bool {
254 match (self, other) {
255 (Self::GetEmptyPortOk(l0), Self::GetEmptyPortOk(r0)) => l0 == r0,
256 (Self::GetPortStateOk(l0), Self::GetPortStateOk(r0)) => l0 == r0,
257 (Self::InvalidCommand(_), Self::InvalidCommand(_)) => true,
258 _ => core::mem::discriminant(self) == core::mem::discriminant(other),
259 }
260 }
261}
262
263#[derive(Debug, EventToken)]
264enum Token {
265 Kill,
266 ManagerCommand,
267 PortReady(RawDescriptor),
268 PlugComplete(RawDescriptor),
269 UnplugComplete(RawDescriptor),
270}
271
272struct PciHotPlugWorker {
275 event_map: BTreeMap<RawDescriptor, (Event, PciAddress)>,
276 port_state_map: BTreeMap<PciAddress, PortState>,
277 port_map: BTreeMap<PortKey, PortWorkerStub>,
278 manager_evt: Event,
279 wait_ctx: WaitContext<Token>,
280 command_receiver: mpsc::Receiver<WorkerCommand>,
281 response_sender: mpsc::Sender<WorkerResponse>,
282 rootbus_controller: mpsc::Sender<PciRootCommand>,
283}
284
285impl PciHotPlugWorker {
286 fn new(
287 rootbus_controller: mpsc::Sender<PciRootCommand>,
288 command_receiver: mpsc::Receiver<WorkerCommand>,
289 response_sender: mpsc::Sender<WorkerResponse>,
290 manager_evt: Event,
291 kill_evt: &Event,
292 ) -> Result<Self> {
293 let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
294 (&manager_evt, Token::ManagerCommand),
295 (kill_evt, Token::Kill),
296 ])?;
297 Ok(Self {
298 event_map: BTreeMap::new(),
299 port_state_map: BTreeMap::new(),
300 port_map: BTreeMap::new(),
301 manager_evt,
302 wait_ctx,
303 command_receiver,
304 response_sender,
305 rootbus_controller,
306 })
307 }
308
309 fn run(&mut self, kill_evt: Event) -> Result<()> {
312 'wait: loop {
313 let events = self.wait_ctx.wait()?;
314 for triggered_event in events.iter().filter(|e| e.is_readable) {
315 match triggered_event.token {
316 Token::ManagerCommand => {
317 self.manager_evt.wait()?;
318 self.handle_manager_command()?;
319 }
320 Token::PortReady(descriptor) => {
321 let (event, pci_address) = self
322 .event_map
323 .remove(&descriptor)
324 .context("Cannot find event")?;
325 event.wait()?;
326 self.wait_ctx.delete(&event)?;
327 self.handle_port_ready(pci_address)?;
328 }
329 Token::PlugComplete(descriptor) => {
330 let (event, pci_address) = self
331 .event_map
332 .remove(&descriptor)
333 .context("Cannot find event")?;
334 event.wait()?;
335 self.wait_ctx.delete(&event)?;
336 self.handle_plug_complete(pci_address)?;
337 }
338 Token::UnplugComplete(descriptor) => {
339 let (event, pci_address) = self
340 .event_map
341 .remove(&descriptor)
342 .context("Cannot find event")?;
343 self.wait_ctx.delete(&event)?;
344 self.handle_unplug_complete(pci_address)?;
345 }
346 Token::Kill => {
347 let _ = kill_evt.wait();
348 break 'wait;
349 }
350 }
351 }
352 }
353 Ok(())
354 }
355
356 fn handle_manager_command(&mut self) -> Result<()> {
357 let response = match self.command_receiver.recv()? {
358 WorkerCommand::AddPort(pci_address, port) => self.handle_add_port(pci_address, port),
359 WorkerCommand::GetPortState(pci_address) => self.handle_get_port_state(pci_address),
360 WorkerCommand::GetEmptyPort => self.handle_get_empty_port(),
361 WorkerCommand::SignalHotPlug(hotplug_command) => {
362 self.handle_plug_request(hotplug_command)
363 }
364 WorkerCommand::SignalHotUnplug(pci_address) => self.handle_unplug_request(pci_address),
365 }?;
366 Ok(self.response_sender.send(response)?)
367 }
368
369 fn handle_add_port(
371 &mut self,
372 pci_address: PciAddress,
373 port: PortWorkerStub,
374 ) -> Result<WorkerResponse> {
375 if self.port_state_map.contains_key(&pci_address) {
376 return Ok(WorkerResponse::InvalidCommand(anyhow!(
377 "Conflicting upstream PCI address"
378 )));
379 }
380 let port_state = PortState::EmptyNotReady;
381 let port_ready_event = port.port.lock().get_ready_notification()?;
382 self.wait_ctx.add(
383 &port_ready_event,
384 Token::PortReady(port_ready_event.as_raw_descriptor()),
385 )?;
386 self.event_map.insert(
387 port_ready_event.as_raw_descriptor(),
388 (port_ready_event, pci_address),
389 );
390 self.port_state_map.insert(pci_address, port_state);
391 self.port_map.insert(
392 PortKey {
393 port_state,
394 pci_address,
395 },
396 port,
397 );
398 Ok(WorkerResponse::AddPortOk)
399 }
400
401 fn handle_get_port_state(&self, pci_address: PciAddress) -> Result<WorkerResponse> {
403 match self.get_port_state(pci_address) {
404 Ok(ps) => Ok(WorkerResponse::GetPortStateOk(ps)),
405 Err(e) => Ok(WorkerResponse::InvalidCommand(e)),
406 }
407 }
408
409 fn handle_get_empty_port(&self) -> Result<WorkerResponse> {
411 let most_empty_port = match self.port_map.first_key_value() {
412 Some(p) => p.0,
413 None => return Ok(WorkerResponse::InvalidCommand(anyhow!("No ports added"))),
414 };
415 match most_empty_port.port_state {
416 PortState::Empty(_) | PortState::EmptyNotReady => {
417 Ok(WorkerResponse::GetEmptyPortOk(most_empty_port.pci_address))
418 }
419 PortState::Occupied(_) | PortState::OccupiedNotReady => {
420 Ok(WorkerResponse::InvalidCommand(anyhow!("No empty port")))
421 }
422 }
423 }
424
425 fn handle_plug_request(
428 &mut self,
429 hotplug_command: SignalHotPlugCommand,
430 ) -> Result<WorkerResponse> {
431 let pci_address = hotplug_command.upstream_address;
432 let next_state = match self.get_port_state(pci_address) {
433 Ok(PortState::Empty(n)) => {
434 self.get_port_mut(pci_address)?
435 .add_hotplug_devices(hotplug_command.guest_devices)?;
436 if n == 0 {
437 self.schedule_plug_event(pci_address)?;
438 }
439 PortState::Occupied(n + 1)
440 }
441 Ok(PortState::EmptyNotReady) => {
442 self.get_port_mut(pci_address)?
443 .add_hotplug_devices(hotplug_command.guest_devices)?;
444 PortState::OccupiedNotReady
445 }
446 Ok(PortState::Occupied(_)) | Ok(PortState::OccupiedNotReady) => {
447 return Ok(WorkerResponse::InvalidCommand(anyhow!(
448 "Attempt to plug into an occupied port"
449 )))
450 }
451 Err(e) => return Ok(WorkerResponse::InvalidCommand(e)),
452 };
453 self.set_port_state(pci_address, next_state)?;
454 Ok(WorkerResponse::SignalOk)
455 }
456
457 fn handle_unplug_request(&mut self, pci_address: PciAddress) -> Result<WorkerResponse> {
465 let next_state = match self.get_port_state(pci_address) {
466 Ok(PortState::Occupied(n)) => {
467 if n >= 2 {
468 self.get_port_mut(pci_address)?.cancel_queued_add()?;
469 }
470 if n == 0 {
471 self.schedule_unplug_event(pci_address)?;
472 }
473 PortState::Empty(n % 2 + 1)
474 }
475 Ok(PortState::OccupiedNotReady) => PortState::EmptyNotReady,
476 Ok(PortState::Empty(_)) | Ok(PortState::EmptyNotReady) => {
477 return Ok(WorkerResponse::InvalidCommand(anyhow!(
478 "Attempt to unplug from an empty port"
479 )))
480 }
481 Err(e) => return Ok(WorkerResponse::InvalidCommand(e)),
482 };
483 self.set_port_state(pci_address, next_state)?;
484 Ok(WorkerResponse::SignalOk)
485 }
486
487 fn handle_port_ready(&mut self, pci_address: PciAddress) -> Result<()> {
490 let next_state = match self.get_port_state(pci_address)? {
491 PortState::EmptyNotReady => PortState::Empty(0),
492 PortState::OccupiedNotReady => {
493 self.schedule_plug_event(pci_address)?;
494 PortState::Occupied(1)
495 }
496 PortState::Empty(_) | PortState::Occupied(_) => {
497 bail!("Received port ready on an already enabled port");
498 }
499 };
500 self.set_port_state(pci_address, next_state)
501 }
502
503 fn handle_plug_complete(&mut self, pci_address: PciAddress) -> Result<()> {
506 let (n, next_state) = match self.get_port_state(pci_address)? {
507 PortState::Empty(n) => (n, PortState::Empty(n - 1)),
509 PortState::Occupied(n) => (n, PortState::Occupied(n - 1)),
510 PortState::EmptyNotReady | PortState::OccupiedNotReady => {
511 bail!("Received plug completed on a not enabled port");
512 }
513 };
514 if n > 1 {
515 self.schedule_unplug_event(pci_address)?;
516 }
517 self.set_port_state(pci_address, next_state)
518 }
519
520 fn handle_unplug_complete(&mut self, pci_address: PciAddress) -> Result<()> {
523 let (n, next_state) = match self.get_port_state(pci_address)? {
524 PortState::Empty(n) => (n, PortState::Empty(n - 1)),
526 PortState::Occupied(n) => (n, PortState::Occupied(n - 1)),
527 PortState::EmptyNotReady | PortState::OccupiedNotReady => {
528 bail!("Received unplug completed on a not enabled port");
529 }
530 };
531 if n > 1 {
532 self.schedule_plug_event(pci_address)?;
533 }
534 self.set_port_state(pci_address, next_state)
535 }
536
537 fn get_port_state(&self, pci_address: PciAddress) -> Result<PortState> {
538 Ok(*self
539 .port_state_map
540 .get(&pci_address)
541 .with_context(|| format!("Cannot find port state on {pci_address}"))?)
542 }
543
544 fn set_port_state(&mut self, pci_address: PciAddress, port_state: PortState) -> Result<()> {
545 let old_port_state = self.get_port_state(pci_address)?;
546 let port = self
547 .port_map
548 .remove(&PortKey {
549 port_state: old_port_state,
550 pci_address,
551 })
552 .context("Cannot find port")?;
553 self.port_map.insert(
554 PortKey {
555 port_state,
556 pci_address,
557 },
558 port,
559 );
560 self.port_state_map.insert(pci_address, port_state);
561 Ok(())
562 }
563
564 fn schedule_plug_event(&mut self, pci_address: PciAddress) -> Result<()> {
565 let rootbus_controller = self.rootbus_controller.clone();
566 let plug_event = self
567 .get_port_mut(pci_address)?
568 .send_hot_plug_signal(&rootbus_controller)?;
569 self.wait_ctx.add(
570 &plug_event,
571 Token::PlugComplete(plug_event.as_raw_descriptor()),
572 )?;
573 self.event_map
574 .insert(plug_event.as_raw_descriptor(), (plug_event, pci_address));
575 Ok(())
576 }
577
578 fn schedule_unplug_event(&mut self, pci_address: PciAddress) -> Result<()> {
579 let rootbus_controller = self.rootbus_controller.clone();
580 let unplug_event = self
581 .get_port_mut(pci_address)?
582 .send_hot_unplug_signal(&rootbus_controller)?;
583 self.wait_ctx.add(
584 &unplug_event,
585 Token::UnplugComplete(unplug_event.as_raw_descriptor()),
586 )?;
587 self.event_map.insert(
588 unplug_event.as_raw_descriptor(),
589 (unplug_event, pci_address),
590 );
591 Ok(())
592 }
593
594 fn get_port_mut(&mut self, pci_address: PciAddress) -> Result<&mut PortWorkerStub> {
595 let port_state = self.get_port_state(pci_address)?;
596 self.port_map
597 .get_mut(&PortKey {
598 port_state,
599 pci_address,
600 })
601 .context("PciHotPlugWorker is in invalid state")
602 }
603}
604
605#[derive(Clone, Copy, Debug, PartialEq, Eq)]
627enum PortState {
628 Empty(u8),
630 EmptyNotReady,
632 Occupied(u8),
634 OccupiedNotReady,
636}
637
638impl PortState {
639 fn variant_order_index(&self) -> u8 {
640 match self {
641 PortState::Empty(_) => 0,
642 PortState::EmptyNotReady => 1,
643 PortState::Occupied(_) => 2,
644 PortState::OccupiedNotReady => 3,
645 }
646 }
647}
648
649impl Ord for PortState {
651 fn cmp(&self, other: &Self) -> Ordering {
652 match self.variant_order_index().cmp(&other.variant_order_index()) {
654 Ordering::Less => {
655 return Ordering::Less;
656 }
657 Ordering::Equal => {}
658 Ordering::Greater => return Ordering::Greater,
659 }
660 match (self, other) {
662 (PortState::Empty(lhs), PortState::Empty(rhs)) => lhs.cmp(rhs),
663 (PortState::Occupied(lhs), PortState::Occupied(rhs)) => lhs.cmp(rhs),
664 _ => Ordering::Equal,
665 }
666 }
667}
668
669impl PartialOrd for PortState {
670 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
671 Some(self.cmp(other))
672 }
673}
674
675#[derive(PartialEq, Eq, PartialOrd, Ord)]
681struct PortKey {
682 port_state: PortState,
683 pci_address: PciAddress,
684}
685
686impl PciHotPlugManager {
687 pub fn new(
692 guest_memory: GuestMemory,
693 config: &Config,
694 #[cfg(feature = "swap")] swap_device_helper: Option<SwapDeviceHelper>,
695 ) -> Result<Self> {
696 let jail_warden: Box<dyn JailWarden> = match config.jail_config {
697 Some(_) => Box::new(
698 JailWardenImpl::new(
699 guest_memory,
700 config,
701 #[cfg(feature = "swap")]
702 swap_device_helper,
703 )
704 .context("jail warden construction")?,
705 ),
706 None => Box::new(
707 PermissiveJailWarden::new(
708 guest_memory,
709 config,
710 #[cfg(feature = "swap")]
711 swap_device_helper,
712 )
713 .context("jail warden construction")?,
714 ),
715 };
716 Ok(Self {
717 jail_warden,
718 port_stubs: BTreeMap::new(),
719 bus_address_map: BTreeMap::new(),
720 worker_client: None,
721 })
722 }
723
724 #[allow(unused)]
731 pub fn set_rootbus_controller(
732 &mut self,
733 rootbus_controller: mpsc::Sender<PciRootCommand>,
734 ) -> Result<()> {
735 self.worker_client = Some(WorkerClient::new(rootbus_controller)?);
737 Ok(())
738 }
739
740 #[allow(unused)]
745 pub fn add_port(&mut self, port: Arc<Mutex<dyn HotPlugBus>>) -> Result<()> {
746 let worker_client = self
747 .worker_client
748 .as_ref()
749 .context("No worker thread. Is set_rootbus_controller not called?")?;
750 let port_lock = port.lock();
751 if !port_lock.is_empty() {
753 bail!("invalid hotplug bus");
754 }
755 let pci_address = port_lock
756 .get_address()
757 .context("Hotplug bus PCI address missing")?;
758 if pci_address.bus != 0 {
761 bail!("hotplug port on non-root bus not supported");
762 }
763 let downstream_bus = port_lock
764 .get_secondary_bus_number()
765 .context("cannot get downstream bus")?;
766 drop(port_lock);
767 if let Some(prev_address) = self.bus_address_map.insert(downstream_bus, pci_address) {
768 bail!(
769 "Downstream bus of new port is conflicting with previous port at {}",
770 &prev_address
771 );
772 }
773 self.port_stubs.insert(
774 pci_address,
775 PortManagerStub {
776 downstream_bus,
777 devices: HashMap::new(),
778 },
779 );
780 match worker_client.send_worker_command(WorkerCommand::AddPort(
781 pci_address,
782 PortWorkerStub::new(port, downstream_bus)?,
783 ))? {
784 WorkerResponse::AddPortOk => Ok(()),
785 WorkerResponse::InvalidCommand(e) => Err(e),
786 r => bail!("Unexpected response from worker: {:?}", &r),
787 }
788 }
789
790 pub fn hotplug_device(
794 &mut self,
795 resource_carriers: Vec<ResourceCarrier>,
796 linux: &mut RunnableLinuxVm,
797 resources: &mut SystemAllocator,
798 ) -> Result<u8> {
799 let worker_client = self
800 .worker_client
801 .as_ref()
802 .context("No worker thread. Is set_rootbus_controller not called?")?;
803 if resource_carriers.len() > 8 || resource_carriers.is_empty() {
804 bail!("PCI function count has to be 1 to 8 inclusive");
805 }
806 let pci_address = match worker_client.send_worker_command(WorkerCommand::GetEmptyPort)? {
807 WorkerResponse::GetEmptyPortOk(p) => Ok(p),
808 WorkerResponse::InvalidCommand(e) => Err(e),
809 r => bail!("Unexpected response from worker: {:?}", &r),
810 }?;
811 let port_stub = self
812 .port_stubs
813 .get_mut(&pci_address)
814 .context("Cannot find port")?;
815 let downstream_bus = port_stub.downstream_bus;
816 let mut devices = Vec::new();
817 for (func_num, mut resource_carrier) in resource_carriers.into_iter().enumerate() {
818 let device_address = PciAddress::new(0, downstream_bus as u32, 0, func_num as u32)?;
819 let hotplug_key = HotPlugKey::GuestDevice {
820 guest_addr: device_address,
821 };
822 resource_carrier.allocate_address(device_address, resources)?;
823 let irq_evt = IrqLevelEvent::new()?;
824 let (pin, irq_num) = match downstream_bus % 4 {
825 0 => (PciInterruptPin::IntA, 0),
826 1 => (PciInterruptPin::IntB, 1),
827 2 => (PciInterruptPin::IntC, 2),
828 _ => (PciInterruptPin::IntD, 3),
829 };
830 resource_carrier.assign_irq(irq_evt.try_clone()?, pin, irq_num);
831 let (proxy_device, pid) = self
832 .jail_warden
833 .make_proxy_device(resource_carrier)
834 .context("make proxy device")?;
835 let device_id = proxy_device.lock().device_id();
836 let device_name = proxy_device.lock().debug_label();
837 linux.irq_chip.register_level_irq_event(
838 irq_num,
839 &irq_evt,
840 IrqEventSource {
841 device_id,
842 queue_id: 0,
843 device_name: device_name.clone(),
844 },
845 )?;
846 let pid: u32 = pid.try_into().context("fork fail")?;
847 if pid > 0 {
848 linux.pid_debug_label_map.insert(pid, device_name);
849 }
850 devices.push(GuestDeviceStub {
851 pci_addr: device_address,
852 key: hotplug_key,
853 device: proxy_device,
854 });
855 port_stub
856 .devices
857 .insert(device_address, RecoverableResource { irq_num, irq_evt });
858 }
859 match worker_client.send_worker_command(WorkerCommand::SignalHotPlug(
861 SignalHotPlugCommand::new(pci_address, devices)?,
862 ))? {
863 WorkerResponse::SignalOk => Ok(downstream_bus),
864 WorkerResponse::InvalidCommand(e) => Err(e),
865 r => bail!("Unexpected response from worker: {:?}", &r),
866 }
867 }
868
869 pub fn remove_hotplug_device(
871 &mut self,
872 bus: u8,
873 linux: &mut RunnableLinuxVm,
874 resources: &mut SystemAllocator,
875 ) -> Result<()> {
876 let worker_client = self
877 .worker_client
878 .as_ref()
879 .context("No worker thread. Is set_rootbus_controller not called?")?;
880 let pci_address = self
881 .bus_address_map
882 .get(&bus)
883 .with_context(|| format!("Port {} is not known", &bus))?;
884 match worker_client.send_worker_command(WorkerCommand::GetPortState(*pci_address))? {
885 WorkerResponse::GetPortStateOk(PortState::Occupied(_)) => {}
886 WorkerResponse::GetPortStateOk(PortState::Empty(_)) => {
887 bail!("Port {} is empty", &bus)
888 }
889 WorkerResponse::InvalidCommand(e) => {
890 return Err(e);
891 }
892 wr => bail!("Unexpected response from worker: {:?}", &wr),
893 };
894 match worker_client.send_worker_command(WorkerCommand::SignalHotUnplug(*pci_address))? {
897 WorkerResponse::SignalOk => {}
898 WorkerResponse::InvalidCommand(e) => {
899 return Err(e);
900 }
901 wr => bail!("Unexpected response from worker: {:?}", &wr),
902 }
903 let port_stub = self
905 .port_stubs
906 .get_mut(pci_address)
907 .with_context(|| format!("Port {} is not known", &bus))?;
908 for (downstream_address, recoverable_resource) in port_stub.devices.drain() {
909 resources.release_pci(downstream_address);
912 linux.irq_chip.unregister_level_irq_event(
913 recoverable_resource.irq_num,
914 &recoverable_resource.irq_evt,
915 )?;
916 }
917 Ok(())
918 }
919}
920
921#[cfg(test)]
922mod tests {
923 use std::thread;
924 use std::time::Duration;
925
926 use devices::MockDevice;
927
928 use super::*;
929
930 struct MockPort {
933 cc_event: Event,
934 downstream_bus: u8,
935 ready_events: Vec<Event>,
936 }
937
938 impl MockPort {
939 fn new(downstream_bus: u8) -> Self {
940 Self {
941 cc_event: Event::new().unwrap(),
942 downstream_bus,
943 ready_events: Vec::new(),
944 }
945 }
946
947 fn signal_cc(&self) {
948 self.cc_event.reset().unwrap();
949 self.cc_event.signal().unwrap();
950 }
951
952 fn signal_ready(&mut self) {
953 for event in self.ready_events.drain(..) {
954 event.reset().unwrap();
955 event.signal().unwrap();
956 }
957 }
958 }
959
960 impl HotPlugBus for MockPort {
961 fn hot_plug(&mut self, _addr: PciAddress) -> anyhow::Result<Option<Event>> {
962 self.cc_event = Event::new().unwrap();
963 Ok(Some(self.cc_event.try_clone().unwrap()))
964 }
965
966 fn hot_unplug(&mut self, _addr: PciAddress) -> anyhow::Result<Option<Event>> {
967 self.cc_event = Event::new().unwrap();
968 Ok(Some(self.cc_event.try_clone().unwrap()))
969 }
970
971 fn get_ready_notification(&mut self) -> anyhow::Result<Event> {
972 let event = Event::new()?;
973 self.ready_events.push(event.try_clone()?);
974 Ok(event)
975 }
976
977 fn is_match(&self, _host_addr: PciAddress) -> Option<u8> {
978 None
979 }
980
981 fn get_address(&self) -> Option<PciAddress> {
982 None
983 }
984
985 fn get_secondary_bus_number(&self) -> Option<u8> {
986 Some(self.downstream_bus)
987 }
988
989 fn add_hotplug_device(&mut self, _hotplug_key: HotPlugKey, _guest_addr: PciAddress) {}
990
991 fn get_hotplug_device(&self, _hotplug_key: HotPlugKey) -> Option<PciAddress> {
992 None
993 }
994
995 fn is_empty(&self) -> bool {
996 true
997 }
998
999 fn get_hotplug_key(&self) -> Option<HotPlugKey> {
1000 None
1001 }
1002 }
1003
1004 fn new_port(downstream_bus: u8) -> Arc<Mutex<MockPort>> {
1005 Arc::new(Mutex::new(MockPort::new(downstream_bus)))
1006 }
1007
1008 fn poll_until_with_timeout<F>(f: F, timeout: Duration) -> bool
1009 where
1010 F: Fn() -> bool,
1011 {
1012 for _ in 0..timeout.as_millis() {
1013 if f() {
1014 return true;
1015 }
1016 thread::sleep(Duration::from_millis(1));
1017 }
1018 false
1019 }
1020
1021 #[test]
1022 fn worker_empty_port_ordering() {
1023 let (rootbus_controller, _rootbus_recvr) = mpsc::channel();
1024 let client = WorkerClient::new(rootbus_controller).unwrap();
1025 let upstream_addr_a = PciAddress {
1027 bus: 0,
1028 dev: 1,
1029 func: 1,
1030 };
1031 let bus_a = 2;
1032 let downstream_addr_a = PciAddress {
1033 bus: bus_a,
1034 dev: 0,
1035 func: 0,
1036 };
1037 let hotplug_key_a = HotPlugKey::GuestDevice {
1038 guest_addr: downstream_addr_a,
1039 };
1040 let device_a = GuestDeviceStub {
1041 pci_addr: downstream_addr_a,
1042 key: hotplug_key_a,
1043 device: Arc::new(Mutex::new(MockDevice::new())),
1044 };
1045 let hotplug_command_a =
1046 SignalHotPlugCommand::new(upstream_addr_a, [device_a].to_vec()).unwrap();
1047 let port_a = new_port(bus_a);
1048 let upstream_addr_b = PciAddress {
1050 bus: 0,
1051 dev: 1,
1052 func: 0,
1053 };
1054 let bus_b = 3;
1055 let downstream_addr_b = PciAddress {
1056 bus: bus_b,
1057 dev: 0,
1058 func: 0,
1059 };
1060 let hotplug_key_b = HotPlugKey::GuestDevice {
1061 guest_addr: downstream_addr_b,
1062 };
1063 let device_b = GuestDeviceStub {
1064 pci_addr: downstream_addr_b,
1065 key: hotplug_key_b,
1066 device: Arc::new(Mutex::new(MockDevice::new())),
1067 };
1068 let hotplug_command_b =
1069 SignalHotPlugCommand::new(upstream_addr_b, [device_b].to_vec()).unwrap();
1070 let port_b = new_port(bus_b);
1071 let upstream_addr_c = PciAddress {
1073 bus: 0,
1074 dev: 2,
1075 func: 0,
1076 };
1077 let bus_c = 4;
1078 let downstream_addr_c = PciAddress {
1079 bus: bus_c,
1080 dev: 0,
1081 func: 0,
1082 };
1083 let hotplug_key_c = HotPlugKey::GuestDevice {
1084 guest_addr: downstream_addr_c,
1085 };
1086 let device_c = GuestDeviceStub {
1087 pci_addr: downstream_addr_c,
1088 key: hotplug_key_c,
1089 device: Arc::new(Mutex::new(MockDevice::new())),
1090 };
1091 let hotplug_command_c =
1092 SignalHotPlugCommand::new(upstream_addr_c, [device_c].to_vec()).unwrap();
1093 let port_c = new_port(bus_c);
1094 assert_eq!(
1095 WorkerResponse::AddPortOk,
1096 client
1097 .send_worker_command(WorkerCommand::AddPort(
1098 upstream_addr_a,
1099 PortWorkerStub::new(port_a.clone(), bus_a).unwrap()
1100 ))
1101 .unwrap()
1102 );
1103 assert_eq!(
1104 WorkerResponse::AddPortOk,
1105 client
1106 .send_worker_command(WorkerCommand::AddPort(
1107 upstream_addr_b,
1108 PortWorkerStub::new(port_b.clone(), bus_b).unwrap()
1109 ))
1110 .unwrap()
1111 );
1112 assert_eq!(
1113 WorkerResponse::AddPortOk,
1114 client
1115 .send_worker_command(WorkerCommand::AddPort(
1116 upstream_addr_c,
1117 PortWorkerStub::new(port_c.clone(), bus_c).unwrap()
1118 ))
1119 .unwrap()
1120 );
1121 port_a.lock().signal_ready();
1122 assert!(poll_until_with_timeout(
1123 || client
1124 .send_worker_command(WorkerCommand::GetPortState(upstream_addr_a))
1125 .unwrap()
1126 == WorkerResponse::GetPortStateOk(PortState::Empty(0)),
1127 Duration::from_millis(500)
1128 ));
1129 port_b.lock().signal_ready();
1130 assert!(poll_until_with_timeout(
1131 || client
1132 .send_worker_command(WorkerCommand::GetPortState(upstream_addr_b))
1133 .unwrap()
1134 == WorkerResponse::GetPortStateOk(PortState::Empty(0)),
1135 Duration::from_millis(500)
1136 ));
1137 port_c.lock().signal_ready();
1138 assert!(poll_until_with_timeout(
1139 || client
1140 .send_worker_command(WorkerCommand::GetPortState(upstream_addr_c))
1141 .unwrap()
1142 == WorkerResponse::GetPortStateOk(PortState::Empty(0)),
1143 Duration::from_millis(500)
1144 ));
1145 assert_eq!(
1147 WorkerResponse::GetEmptyPortOk(upstream_addr_b),
1148 client
1149 .send_worker_command(WorkerCommand::GetEmptyPort)
1150 .unwrap()
1151 );
1152 assert_eq!(
1153 WorkerResponse::SignalOk,
1154 client
1155 .send_worker_command(WorkerCommand::SignalHotPlug(hotplug_command_b))
1156 .unwrap()
1157 );
1158 assert_eq!(
1160 WorkerResponse::GetEmptyPortOk(upstream_addr_a),
1161 client
1162 .send_worker_command(WorkerCommand::GetEmptyPort)
1163 .unwrap()
1164 );
1165 assert_eq!(
1166 WorkerResponse::SignalOk,
1167 client
1168 .send_worker_command(WorkerCommand::SignalHotPlug(hotplug_command_a))
1169 .unwrap()
1170 );
1171 assert_eq!(
1173 WorkerResponse::GetEmptyPortOk(upstream_addr_c),
1174 client
1175 .send_worker_command(WorkerCommand::GetEmptyPort)
1176 .unwrap()
1177 );
1178 assert_eq!(
1179 WorkerResponse::SignalOk,
1180 client
1181 .send_worker_command(WorkerCommand::SignalHotPlug(hotplug_command_c))
1182 .unwrap()
1183 );
1184 if let WorkerResponse::InvalidCommand(_) = client
1186 .send_worker_command(WorkerCommand::GetEmptyPort)
1187 .unwrap()
1188 {
1189 } else {
1191 unreachable!();
1192 }
1193 assert_eq!(
1195 WorkerResponse::SignalOk,
1196 client
1197 .send_worker_command(WorkerCommand::SignalHotUnplug(upstream_addr_a))
1198 .unwrap()
1199 );
1200 assert_eq!(
1201 WorkerResponse::GetEmptyPortOk(upstream_addr_a),
1202 client
1203 .send_worker_command(WorkerCommand::GetEmptyPort)
1204 .unwrap()
1205 );
1206 assert_eq!(
1208 WorkerResponse::GetPortStateOk(PortState::Empty(2)),
1209 client
1210 .send_worker_command(WorkerCommand::GetPortState(upstream_addr_a))
1211 .unwrap()
1212 );
1213 }
1214
1215 #[test]
1216 fn worker_port_state_transitions() {
1217 let (rootbus_controller, _rootbus_recvr) = mpsc::channel();
1218 let client = WorkerClient::new(rootbus_controller).unwrap();
1219 let upstream_addr = PciAddress {
1220 bus: 0,
1221 dev: 1,
1222 func: 1,
1223 };
1224 let bus = 2;
1225 let downstream_addr = PciAddress {
1226 bus,
1227 dev: 0,
1228 func: 0,
1229 };
1230 let hotplug_key = HotPlugKey::GuestDevice {
1231 guest_addr: downstream_addr,
1232 };
1233 let device = GuestDeviceStub {
1234 pci_addr: downstream_addr,
1235 key: hotplug_key,
1236 device: Arc::new(Mutex::new(MockDevice::new())),
1237 };
1238 let hotplug_command = SignalHotPlugCommand::new(upstream_addr, [device].to_vec()).unwrap();
1239 let port = new_port(bus);
1240 assert_eq!(
1241 WorkerResponse::AddPortOk,
1242 client
1243 .send_worker_command(WorkerCommand::AddPort(
1244 upstream_addr,
1245 PortWorkerStub::new(port.clone(), bus).unwrap()
1246 ))
1247 .unwrap()
1248 );
1249 port.lock().signal_ready();
1250 assert!(poll_until_with_timeout(
1251 || client
1252 .send_worker_command(WorkerCommand::GetPortState(upstream_addr))
1253 .unwrap()
1254 == WorkerResponse::GetPortStateOk(PortState::Empty(0)),
1255 Duration::from_millis(500)
1256 ));
1257 assert_eq!(
1258 WorkerResponse::SignalOk,
1259 client
1260 .send_worker_command(WorkerCommand::SignalHotPlug(hotplug_command.clone()))
1261 .unwrap()
1262 );
1263 assert!(poll_until_with_timeout(
1264 || client
1265 .send_worker_command(WorkerCommand::GetPortState(upstream_addr))
1266 .unwrap()
1267 == WorkerResponse::GetPortStateOk(PortState::Occupied(1)),
1268 Duration::from_millis(500)
1269 ));
1270 assert_eq!(
1271 WorkerResponse::SignalOk,
1272 client
1273 .send_worker_command(WorkerCommand::SignalHotUnplug(upstream_addr))
1274 .unwrap()
1275 );
1276 assert!(poll_until_with_timeout(
1277 || client
1278 .send_worker_command(WorkerCommand::GetPortState(upstream_addr))
1279 .unwrap()
1280 == WorkerResponse::GetPortStateOk(PortState::Empty(2)),
1281 Duration::from_millis(500)
1282 ));
1283 assert_eq!(
1284 WorkerResponse::SignalOk,
1285 client
1286 .send_worker_command(WorkerCommand::SignalHotPlug(hotplug_command.clone()))
1287 .unwrap()
1288 );
1289 assert!(poll_until_with_timeout(
1290 || client
1291 .send_worker_command(WorkerCommand::GetPortState(upstream_addr))
1292 .unwrap()
1293 == WorkerResponse::GetPortStateOk(PortState::Occupied(3)),
1294 Duration::from_millis(500)
1295 ));
1296 port.lock().signal_cc();
1297 assert!(poll_until_with_timeout(
1298 || client
1299 .send_worker_command(WorkerCommand::GetPortState(upstream_addr))
1300 .unwrap()
1301 == WorkerResponse::GetPortStateOk(PortState::Occupied(2)),
1302 Duration::from_millis(500)
1303 ));
1304 assert_eq!(
1305 WorkerResponse::SignalOk,
1306 client
1307 .send_worker_command(WorkerCommand::SignalHotUnplug(upstream_addr))
1308 .unwrap()
1309 );
1310 assert!(poll_until_with_timeout(
1313 || client
1314 .send_worker_command(WorkerCommand::GetPortState(upstream_addr))
1315 .unwrap()
1316 == WorkerResponse::GetPortStateOk(PortState::Empty(1)),
1317 Duration::from_millis(500)
1318 ));
1319 port.lock().signal_cc();
1320 assert!(poll_until_with_timeout(
1321 || client
1322 .send_worker_command(WorkerCommand::GetPortState(upstream_addr))
1323 .unwrap()
1324 == WorkerResponse::GetPortStateOk(PortState::Empty(0)),
1325 Duration::from_millis(500)
1326 ));
1327 }
1328
1329 #[test]
1330 fn worker_port_early_plug_state_transitions() {
1331 let (rootbus_controller, _rootbus_recvr) = mpsc::channel();
1332 let client = WorkerClient::new(rootbus_controller).unwrap();
1333 let upstream_addr = PciAddress {
1334 bus: 0,
1335 dev: 1,
1336 func: 1,
1337 };
1338 let bus = 2;
1339 let downstream_addr = PciAddress {
1340 bus,
1341 dev: 0,
1342 func: 0,
1343 };
1344 let hotplug_key = HotPlugKey::GuestDevice {
1345 guest_addr: downstream_addr,
1346 };
1347 let device = GuestDeviceStub {
1348 pci_addr: downstream_addr,
1349 key: hotplug_key,
1350 device: Arc::new(Mutex::new(MockDevice::new())),
1351 };
1352 let hotplug_command = SignalHotPlugCommand::new(upstream_addr, [device].to_vec()).unwrap();
1353 let port = new_port(bus);
1354 assert_eq!(
1355 WorkerResponse::AddPortOk,
1356 client
1357 .send_worker_command(WorkerCommand::AddPort(
1358 upstream_addr,
1359 PortWorkerStub::new(port.clone(), bus).unwrap()
1360 ))
1361 .unwrap()
1362 );
1363 assert!(poll_until_with_timeout(
1364 || client
1365 .send_worker_command(WorkerCommand::GetPortState(upstream_addr))
1366 .unwrap()
1367 == WorkerResponse::GetPortStateOk(PortState::EmptyNotReady),
1368 Duration::from_millis(500)
1369 ));
1370 assert_eq!(
1371 WorkerResponse::SignalOk,
1372 client
1373 .send_worker_command(WorkerCommand::SignalHotPlug(hotplug_command.clone()))
1374 .unwrap()
1375 );
1376 assert!(poll_until_with_timeout(
1377 || client
1378 .send_worker_command(WorkerCommand::GetPortState(upstream_addr))
1379 .unwrap()
1380 == WorkerResponse::GetPortStateOk(PortState::OccupiedNotReady),
1381 Duration::from_millis(500)
1382 ));
1383 port.lock().signal_ready();
1384 assert!(poll_until_with_timeout(
1385 || client
1386 .send_worker_command(WorkerCommand::GetPortState(upstream_addr))
1387 .unwrap()
1388 == WorkerResponse::GetPortStateOk(PortState::Occupied(1)),
1389 Duration::from_millis(500)
1390 ));
1391 port.lock().signal_cc();
1392 assert!(poll_until_with_timeout(
1393 || client
1394 .send_worker_command(WorkerCommand::GetPortState(upstream_addr))
1395 .unwrap()
1396 == WorkerResponse::GetPortStateOk(PortState::Occupied(0)),
1397 Duration::from_millis(500)
1398 ));
1399 }
1400}