rp: Fix ROM cache ptr() returning the trampoline

Make sure that the ptr() function for ROM functions always returns
the actual ROM pointer.  This allows the use of flash I/O while the
function cache is enabled.
This commit is contained in:
Derek Hageman 2023-07-25 16:39:11 -06:00
parent 77e34c5e8a
commit a5f2152077

View file

@ -88,9 +88,8 @@ macro_rules! declare_rom_function {
#[doc = stringify!($name)]
#[doc = r"` ROM function."]
pub mod $name {
/// Retrieve a function pointer.
#[cfg(not(feature = "rom-func-cache"))]
pub fn ptr() -> $( $maybe_unsafe )? extern "C" fn( $($argname: $ty),* ) -> $ret {
pub(crate) fn outer_call() -> $( $maybe_unsafe )? extern "C" fn( $($argname: $ty),* ) -> $ret {
let p: *const u32 = $lookup;
unsafe {
let func : $( $maybe_unsafe )? extern "C" fn( $($argname: $ty),* ) -> $ret
@ -99,6 +98,12 @@ macro_rules! declare_rom_function {
}
}
/// Retrieve a function pointer.
#[cfg(not(feature = "rom-func-cache"))]
pub fn ptr() -> $( $maybe_unsafe )? extern "C" fn( $($argname: $ty),* ) -> $ret {
outer_call()
}
#[cfg(feature = "rom-func-cache")]
// unlike rp2040-hal we store a full word, containing the full function pointer.
// rp2040-hal saves two bytes by storing only the rom offset, at the cost of
@ -119,9 +124,8 @@ macro_rules! declare_rom_function {
}
}
/// Retrieve a function pointer.
#[cfg(feature = "rom-func-cache")]
pub fn ptr() -> $( $maybe_unsafe )? extern "C" fn( $($argname: $ty),* ) -> $ret {
pub(crate) fn outer_call() -> $( $maybe_unsafe )? extern "C" fn( $($argname: $ty),* ) -> $ret {
use core::sync::atomic::{compiler_fence, Ordering};
// This is safe because the lookup will always resolve
@ -138,11 +142,37 @@ macro_rules! declare_rom_function {
CACHE
}
}
/// Retrieve a function pointer.
#[cfg(feature = "rom-func-cache")]
pub fn ptr() -> $( $maybe_unsafe )? extern "C" fn( $($argname: $ty),* ) -> $ret {
use core::sync::atomic::{compiler_fence, Ordering};
// We can't just return the trampoline here because we need
// the actual resolved function address (e.x. flash operations
// can't reference a trampoline which itself is in flash). We
// can still utilize the cache, but we have to make sure it has
// been resolved already. Like the normal call path, we
// don't need anything stronger than fences because the
// final value always resolves to the same thing and SRAM
// itself is not cached.
compiler_fence(Ordering::Acquire);
#[allow(unused_unsafe)]
unsafe {
// ROM is 16kB in size at 0x0, so anything outside is cached
if CACHE as u32 >> 14 != 0 {
let p: *const u32 = $lookup;
CACHE = core::mem::transmute(p);
compiler_fence(Ordering::Release);
}
CACHE
}
}
}
$(#[$outer])*
pub $( $maybe_unsafe )? extern "C" fn $name( $($argname: $ty),* ) -> $ret {
$name::ptr()($($argname),*)
$name::outer_call()($($argname),*)
}
};
}