xref: /qemu/rust/qemu-api/src/irq.rs (revision e4fb0be1d1d6b67df7709d84d16133b64f455ce8)
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