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