Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,8 @@ jobs:
# if: matrix.rust == 'stable'
- run: tools/no-std.sh +esp xtensa-esp32s2-none-elf
if: matrix.rust == 'stable'
- run: tools/no-std.sh +esp xtensa-esp32s3-none-elf
if: matrix.rust == 'stable'

miri:
needs: tidy
Expand Down
38 changes: 37 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,17 @@ fn main() {
// Custom cfgs set by build script. Not public API.
// grep -F 'cargo:rustc-cfg=' build.rs | grep -Ev '^ *//' | sed -E 's/^.*cargo:rustc-cfg=//; s/(=\\)?".*$//' | LC_ALL=C sort -u | tr '\n' ',' | sed -E 's/,$/\n/'
println!(
"cargo:rustc-check-cfg=cfg(portable_atomic_atomic_intrinsics,portable_atomic_disable_fiq,portable_atomic_force_amo,portable_atomic_ll_sc_rmw,portable_atomic_no_asm,portable_atomic_no_asm_maybe_uninit,portable_atomic_no_atomic_64,portable_atomic_no_atomic_cas,portable_atomic_no_atomic_load_store,portable_atomic_no_atomic_min_max,portable_atomic_no_cfg_target_has_atomic,portable_atomic_no_cmpxchg16b_intrinsic,portable_atomic_no_cmpxchg16b_target_feature,portable_atomic_no_const_mut_refs,portable_atomic_no_const_raw_ptr_deref,portable_atomic_no_const_transmute,portable_atomic_no_core_unwind_safe,portable_atomic_no_diagnostic_namespace,portable_atomic_no_strict_provenance,portable_atomic_no_strict_provenance_atomic_ptr,portable_atomic_no_stronger_failure_ordering,portable_atomic_no_track_caller,portable_atomic_no_unsafe_op_in_unsafe_fn,portable_atomic_pre_llvm_15,portable_atomic_pre_llvm_16,portable_atomic_pre_llvm_18,portable_atomic_pre_llvm_20,portable_atomic_s_mode,portable_atomic_sanitize_thread,portable_atomic_target_feature,portable_atomic_unsafe_assume_privileged,portable_atomic_unsafe_assume_single_core,portable_atomic_unstable_asm,portable_atomic_unstable_asm_experimental_arch,portable_atomic_unstable_cfg_target_has_atomic,portable_atomic_unstable_isa_attribute)"
"cargo:rustc-check-cfg=cfg(portable_atomic_atomic_intrinsics,portable_atomic_disable_fiq,portable_atomic_force_amo,portable_atomic_ll_sc_rmw,portable_atomic_no_asm,portable_atomic_no_asm_maybe_uninit,portable_atomic_no_atomic_64,portable_atomic_no_atomic_cas,portable_atomic_no_atomic_load_store,portable_atomic_no_atomic_min_max,portable_atomic_no_cfg_target_has_atomic,portable_atomic_no_cmpxchg16b_intrinsic,portable_atomic_no_cmpxchg16b_target_feature,portable_atomic_no_const_mut_refs,portable_atomic_no_const_raw_ptr_deref,portable_atomic_no_const_transmute,portable_atomic_no_core_unwind_safe,portable_atomic_no_diagnostic_namespace,portable_atomic_no_outline_atomics,portable_atomic_no_strict_provenance,portable_atomic_no_strict_provenance_atomic_ptr,portable_atomic_no_stronger_failure_ordering,portable_atomic_no_track_caller,portable_atomic_no_unsafe_op_in_unsafe_fn,portable_atomic_pre_llvm_15,portable_atomic_pre_llvm_16,portable_atomic_pre_llvm_18,portable_atomic_pre_llvm_20,portable_atomic_s_mode,portable_atomic_sanitize_thread,portable_atomic_target_cpu,portable_atomic_target_feature,portable_atomic_unsafe_assume_privileged,portable_atomic_unsafe_assume_single_core,portable_atomic_unstable_asm,portable_atomic_unstable_asm_experimental_arch,portable_atomic_unstable_cfg_target_has_atomic,portable_atomic_unstable_isa_attribute)"
);
// TODO: handle multi-line target_feature_fallback
// grep -F 'target_feature_fallback("' build.rs | grep -Ev '^ *//' | sed -E 's/^.*target_feature_fallback\(//; s/",.*$/"/' | LC_ALL=C sort -u | tr '\n' ',' | sed -E 's/,$/\n/'
println!(
r#"cargo:rustc-check-cfg=cfg(portable_atomic_target_feature,values("cmpxchg16b","distinct-ops","fast-serialization","load-store-on-cond","lse","lse128","lse2","lsfe","mclass","miscellaneous-extensions-3","quadword-atomics","rcpc3","rmw","v6","v7","zaamo","zabha","zacas"))"#
);
// grep -F 'target_cpu_fallback("' build.rs | grep -Ev '^ *//' | sed -E 's/^.*target_cpu_fallback\(//; s/"\).*$/"/' | LC_ALL=C sort -u | tr '\n' ',' | sed -E 's/,$/\n/'
println!(
r#"cargo:rustc-check-cfg=cfg(portable_atomic_target_cpu,values("esp32","esp32s3"))"#
);
}

// https://github.com/rust-lang/rust/pull/123745 (includes https://github.com/rust-lang/cargo/pull/13560) merged in Rust 1.79 (nightly-2024-04-11).
Expand Down Expand Up @@ -193,6 +197,12 @@ fn main() {
println!("cargo:rustc-cfg=portable_atomic_unstable_asm_experimental_arch");
}
}
"xtensa" => {
// https://github.com/rust-lang/rust/pull/93868 merged in Rust 1.60 (nightly-2022-02-13).
if is_allowed_feature("asm_experimental_arch") {
println!("cargo:rustc-cfg=portable_atomic_unstable_asm_experimental_arch");
}
}
_ => {}
}
}
Expand Down Expand Up @@ -502,6 +512,27 @@ fn main() {
}
target_feature_fallback("rmw", xmegau);
}
"xtensa" => {
// Some Xtensa CPUs have CAS for internal memory, but also have an external address space,
// which does not correctly provide atomic access. The affected CPUs have their own build targets,
// but may also be specified with `-C target-cpu`.
// Xtensa targets have been introduced in Rust 1.81.0.
if let Some(cpu) = target_cpu() {
if cpu == "esp32" || cpu == "esp32s3" {
target_cpu_fallback(&cpu);
}
} else {
match target {
"xtensa-esp32-none-elf" | "xtensa-esp32-espidf" => target_cpu_fallback("esp32"),
"xtensa-esp32s3-none-elf" | "xtensa-esp32s3-espidf" => {
target_cpu_fallback("esp32s3")
}
// ESP32-S2 does not have atomic CAS, so it is not affected by the issue the same way.
// For other Xtensa CPUs, assume they are not affected.
_ => {}
}
}
}
_ => {}
}
}
Expand Down Expand Up @@ -560,6 +591,11 @@ fn target_cpu() -> Option<String> {
cpu.map(str::to_owned)
}

// `target_cpu` is not a valid cfg option. Where there is absolutely no other option, inject a cfg fallback.
fn target_cpu_fallback(cpu: &str) {
println!("cargo:rustc-cfg=portable_atomic_target_cpu=\"{}\"", cpu);
}

fn is_allowed_feature(name: &str) -> bool {
// https://github.com/dtolnay/thiserror/pull/248
if env::var_os("RUSTC_STAGE").is_some() {
Expand Down
65 changes: 62 additions & 3 deletions src/imp/interrupt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ Fallback implementation based on disabling interrupts or critical-section
See README.md of this directory for details.
*/

#[cfg(not(feature = "critical-section"))]
#[cfg(any(
not(feature = "critical-section"),
portable_atomic_target_cpu = "esp32",
portable_atomic_target_cpu = "esp32s3",
))]
#[cfg_attr(
all(
target_arch = "arm",
Expand All @@ -30,13 +34,26 @@ See README.md of this directory for details.
#[cfg_attr(target_arch = "xtensa", path = "xtensa.rs")]
pub(super) mod arch;

// ESP32 and ESP32-S3 require a critical-section based implementation for some of their address spaces.
#[cfg_attr(
portable_atomic_no_cfg_target_has_atomic,
cfg(any(test, portable_atomic_no_atomic_cas, portable_atomic_unsafe_assume_single_core))
cfg(any(
test,
portable_atomic_no_atomic_cas,
portable_atomic_unsafe_assume_single_core,
portable_atomic_target_cpu = "esp32",
portable_atomic_target_cpu = "esp32s3",
))
)]
#[cfg_attr(
not(portable_atomic_no_cfg_target_has_atomic),
cfg(any(test, not(target_has_atomic = "ptr"), portable_atomic_unsafe_assume_single_core))
cfg(any(
test,
not(target_has_atomic = "ptr"),
portable_atomic_unsafe_assume_single_core,
portable_atomic_target_cpu = "esp32",
portable_atomic_target_cpu = "esp32s3",
))
)]
items!({
use core::{cell::UnsafeCell, sync::atomic::Ordering};
Expand Down Expand Up @@ -243,6 +260,8 @@ items!({
test,
target_arch = "avr",
target_arch = "msp430",
portable_atomic_target_cpu = "esp32",
portable_atomic_target_cpu = "esp32s3",
not(target_has_atomic = "ptr")
))
)]
Expand Down Expand Up @@ -616,6 +635,46 @@ items!({
}
});

// Current target data unsoundly enables CAS for these devices. Generate the necessary
// critical-section based implementations that we'll wrap in `imp/xtensa.rs`.
#[cfg_attr(portable_atomic_no_cfg_target_has_atomic, cfg(all()))]
#[cfg_attr(
not(portable_atomic_no_cfg_target_has_atomic),
cfg(all(
target_has_atomic,
any(portable_atomic_target_cpu = "esp32", portable_atomic_target_cpu = "esp32s3")
))
)]
items!({
use self::arch::atomic;

atomic_int!(load_store_atomic, AtomicIsize, isize, 4);
atomic_int!(load_store_atomic, AtomicUsize, usize, 4);

atomic_int!(load_store_atomic[sub_word], AtomicI8, i8, 1);
atomic_int!(load_store_atomic[sub_word], AtomicU8, u8, 1);

atomic_int!(load_store_atomic[sub_word], AtomicI16, i16, 2);
atomic_int!(load_store_atomic[sub_word], AtomicU16, u16, 2);

atomic_int!(load_store_atomic, AtomicI32, i32, 4);
atomic_int!(load_store_atomic, AtomicU32, u32, 4);

atomic_base!(native_load_store, [T] AtomicPtr, *mut T);
impl<T> AtomicPtr<T> {
#[cfg(test)]
#[inline]
fn fetch_ptr_add(&self, val: usize, order: Ordering) -> *mut T {
self.fetch_byte_add(val.wrapping_mul(core::mem::size_of::<T>()), order)
}
#[cfg(test)]
#[inline]
fn fetch_ptr_sub(&self, val: usize, order: Ordering) -> *mut T {
self.fetch_byte_sub(val.wrapping_mul(core::mem::size_of::<T>()), order)
}
}
});

// Double or more width atomics (require fallback feature for consistency with other situations).
#[cfg(target_pointer_width = "16")]
#[cfg(any(test, feature = "fallback"))]
Expand Down
12 changes: 11 additions & 1 deletion src/imp/interrupt/xtensa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,20 @@ use core::arch::asm;
)]
#[cfg_attr(
not(portable_atomic_no_cfg_target_has_atomic),
cfg(any(test, not(target_has_atomic = "ptr")))
cfg(any(
test,
not(any(
portable_atomic_target_cpu = "esp32",
portable_atomic_target_cpu = "esp32s3",
target_has_atomic = "ptr"
))
))
)]
pub(super) use core::sync::atomic;

#[cfg(any(portable_atomic_target_cpu = "esp32", portable_atomic_target_cpu = "esp32s3"))]
pub(super) use crate::imp::xtensa as atomic;

pub(crate) type State = u32;

/// Disables interrupts and returns the previous interrupt state.
Expand Down
Loading
Loading