Browse Source

rust: pl011: extend registers to 32 bits

The PL011 Technical Reference Manual lists the "real" size of the
registers in table 3-1, and only rounds up to the next byte when
describing the registers; for example, UARTDR is listed as having
width 12/8 (12 bits read, 8 written) and only bits 15:0 are listed
in "Table 3-2 UARTDR Register".

However, in practice these are 32-bit registers, accessible only
through 32-bit MMIO accesses; preserving the fiction that they're
smaller introduces multiple casts (to go from the bilge bitfield
type to e.g u16 to u64) and more importantly it breaks the
migration stream because the Rust vmstate macros are not yet
type safe.

So, just make everything 32-bits wide.

Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Paolo Bonzini 8 months ago
parent
commit
e2e0828e0f
2 changed files with 26 additions and 33 deletions
  1. 16 20
      rust/hw/char/pl011/src/device.rs
  2. 10 13
      rust/hw/char/pl011/src/lib.rs

+ 16 - 20
rust/hw/char/pl011/src/device.rs

@@ -186,9 +186,9 @@ unsafe fn init(&mut self) {
     pub fn read(&mut self, offset: hwaddr, _size: c_uint) -> std::ops::ControlFlow<u64, u64> {
     pub fn read(&mut self, offset: hwaddr, _size: c_uint) -> std::ops::ControlFlow<u64, u64> {
         use RegisterOffset::*;
         use RegisterOffset::*;
 
 
-        std::ops::ControlFlow::Break(match RegisterOffset::try_from(offset) {
+        let value = match RegisterOffset::try_from(offset) {
             Err(v) if (0x3f8..0x400).contains(&(v >> 2)) => {
             Err(v) if (0x3f8..0x400).contains(&(v >> 2)) => {
-                u64::from(self.device_id[(offset - 0xfe0) >> 2])
+                u32::from(self.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);
@@ -214,27 +214,25 @@ pub fn read(&mut self, offset: hwaddr, _size: c_uint) -> std::ops::ControlFlow<u
                 let c = u32::from(c);
                 let c = u32::from(c);
                 return std::ops::ControlFlow::Continue(u64::from(c));
                 return std::ops::ControlFlow::Continue(u64::from(c));
             }
             }
-            Ok(RSR) => u8::from(self.receive_status_error_clear).into(),
-            Ok(FR) => u16::from(self.flags).into(),
-            Ok(FBRD) => self.fbrd.into(),
-            Ok(ILPR) => self.ilpr.into(),
-            Ok(IBRD) => self.ibrd.into(),
-            Ok(LCR_H) => u16::from(self.line_control).into(),
-            Ok(CR) => {
-                // We exercise our self-control.
-                u16::from(self.control).into()
-            }
-            Ok(FLS) => self.ifl.into(),
-            Ok(IMSC) => self.int_enabled.into(),
-            Ok(RIS) => self.int_level.into(),
-            Ok(MIS) => u64::from(self.int_level & self.int_enabled),
+            Ok(RSR) => u32::from(self.receive_status_error_clear),
+            Ok(FR) => u32::from(self.flags),
+            Ok(FBRD) => self.fbrd,
+            Ok(ILPR) => self.ilpr,
+            Ok(IBRD) => self.ibrd,
+            Ok(LCR_H) => u32::from(self.line_control),
+            Ok(CR) => u32::from(self.control),
+            Ok(FLS) => self.ifl,
+            Ok(IMSC) => self.int_enabled,
+            Ok(RIS) => self.int_level,
+            Ok(MIS) => self.int_level & self.int_enabled,
             Ok(ICR) => {
             Ok(ICR) => {
                 // "The UARTICR Register is the interrupt clear register and is write-only"
                 // "The UARTICR Register is the interrupt clear register and is write-only"
                 // Source: ARM DDI 0183G 3.3.13 Interrupt Clear Register, UARTICR
                 // Source: ARM DDI 0183G 3.3.13 Interrupt Clear Register, UARTICR
                 0
                 0
             }
             }
-            Ok(DMACR) => self.dmacr.into(),
-        })
+            Ok(DMACR) => self.dmacr,
+        };
+        std::ops::ControlFlow::Break(value.into())
     }
     }
 
 
     pub fn write(&mut self, offset: hwaddr, value: u64) {
     pub fn write(&mut self, offset: hwaddr, value: u64) {
@@ -276,7 +274,6 @@ pub fn write(&mut self, offset: hwaddr, value: u64) {
                 self.fbrd = value;
                 self.fbrd = value;
             }
             }
             Ok(LCR_H) => {
             Ok(LCR_H) => {
-                let value = value as u16;
                 let new_val: registers::LineControl = value.into();
                 let new_val: registers::LineControl = value.into();
                 // Reset the FIFO state on FIFO enable or disable
                 // Reset the FIFO state on FIFO enable or disable
                 if bool::from(self.line_control.fifos_enabled())
                 if bool::from(self.line_control.fifos_enabled())
@@ -303,7 +300,6 @@ pub fn write(&mut self, offset: hwaddr, value: u64) {
             }
             }
             Ok(CR) => {
             Ok(CR) => {
                 // ??? Need to implement the enable bit.
                 // ??? Need to implement the enable bit.
-                let value = value as u16;
                 self.control = value.into();
                 self.control = value.into();
                 self.loopback_mdmctrl();
                 self.loopback_mdmctrl();
             }
             }

+ 10 - 13
rust/hw/char/pl011/src/lib.rs

@@ -131,12 +131,6 @@ const fn _assert_exhaustive(val: RegisterOffset) {
 pub mod registers {
 pub mod registers {
     //! Device registers exposed as typed structs which are backed by arbitrary
     //! Device registers exposed as typed structs which are backed by arbitrary
     //! integer bitmaps. [`Data`], [`Control`], [`LineControl`], etc.
     //! integer bitmaps. [`Data`], [`Control`], [`LineControl`], etc.
-    //!
-    //! All PL011 registers are essentially 32-bit wide, but are typed here as
-    //! bitmaps with only the necessary width. That is, if a struct bitmap
-    //! in this module is for example 16 bits long, it should be conceived
-    //! as a 32-bit register where the unmentioned higher bits are always
-    //! unused thus treated as zero when read or written.
     use bilge::prelude::*;
     use bilge::prelude::*;
 
 
     /// Receive Status Register / Data Register common error bits
     /// Receive Status Register / Data Register common error bits
@@ -234,10 +228,11 @@ impl Data {
     /// # Source
     /// # Source
     /// ARM DDI 0183G 3.3.2 Receive Status Register/Error Clear Register,
     /// ARM DDI 0183G 3.3.2 Receive Status Register/Error Clear Register,
     /// UARTRSR/UARTECR
     /// UARTRSR/UARTECR
-    #[bitsize(8)]
+    #[bitsize(32)]
     #[derive(Clone, Copy, DebugBits, FromBits)]
     #[derive(Clone, Copy, DebugBits, FromBits)]
     pub struct ReceiveStatusErrorClear {
     pub struct ReceiveStatusErrorClear {
         pub errors: Errors,
         pub errors: Errors,
+        _reserved_unpredictable: u24,
     }
     }
 
 
     impl ReceiveStatusErrorClear {
     impl ReceiveStatusErrorClear {
@@ -257,7 +252,7 @@ fn default() -> Self {
         }
         }
     }
     }
 
 
-    #[bitsize(16)]
+    #[bitsize(32)]
     #[derive(Clone, Copy, DebugBits, FromBits)]
     #[derive(Clone, Copy, DebugBits, FromBits)]
     /// Flag Register, `UARTFR`
     /// Flag Register, `UARTFR`
     #[doc(alias = "UARTFR")]
     #[doc(alias = "UARTFR")]
@@ -309,7 +304,7 @@ pub struct Flags {
         pub transmit_fifo_empty: bool,
         pub transmit_fifo_empty: bool,
         /// `RI`, is `true` when `nUARTRI` is `LOW`.
         /// `RI`, is `true` when `nUARTRI` is `LOW`.
         pub ring_indicator: bool,
         pub ring_indicator: bool,
-        _reserved_zero_no_modify: u7,
+        _reserved_zero_no_modify: u23,
     }
     }
 
 
     impl Flags {
     impl Flags {
@@ -328,7 +323,7 @@ fn default() -> Self {
         }
         }
     }
     }
 
 
-    #[bitsize(16)]
+    #[bitsize(32)]
     #[derive(Clone, Copy, DebugBits, FromBits)]
     #[derive(Clone, Copy, DebugBits, FromBits)]
     /// Line Control Register, `UARTLCR_H`
     /// Line Control Register, `UARTLCR_H`
     #[doc(alias = "UARTLCR_H")]
     #[doc(alias = "UARTLCR_H")]
@@ -382,8 +377,8 @@ pub struct LineControl {
         /// the PEN bit disables parity checking and generation. See Table 3-11
         /// the PEN bit disables parity checking and generation. See Table 3-11
         /// on page 3-14 for the parity truth table.
         /// on page 3-14 for the parity truth table.
         pub sticky_parity: bool,
         pub sticky_parity: bool,
-        /// 15:8 - Reserved, do not modify, read as zero.
-        _reserved_zero_no_modify: u8,
+        /// 31:8 - Reserved, do not modify, read as zero.
+        _reserved_zero_no_modify: u24,
     }
     }
 
 
     impl LineControl {
     impl LineControl {
@@ -454,7 +449,7 @@ pub enum WordLength {
     ///
     ///
     /// # Source
     /// # Source
     /// ARM DDI 0183G, 3.3.8 Control Register, `UARTCR`, Table 3-12
     /// ARM DDI 0183G, 3.3.8 Control Register, `UARTCR`, Table 3-12
-    #[bitsize(16)]
+    #[bitsize(32)]
     #[doc(alias = "UARTCR")]
     #[doc(alias = "UARTCR")]
     #[derive(Clone, Copy, DebugBits, FromBits)]
     #[derive(Clone, Copy, DebugBits, FromBits)]
     pub struct Control {
     pub struct Control {
@@ -532,6 +527,8 @@ pub struct Control {
         /// CTS hardware flow control is enabled. Data is only transmitted when
         /// CTS hardware flow control is enabled. Data is only transmitted when
         /// the `nUARTCTS` signal is asserted.
         /// the `nUARTCTS` signal is asserted.
         pub cts_hardware_flow_control_enable: bool,
         pub cts_hardware_flow_control_enable: bool,
+        /// 31:16 - Reserved, do not modify, read as zero.
+        _reserved_zero_no_modify2: u16,
     }
     }
 
 
     impl Control {
     impl Control {