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