rust: pl011: pull device-specific code out of MemoryRegionOps callbacks

read() can now return a simple u64.

Reviewed-by: Zhao Liu <zhao1.liu@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2025-01-17 17:56:00 +01:00
parent c44818a5fd
commit b3a29b3dc0
2 changed files with 15 additions and 26 deletions

View File

@ -12,9 +12,10 @@ use std::{
use qemu_api::{ use qemu_api::{
bindings::{ bindings::{
error_fatal, hwaddr, memory_region_init_io, qdev_init_clock_in, qdev_new, error_fatal, hwaddr, memory_region_init_io, qdev_init_clock_in, qdev_new,
qdev_prop_set_chr, qemu_chr_fe_ioctl, qemu_chr_fe_set_handlers, qemu_chr_fe_write_all, qdev_prop_set_chr, qemu_chr_fe_accept_input, qemu_chr_fe_ioctl, qemu_chr_fe_set_handlers,
qemu_irq, sysbus_connect_irq, sysbus_mmio_map, sysbus_realize_and_unref, CharBackend, qemu_chr_fe_write_all, qemu_irq, sysbus_connect_irq, sysbus_mmio_map,
Chardev, Clock, ClockEvent, MemoryRegion, QEMUChrEvent, CHR_IOCTL_SERIAL_SET_BREAK, sysbus_realize_and_unref, CharBackend, Chardev, Clock, ClockEvent, MemoryRegion,
QEMUChrEvent, CHR_IOCTL_SERIAL_SET_BREAK,
}, },
c_str, impl_vmstate_forward, c_str, impl_vmstate_forward,
irq::InterruptSource, irq::InterruptSource,
@ -528,30 +529,32 @@ impl PL011State {
} }
} }
#[allow(clippy::needless_pass_by_ref_mut)] pub fn read(&mut self, offset: hwaddr, _size: u32) -> u64 {
pub fn read(&mut self, offset: hwaddr, _size: u32) -> ControlFlow<u64, u64> {
let mut update_irq = false; let mut update_irq = false;
let result = match RegisterOffset::try_from(offset) { let result = match RegisterOffset::try_from(offset) {
Err(v) if (0x3f8..0x400).contains(&(v >> 2)) => { Err(v) if (0x3f8..0x400).contains(&(v >> 2)) => {
let device_id = self.get_class().device_id; let device_id = self.get_class().device_id;
ControlFlow::Break(u64::from(device_id[(offset - 0xfe0) >> 2])) u32::from(device_id[(offset - 0xfe0) >> 2])
} }
Err(_) => { Err(_) => {
// qemu_log_mask(LOG_GUEST_ERROR, "pl011_read: Bad offset 0x%x\n", (int)offset); // qemu_log_mask(LOG_GUEST_ERROR, "pl011_read: Bad offset 0x%x\n", (int)offset);
ControlFlow::Break(0) 0
} }
Ok(field) => match self.regs.borrow_mut().read(field) { Ok(field) => match self.regs.borrow_mut().read(field) {
ControlFlow::Break(value) => ControlFlow::Break(value.into()), ControlFlow::Break(value) => value,
ControlFlow::Continue(value) => { ControlFlow::Continue(value) => {
update_irq = true; update_irq = true;
ControlFlow::Continue(value.into()) value
} }
}, },
}; };
if update_irq { if update_irq {
self.update(); self.update();
unsafe {
qemu_chr_fe_accept_input(&mut self.char_backend);
} }
result }
result.into()
} }
pub fn write(&mut self, offset: hwaddr, value: u64) { pub fn write(&mut self, offset: hwaddr, value: u64) {

View File

@ -24,25 +24,11 @@ pub static PL011_OPS: MemoryRegionOps = MemoryRegionOps {
}; };
unsafe extern "C" fn pl011_read(opaque: *mut c_void, addr: hwaddr, size: c_uint) -> u64 { unsafe extern "C" fn pl011_read(opaque: *mut c_void, addr: hwaddr, size: c_uint) -> u64 {
assert!(!opaque.is_null());
let mut state = NonNull::new(opaque).unwrap().cast::<PL011State>(); let mut state = NonNull::new(opaque).unwrap().cast::<PL011State>();
let val = unsafe { state.as_mut().read(addr, size) }; unsafe { state.as_mut() }.read(addr, size)
match val {
std::ops::ControlFlow::Break(val) => val,
std::ops::ControlFlow::Continue(val) => {
// SAFETY: self.char_backend is a valid CharBackend instance after it's been
// initialized in realize().
let cb_ptr = unsafe { core::ptr::addr_of_mut!(state.as_mut().char_backend) };
unsafe {
qemu_chr_fe_accept_input(cb_ptr);
}
val
}
}
} }
unsafe extern "C" fn pl011_write(opaque: *mut c_void, addr: hwaddr, data: u64, _size: c_uint) { unsafe extern "C" fn pl011_write(opaque: *mut c_void, addr: hwaddr, data: u64, _size: c_uint) {
let mut state = NonNull::new(opaque).unwrap().cast::<PL011State>(); let mut state = NonNull::new(opaque).unwrap().cast::<PL011State>();
unsafe { state.as_mut().write(addr, data) } unsafe { state.as_mut() }.write(addr, data);
} }