Add a device specialization for the Luminary UART device. This commit adds a DeviceId enum that utilizes the Index trait to return different bytes depending on what device id the UART has (Arm -default- or Luminary)
Signed-off-by: Manos Pitsidianakis <manos.pitsidiana...@linaro.org> --- rust/hw/char/pl011/src/device.rs | 59 ++++++++++++++++++++++++++++++++++++++-- rust/hw/char/pl011/src/lib.rs | 1 + 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs index 115786f9fa7f03c16cd44462cb7df5623ba3a6d7..3aa055dee4b10866a624505a9d05ef1ab8182dce 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -20,8 +20,6 @@ RegisterOffset, }; -static PL011_ID_ARM: [c_uchar; 8] = [0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1]; - /// Integer Baud Rate Divider, `UARTIBRD` const IBRD_MASK: u32 = 0x3f; @@ -64,6 +62,29 @@ extern "C" fn pl011_clock_needed(opaque: *mut c_void) -> bool { }; } +#[derive(Clone, Copy, Debug)] +enum DeviceId { + #[allow(dead_code)] + Arm = 0, + Luminary, +} + +impl std::ops::Index<hwaddr> for DeviceId { + type Output = c_uchar; + + fn index(&self, idx: hwaddr) -> &Self::Output { + match self { + Self::Arm => &Self::PL011_ID_ARM[idx as usize], + Self::Luminary => &Self::PL011_ID_LUMINARY[idx as usize], + } + } +} + +impl DeviceId { + const PL011_ID_ARM: [c_uchar; 8] = [0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1]; + const PL011_ID_LUMINARY: [c_uchar; 8] = [0x11, 0x00, 0x18, 0x01, 0x0d, 0xf0, 0x05, 0xb1]; +} + #[repr(C)] #[derive(Debug, qemu_api_macros::Object, qemu_api_macros::Device)] #[device( @@ -134,6 +155,8 @@ pub struct PL011State { #[doc(alias = "migrate_clk")] #[property(name = c"migrate-clk", qdev_prop = qdev_prop_bool)] pub migrate_clock: bool, + /// The byte string that identifies the device. + device_id: DeviceId, } impl ObjectImpl for PL011State { @@ -267,7 +290,7 @@ pub fn read( std::ops::ControlFlow::Break(match RegisterOffset::try_from(offset) { Err(v) if (0x3f8..0x400).contains(&v) => { - u64::from(PL011_ID_ARM[((offset - 0xfe0) >> 2) as usize]) + u64::from(self.device_id[(offset - 0xfe0) >> 2]) } Err(_) => { // qemu_log_mask(LOG_GUEST_ERROR, "pl011_read: Bad offset 0x%x\n", (int)offset); @@ -660,3 +683,33 @@ pub fn update(&self) { dev } } + +#[repr(C)] +#[derive(Debug, qemu_api_macros::Object, qemu_api_macros::Device)] +/// PL011 Luminary device model. +pub struct PL011Luminary { + parent_obj: PL011State, +} + +impl ObjectImpl for PL011Luminary { + type Class = PL011LuminaryClass; + + const TYPE_NAME: &'static CStr = crate::TYPE_PL011_LUMINARY; + const PARENT_TYPE_NAME: Option<&'static CStr> = Some(crate::TYPE_PL011); + const ABSTRACT: bool = false; + + /// Initializes a pre-allocated, unitialized instance of `PL011Luminary`. + /// + /// # Safety + /// + /// `self` must point to a correctly sized and aligned location for the + /// `PL011Luminary` type. It must not be called more than once on the same + /// location/instance. All its fields are expected to hold unitialized + /// values with the sole exception of `parent_obj`. + unsafe fn instance_init(&mut self) { + self.parent_obj.device_id = DeviceId::Luminary; + } +} + +impl DeviceImpl for PL011Luminary {} +impl qemu_api::objects::Migrateable for PL011Luminary {} diff --git a/rust/hw/char/pl011/src/lib.rs b/rust/hw/char/pl011/src/lib.rs index f4d9cce4b01f605cfcbec7ea87c8b2009d77ee52..5516e018b4bfebe5175c515e5aa4598f54b39dfc 100644 --- a/rust/hw/char/pl011/src/lib.rs +++ b/rust/hw/char/pl011/src/lib.rs @@ -45,6 +45,7 @@ pub mod memory_ops; pub const TYPE_PL011: &::core::ffi::CStr = c"pl011"; +pub const TYPE_PL011_LUMINARY: &::core::ffi::CStr = c"pl011_luminary"; /// Offset of each register from the base memory address of the device. /// -- 2.45.2