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:
Kyle Evans 2023-05-11 13:23:03 -05:00
parent 9244506a1b
commit 86c31aca33
3 changed files with 127 additions and 0 deletions

View File

@ -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)
*/

View File

@ -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);
}

View File

@ -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_ */