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