arm64: add swapueword8/32
Much like casueword*, except just a plain old swap. Maintains a similar interface to casu(9)- return value -1 (fault), 0 (success), or 1 (fail), and also both ll/sc and LSE variants are implemented. These will be used to implement 32-bit swp/swpb emulation on aarch64. Reveiwed by: andrew Sponsored by: Stormshield Sponsored by: Klara, Inc. Differential Revision: https://reviews.freebsd.org/D39837
This commit is contained in:
parent
9244506a1b
commit
86c31aca33
@ -55,6 +55,98 @@ fsu_fault_nopcb:
|
||||
ret
|
||||
END(fsu_fault)
|
||||
|
||||
/*
|
||||
* int swapueword8_llsc(volatile uint8_t *, uint8_t *)
|
||||
*/
|
||||
ENTRY(swapueword8_llsc)
|
||||
check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
|
||||
adr x6, fsu_fault /* Load the fault handler */
|
||||
SET_FAULT_HANDLER(x6, x4) /* And set it */
|
||||
ENTER_USER_ACCESS(w6, x4)
|
||||
|
||||
ldrb w7, [x1]
|
||||
|
||||
ldxrb w2, [x0]
|
||||
stxrb w3, w7, [x0]
|
||||
cbnz w3, 1f
|
||||
|
||||
strb w2, [x1] /* Stash old value in *val */
|
||||
|
||||
1: EXIT_USER_ACCESS(w6)
|
||||
SET_FAULT_HANDLER(xzr, x6)
|
||||
mov w0, w3
|
||||
ret
|
||||
END(swapueword8_llsc)
|
||||
|
||||
/*
|
||||
* int swapueword8_lse(volatile uint8_t *, uint8_t *)
|
||||
*/
|
||||
ENTRY(swapueword8_lse)
|
||||
check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
|
||||
adr x6, fsu_fault /* Load the fault handler */
|
||||
SET_FAULT_HANDLER(x6, x4) /* And set it */
|
||||
ENTER_USER_ACCESS(w6, x4)
|
||||
|
||||
ldrb w7, [x1]
|
||||
|
||||
.arch_extension lse
|
||||
swpb w7, w2, [x0]
|
||||
.arch_extension nolse
|
||||
|
||||
strb w2, [x1] /* Stash old value in *val */
|
||||
|
||||
EXIT_USER_ACCESS(w6)
|
||||
SET_FAULT_HANDLER(xzr, x6)
|
||||
mov w0, #0
|
||||
ret
|
||||
END(swapueword8_lse)
|
||||
|
||||
/*
|
||||
* int swapueword32_llsc(volatile uint32_t *, uint32_t *)
|
||||
*/
|
||||
ENTRY(swapueword32_llsc)
|
||||
check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
|
||||
adr x6, fsu_fault /* Load the fault handler */
|
||||
SET_FAULT_HANDLER(x6, x4) /* And set it */
|
||||
ENTER_USER_ACCESS(w6, x4)
|
||||
|
||||
ldr w7, [x1]
|
||||
|
||||
ldxr w2, [x0] /* Stash the old value in w2 */
|
||||
stxr w3, w7, [x0] /* Store new value */
|
||||
cbnz w3, 1f
|
||||
|
||||
str w2, [x1] /* Stash old value in *val */
|
||||
|
||||
1: EXIT_USER_ACCESS(w6)
|
||||
SET_FAULT_HANDLER(xzr, x6)
|
||||
mov w0, w3
|
||||
ret
|
||||
END(swapueword32_llsc)
|
||||
|
||||
/*
|
||||
* int swapueword32_lse(volatile uint32_t *, uint32_t *)
|
||||
*/
|
||||
ENTRY(swapueword32_lse)
|
||||
check_user_access 0, (VM_MAXUSER_ADDRESS-3), fsu_fault_nopcb
|
||||
adr x6, fsu_fault /* Load the fault handler */
|
||||
SET_FAULT_HANDLER(x6, x4) /* And set it */
|
||||
ENTER_USER_ACCESS(w6, x4)
|
||||
|
||||
ldr w7, [x1]
|
||||
|
||||
.arch_extension lse
|
||||
swp w7, w2, [x0]
|
||||
.arch_extension nolse
|
||||
|
||||
str w2, [x1] /* Stash old value in *val */
|
||||
|
||||
EXIT_USER_ACCESS(w6)
|
||||
SET_FAULT_HANDLER(xzr, x6)
|
||||
mov w0, #0
|
||||
ret
|
||||
END(swapueword32_llsc)
|
||||
|
||||
/*
|
||||
* int casueword32_llsc(volatile uint32_t *, uint32_t, uint32_t *, uint32_t)
|
||||
*/
|
||||
|
@ -32,6 +32,8 @@
|
||||
|
||||
#include <machine/atomic.h>
|
||||
#include <machine/ifunc.h>
|
||||
#define _MD_WANT_SWAPWORD
|
||||
#include <machine/md_var.h>
|
||||
|
||||
int casueword32_llsc(volatile uint32_t *, uint32_t, uint32_t *, uint32_t);
|
||||
int casueword32_lse(volatile uint32_t *, uint32_t, uint32_t *, uint32_t);
|
||||
@ -39,6 +41,12 @@ int casueword32_lse(volatile uint32_t *, uint32_t, uint32_t *, uint32_t);
|
||||
int casueword_llsc(volatile u_long *, u_long, u_long *, u_long);
|
||||
int casueword_lse(volatile u_long *, u_long, u_long *, u_long);
|
||||
|
||||
int swapueword8_llsc(volatile uint8_t *, uint8_t *);
|
||||
int swapueword8_lse(volatile uint8_t *, uint8_t *);
|
||||
|
||||
int swapueword32_llsc(volatile uint32_t *, uint32_t *);
|
||||
int swapueword32_lse(volatile uint32_t *, uint32_t *);
|
||||
|
||||
DEFINE_IFUNC(, int, casueword32, (volatile uint32_t *base, uint32_t oldval,
|
||||
uint32_t *oldvalp, uint32_t newval))
|
||||
{
|
||||
@ -56,3 +64,19 @@ DEFINE_IFUNC(, int, casueword, (volatile u_long *base, u_long oldval,
|
||||
|
||||
return (casueword_llsc);
|
||||
}
|
||||
|
||||
DEFINE_IFUNC(, int, swapueword8, (volatile uint8_t *base, uint8_t *val))
|
||||
{
|
||||
if (lse_supported)
|
||||
return (swapueword8_lse);
|
||||
|
||||
return (swapueword8_llsc);
|
||||
}
|
||||
|
||||
DEFINE_IFUNC(, int, swapueword32, (volatile uint32_t *base, uint32_t *val))
|
||||
{
|
||||
if (lse_supported)
|
||||
return (swapueword32_lse);
|
||||
|
||||
return (swapueword32_llsc);
|
||||
}
|
||||
|
@ -57,4 +57,15 @@ void generic_bs_poke_2(void) __asm(__STRING(generic_bs_poke_2));
|
||||
void generic_bs_poke_4(void) __asm(__STRING(generic_bs_poke_4));
|
||||
void generic_bs_poke_8(void) __asm(__STRING(generic_bs_poke_8));
|
||||
|
||||
#ifdef _MD_WANT_SWAPWORD
|
||||
/*
|
||||
* XXX These are implemented primarily for swp/swpb emulation at the moment, and
|
||||
* should be used sparingly with consideration -- they aren't implemented for
|
||||
* any other platform. If we use them anywhere else, at a minimum they need
|
||||
* KASAN/KMSAN interceptors added.
|
||||
*/
|
||||
int swapueword8(volatile uint8_t *base, uint8_t *val);
|
||||
int swapueword32(volatile uint32_t *base, uint32_t *val);
|
||||
#endif
|
||||
|
||||
#endif /* !_MACHINE_MD_VAR_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user