From 5e8ea615aaf444a9fbc2326e00d1be0d62a682a3 Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 14 Nov 2017 06:39:46 +0100 Subject: [PATCH] Fix downstream errors due to inline assembly Even though this crate is intended for ARM Cortex-M microcontrollers, its code must be compilable on other platforms, for example when running unit tests in a downstream crate. This could lead to compile or link errors, due to inline assembly that was invalid on the host platform. Those errors wouldn't show up when compiling this crate, as inline assembly within functions marked as `#[inline(always)]` bypasses validation, unless the function is used.[1] This commit fixes the issue, by only compiling inline assembly when running on ARM. In some cases, some replacement code had to be added, to make the compiler happy. [1]: https://github.com/rust-lang/rust/issues/36718 --- src/register/apsr.rs | 16 ++++++++++++++++ src/register/basepri.rs | 22 ++++++++++++++++++++-- src/register/control.rs | 16 ++++++++++++++++ src/register/faultmask.rs | 16 ++++++++++++++++ src/register/lr.rs | 22 ++++++++++++++++++++-- src/register/msp.rs | 22 ++++++++++++++++++++-- src/register/pc.rs | 22 ++++++++++++++++++++-- src/register/primask.rs | 16 ++++++++++++++++ src/register/psp.rs | 22 ++++++++++++++++++++-- 9 files changed, 164 insertions(+), 10 deletions(-) diff --git a/src/register/apsr.rs b/src/register/apsr.rs index d966de0d..e86d7ab7 100644 --- a/src/register/apsr.rs +++ b/src/register/apsr.rs @@ -42,6 +42,8 @@ impl Apsr { #[inline(always)] pub fn read() -> Apsr { let r: u32; + + #[cfg(target_arch = "arm")] unsafe { asm!("mrs $0, APSR" : "=r"(r) @@ -49,5 +51,19 @@ pub fn read() -> Apsr { : : "volatile"); } + + #[cfg(not(target_arch = "arm"))] + { r = 0; } + Apsr { bits: r } } + + +#[cfg(test)] +mod tests { + #[test] + fn it_should_compile() { + // Make sure that ARM-specific inline assembly is only included on ARM. + super::read(); + } +} diff --git a/src/register/basepri.rs b/src/register/basepri.rs index c02fe843..6110e216 100644 --- a/src/register/basepri.rs +++ b/src/register/basepri.rs @@ -4,6 +4,8 @@ #[inline(always)] pub fn read() -> u8 { let r: u32; + + #[cfg(target_arch = "arm")] unsafe { asm!("mrs $0, BASEPRI" : "=r"(r) @@ -11,15 +13,31 @@ pub fn read() -> u8 { : : "volatile"); } + + #[cfg(not(target_arch = "arm"))] + { r = 0; } + r as u8 } /// Writes to the CPU register #[inline(always)] -pub unsafe fn write(basepri: u8) { +pub unsafe fn write(_basepri: u8) { + #[cfg(target_arch = "arm")] asm!("msr BASEPRI, $0" : - : "r"(basepri) + : "r"(_basepri) : "memory" : "volatile"); } + + +#[cfg(test)] +mod tests { + #[test] + fn it_should_compile() { + // Make sure that ARM-specific inline assembly is only included on ARM. + super::read(); + unsafe { super::write(5); } + } +} diff --git a/src/register/control.rs b/src/register/control.rs index d5cb8ec8..afc83792 100644 --- a/src/register/control.rs +++ b/src/register/control.rs @@ -107,6 +107,8 @@ impl Fpca { #[inline(always)] pub fn read() -> Control { let r: u32; + + #[cfg(target_arch = "arm")] unsafe { asm!("mrs $0, CONTROL" : "=r"(r) @@ -114,5 +116,19 @@ pub fn read() -> Control { : : "volatile"); } + + #[cfg(not(target_arch = "arm"))] + { r = 0; } + Control { bits: r } } + + +#[cfg(test)] +mod tests { + #[test] + fn it_should_compile() { + // Make sure that ARM-specific inline assembly is only included on ARM. + super::read(); + } +} diff --git a/src/register/faultmask.rs b/src/register/faultmask.rs index 7a0d06c5..7d116a90 100644 --- a/src/register/faultmask.rs +++ b/src/register/faultmask.rs @@ -25,6 +25,8 @@ impl Faultmask { #[inline(always)] pub fn read() -> Faultmask { let r: u32; + + #[cfg(target_arch = "arm")] unsafe { asm!("mrs $0, FAULTMASK" : "=r"(r) @@ -32,9 +34,23 @@ pub fn read() -> Faultmask { : : "volatile"); } + + #[cfg(not(target_arch = "arm"))] + { r = 0; } + if r & (1 << 0) == (1 << 0) { Faultmask::Inactive } else { Faultmask::Active } } + + +#[cfg(test)] +mod tests { + #[test] + fn it_should_compile() { + // Make sure that ARM-specific inline assembly is only included on ARM. + super::read(); + } +} diff --git a/src/register/lr.rs b/src/register/lr.rs index fecfecbe..67c49b2d 100644 --- a/src/register/lr.rs +++ b/src/register/lr.rs @@ -4,6 +4,8 @@ #[inline(always)] pub fn read() -> u32 { let r: u32; + + #[cfg(target_arch = "arm")] unsafe { asm!("mov $0,R14" : "=r"(r) @@ -11,15 +13,31 @@ pub fn read() -> u32 { : : "volatile"); } + + #[cfg(not(target_arch = "arm"))] + { r = 0; } + r } /// Writes `bits` to the CPU register #[inline(always)] -pub unsafe fn write(bits: u32) { +pub unsafe fn write(_bits: u32) { + #[cfg(target_arch = "arm")] asm!("mov R14,$0" : - : "r"(bits) + : "r"(_bits) : : "volatile"); } + + +#[cfg(test)] +mod tests { + #[test] + fn it_should_compile() { + // Make sure that ARM-specific inline assembly is only included on ARM. + super::read(); + unsafe { super::write(5); } + } +} diff --git a/src/register/msp.rs b/src/register/msp.rs index ebea6ed5..384eb134 100644 --- a/src/register/msp.rs +++ b/src/register/msp.rs @@ -4,6 +4,8 @@ #[inline(always)] pub fn read() -> u32 { let r; + + #[cfg(target_arch = "arm")] unsafe { asm!("mrs $0,MSP" : "=r"(r) @@ -11,15 +13,31 @@ pub fn read() -> u32 { : : "volatile"); } + + #[cfg(not(target_arch = "arm"))] + { r = 0; } + r } /// Writes `bits` to the CPU register #[inline(always)] -pub unsafe fn write(bits: u32) { +pub unsafe fn write(_bits: u32) { + #[cfg(target_arch = "arm")] asm!("msr MSP,$0" : - : "r"(bits) + : "r"(_bits) : : "volatile"); } + + +#[cfg(test)] +mod tests { + #[test] + fn it_should_compile() { + // Make sure that ARM-specific inline assembly is only included on ARM. + super::read(); + unsafe { super::write(5); } + } +} diff --git a/src/register/pc.rs b/src/register/pc.rs index 3fec1aeb..155c4110 100644 --- a/src/register/pc.rs +++ b/src/register/pc.rs @@ -4,6 +4,8 @@ #[inline(always)] pub fn read() -> u32 { let r; + + #[cfg(target_arch = "arm")] unsafe { asm!("mov $0,R15" : "=r"(r) @@ -11,15 +13,31 @@ pub fn read() -> u32 { : : "volatile"); } + + #[cfg(not(target_arch = "arm"))] + { r = 0; } + r } /// Writes `bits` to the CPU register #[inline(always)] -pub unsafe fn write(bits: u32) { +pub unsafe fn write(_bits: u32) { + #[cfg(target_arch = "arm")] asm!("mov R15,$0" : - : "r"(bits) + : "r"(_bits) : : "volatile"); } + + +#[cfg(test)] +mod tests { + #[test] + fn it_should_compile() { + // Make sure that ARM-specific inline assembly is only included on ARM. + super::read(); + unsafe { super::write(5); } + } +} diff --git a/src/register/primask.rs b/src/register/primask.rs index 313693f3..ac53565d 100644 --- a/src/register/primask.rs +++ b/src/register/primask.rs @@ -25,6 +25,8 @@ impl Primask { #[inline(always)] pub fn read() -> Primask { let r: u32; + + #[cfg(target_arch = "arm")] unsafe { asm!("mrs $0, PRIMASK" : "=r"(r) @@ -32,9 +34,23 @@ pub fn read() -> Primask { : : "volatile"); } + + #[cfg(not(target_arch = "arm"))] + { r = 0; } + if r & (1 << 0) == (1 << 0) { Primask::Inactive } else { Primask::Active } } + + +#[cfg(test)] +mod tests { + #[test] + fn it_should_compile() { + // Make sure that ARM-specific inline assembly is only included on ARM. + super::read(); + } +} diff --git a/src/register/psp.rs b/src/register/psp.rs index ecd6f9cb..334a97bd 100644 --- a/src/register/psp.rs +++ b/src/register/psp.rs @@ -4,6 +4,8 @@ #[inline(always)] pub fn read() -> u32 { let r; + + #[cfg(target_arch = "arm")] unsafe { asm!("mrs $0,PSP" : "=r"(r) @@ -11,15 +13,31 @@ pub fn read() -> u32 { : : "volatile"); } + + #[cfg(not(target_arch = "arm"))] + { r = 0; } + r } /// Writes `bits` to the CPU register #[inline(always)] -pub unsafe fn write(bits: u32) { +pub unsafe fn write(_bits: u32) { + #[cfg(target_arch = "arm")] asm!("msr PSP,$0" : - : "r"(bits) + : "r"(_bits) : : "volatile"); } + + +#[cfg(test)] +mod tests { + #[test] + fn it_should_compile() { + // Make sure that ARM-specific inline assembly is only included on ARM. + super::read(); + unsafe { super::write(5); } + } +}