xref: /qemu/rust/qemu-api/src/chardev.rs (revision 2d0050cbe27fed5233561451e6de64af5ecb6571)
1a22bd55fSPaolo Bonzini // Copyright 2024 Red Hat, Inc.
2a22bd55fSPaolo Bonzini // Author(s): Paolo Bonzini <pbonzini@redhat.com>
3a22bd55fSPaolo Bonzini // SPDX-License-Identifier: GPL-2.0-or-later
4a22bd55fSPaolo Bonzini 
5a22bd55fSPaolo Bonzini //! Bindings for character devices
6*2d0050cbSPaolo Bonzini //!
7*2d0050cbSPaolo Bonzini //! Character devices in QEMU can run under the big QEMU lock or in a separate
8*2d0050cbSPaolo Bonzini //! `GMainContext`. Here we only support the former, because the bindings
9*2d0050cbSPaolo Bonzini //! enforce that the BQL is taken whenever the functions in [`CharBackend`] are
10*2d0050cbSPaolo Bonzini //! called.
11a22bd55fSPaolo Bonzini 
12*2d0050cbSPaolo Bonzini use std::{
13*2d0050cbSPaolo Bonzini     ffi::CStr,
14*2d0050cbSPaolo Bonzini     fmt::{self, Debug},
15*2d0050cbSPaolo Bonzini     io::{self, ErrorKind, Write},
16*2d0050cbSPaolo Bonzini     marker::PhantomPinned,
17*2d0050cbSPaolo Bonzini     os::raw::{c_int, c_void},
18*2d0050cbSPaolo Bonzini     ptr::addr_of_mut,
19*2d0050cbSPaolo Bonzini     slice,
20*2d0050cbSPaolo Bonzini };
21a22bd55fSPaolo Bonzini 
22*2d0050cbSPaolo Bonzini use crate::{
23*2d0050cbSPaolo Bonzini     bindings,
24*2d0050cbSPaolo Bonzini     callbacks::FnCall,
25*2d0050cbSPaolo Bonzini     cell::{BqlRefMut, Opaque},
26*2d0050cbSPaolo Bonzini     prelude::*,
27*2d0050cbSPaolo Bonzini };
28a22bd55fSPaolo Bonzini 
2948627510SPaolo Bonzini /// A safe wrapper around [`bindings::Chardev`].
3048627510SPaolo Bonzini #[repr(transparent)]
3148627510SPaolo Bonzini #[derive(qemu_api_macros::Wrapper)]
3248627510SPaolo Bonzini pub struct Chardev(Opaque<bindings::Chardev>);
3348627510SPaolo Bonzini 
34a22bd55fSPaolo Bonzini pub type ChardevClass = bindings::ChardevClass;
35*2d0050cbSPaolo Bonzini pub type Event = bindings::QEMUChrEvent;
36*2d0050cbSPaolo Bonzini 
37*2d0050cbSPaolo Bonzini /// A safe wrapper around [`bindings::CharBackend`], denoting the character
38*2d0050cbSPaolo Bonzini /// back-end that is used for example by a device.  Compared to the
39*2d0050cbSPaolo Bonzini /// underlying C struct it adds BQL protection, and is marked as pinned
40*2d0050cbSPaolo Bonzini /// because the QOM object ([`bindings::Chardev`]) contains a pointer to
41*2d0050cbSPaolo Bonzini /// the `CharBackend`.
42*2d0050cbSPaolo Bonzini pub struct CharBackend {
43*2d0050cbSPaolo Bonzini     inner: BqlRefCell<bindings::CharBackend>,
44*2d0050cbSPaolo Bonzini     _pin: PhantomPinned,
45*2d0050cbSPaolo Bonzini }
46*2d0050cbSPaolo Bonzini 
47*2d0050cbSPaolo Bonzini impl Write for BqlRefMut<'_, bindings::CharBackend> {
48*2d0050cbSPaolo Bonzini     fn flush(&mut self) -> io::Result<()> {
49*2d0050cbSPaolo Bonzini         Ok(())
50*2d0050cbSPaolo Bonzini     }
51*2d0050cbSPaolo Bonzini 
52*2d0050cbSPaolo Bonzini     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
53*2d0050cbSPaolo Bonzini         let chr: &mut bindings::CharBackend = self;
54*2d0050cbSPaolo Bonzini 
55*2d0050cbSPaolo Bonzini         let len = buf.len().try_into().unwrap();
56*2d0050cbSPaolo Bonzini         let r = unsafe { bindings::qemu_chr_fe_write(addr_of_mut!(*chr), buf.as_ptr(), len) };
57*2d0050cbSPaolo Bonzini         errno::into_io_result(r).map(|cnt| cnt as usize)
58*2d0050cbSPaolo Bonzini     }
59*2d0050cbSPaolo Bonzini 
60*2d0050cbSPaolo Bonzini     fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
61*2d0050cbSPaolo Bonzini         let chr: &mut bindings::CharBackend = self;
62*2d0050cbSPaolo Bonzini 
63*2d0050cbSPaolo Bonzini         let len = buf.len().try_into().unwrap();
64*2d0050cbSPaolo Bonzini         let r = unsafe { bindings::qemu_chr_fe_write_all(addr_of_mut!(*chr), buf.as_ptr(), len) };
65*2d0050cbSPaolo Bonzini         errno::into_io_result(r).and_then(|cnt| {
66*2d0050cbSPaolo Bonzini             if cnt as usize == buf.len() {
67*2d0050cbSPaolo Bonzini                 Ok(())
68*2d0050cbSPaolo Bonzini             } else {
69*2d0050cbSPaolo Bonzini                 Err(ErrorKind::WriteZero.into())
70*2d0050cbSPaolo Bonzini             }
71*2d0050cbSPaolo Bonzini         })
72*2d0050cbSPaolo Bonzini     }
73*2d0050cbSPaolo Bonzini }
74*2d0050cbSPaolo Bonzini 
75*2d0050cbSPaolo Bonzini impl Debug for CharBackend {
76*2d0050cbSPaolo Bonzini     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77*2d0050cbSPaolo Bonzini         // SAFETY: accessed just to print the values
78*2d0050cbSPaolo Bonzini         let chr = self.inner.as_ptr();
79*2d0050cbSPaolo Bonzini         Debug::fmt(unsafe { &*chr }, f)
80*2d0050cbSPaolo Bonzini     }
81*2d0050cbSPaolo Bonzini }
82*2d0050cbSPaolo Bonzini 
83*2d0050cbSPaolo Bonzini // FIXME: use something like PinnedDrop from the pinned_init crate
84*2d0050cbSPaolo Bonzini impl Drop for CharBackend {
85*2d0050cbSPaolo Bonzini     fn drop(&mut self) {
86*2d0050cbSPaolo Bonzini         self.disable_handlers();
87*2d0050cbSPaolo Bonzini     }
88*2d0050cbSPaolo Bonzini }
89*2d0050cbSPaolo Bonzini 
90*2d0050cbSPaolo Bonzini impl CharBackend {
91*2d0050cbSPaolo Bonzini     /// Enable the front-end's character device handlers, if there is an
92*2d0050cbSPaolo Bonzini     /// associated `Chardev`.
93*2d0050cbSPaolo Bonzini     pub fn enable_handlers<
94*2d0050cbSPaolo Bonzini         'chardev,
95*2d0050cbSPaolo Bonzini         'owner: 'chardev,
96*2d0050cbSPaolo Bonzini         T,
97*2d0050cbSPaolo Bonzini         CanReceiveFn: for<'a> FnCall<(&'a T,), u32>,
98*2d0050cbSPaolo Bonzini         ReceiveFn: for<'a, 'b> FnCall<(&'a T, &'b [u8])>,
99*2d0050cbSPaolo Bonzini         EventFn: for<'a> FnCall<(&'a T, Event)>,
100*2d0050cbSPaolo Bonzini     >(
101*2d0050cbSPaolo Bonzini         // When "self" is dropped, the handlers are automatically disabled.
102*2d0050cbSPaolo Bonzini         // However, this is not necessarily true if the owner is dropped.
103*2d0050cbSPaolo Bonzini         // So require the owner to outlive the character device.
104*2d0050cbSPaolo Bonzini         &'chardev self,
105*2d0050cbSPaolo Bonzini         owner: &'owner T,
106*2d0050cbSPaolo Bonzini         _can_receive: CanReceiveFn,
107*2d0050cbSPaolo Bonzini         _receive: ReceiveFn,
108*2d0050cbSPaolo Bonzini         _event: EventFn,
109*2d0050cbSPaolo Bonzini     ) {
110*2d0050cbSPaolo Bonzini         unsafe extern "C" fn rust_can_receive_cb<T, F: for<'a> FnCall<(&'a T,), u32>>(
111*2d0050cbSPaolo Bonzini             opaque: *mut c_void,
112*2d0050cbSPaolo Bonzini         ) -> c_int {
113*2d0050cbSPaolo Bonzini             // SAFETY: the values are safe according to the contract of
114*2d0050cbSPaolo Bonzini             // enable_handlers() and qemu_chr_fe_set_handlers()
115*2d0050cbSPaolo Bonzini             let owner: &T = unsafe { &*(opaque.cast::<T>()) };
116*2d0050cbSPaolo Bonzini             let r = F::call((owner,));
117*2d0050cbSPaolo Bonzini             r.try_into().unwrap()
118*2d0050cbSPaolo Bonzini         }
119*2d0050cbSPaolo Bonzini 
120*2d0050cbSPaolo Bonzini         unsafe extern "C" fn rust_receive_cb<T, F: for<'a, 'b> FnCall<(&'a T, &'b [u8])>>(
121*2d0050cbSPaolo Bonzini             opaque: *mut c_void,
122*2d0050cbSPaolo Bonzini             buf: *const u8,
123*2d0050cbSPaolo Bonzini             size: c_int,
124*2d0050cbSPaolo Bonzini         ) {
125*2d0050cbSPaolo Bonzini             // SAFETY: the values are safe according to the contract of
126*2d0050cbSPaolo Bonzini             // enable_handlers() and qemu_chr_fe_set_handlers()
127*2d0050cbSPaolo Bonzini             let owner: &T = unsafe { &*(opaque.cast::<T>()) };
128*2d0050cbSPaolo Bonzini             let buf = unsafe { slice::from_raw_parts(buf, size.try_into().unwrap()) };
129*2d0050cbSPaolo Bonzini             F::call((owner, buf))
130*2d0050cbSPaolo Bonzini         }
131*2d0050cbSPaolo Bonzini 
132*2d0050cbSPaolo Bonzini         unsafe extern "C" fn rust_event_cb<T, F: for<'a> FnCall<(&'a T, Event)>>(
133*2d0050cbSPaolo Bonzini             opaque: *mut c_void,
134*2d0050cbSPaolo Bonzini             event: Event,
135*2d0050cbSPaolo Bonzini         ) {
136*2d0050cbSPaolo Bonzini             // SAFETY: the values are safe according to the contract of
137*2d0050cbSPaolo Bonzini             // enable_handlers() and qemu_chr_fe_set_handlers()
138*2d0050cbSPaolo Bonzini             let owner: &T = unsafe { &*(opaque.cast::<T>()) };
139*2d0050cbSPaolo Bonzini             F::call((owner, event))
140*2d0050cbSPaolo Bonzini         }
141*2d0050cbSPaolo Bonzini 
142*2d0050cbSPaolo Bonzini         let _: () = CanReceiveFn::ASSERT_IS_SOME;
143*2d0050cbSPaolo Bonzini         let receive_cb: Option<unsafe extern "C" fn(*mut c_void, *const u8, c_int)> =
144*2d0050cbSPaolo Bonzini             if ReceiveFn::is_some() {
145*2d0050cbSPaolo Bonzini                 Some(rust_receive_cb::<T, ReceiveFn>)
146*2d0050cbSPaolo Bonzini             } else {
147*2d0050cbSPaolo Bonzini                 None
148*2d0050cbSPaolo Bonzini             };
149*2d0050cbSPaolo Bonzini         let event_cb: Option<unsafe extern "C" fn(*mut c_void, Event)> = if EventFn::is_some() {
150*2d0050cbSPaolo Bonzini             Some(rust_event_cb::<T, EventFn>)
151*2d0050cbSPaolo Bonzini         } else {
152*2d0050cbSPaolo Bonzini             None
153*2d0050cbSPaolo Bonzini         };
154*2d0050cbSPaolo Bonzini 
155*2d0050cbSPaolo Bonzini         let mut chr = self.inner.borrow_mut();
156*2d0050cbSPaolo Bonzini         // SAFETY: the borrow promises that the BQL is taken
157*2d0050cbSPaolo Bonzini         unsafe {
158*2d0050cbSPaolo Bonzini             bindings::qemu_chr_fe_set_handlers(
159*2d0050cbSPaolo Bonzini                 addr_of_mut!(*chr),
160*2d0050cbSPaolo Bonzini                 Some(rust_can_receive_cb::<T, CanReceiveFn>),
161*2d0050cbSPaolo Bonzini                 receive_cb,
162*2d0050cbSPaolo Bonzini                 event_cb,
163*2d0050cbSPaolo Bonzini                 None,
164*2d0050cbSPaolo Bonzini                 (owner as *const T as *mut T).cast::<c_void>(),
165*2d0050cbSPaolo Bonzini                 core::ptr::null_mut(),
166*2d0050cbSPaolo Bonzini                 true,
167*2d0050cbSPaolo Bonzini             );
168*2d0050cbSPaolo Bonzini         }
169*2d0050cbSPaolo Bonzini     }
170*2d0050cbSPaolo Bonzini 
171*2d0050cbSPaolo Bonzini     /// Disable the front-end's character device handlers.
172*2d0050cbSPaolo Bonzini     pub fn disable_handlers(&self) {
173*2d0050cbSPaolo Bonzini         let mut chr = self.inner.borrow_mut();
174*2d0050cbSPaolo Bonzini         // SAFETY: the borrow promises that the BQL is taken
175*2d0050cbSPaolo Bonzini         unsafe {
176*2d0050cbSPaolo Bonzini             bindings::qemu_chr_fe_set_handlers(
177*2d0050cbSPaolo Bonzini                 addr_of_mut!(*chr),
178*2d0050cbSPaolo Bonzini                 None,
179*2d0050cbSPaolo Bonzini                 None,
180*2d0050cbSPaolo Bonzini                 None,
181*2d0050cbSPaolo Bonzini                 None,
182*2d0050cbSPaolo Bonzini                 core::ptr::null_mut(),
183*2d0050cbSPaolo Bonzini                 core::ptr::null_mut(),
184*2d0050cbSPaolo Bonzini                 true,
185*2d0050cbSPaolo Bonzini             );
186*2d0050cbSPaolo Bonzini         }
187*2d0050cbSPaolo Bonzini     }
188*2d0050cbSPaolo Bonzini 
189*2d0050cbSPaolo Bonzini     /// Notify that the frontend is ready to receive data.
190*2d0050cbSPaolo Bonzini     pub fn accept_input(&self) {
191*2d0050cbSPaolo Bonzini         let mut chr = self.inner.borrow_mut();
192*2d0050cbSPaolo Bonzini         // SAFETY: the borrow promises that the BQL is taken
193*2d0050cbSPaolo Bonzini         unsafe { bindings::qemu_chr_fe_accept_input(addr_of_mut!(*chr)) }
194*2d0050cbSPaolo Bonzini     }
195*2d0050cbSPaolo Bonzini 
196*2d0050cbSPaolo Bonzini     /// Temporarily borrow the character device, allowing it to be used
197*2d0050cbSPaolo Bonzini     /// as an implementor of `Write`.  Note that it is not valid to drop
198*2d0050cbSPaolo Bonzini     /// the big QEMU lock while the character device is borrowed, as
199*2d0050cbSPaolo Bonzini     /// that might cause C code to write to the character device.
200*2d0050cbSPaolo Bonzini     pub fn borrow_mut(&self) -> impl Write + '_ {
201*2d0050cbSPaolo Bonzini         self.inner.borrow_mut()
202*2d0050cbSPaolo Bonzini     }
203*2d0050cbSPaolo Bonzini 
204*2d0050cbSPaolo Bonzini     /// Send a continuous stream of zero bits on the line if `enabled` is
205*2d0050cbSPaolo Bonzini     /// true, or a short stream if `enabled` is false.
206*2d0050cbSPaolo Bonzini     pub fn send_break(&self, long: bool) -> io::Result<()> {
207*2d0050cbSPaolo Bonzini         let mut chr = self.inner.borrow_mut();
208*2d0050cbSPaolo Bonzini         let mut duration: c_int = long.into();
209*2d0050cbSPaolo Bonzini         // SAFETY: the borrow promises that the BQL is taken
210*2d0050cbSPaolo Bonzini         let r = unsafe {
211*2d0050cbSPaolo Bonzini             bindings::qemu_chr_fe_ioctl(
212*2d0050cbSPaolo Bonzini                 addr_of_mut!(*chr),
213*2d0050cbSPaolo Bonzini                 bindings::CHR_IOCTL_SERIAL_SET_BREAK as i32,
214*2d0050cbSPaolo Bonzini                 addr_of_mut!(duration).cast::<c_void>(),
215*2d0050cbSPaolo Bonzini             )
216*2d0050cbSPaolo Bonzini         };
217*2d0050cbSPaolo Bonzini 
218*2d0050cbSPaolo Bonzini         errno::into_io_result(r).map(|_| ())
219*2d0050cbSPaolo Bonzini     }
220*2d0050cbSPaolo Bonzini 
221*2d0050cbSPaolo Bonzini     /// Write data to a character backend from the front end.  This function
222*2d0050cbSPaolo Bonzini     /// will send data from the front end to the back end.  Unlike
223*2d0050cbSPaolo Bonzini     /// `write`, this function will block if the back end cannot
224*2d0050cbSPaolo Bonzini     /// consume all of the data attempted to be written.
225*2d0050cbSPaolo Bonzini     ///
226*2d0050cbSPaolo Bonzini     /// Returns the number of bytes consumed (0 if no associated Chardev) or an
227*2d0050cbSPaolo Bonzini     /// error.
228*2d0050cbSPaolo Bonzini     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
229*2d0050cbSPaolo Bonzini         let len = buf.len().try_into().unwrap();
230*2d0050cbSPaolo Bonzini         // SAFETY: qemu_chr_fe_write is thread-safe
231*2d0050cbSPaolo Bonzini         let r = unsafe { bindings::qemu_chr_fe_write(self.inner.as_ptr(), buf.as_ptr(), len) };
232*2d0050cbSPaolo Bonzini         errno::into_io_result(r).map(|cnt| cnt as usize)
233*2d0050cbSPaolo Bonzini     }
234*2d0050cbSPaolo Bonzini 
235*2d0050cbSPaolo Bonzini     /// Write data to a character backend from the front end.  This function
236*2d0050cbSPaolo Bonzini     /// will send data from the front end to the back end.  Unlike
237*2d0050cbSPaolo Bonzini     /// `write`, this function will block if the back end cannot
238*2d0050cbSPaolo Bonzini     /// consume all of the data attempted to be written.
239*2d0050cbSPaolo Bonzini     ///
240*2d0050cbSPaolo Bonzini     /// Returns the number of bytes consumed (0 if no associated Chardev) or an
241*2d0050cbSPaolo Bonzini     /// error.
242*2d0050cbSPaolo Bonzini     pub fn write_all(&self, buf: &[u8]) -> io::Result<()> {
243*2d0050cbSPaolo Bonzini         let len = buf.len().try_into().unwrap();
244*2d0050cbSPaolo Bonzini         // SAFETY: qemu_chr_fe_write_all is thread-safe
245*2d0050cbSPaolo Bonzini         let r = unsafe { bindings::qemu_chr_fe_write_all(self.inner.as_ptr(), buf.as_ptr(), len) };
246*2d0050cbSPaolo Bonzini         errno::into_io_result(r).and_then(|cnt| {
247*2d0050cbSPaolo Bonzini             if cnt as usize == buf.len() {
248*2d0050cbSPaolo Bonzini                 Ok(())
249*2d0050cbSPaolo Bonzini             } else {
250*2d0050cbSPaolo Bonzini                 Err(ErrorKind::WriteZero.into())
251*2d0050cbSPaolo Bonzini             }
252*2d0050cbSPaolo Bonzini         })
253*2d0050cbSPaolo Bonzini     }
254*2d0050cbSPaolo Bonzini }
255a22bd55fSPaolo Bonzini 
256a22bd55fSPaolo Bonzini unsafe impl ObjectType for Chardev {
257a22bd55fSPaolo Bonzini     type Class = ChardevClass;
258a22bd55fSPaolo Bonzini     const TYPE_NAME: &'static CStr =
259a22bd55fSPaolo Bonzini         unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_CHARDEV) };
260a22bd55fSPaolo Bonzini }
261a22bd55fSPaolo Bonzini qom_isa!(Chardev: Object);
262