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