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 62d0050cbSPaolo Bonzini //! 72d0050cbSPaolo Bonzini //! Character devices in QEMU can run under the big QEMU lock or in a separate 82d0050cbSPaolo Bonzini //! `GMainContext`. Here we only support the former, because the bindings 92d0050cbSPaolo Bonzini //! enforce that the BQL is taken whenever the functions in [`CharBackend`] are 102d0050cbSPaolo Bonzini //! called. 11a22bd55fSPaolo Bonzini 122d0050cbSPaolo Bonzini use std::{ 13e4fb0be1SPaolo Bonzini ffi::{c_int, c_void, CStr}, 142d0050cbSPaolo Bonzini fmt::{self, Debug}, 152d0050cbSPaolo Bonzini io::{self, ErrorKind, Write}, 162d0050cbSPaolo Bonzini marker::PhantomPinned, 172d0050cbSPaolo Bonzini ptr::addr_of_mut, 182d0050cbSPaolo Bonzini slice, 192d0050cbSPaolo Bonzini }; 20a22bd55fSPaolo Bonzini 212d0050cbSPaolo Bonzini use crate::{ 222d0050cbSPaolo Bonzini bindings, 232d0050cbSPaolo Bonzini callbacks::FnCall, 242d0050cbSPaolo Bonzini cell::{BqlRefMut, Opaque}, 252d0050cbSPaolo Bonzini prelude::*, 262d0050cbSPaolo Bonzini }; 27a22bd55fSPaolo Bonzini 2848627510SPaolo Bonzini /// A safe wrapper around [`bindings::Chardev`]. 2948627510SPaolo Bonzini #[repr(transparent)] 3048627510SPaolo Bonzini #[derive(qemu_api_macros::Wrapper)] 3148627510SPaolo Bonzini pub struct Chardev(Opaque<bindings::Chardev>); 3248627510SPaolo Bonzini 33a22bd55fSPaolo Bonzini pub type ChardevClass = bindings::ChardevClass; 342d0050cbSPaolo Bonzini pub type Event = bindings::QEMUChrEvent; 352d0050cbSPaolo Bonzini 362d0050cbSPaolo Bonzini /// A safe wrapper around [`bindings::CharBackend`], denoting the character 372d0050cbSPaolo Bonzini /// back-end that is used for example by a device. Compared to the 382d0050cbSPaolo Bonzini /// underlying C struct it adds BQL protection, and is marked as pinned 392d0050cbSPaolo Bonzini /// because the QOM object ([`bindings::Chardev`]) contains a pointer to 402d0050cbSPaolo Bonzini /// the `CharBackend`. 412d0050cbSPaolo Bonzini pub struct CharBackend { 422d0050cbSPaolo Bonzini inner: BqlRefCell<bindings::CharBackend>, 432d0050cbSPaolo Bonzini _pin: PhantomPinned, 442d0050cbSPaolo Bonzini } 452d0050cbSPaolo Bonzini 462d0050cbSPaolo Bonzini impl Write for BqlRefMut<'_, bindings::CharBackend> { flush(&mut self) -> io::Result<()>472d0050cbSPaolo Bonzini fn flush(&mut self) -> io::Result<()> { 482d0050cbSPaolo Bonzini Ok(()) 492d0050cbSPaolo Bonzini } 502d0050cbSPaolo Bonzini write(&mut self, buf: &[u8]) -> io::Result<usize>512d0050cbSPaolo Bonzini fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 522d0050cbSPaolo Bonzini let chr: &mut bindings::CharBackend = self; 532d0050cbSPaolo Bonzini 542d0050cbSPaolo Bonzini let len = buf.len().try_into().unwrap(); 552d0050cbSPaolo Bonzini let r = unsafe { bindings::qemu_chr_fe_write(addr_of_mut!(*chr), buf.as_ptr(), len) }; 562d0050cbSPaolo Bonzini errno::into_io_result(r).map(|cnt| cnt as usize) 572d0050cbSPaolo Bonzini } 582d0050cbSPaolo Bonzini write_all(&mut self, buf: &[u8]) -> io::Result<()>592d0050cbSPaolo Bonzini fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { 602d0050cbSPaolo Bonzini let chr: &mut bindings::CharBackend = self; 612d0050cbSPaolo Bonzini 622d0050cbSPaolo Bonzini let len = buf.len().try_into().unwrap(); 632d0050cbSPaolo Bonzini let r = unsafe { bindings::qemu_chr_fe_write_all(addr_of_mut!(*chr), buf.as_ptr(), len) }; 642d0050cbSPaolo Bonzini errno::into_io_result(r).and_then(|cnt| { 652d0050cbSPaolo Bonzini if cnt as usize == buf.len() { 662d0050cbSPaolo Bonzini Ok(()) 672d0050cbSPaolo Bonzini } else { 682d0050cbSPaolo Bonzini Err(ErrorKind::WriteZero.into()) 692d0050cbSPaolo Bonzini } 702d0050cbSPaolo Bonzini }) 712d0050cbSPaolo Bonzini } 722d0050cbSPaolo Bonzini } 732d0050cbSPaolo Bonzini 742d0050cbSPaolo Bonzini impl Debug for CharBackend { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result752d0050cbSPaolo Bonzini fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 762d0050cbSPaolo Bonzini // SAFETY: accessed just to print the values 772d0050cbSPaolo Bonzini let chr = self.inner.as_ptr(); 782d0050cbSPaolo Bonzini Debug::fmt(unsafe { &*chr }, f) 792d0050cbSPaolo Bonzini } 802d0050cbSPaolo Bonzini } 812d0050cbSPaolo Bonzini 822d0050cbSPaolo Bonzini // FIXME: use something like PinnedDrop from the pinned_init crate 832d0050cbSPaolo Bonzini impl Drop for CharBackend { drop(&mut self)842d0050cbSPaolo Bonzini fn drop(&mut self) { 852d0050cbSPaolo Bonzini self.disable_handlers(); 862d0050cbSPaolo Bonzini } 872d0050cbSPaolo Bonzini } 882d0050cbSPaolo Bonzini 892d0050cbSPaolo Bonzini impl CharBackend { 902d0050cbSPaolo Bonzini /// Enable the front-end's character device handlers, if there is an 912d0050cbSPaolo Bonzini /// associated `Chardev`. enable_handlers< 'chardev, 'owner: 'chardev, T, CanReceiveFn: for<'a> FnCall<(&'a T,), u32>, ReceiveFn: for<'a, 'b> FnCall<(&'a T, &'b [u8])>, EventFn: for<'a> FnCall<(&'a T, Event)>, >( &'chardev self, owner: &'owner T, _can_receive: CanReceiveFn, _receive: ReceiveFn, _event: EventFn, )922d0050cbSPaolo Bonzini pub fn enable_handlers< 932d0050cbSPaolo Bonzini 'chardev, 942d0050cbSPaolo Bonzini 'owner: 'chardev, 952d0050cbSPaolo Bonzini T, 962d0050cbSPaolo Bonzini CanReceiveFn: for<'a> FnCall<(&'a T,), u32>, 972d0050cbSPaolo Bonzini ReceiveFn: for<'a, 'b> FnCall<(&'a T, &'b [u8])>, 982d0050cbSPaolo Bonzini EventFn: for<'a> FnCall<(&'a T, Event)>, 992d0050cbSPaolo Bonzini >( 1002d0050cbSPaolo Bonzini // When "self" is dropped, the handlers are automatically disabled. 1012d0050cbSPaolo Bonzini // However, this is not necessarily true if the owner is dropped. 1022d0050cbSPaolo Bonzini // So require the owner to outlive the character device. 1032d0050cbSPaolo Bonzini &'chardev self, 1042d0050cbSPaolo Bonzini owner: &'owner T, 1052d0050cbSPaolo Bonzini _can_receive: CanReceiveFn, 1062d0050cbSPaolo Bonzini _receive: ReceiveFn, 1072d0050cbSPaolo Bonzini _event: EventFn, 1082d0050cbSPaolo Bonzini ) { 1092d0050cbSPaolo Bonzini unsafe extern "C" fn rust_can_receive_cb<T, F: for<'a> FnCall<(&'a T,), u32>>( 1102d0050cbSPaolo Bonzini opaque: *mut c_void, 1112d0050cbSPaolo Bonzini ) -> c_int { 1122d0050cbSPaolo Bonzini // SAFETY: the values are safe according to the contract of 1132d0050cbSPaolo Bonzini // enable_handlers() and qemu_chr_fe_set_handlers() 1142d0050cbSPaolo Bonzini let owner: &T = unsafe { &*(opaque.cast::<T>()) }; 1152d0050cbSPaolo Bonzini let r = F::call((owner,)); 1162d0050cbSPaolo Bonzini r.try_into().unwrap() 1172d0050cbSPaolo Bonzini } 1182d0050cbSPaolo Bonzini 1192d0050cbSPaolo Bonzini unsafe extern "C" fn rust_receive_cb<T, F: for<'a, 'b> FnCall<(&'a T, &'b [u8])>>( 1202d0050cbSPaolo Bonzini opaque: *mut c_void, 1212d0050cbSPaolo Bonzini buf: *const u8, 1222d0050cbSPaolo Bonzini size: c_int, 1232d0050cbSPaolo Bonzini ) { 1242d0050cbSPaolo Bonzini // SAFETY: the values are safe according to the contract of 1252d0050cbSPaolo Bonzini // enable_handlers() and qemu_chr_fe_set_handlers() 1262d0050cbSPaolo Bonzini let owner: &T = unsafe { &*(opaque.cast::<T>()) }; 1272d0050cbSPaolo Bonzini let buf = unsafe { slice::from_raw_parts(buf, size.try_into().unwrap()) }; 1282d0050cbSPaolo Bonzini F::call((owner, buf)) 1292d0050cbSPaolo Bonzini } 1302d0050cbSPaolo Bonzini 1312d0050cbSPaolo Bonzini unsafe extern "C" fn rust_event_cb<T, F: for<'a> FnCall<(&'a T, Event)>>( 1322d0050cbSPaolo Bonzini opaque: *mut c_void, 1332d0050cbSPaolo Bonzini event: Event, 1342d0050cbSPaolo Bonzini ) { 1352d0050cbSPaolo Bonzini // SAFETY: the values are safe according to the contract of 1362d0050cbSPaolo Bonzini // enable_handlers() and qemu_chr_fe_set_handlers() 1372d0050cbSPaolo Bonzini let owner: &T = unsafe { &*(opaque.cast::<T>()) }; 1382d0050cbSPaolo Bonzini F::call((owner, event)) 1392d0050cbSPaolo Bonzini } 1402d0050cbSPaolo Bonzini 1412d0050cbSPaolo Bonzini let _: () = CanReceiveFn::ASSERT_IS_SOME; 1422d0050cbSPaolo Bonzini let receive_cb: Option<unsafe extern "C" fn(*mut c_void, *const u8, c_int)> = 1432d0050cbSPaolo Bonzini if ReceiveFn::is_some() { 1442d0050cbSPaolo Bonzini Some(rust_receive_cb::<T, ReceiveFn>) 1452d0050cbSPaolo Bonzini } else { 1462d0050cbSPaolo Bonzini None 1472d0050cbSPaolo Bonzini }; 1482d0050cbSPaolo Bonzini let event_cb: Option<unsafe extern "C" fn(*mut c_void, Event)> = if EventFn::is_some() { 1492d0050cbSPaolo Bonzini Some(rust_event_cb::<T, EventFn>) 1502d0050cbSPaolo Bonzini } else { 1512d0050cbSPaolo Bonzini None 1522d0050cbSPaolo Bonzini }; 1532d0050cbSPaolo Bonzini 1542d0050cbSPaolo Bonzini let mut chr = self.inner.borrow_mut(); 1552d0050cbSPaolo Bonzini // SAFETY: the borrow promises that the BQL is taken 1562d0050cbSPaolo Bonzini unsafe { 1572d0050cbSPaolo Bonzini bindings::qemu_chr_fe_set_handlers( 1582d0050cbSPaolo Bonzini addr_of_mut!(*chr), 1592d0050cbSPaolo Bonzini Some(rust_can_receive_cb::<T, CanReceiveFn>), 1602d0050cbSPaolo Bonzini receive_cb, 1612d0050cbSPaolo Bonzini event_cb, 1622d0050cbSPaolo Bonzini None, 163*5df3fe06SPaolo Bonzini (owner as *const T).cast_mut().cast::<c_void>(), 1642d0050cbSPaolo Bonzini core::ptr::null_mut(), 1652d0050cbSPaolo Bonzini true, 1662d0050cbSPaolo Bonzini ); 1672d0050cbSPaolo Bonzini } 1682d0050cbSPaolo Bonzini } 1692d0050cbSPaolo Bonzini 1702d0050cbSPaolo Bonzini /// Disable the front-end's character device handlers. disable_handlers(&self)1712d0050cbSPaolo Bonzini pub fn disable_handlers(&self) { 1722d0050cbSPaolo Bonzini let mut chr = self.inner.borrow_mut(); 1732d0050cbSPaolo Bonzini // SAFETY: the borrow promises that the BQL is taken 1742d0050cbSPaolo Bonzini unsafe { 1752d0050cbSPaolo Bonzini bindings::qemu_chr_fe_set_handlers( 1762d0050cbSPaolo Bonzini addr_of_mut!(*chr), 1772d0050cbSPaolo Bonzini None, 1782d0050cbSPaolo Bonzini None, 1792d0050cbSPaolo Bonzini None, 1802d0050cbSPaolo Bonzini None, 1812d0050cbSPaolo Bonzini core::ptr::null_mut(), 1822d0050cbSPaolo Bonzini core::ptr::null_mut(), 1832d0050cbSPaolo Bonzini true, 1842d0050cbSPaolo Bonzini ); 1852d0050cbSPaolo Bonzini } 1862d0050cbSPaolo Bonzini } 1872d0050cbSPaolo Bonzini 1882d0050cbSPaolo Bonzini /// Notify that the frontend is ready to receive data. accept_input(&self)1892d0050cbSPaolo Bonzini pub fn accept_input(&self) { 1902d0050cbSPaolo Bonzini let mut chr = self.inner.borrow_mut(); 1912d0050cbSPaolo Bonzini // SAFETY: the borrow promises that the BQL is taken 1922d0050cbSPaolo Bonzini unsafe { bindings::qemu_chr_fe_accept_input(addr_of_mut!(*chr)) } 1932d0050cbSPaolo Bonzini } 1942d0050cbSPaolo Bonzini 1952d0050cbSPaolo Bonzini /// Temporarily borrow the character device, allowing it to be used 1962d0050cbSPaolo Bonzini /// as an implementor of `Write`. Note that it is not valid to drop 1972d0050cbSPaolo Bonzini /// the big QEMU lock while the character device is borrowed, as 1982d0050cbSPaolo Bonzini /// that might cause C code to write to the character device. borrow_mut(&self) -> impl Write + '_1992d0050cbSPaolo Bonzini pub fn borrow_mut(&self) -> impl Write + '_ { 2002d0050cbSPaolo Bonzini self.inner.borrow_mut() 2012d0050cbSPaolo Bonzini } 2022d0050cbSPaolo Bonzini 2032d0050cbSPaolo Bonzini /// Send a continuous stream of zero bits on the line if `enabled` is 2042d0050cbSPaolo Bonzini /// true, or a short stream if `enabled` is false. send_break(&self, long: bool) -> io::Result<()>2052d0050cbSPaolo Bonzini pub fn send_break(&self, long: bool) -> io::Result<()> { 2062d0050cbSPaolo Bonzini let mut chr = self.inner.borrow_mut(); 2072d0050cbSPaolo Bonzini let mut duration: c_int = long.into(); 2082d0050cbSPaolo Bonzini // SAFETY: the borrow promises that the BQL is taken 2092d0050cbSPaolo Bonzini let r = unsafe { 2102d0050cbSPaolo Bonzini bindings::qemu_chr_fe_ioctl( 2112d0050cbSPaolo Bonzini addr_of_mut!(*chr), 2122d0050cbSPaolo Bonzini bindings::CHR_IOCTL_SERIAL_SET_BREAK as i32, 2132d0050cbSPaolo Bonzini addr_of_mut!(duration).cast::<c_void>(), 2142d0050cbSPaolo Bonzini ) 2152d0050cbSPaolo Bonzini }; 2162d0050cbSPaolo Bonzini 2172d0050cbSPaolo Bonzini errno::into_io_result(r).map(|_| ()) 2182d0050cbSPaolo Bonzini } 2192d0050cbSPaolo Bonzini 2202d0050cbSPaolo Bonzini /// Write data to a character backend from the front end. This function 2212d0050cbSPaolo Bonzini /// will send data from the front end to the back end. Unlike 2222d0050cbSPaolo Bonzini /// `write`, this function will block if the back end cannot 2232d0050cbSPaolo Bonzini /// consume all of the data attempted to be written. 2242d0050cbSPaolo Bonzini /// 2252d0050cbSPaolo Bonzini /// Returns the number of bytes consumed (0 if no associated Chardev) or an 2262d0050cbSPaolo Bonzini /// error. write(&self, buf: &[u8]) -> io::Result<usize>2272d0050cbSPaolo Bonzini pub fn write(&self, buf: &[u8]) -> io::Result<usize> { 2282d0050cbSPaolo Bonzini let len = buf.len().try_into().unwrap(); 2292d0050cbSPaolo Bonzini // SAFETY: qemu_chr_fe_write is thread-safe 2302d0050cbSPaolo Bonzini let r = unsafe { bindings::qemu_chr_fe_write(self.inner.as_ptr(), buf.as_ptr(), len) }; 2312d0050cbSPaolo Bonzini errno::into_io_result(r).map(|cnt| cnt as usize) 2322d0050cbSPaolo Bonzini } 2332d0050cbSPaolo Bonzini 2342d0050cbSPaolo Bonzini /// Write data to a character backend from the front end. This function 2352d0050cbSPaolo Bonzini /// will send data from the front end to the back end. Unlike 2362d0050cbSPaolo Bonzini /// `write`, this function will block if the back end cannot 2372d0050cbSPaolo Bonzini /// consume all of the data attempted to be written. 2382d0050cbSPaolo Bonzini /// 2392d0050cbSPaolo Bonzini /// Returns the number of bytes consumed (0 if no associated Chardev) or an 2402d0050cbSPaolo Bonzini /// error. write_all(&self, buf: &[u8]) -> io::Result<()>2412d0050cbSPaolo Bonzini pub fn write_all(&self, buf: &[u8]) -> io::Result<()> { 2422d0050cbSPaolo Bonzini let len = buf.len().try_into().unwrap(); 2432d0050cbSPaolo Bonzini // SAFETY: qemu_chr_fe_write_all is thread-safe 2442d0050cbSPaolo Bonzini let r = unsafe { bindings::qemu_chr_fe_write_all(self.inner.as_ptr(), buf.as_ptr(), len) }; 2452d0050cbSPaolo Bonzini errno::into_io_result(r).and_then(|cnt| { 2462d0050cbSPaolo Bonzini if cnt as usize == buf.len() { 2472d0050cbSPaolo Bonzini Ok(()) 2482d0050cbSPaolo Bonzini } else { 2492d0050cbSPaolo Bonzini Err(ErrorKind::WriteZero.into()) 2502d0050cbSPaolo Bonzini } 2512d0050cbSPaolo Bonzini }) 2522d0050cbSPaolo Bonzini } 2532d0050cbSPaolo Bonzini } 254a22bd55fSPaolo Bonzini 255a22bd55fSPaolo Bonzini unsafe impl ObjectType for Chardev { 256a22bd55fSPaolo Bonzini type Class = ChardevClass; 257a22bd55fSPaolo Bonzini const TYPE_NAME: &'static CStr = 258a22bd55fSPaolo Bonzini unsafe { CStr::from_bytes_with_nul_unchecked(bindings::TYPE_CHARDEV) }; 259a22bd55fSPaolo Bonzini } 260a22bd55fSPaolo Bonzini qom_isa!(Chardev: Object); 261