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