diff --git a/.github/.cspell/project-dictionary.txt b/.github/.cspell/project-dictionary.txt index e54307684..86fe0d3e7 100644 --- a/.github/.cspell/project-dictionary.txt +++ b/.github/.cspell/project-dictionary.txt @@ -43,6 +43,7 @@ docsrs doctests DWCAS endianness +espup exynos FIQs getauxval @@ -95,6 +96,7 @@ RAII rclass rcpc reentrancy +rsil sbcs seqlock setb diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2c1e5188b..8dee9649f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -243,6 +243,9 @@ jobs: persist-credentials: false - name: Install Rust run: rustup toolchain add nightly --no-self-update && rustup default nightly + - uses: taiki-e/install-action@v2 + with: + tool: espup - run: | set -euxo pipefail sudo apt-get -o Acquire::Retries=10 -qq update && sudo apt-get -o Acquire::Retries=10 -o Dpkg::Use-Pty=0 install -y --no-install-recommends \ @@ -259,7 +262,10 @@ jobs: sudo mv "opensbi-${OPENSBI_VERSION}-rv-bin/share/opensbi/ilp32/generic/firmware/fw_dynamic.bin" /usr/share/qemu/opensbi-riscv32-generic-fw_dynamic.bin sudo mv "opensbi-${OPENSBI_VERSION}-rv-bin/share/opensbi/ilp32/generic/firmware/fw_dynamic.elf" /usr/share/qemu/opensbi-riscv32-generic-fw_dynamic.elf rm -rf "opensbi-${OPENSBI_VERSION}-rv-bin" + - run: espup install - run: tools/no-std.sh + - run: tools/build.sh +esp xtensa-esp32-none-elf + # - run: tools/no-std.sh +esp xtensa-esp32-none-elf # TODO miri: strategy: diff --git a/README.md b/README.md index b270bccee..98d361778 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Portable atomic types including support for 128-bit atomics, atomic float, etc. - Provide `AtomicI128` and `AtomicU128`. - Provide `AtomicF32` and `AtomicF64`. ([optional, requires the `float` feature](#optional-features-float)) - Provide atomic load/store for targets where atomic is not available at all in the standard library. (RISC-V without A-extension, MSP430, AVR) -- Provide atomic CAS for targets where atomic CAS is not available in the standard library. (thumbv6m, pre-v6 ARM, RISC-V without A-extension, MSP430, AVR, etc.) (always enabled for MSP430 and AVR, [optional](#optional-cfg-unsafe-assume-single-core) otherwise) +- Provide atomic CAS for targets where atomic CAS is not available in the standard library. (thumbv6m, pre-v6 ARM, RISC-V without A-extension, MSP430, AVR, Xtensa, etc.) (always enabled for MSP430 and AVR, [optional](#optional-cfg-unsafe-assume-single-core) otherwise) - Provide stable equivalents of the standard library's atomic types' unstable APIs, such as [`AtomicPtr::fetch_*`](https://github.com/rust-lang/rust/issues/99108), [`AtomicBool::fetch_not`](https://github.com/rust-lang/rust/issues/98485), [`Atomic*::as_ptr`](https://github.com/rust-lang/rust/issues/66893). - Make features that require newer compilers, such as [fetch_max](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicUsize.html#method.fetch_max), [fetch_min](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicUsize.html#method.fetch_min), [fetch_update](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicPtr.html#method.fetch_update), and [stronger CAS failure ordering](https://github.com/rust-lang/rust/pull/98383) available on Rust 1.34+. - Provide workaround for bugs in the standard library's atomic-related APIs, such as [rust-lang/rust#100650], `fence`/`compiler_fence` on MSP430 that cause LLVM error, etc. @@ -113,7 +113,7 @@ See also the [`atomic128` module's readme](https://github.com/taiki-e/portable-a This is intentionally not an optional feature. (If this is an optional feature, dependencies can implicitly enable the feature, resulting in the use of unsound code without the end-user being aware of it.) - ARMv6-M (thumbv6m), pre-v6 ARM (e.g., thumbv4t, thumbv5te), RISC-V without A-extension are currently supported. + ARMv6-M (thumbv6m), pre-v6 ARM (e.g., thumbv4t, thumbv5te), RISC-V without A-extension, and Xtensa are currently supported. Since all MSP430 and AVR are single-core, we always provide atomic CAS for them without this cfg. diff --git a/src/imp/interrupt/mod.rs b/src/imp/interrupt/mod.rs index d5c38257e..340b83c8d 100644 --- a/src/imp/interrupt/mod.rs +++ b/src/imp/interrupt/mod.rs @@ -60,6 +60,7 @@ use arch::atomic; #[cfg_attr(target_arch = "avr", path = "avr.rs")] #[cfg_attr(target_arch = "msp430", path = "msp430.rs")] #[cfg_attr(any(target_arch = "riscv32", target_arch = "riscv64"), path = "riscv.rs")] +#[cfg_attr(target_arch = "xtensa", path = "xtensa.rs")] mod arch; use core::{cell::UnsafeCell, sync::atomic::Ordering}; diff --git a/src/imp/interrupt/xtensa.rs b/src/imp/interrupt/xtensa.rs new file mode 100644 index 000000000..7cbf2e6a9 --- /dev/null +++ b/src/imp/interrupt/xtensa.rs @@ -0,0 +1,39 @@ +// Refs: +// - Xtensa Instruction Set Architecture (ISA) Reference Manual https://0x04.net/~mwk/doc/xtensa.pdf +// - Linux kernel's Xtensa atomic implementation https://github.com/torvalds/linux/blob/v6.1/arch/xtensa/include/asm/atomic.h + +#[cfg(not(portable_atomic_no_asm))] +use core::arch::asm; + +pub(super) use core::sync::atomic; + +pub(super) type State = u32; + +/// Disables interrupts and returns the previous interrupt state. +#[inline] +pub(super) fn disable() -> State { + let r: u32; + // SAFETY: reading mstatus and disabling interrupts is safe. + // (see module-level comments of interrupt/mod.rs on the safety of using privileged instructions) + unsafe { + // Do not use `nomem` and `readonly` because prevent subsequent memory accesses from being reordered before interrupts are disabled. + asm!("rsil {0}, 15", out(reg) r, options(nostack)); + } + r +} + +/// Restores the previous interrupt state. +#[inline] +pub(super) unsafe fn restore(r: State) { + // SAFETY: the caller must guarantee that the state was retrieved by the previous `disable`, + // and we've checked that interrupts were enabled before disabling interrupts. + unsafe { + // Do not use `nomem` and `readonly` because prevent preceding memory accesses from being reordered after interrupts are enabled. + asm!( + "wsr.ps {0}", + "rsync", + in(reg) r, + options(nostack), + ); + } +} diff --git a/src/imp/mod.rs b/src/imp/mod.rs index 8da5ef1ad..f3fdcce4f 100644 --- a/src/imp/mod.rs +++ b/src/imp/mod.rs @@ -152,6 +152,7 @@ mod fallback; target_arch = "msp430", target_arch = "riscv32", target_arch = "riscv64", + target_arch = "xtensa", ))] mod interrupt; diff --git a/src/lib.rs b/src/lib.rs index cbc840284..908180bed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,7 @@ Portable atomic types including support for 128-bit atomics, atomic float, etc. - Provide `AtomicI128` and `AtomicU128`. - Provide `AtomicF32` and `AtomicF64`. ([optional, requires the `float` feature](#optional-features-float)) - Provide atomic load/store for targets where atomic is not available at all in the standard library. (RISC-V without A-extension, MSP430, AVR) -- Provide atomic CAS for targets where atomic CAS is not available in the standard library. (thumbv6m, pre-v6 ARM, RISC-V without A-extension, MSP430, AVR, etc.) (always enabled for MSP430 and AVR, [optional](#optional-cfg-unsafe-assume-single-core) otherwise) +- Provide atomic CAS for targets where atomic CAS is not available in the standard library. (thumbv6m, pre-v6 ARM, RISC-V without A-extension, MSP430, AVR, Xtensa, etc.) (always enabled for MSP430 and AVR, [optional](#optional-cfg-unsafe-assume-single-core) otherwise) - Provide stable equivalents of the standard library's atomic types' unstable APIs, such as [`AtomicPtr::fetch_*`](https://github.com/rust-lang/rust/issues/99108), [`AtomicBool::fetch_not`](https://github.com/rust-lang/rust/issues/98485), [`Atomic*::as_ptr`](https://github.com/rust-lang/rust/issues/66893). - Make features that require newer compilers, such as [fetch_max](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicUsize.html#method.fetch_max), [fetch_min](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicUsize.html#method.fetch_min), [fetch_update](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicPtr.html#method.fetch_update), and [stronger CAS failure ordering](https://github.com/rust-lang/rust/pull/98383) available on Rust 1.34+. - Provide workaround for bugs in the standard library's atomic-related APIs, such as [rust-lang/rust#100650], `fence`/`compiler_fence` on MSP430 that cause LLVM error, etc. @@ -105,7 +105,7 @@ See also the [`atomic128` module's readme](https://github.com/taiki-e/portable-a This is intentionally not an optional feature. (If this is an optional feature, dependencies can implicitly enable the feature, resulting in the use of unsound code without the end-user being aware of it.) - ARMv6-M (thumbv6m), pre-v6 ARM (e.g., thumbv4t, thumbv5te), RISC-V without A-extension are currently supported. + ARMv6-M (thumbv6m), pre-v6 ARM (e.g., thumbv4t, thumbv5te), RISC-V without A-extension, and Xtensa are currently supported. Since all MSP430 and AVR are single-core, we always provide atomic CAS for them without this cfg. @@ -190,7 +190,7 @@ See also the [`atomic128` module's readme](https://github.com/taiki-e/portable-a clippy::unreadable_literal, )] // asm_experimental_arch -// AVR and MSP430 are tier 3 platforms and require nightly anyway. +// AVR, MSP430, and xtensa are tier 3 platforms and require nightly anyway. // On tier 2 platforms (powerpc64 and s390x), we use cfg set by build script to // determine whether this feature is available or not. #![cfg_attr( @@ -199,6 +199,7 @@ See also the [`atomic128` module's readme](https://github.com/taiki-e/portable-a any( target_arch = "avr", target_arch = "msp430", + all(target_arch = "xtensa", portable_atomic_unsafe_assume_single_core), all( portable_atomic_unstable_asm_experimental_arch, target_arch = "powerpc64", @@ -314,6 +315,7 @@ compile_error!( target_arch = "msp430", target_arch = "riscv32", target_arch = "riscv64", + target_arch = "xtensa", )), )) )] @@ -327,6 +329,7 @@ compile_error!( target_arch = "msp430", target_arch = "riscv32", target_arch = "riscv64", + target_arch = "xtensa", )), )) )] diff --git a/tools/build.sh b/tools/build.sh index 8d78dd0f3..d7770ba88 100755 --- a/tools/build.sh +++ b/tools/build.sh @@ -121,7 +121,11 @@ is_no_std() { } pre_args=() +is_custom_toolchain='' if [[ "${1:-}" == "+"* ]]; then + if [[ "$1" == "+esp" ]]; then + is_custom_toolchain=1 + fi pre_args+=("$1") shift fi @@ -131,7 +135,10 @@ else targets=("${default_targets[@]}") fi -rustup_target_list=$(rustup ${pre_args[@]+"${pre_args[@]}"} target list) +rustup_target_list='' +if [[ -z "${is_custom_toolchain}" ]]; then + rustup_target_list=$(rustup ${pre_args[@]+"${pre_args[@]}"} target list) +fi rustc_target_list=$(rustc ${pre_args[@]+"${pre_args[@]}"} --print target-list) rustc_version=$(rustc ${pre_args[@]+"${pre_args[@]}"} -Vv | grep 'release: ' | sed 's/release: //') host=$(rustc ${pre_args[@]+"${pre_args[@]}"} -Vv | grep 'host: ' | sed 's/host: //') @@ -146,7 +153,9 @@ esac nightly='' if [[ "${rustc_version}" == *"nightly"* ]] || [[ "${rustc_version}" == *"dev"* ]]; then nightly=1 - rustup ${pre_args[@]+"${pre_args[@]}"} component add rust-src &>/dev/null + if [[ -z "${is_custom_toolchain}" ]]; then + rustup ${pre_args[@]+"${pre_args[@]}"} component add rust-src &>/dev/null + fi # -Z check-cfg requires 1.63.0-nightly # shellcheck disable=SC2207 if [[ "${rustc_minor_version}" -gt 62 ]] && [[ -n "${TESTS:-}" ]]; then diff --git a/tools/no-std.sh b/tools/no-std.sh index 22403954a..d013ef450 100755 --- a/tools/no-std.sh +++ b/tools/no-std.sh @@ -61,7 +61,13 @@ bail() { } pre_args=() +is_custom_toolchain='' if [[ "${1:-}" == "+"* ]]; then + if [[ "$1" == "+esp" ]]; then + # shellcheck disable=SC1091 + . "${HOME}/export-esp.sh" + is_custom_toolchain=1 + fi pre_args+=("$1") shift fi @@ -71,13 +77,18 @@ else targets=("${default_targets[@]}") fi -rustup_target_list=$(rustup ${pre_args[@]+"${pre_args[@]}"} target list) +rustup_target_list='' +if [[ -z "${is_custom_toolchain}" ]]; then + rustup_target_list=$(rustup ${pre_args[@]+"${pre_args[@]}"} target list) +fi rustc_target_list=$(rustc ${pre_args[@]+"${pre_args[@]}"} --print target-list) rustc_version=$(rustc ${pre_args[@]+"${pre_args[@]}"} -Vv | grep 'release: ' | sed 's/release: //') nightly='' if [[ "${rustc_version}" == *"nightly"* ]] || [[ "${rustc_version}" == *"dev"* ]]; then nightly=1 - rustup ${pre_args[@]+"${pre_args[@]}"} component add rust-src &>/dev/null + if [[ -z "${is_custom_toolchain}" ]]; then + rustup ${pre_args[@]+"${pre_args[@]}"} component add rust-src &>/dev/null + fi fi run() {