/* SPDX-License-Identifier: MPL-2.0 */
.text
.option push
# We explicitly add this directive due to a known bug in how rustc treats target
# features in `global_asm`. Check https://github.com/rust-lang/rust/issues/111637#issuecomment-1870096878
# for details.
.option arch, rv64imac
# Atomically compares and exchanges a 32-bit integer value. This function works
# with exception handling and can recover from a page fault.
#
# Returns the previous value or `!0u64` if failed to update.
.global __atomic_cmpxchg_fallible
.type __atomic_cmpxchg_fallible, @function
__atomic_cmpxchg_fallible: # (ptr: *mut u32, old_val: u32, new_val: u32) -> u64
li t2, {SSTATUS_SUM}
csrs sstatus, t2
cmpxchg_load:
lr.w t0, (a0)
bne t0, a1, cmpxchg_done
cmpxchg_store:
sc.w t1, a2, (a0)
bnez t1, cmpxchg_load
cmpxchg_done:
mv a0, t0
csrc sstatus, t2
ret
cmpxchg_fault:
li a0, -1
csrc sstatus, t2
ret
.size __atomic_cmpxchg_fallible, .-__atomic_cmpxchg_fallible
.option pop
.pushsection .ex_table, "a", @progbits
.balign 8
.quad cmpxchg_load
.quad cmpxchg_fault
.quad cmpxchg_store
.quad cmpxchg_fault
.popsection