commit ef6e6071ef1581633c3f3782b8fab508501143a4 Author: Brandon Bergren Date: Mon Dec 30 15:00:23 2019 -0600 Atomic64 for PPC32, User side diff --git a/lib/libc/gen/Symbol-atomic64e.map b/lib/libc/gen/Symbol-atomic64e.map new file mode 100644 index 000000000000..61f7d99709e7 --- /dev/null +++ b/lib/libc/gen/Symbol-atomic64e.map @@ -0,0 +1,17 @@ +/* + * $FreeBSD$ + */ + +FBSD_1.6 { + atomic_add_64; + atomic_cmpset_64; + atomic_clear_64; + atomic_fcmpset_64; + atomic_fetchadd_64; + atomic_load_64; + atomic_readandclear_64; + atomic_set_64; + atomic_subtract_64; + atomic_store_64; + atomic_swap_64; +}; diff --git a/lib/libc/powerpc/gen/Makefile.common b/lib/libc/powerpc/gen/Makefile.common index 4ba72799a5cf..7374286d05d4 100644 --- a/lib/libc/powerpc/gen/Makefile.common +++ b/lib/libc/powerpc/gen/Makefile.common @@ -4,3 +4,13 @@ SRCS += _ctx_start.S eabi.S infinity.c ldexp.c makecontext.c \ signalcontext.c syncicache.c _set_tp.c trivial-getcontextx.c + +SRCS+= subr_atomic64.c + +# Copy kern/subr_atomic64.c to the libc object directory. +subr_atomic64.c: ${SRCTOP}/sys/kern/subr_atomic64.c + cat ${.ALLSRC} > ${.TARGET} + +CLEANFILES+= subr_atomic64.c + +SYM_MAPS+=${LIBC_SRCTOP}/gen/Symbol-atomic64e.map diff --git a/sys/kern/subr_atomic64.c b/sys/kern/subr_atomic64.c index 5dffb161e8f2..671c8635c5ca 100644 --- a/sys/kern/subr_atomic64.c +++ b/sys/kern/subr_atomic64.c @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -54,6 +55,14 @@ enum { ATOMIC64_SWAP }; +struct atomic64_sysarch_args { + u_int64_t *p; + u_int64_t v; + u_int64_t arg2; + int type; + u_int64_t rval; +}; + #ifdef _KERNEL #ifdef SMP @@ -147,4 +156,122 @@ atomic64_mtxinit(void *x __unused) SYSINIT(atomic64_mtxinit, SI_SUB_LOCK, SI_ORDER_MIDDLE, atomic64_mtxinit, NULL); #endif /* SMP */ +struct mtx atomic64_user_mtx; +MTX_SYSINIT(atomic64_user, &atomic64_user_mtx, "atomic64 user mutex", MTX_DEF); +int +sysarch_atomic64(void *args) +{ + struct atomic64_sysarch_args a64_args; + u_int64_t p; + int err; + + err = copyin(args, &a64_args, sizeof(a64_args)); + if (err < 0) + return (err); + + mtx_lock(&atomic64_user_mtx); + err = copyin(a64_args.p, &p, sizeof(p)); + if (err < 0) { + mtx_unlock(&atomic64_user_mtx); + goto err; + } + switch (a64_args.type) { + case ATOMIC64_ADD: + atomic_add_64(&p, a64_args.v); + break; + case ATOMIC64_CLEAR: + atomic_clear_64(&p, a64_args.v); + break; + case ATOMIC64_CMPSET: + a64_args.rval = + atomic_cmpset_64(&p, a64_args.v, a64_args.arg2); + break; + case ATOMIC64_FCMPSET: + /* XXX arg2 is a pointer */ + a64_args.rval = + atomic_fcmpset_64(&p, &a64_args.v, a64_args.arg2); + break; + case ATOMIC64_FETCHADD: + atomic_fetchadd_64(&p, a64_args.v); + break; + case ATOMIC64_LOAD: + a64_args.rval = p; + break; + case ATOMIC64_SET: + atomic_set_64(&p, a64_args.v); + break; + case ATOMIC64_SUBTRACT: + atomic_subtract_64(&p, a64_args.v); + break; + case ATOMIC64_STORE: + copyout(&a64_args.v, a64_args.p, sizeof(a64_args.p)); + break; + case ATOMIC64_SWAP: + a64_args.rval = p; + copyout(&a64_args.v, a64_args.p, sizeof(a64_args.p)); + break; + }; + + mtx_unlock(&atomic64_user_mtx); + + err = copyout(&a64_args, args, sizeof(a64_args)); +err: + return (err); +} + +#else /* !_KERNEL */ + +#define ATOMIC64_EMU_BIN_V(op, op_enum) \ + void \ + atomic_##op##_64(volatile u_int64_t *p, u_int64_t v) { \ + struct atomic64_sysarch_args args; \ + args.p = __DEVOLATILE(u_int64_t *, p); \ + args.v = v; \ + args.type = ATOMIC64_##op_enum; \ + sysarch(ATOMIC64_SYSARCH, &args); \ + return; } struct hack + +#define ATOMIC64_EMU_BIN(op, rtype, op_enum) \ + rtype \ + atomic_##op##_64(volatile u_int64_t *p, u_int64_t v) { \ + struct atomic64_sysarch_args args; \ + args.p = __DEVOLATILE(u_int64_t *, p); \ + args.v = v; \ + args.type = ATOMIC64_##op_enum; \ + sysarch(ATOMIC64_SYSARCH, &args); \ + return args.rval; } struct hack + +ATOMIC64_EMU_BIN_V(add, ADD); +ATOMIC64_EMU_BIN_V(clear, CLEAR); +ATOMIC64_EMU_BIN_V(set, SET); +ATOMIC64_EMU_BIN_V(subtract, SUBTRACT); +ATOMIC64_EMU_BIN_V(store, STORE); + +ATOMIC64_EMU_BIN(fetchadd, u_int64_t, FETCHADD); +ATOMIC64_EMU_BIN(swap, u_int64_t, SWAP); + +int +atomic_cmpset_64(volatile u_int64_t *dst, u_int64_t old, u_int64_t new) +{ + struct atomic64_sysarch_args args; + + args.p = __DEVOLATILE(u_int64_t *, dst); + args.v = old; + args.type = ATOMIC64_FCMPSET; + sysarch(ATOMIC64_SYSARCH, &args); + return args.rval; +} + +int +atomic_fcmpset_64(volatile u_int64_t *dst, u_int64_t *old, u_int64_t new) +{ + struct atomic64_sysarch_args args; + + args.p = __DEVOLATILE(u_int64_t *, dst); + args.v = *old; + args.type = ATOMIC64_FCMPSET; + sysarch(ATOMIC64_SYSARCH, &args); + *old = args.v; + return args.rval; +} #endif /* _KERNEL */ diff --git a/sys/powerpc/include/sysarch.h b/sys/powerpc/include/sysarch.h index a18451e9e09a..49b394b4137b 100644 --- a/sys/powerpc/include/sysarch.h +++ b/sys/powerpc/include/sysarch.h @@ -42,4 +42,6 @@ int sysarch(int, void *); __END_DECLS #endif +#define ATOMIC64_SYSARCH -1 + #endif /* !_MACHINE_SYSARCH_H_ */ diff --git a/sys/powerpc/powerpc/sys_machdep.c b/sys/powerpc/powerpc/sys_machdep.c index 0bd357f2d197..f41a618efcd1 100644 --- a/sys/powerpc/powerpc/sys_machdep.c +++ b/sys/powerpc/powerpc/sys_machdep.c @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #ifdef COMPAT_FREEBSD32 #include @@ -40,6 +41,11 @@ int freebsd32_sysarch(struct thread *td, struct freebsd32_sysarch_args *uap) { + switch (uap->op) { + case ATOMIC64_SYSARCH: + return (sysarch_atomic64(uap->parms)); + } + return (EINVAL); } #endif @@ -48,5 +54,11 @@ int sysarch(struct thread *td, struct sysarch_args *uap) { +#ifndef __powerpc64__ + switch (uap->op) { + case ATOMIC64_SYSARCH: + return (sysarch_atomic64(uap->parms)); + } +#endif return (EINVAL); } diff --git a/sys/sys/_atomic64e.h b/sys/sys/_atomic64e.h index d0abdc2e5a89..358489c9a896 100644 --- a/sys/sys/_atomic64e.h +++ b/sys/sys/_atomic64e.h @@ -36,6 +36,7 @@ #ifdef _KERNEL #define HAS_EMULATED_ATOMIC64 +#endif /* Emulated versions of 64-bit atomic operations. */ @@ -75,5 +76,7 @@ void atomic_store_64(volatile u_int64_t *, u_int64_t); u_int64_t atomic_swap_64(volatile u_int64_t *, u_int64_t); -#endif /* _KERNEL */ +#ifdef _KERNEL +int sysarch_atomic64(void *); +#endif #endif /* _SYS_ATOMIC64E_H_ */