vmbase: uart: Move asm block to crate::arch
Move the manual assembly into the vmbase::arch module so that the
vmbase::uart driver remains arch-agnostic, making it easier to port to
other CPU architectures.
Note that the manual assembly is preferred over using the standard
write_volatile() due to b/345658173 and [1] (see also aosp/3125955).
[1]: https://github.com/rust-lang/rust/issues/131894
Test: m pvmfw # Then check disassembly for STRB
Change-Id: I6d404df4c0439b8e208d1ef533b60434d2b2bec8
diff --git a/libs/libvmbase/src/arch.rs b/libs/libvmbase/src/arch.rs
index d8bb8b2..992ab27 100644
--- a/libs/libvmbase/src/arch.rs
+++ b/libs/libvmbase/src/arch.rs
@@ -91,3 +91,22 @@
}
}};
}
+
+/// Write with well-defined compiled behavior.
+///
+/// See https://github.com/rust-lang/rust/issues/131894
+///
+/// # Safety
+///
+/// `dst` must be valid for writes.
+pub unsafe fn write_volatile_u8(dst: *mut u8, src: u8) {
+ // SAFETY: strb only modifies *dst, which must be valid for writes.
+ unsafe {
+ core::arch::asm!(
+ "strb {value:w}, [{ptr}]",
+ value = in(reg) src,
+ ptr = in(reg) dst,
+ options(preserves_flags),
+ );
+ }
+}
diff --git a/libs/libvmbase/src/uart.rs b/libs/libvmbase/src/uart.rs
index e35555d..427499b 100644
--- a/libs/libvmbase/src/uart.rs
+++ b/libs/libvmbase/src/uart.rs
@@ -15,6 +15,7 @@
//! Minimal driver for an 8250 UART. This only implements enough to work with the emulated 8250
//! provided by crosvm, and won't work with real hardware.
+use crate::arch::write_volatile_u8;
use core::fmt::{self, Write};
/// Minimal driver for an 8250 UART. This only implements enough to work with the emulated 8250
@@ -39,13 +40,7 @@
pub fn write_byte(&self, byte: u8) {
// SAFETY: We know that the base address points to the control registers of a UART device
// which is appropriately mapped.
- unsafe {
- core::arch::asm!(
- "strb {value:w}, [{ptr}]",
- value = in(reg) byte,
- ptr = in(reg) self.base_address,
- );
- }
+ unsafe { write_volatile_u8(self.base_address, byte) }
}
}