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