Struct devices::irqchip::UserspaceIrqChip
source · pub struct UserspaceIrqChip<V: VcpuX86_64> {Show 13 fields
pub vcpus: Arc<Mutex<Vec<Option<V>>>>,
routes: Arc<Mutex<Routes>>,
pit: Arc<Mutex<Pit>>,
pic: Arc<Mutex<Pic>>,
ioapic: Arc<Mutex<Ioapic>>,
ioapic_pins: usize,
pub apics: Vec<Arc<Mutex<Apic>>>,
waiters: Vec<Arc<Waiter>>,
timer_descriptors: Vec<Descriptor>,
delayed_ioapic_irq_events: Arc<Mutex<DelayedIoApicIrqEvents>>,
irq_events: Arc<Mutex<Vec<Option<IrqEvent>>>>,
dropper: Arc<Mutex<Dropper>>,
activated: bool,
}
Expand description
An IrqChip
with all interrupt devices emulated in userspace. UserspaceIrqChip
works with
any hypervisor, but only supports x86.
Fields§
§vcpus: Arc<Mutex<Vec<Option<V>>>>
§routes: Arc<Mutex<Routes>>
§pit: Arc<Mutex<Pit>>
§pic: Arc<Mutex<Pic>>
§ioapic: Arc<Mutex<Ioapic>>
§ioapic_pins: usize
§apics: Vec<Arc<Mutex<Apic>>>
§waiters: Vec<Arc<Waiter>>
§timer_descriptors: Vec<Descriptor>
§delayed_ioapic_irq_events: Arc<Mutex<DelayedIoApicIrqEvents>>
Delayed ioapic irq object, that contains the delayed events because the ioapic was locked when service_irq was called on the irqchip. This prevents deadlocks when a Vcpu thread has locked the ioapic and the ioapic sends a AddMsiRoute signal to the main thread (which itself may be busy trying to call service_irq).
§Note:
This lock may be locked by itself to access the DelayedIoApicIrqEvents
. If accessed in
conjunction with the irq_events
field, that lock should be taken first to prevent
deadlocks stemming from lock-ordering issues.
irq_events: Arc<Mutex<Vec<Option<IrqEvent>>>>
§dropper: Arc<Mutex<Dropper>>
§activated: bool
Implementations§
source§impl<V: VcpuX86_64 + 'static> UserspaceIrqChip<V>
impl<V: VcpuX86_64 + 'static> UserspaceIrqChip<V>
sourcepub fn new(
num_vcpus: usize,
irq_tube: Tube,
ioapic_pins: Option<usize>
) -> Result<Self>
pub fn new( num_vcpus: usize, irq_tube: Tube, ioapic_pins: Option<usize> ) -> Result<Self>
Constructs a new UserspaceIrqChip
.
sourcepub fn new_with_clock(
num_vcpus: usize,
irq_tube: Tube,
ioapic_pins: Option<usize>,
clock: Arc<Mutex<Clock>>
) -> Result<Self>
pub fn new_with_clock( num_vcpus: usize, irq_tube: Tube, ioapic_pins: Option<usize>, clock: Arc<Mutex<Clock>> ) -> Result<Self>
Constructs a new UserspaceIrqChip
, with a clock. Used for testing.
sourcefn handle_msg(&self, msg: ApicBusMsg)
fn handle_msg(&self, msg: ApicBusMsg)
Handles a message from an APIC.
sourcefn send_msi(&self, addr: u32, data: u32)
fn send_msi(&self, addr: u32, data: u32)
Sends a Message Signaled Interrupt to one or more APICs. MSIs are a 64-bit address and 32-bit data, but in the Intel spec we’re implementing, only the low 32 bits of the address are used.
pub fn send_irq_to_apic(&self, id: usize, irq: &InterruptData)
sourcepub fn send_irq_to_apics(&self, irq: &Interrupt)
pub fn send_irq_to_apics(&self, irq: &Interrupt)
Sends an interrupt to one or more APICs. Used for sending MSIs and IPIs.
sourcefn is_runnable(&self, vcpu_id: usize) -> bool
fn is_runnable(&self, vcpu_id: usize) -> bool
Checks if the specified VCPU is in a runnable state.
source§impl<V: VcpuX86_64 + 'static> UserspaceIrqChip<V>
impl<V: VcpuX86_64 + 'static> UserspaceIrqChip<V>
fn register_irq_event( &mut self, irq: u32, irq_event: &Event, resample_event: Option<&Event>, source: IrqEventSource ) -> Result<Option<IrqEventIndex>>
fn unregister_irq_event(&mut self, irq: u32, irq_event: &Event) -> Result<()>
Trait Implementations§
source§impl<V: VcpuX86_64 + 'static> BusDevice for UserspaceIrqChip<V>
impl<V: VcpuX86_64 + 'static> BusDevice for UserspaceIrqChip<V>
source§fn debug_label(&self) -> String
fn debug_label(&self) -> String
source§fn device_id(&self) -> DeviceId
fn device_id(&self) -> DeviceId
source§fn read(&mut self, offset: BusAccessInfo, data: &mut [u8])
fn read(&mut self, offset: BusAccessInfo, data: &mut [u8])
offset
from this devicesource§fn write(&mut self, offset: BusAccessInfo, data: &[u8])
fn write(&mut self, offset: BusAccessInfo, data: &[u8])
offset
into this devicesource§fn config_register_write(
&mut self,
reg_idx: usize,
offset: u64,
data: &[u8]
) -> ConfigWriteResult
fn config_register_write( &mut self, reg_idx: usize, offset: u64, data: &[u8] ) -> ConfigWriteResult
source§fn config_register_read(&self, reg_idx: usize) -> u32
fn config_register_read(&self, reg_idx: usize) -> u32
source§fn init_pci_config_mapping(
&mut self,
shmem: &SharedMemory,
base: usize,
len: usize
) -> bool
fn init_pci_config_mapping( &mut self, shmem: &SharedMemory, base: usize, len: usize ) -> bool
source§fn virtual_config_register_write(&mut self, reg_idx: usize, value: u32)
fn virtual_config_register_write(&mut self, reg_idx: usize, value: u32)
source§fn virtual_config_register_read(&self, reg_idx: usize) -> u32
fn virtual_config_register_read(&self, reg_idx: usize) -> u32
source§fn on_sandboxed(&mut self)
fn on_sandboxed(&mut self)
source§fn get_ranges(&self) -> Vec<(BusRange, BusType)>
fn get_ranges(&self) -> Vec<(BusRange, BusType)>
source§fn destroy_device(&mut self)
fn destroy_device(&mut self)
source§impl<V: VcpuX86_64 + 'static> BusDeviceSync for UserspaceIrqChip<V>
impl<V: VcpuX86_64 + 'static> BusDeviceSync for UserspaceIrqChip<V>
fn read(&self, info: BusAccessInfo, data: &mut [u8])
fn write(&self, info: BusAccessInfo, data: &[u8])
fn snapshot_sync(&self) -> Result<Value>
source§fn sleep_sync(&self) -> Result<()>
fn sleep_sync(&self) -> Result<()>
source§impl<V: VcpuX86_64 + 'static> IrqChip for UserspaceIrqChip<V>
impl<V: VcpuX86_64 + 'static> IrqChip for UserspaceIrqChip<V>
source§fn service_irq_event(&mut self, event_index: IrqEventIndex) -> Result<()>
fn service_irq_event(&mut self, event_index: IrqEventIndex) -> Result<()>
Services an IRQ event by asserting then deasserting an IRQ line. The associated Event that triggered the irq event will be read from. If the irq is associated with a resample Event, then the deassert will only happen after an EOI is broadcast for a vector associated with the irq line. For UserspaceIrqChip, this function identifies the destination(s) of the irq: PIC, IOAPIC, or APIC (MSI). If it’s a PIC or IOAPIC route, we attempt to call service_irq on those chips. If the IOAPIC is unable to be immediately locked, we add the irq to the delayed_ioapic_irq_events (though we still read from the Event that triggered the irq event). If it’s an MSI route, we call send_msi to decode the MSI and send it to the destination APIC(s).
source§fn broadcast_eoi(&self, vector: u8) -> Result<()>
fn broadcast_eoi(&self, vector: u8) -> Result<()>
Broadcasts an end of interrupt. For UserspaceIrqChip this sends the EOI to the ioapic.
source§fn inject_interrupts(&self, vcpu: &dyn Vcpu) -> Result<()>
fn inject_interrupts(&self, vcpu: &dyn Vcpu) -> Result<()>
Injects any pending interrupts for vcpu
.
For UserspaceIrqChip this:
- Injects a PIC interrupt, if vcpu_id is 0 and vcpu is ready for interrupt
- Injects an APIC fixed interrupt, if vcpu is ready for interrupt and PIC didn’t inject
- Injects APIC NMIs
- Handles APIC INIT IPIs
- Handles APIC SIPIs
- Requests an interrupt window, if PIC or APIC still has pending interrupts for this vcpu
source§fn halted(&self, vcpu_id: usize)
fn halted(&self, vcpu_id: usize)
Notifies the irq chip that the specified VCPU has executed a halt instruction.
For UserspaceIrqChip
, it sets the APIC’s mp_state to MPState::Halted
.
source§fn wait_until_runnable(&self, vcpu: &dyn Vcpu) -> Result<VcpuRunState>
fn wait_until_runnable(&self, vcpu: &dyn Vcpu) -> Result<VcpuRunState>
Blocks until vcpu
is in a runnable state or until interrupted by
IrqChip::kick_halted_vcpus
. Returns VcpuRunState::Runnable if vcpu is runnable, or
VcpuRunState::Interruptedif the wait was interrupted. For
UserspaceIrqChip, if the APIC isn't
MPState::Runnable`, sleep until there are new
interrupts pending on the APIC, inject the interrupts, and go back to sleep if still not
runnable.
source§fn kick_halted_vcpus(&self)
fn kick_halted_vcpus(&self)
Makes unrunnable VCPUs return immediately from wait_until_runnable
.
For UserspaceIrqChip, every vcpu gets kicked so its current or next call to
wait_until_runnable
will immediately return false. After that one kick, subsequent
wait_until_runnable
calls go back to waiting for runnability normally.
source§fn process_delayed_irq_events(&mut self) -> Result<()>
fn process_delayed_irq_events(&mut self) -> Result<()>
The UserspaceIrqChip’s ioapic may be locked because a vcpu thread is currently writing to the ioapic, and the ioapic may be blocking on adding MSI routes, which requires blocking tube communication back to the main thread. Thus, we do not want the main thread to block on a locked ioapic, so any irqs that could not be serviced because the ioapic could not be immediately locked are added to the delayed_ioapic_irq_events Vec. This function processes each delayed event in the vec each time it’s called. If the ioapic is still locked, we keep the queued irqs for the next time this function is called.
source§fn add_vcpu(&mut self, vcpu_id: usize, vcpu: &dyn Vcpu) -> Result<()>
fn add_vcpu(&mut self, vcpu_id: usize, vcpu: &dyn Vcpu) -> Result<()>
source§fn register_edge_irq_event(
&mut self,
irq: u32,
irq_event: &IrqEdgeEvent,
source: IrqEventSource
) -> Result<Option<IrqEventIndex>>
fn register_edge_irq_event( &mut self, irq: u32, irq_event: &IrqEdgeEvent, source: IrqEventSource ) -> Result<Option<IrqEventIndex>>
source§fn unregister_edge_irq_event(
&mut self,
irq: u32,
irq_event: &IrqEdgeEvent
) -> Result<()>
fn unregister_edge_irq_event( &mut self, irq: u32, irq_event: &IrqEdgeEvent ) -> Result<()>
source§fn register_level_irq_event(
&mut self,
irq: u32,
irq_event: &IrqLevelEvent,
source: IrqEventSource
) -> Result<Option<IrqEventIndex>>
fn register_level_irq_event( &mut self, irq: u32, irq_event: &IrqLevelEvent, source: IrqEventSource ) -> Result<Option<IrqEventIndex>>
source§fn unregister_level_irq_event(
&mut self,
irq: u32,
irq_event: &IrqLevelEvent
) -> Result<()>
fn unregister_level_irq_event( &mut self, irq: u32, irq_event: &IrqLevelEvent ) -> Result<()>
source§fn route_irq(&mut self, route: IrqRoute) -> Result<()>
fn route_irq(&mut self, route: IrqRoute) -> Result<()>
source§fn set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()>
fn set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()>
source§fn irq_event_tokens(
&self
) -> Result<Vec<(IrqEventIndex, IrqEventSource, Event)>>
fn irq_event_tokens( &self ) -> Result<Vec<(IrqEventIndex, IrqEventSource, Event)>>
source§fn service_irq(&mut self, irq: u32, level: bool) -> Result<()>
fn service_irq(&mut self, irq: u32, level: bool) -> Result<()>
source§fn get_mp_state(&self, vcpu_id: usize) -> Result<MPState>
fn get_mp_state(&self, vcpu_id: usize) -> Result<MPState>
source§fn set_mp_state(&mut self, vcpu_id: usize, state: &MPState) -> Result<()>
fn set_mp_state(&mut self, vcpu_id: usize, state: &MPState) -> Result<()>
source§fn try_clone(&self) -> Result<Self>
fn try_clone(&self) -> Result<Self>
source§fn finalize_devices(
&mut self,
resources: &mut SystemAllocator,
io_bus: &Bus,
mmio_bus: &Bus
) -> Result<()>
fn finalize_devices( &mut self, resources: &mut SystemAllocator, io_bus: &Bus, mmio_bus: &Bus ) -> Result<()>
source§fn irq_delayed_event_token(&self) -> Result<Option<Event>>
fn irq_delayed_event_token(&self) -> Result<Option<Event>>
source§fn check_capability(&self, c: IrqChipCap) -> bool
fn check_capability(&self, c: IrqChipCap) -> bool
IrqChipCap
is available.source§impl<V: VcpuX86_64 + 'static> IrqChipX86_64 for UserspaceIrqChip<V>
impl<V: VcpuX86_64 + 'static> IrqChipX86_64 for UserspaceIrqChip<V>
source§fn lapic_frequency(&self) -> u32
fn lapic_frequency(&self) -> u32
Get the lapic frequency in Hz
source§fn pit_uses_speaker_port(&self) -> bool
fn pit_uses_speaker_port(&self) -> bool
Returns true if the PIT uses port 0x61 for the PC speaker, false if 0x61 is unused. devices::Pit uses 0x61.
fn try_box_clone(&self) -> Result<Box<dyn IrqChipX86_64>>
fn as_irq_chip(&self) -> &dyn IrqChip
fn as_irq_chip_mut(&mut self) -> &mut dyn IrqChip
source§fn get_pic_state(&self, select: PicSelect) -> Result<PicState>
fn get_pic_state(&self, select: PicSelect) -> Result<PicState>
source§fn set_pic_state(&mut self, select: PicSelect, state: &PicState) -> Result<()>
fn set_pic_state(&mut self, select: PicSelect, state: &PicState) -> Result<()>
source§fn get_ioapic_state(&self) -> Result<IoapicState>
fn get_ioapic_state(&self) -> Result<IoapicState>
source§fn set_ioapic_state(&mut self, state: &IoapicState) -> Result<()>
fn set_ioapic_state(&mut self, state: &IoapicState) -> Result<()>
source§fn get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState>
fn get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState>
source§fn set_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()>
fn set_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()>
source§fn snapshot_chip_specific(&self) -> Result<Value>
fn snapshot_chip_specific(&self) -> Result<Value>
source§impl<V: VcpuX86_64 + 'static> Suspendable for UserspaceIrqChip<V>
impl<V: VcpuX86_64 + 'static> Suspendable for UserspaceIrqChip<V>
source§fn sleep(&mut self) -> Result<()>
fn sleep(&mut self) -> Result<()>
source§fn wake(&mut self) -> Result<()>
fn wake(&mut self) -> Result<()>
Auto Trait Implementations§
impl<V> RefUnwindSafe for UserspaceIrqChip<V>
impl<V> Send for UserspaceIrqChip<V>
impl<V> Sync for UserspaceIrqChip<V>
impl<V> Unpin for UserspaceIrqChip<V>
impl<V> UnwindSafe for UserspaceIrqChip<V>
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.