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