1 // Copyright 2024 Red Hat, Inc. 2 // Author(s): Paolo Bonzini <pbonzini@redhat.com> 3 // SPDX-License-Identifier: GPL-2.0-or-later 4 5 //! Bindings for interrupt sources 6 7 use std::{ 8 ffi::{c_int, CStr}, 9 marker::PhantomData, 10 ptr, 11 }; 12 13 use crate::{ 14 bindings::{self, qemu_set_irq}, 15 cell::Opaque, 16 prelude::*, 17 qom::ObjectClass, 18 }; 19 20 /// An opaque wrapper around [`bindings::IRQState`]. 21 #[repr(transparent)] 22 #[derive(Debug, qemu_api_macros::Wrapper)] 23 pub struct IRQState(Opaque<bindings::IRQState>); 24 25 /// Interrupt sources are used by devices to pass changes to a value (typically 26 /// a boolean). The interrupt sink is usually an interrupt controller or 27 /// GPIO controller. 28 /// 29 /// As far as devices are concerned, interrupt sources are always active-high: 30 /// for example, `InterruptSource<bool>`'s [`raise`](InterruptSource::raise) 31 /// method sends a `true` value to the sink. If the guest has to see a 32 /// different polarity, that change is performed by the board between the 33 /// device and the interrupt controller. 34 /// 35 /// Interrupts are implemented as a pointer to the interrupt "sink", which has 36 /// type [`IRQState`]. A device exposes its source as a QOM link property using 37 /// a function such as [`SysBusDeviceMethods::init_irq`], and 38 /// initially leaves the pointer to a NULL value, representing an unconnected 39 /// interrupt. To connect it, whoever creates the device fills the pointer with 40 /// the sink's `IRQState *`, for example using `sysbus_connect_irq`. Because 41 /// devices are generally shared objects, interrupt sources are an example of 42 /// the interior mutability pattern. 43 /// 44 /// Interrupt sources can only be triggered under the Big QEMU Lock; `BqlCell` 45 /// allows access from whatever thread has it. 46 #[derive(Debug)] 47 #[repr(transparent)] 48 pub struct InterruptSource<T = bool> 49 where 50 c_int: From<T>, 51 { 52 cell: BqlCell<*mut bindings::IRQState>, 53 _marker: PhantomData<T>, 54 } 55 56 // SAFETY: the implementation asserts via `BqlCell` that the BQL is taken 57 unsafe impl<T> Sync for InterruptSource<T> where c_int: From<T> {} 58 59 impl InterruptSource<bool> { 60 /// Send a low (`false`) value to the interrupt sink. 61 pub fn lower(&self) { 62 self.set(false); 63 } 64 65 /// Send a high-low pulse to the interrupt sink. 66 pub fn pulse(&self) { 67 self.set(true); 68 self.set(false); 69 } 70 71 /// Send a high (`true`) value to the interrupt sink. 72 pub fn raise(&self) { 73 self.set(true); 74 } 75 } 76 77 impl<T> InterruptSource<T> 78 where 79 c_int: From<T>, 80 { 81 /// Send `level` to the interrupt sink. 82 pub fn set(&self, level: T) { 83 let ptr = self.cell.get(); 84 // SAFETY: the pointer is retrieved under the BQL and remains valid 85 // until the BQL is released, which is after qemu_set_irq() is entered. 86 unsafe { 87 qemu_set_irq(ptr, level.into()); 88 } 89 } 90 91 pub(crate) const fn as_ptr(&self) -> *mut *mut bindings::IRQState { 92 self.cell.as_ptr() 93 } 94 95 pub(crate) const fn slice_as_ptr(slice: &[Self]) -> *mut *mut bindings::IRQState { 96 assert!(!slice.is_empty()); 97 slice[0].as_ptr() 98 } 99 } 100 101 impl Default for InterruptSource { 102 fn default() -> Self { 103 InterruptSource { 104 cell: BqlCell::new(ptr::null_mut()), 105 _marker: PhantomData, 106 } 107 } 108 } 109 110 unsafe impl ObjectType for IRQState { 111 type Class = ObjectClass; 112 const TYPE_NAME: &'static CStr = 113 unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_IRQ) }; 114 } 115 qom_isa!(IRQState: Object); 116