xref: /qemu/rust/qemu-api/src/irq.rs (revision d31f1185fb029b44c439a6961a6cb087df6567d9)
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     pub(crate) const fn slice_as_ptr(slice: &[Self]) -> *mut *mut IRQState {
88         assert!(!slice.is_empty());
89         slice[0].as_ptr()
90     }
91 }
92 
93 impl Default for InterruptSource {
94     fn default() -> Self {
95         InterruptSource {
96             cell: BqlCell::new(ptr::null_mut()),
97             _marker: PhantomData,
98         }
99     }
100 }
101 
102 unsafe impl ObjectType for IRQState {
103     type Class = ObjectClass;
104     const TYPE_NAME: &'static CStr =
105         unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_IRQ) };
106 }
107 qom_isa!(IRQState: Object);
108