Skip to content
Draft
Show file tree
Hide file tree
Changes from 6 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");
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

xtensa is tier 3 platform, so this is unneeded.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if I understand what you're telling me here. Are you saying I can replace portable_atomic_unstable_asm_experimental_arch with target_arch = "xtensa" in code? I would prefer not adding more conditionals than I absolutely have to.

}
}
_ => {}
}
}
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