Index | Thread | Search

From:
Jeremie Courreges-Anglas <jca@wxcvbn.org>
Subject:
Re: arm64 LSE support in userland: introduce elf_aux_info?
To:
Mark Kettenis <mark.kettenis@xs4all.nl>
Cc:
deraadt@openbsd.org, tech@openbsd.org, brad@comstyle.com
Date:
Fri, 12 Jul 2024 18:23:25 +0200

Download raw body.

Thread
On Fri, Jul 12, 2024 at 01:18:41PM +0200, Mark Kettenis wrote:
> > Date: Wed, 10 Jul 2024 18:41:57 +0200
> > From: Jeremie Courreges-Anglas <jca@wxcvbn.org>
> > 
> > On Mon, Jul 08, 2024 at 09:17:23AM +0200, Mark Kettenis wrote:
> > > > Date: Sun, 7 Jul 2024 17:44:39 +0200
> > > > From: Jeremie Courreges-Anglas <jca@wxcvbn.org>
> > > > 
> > > > On Sun, Jul 07, 2024 at 03:00:55PM +0200, Mark Kettenis wrote:
> > > > > > Date: Sat, 6 Jul 2024 14:47:28 +0200
> > > > > > From: Jeremie Courreges-Anglas <jca@wxcvbn.org>
> > > > > > 
> > > > > > On Thu, Jul 04, 2024 at 08:14:15AM -0600, Theo de Raadt wrote:
> > > > > > > In glibc, getauxval(3) is a monster API that keeps growing additional
> > > > > > > heads and tentacles.  Exporting a tiny version of it to userland is
> > > > > > > worrying.
> > > > > > 
> > > > > > Agreed about getauxval.
> > > > > 
> > > > > Not sure what you folks mean with that.  Is the problem that there are
> > > > > too many AT_xxx constants for which we would not want to add support?
> > > > > That I do agree with.
> > > > 
> > > > Yep.
> > > > 
> > > > > So do yout think that adding just the few AT_xxx constants that we
> > > > > care about would cause too many problems in ports?
> > > > 
> > > > (One common pattern visible in ports is to #define some AT_xxx
> > > > constants (with a hardcoded value copied from Linux headers) if
> > > > they're not already #defined.)
> > > > 
> > > > I fear that detection of the getauxval() symbol may trigger the use of
> > > > Linux-specific code paths, possibly with no useful/usable fallback in
> > > > case of an error.  Also, some ports may start to include <linux/*.h>
> > > > headers along with their use of getauxval().  It would be a shame to
> > > > implement getauxval() and yet need non-trivial patches in ports.
> > > > 
> > > > > > > When the real problem here is a tiny little check to use done only
> > > > > > > internal to only our libc, and therefore why not use an OpenBSD private
> > > > > > > interface.
> > > > > > 
> > > > > > Indeed we could use a private API for this specific need.  But the
> > > > > > problem is not just about our libc, ports also want a way to query
> > > > > > hardware capabilities.  We usually have to patch them to use a
> > > > > > sysctl(2) or just drop the code that detects such capabilities.
> > > > > > I feel like implementing elf_aux_info(3) should be considered.  Has
> > > > > > someone already tried that?  If people don't object, that could be a
> > > > > > todo entry for c2k24.
> > > > > 
> > > > > So elf_aux_info(3) is just getauxval(3) with a somewhat different API.
> > > > > It is a bit better in the sense that it unambiguously tells you if an
> > > > > AT_xxx value isn't supported.
> > > > > 
> > > > > Are you less worried about us not implementing all the AT_xxx defines
> > > > > that FreeBSD has?
> > > > 
> > > > Yes.  Dumb comparison:
> > > > 
> > > >   https://www.man7.org/linux/man-pages/man3/getauxval.3.html 34 defines
> > > >   https://man.freebsd.org/cgi/man.cgi?elf_aux_info(3) 11 defines
> > > > 
> > > > Compare that to the 8 AUX_xxx values handled in our kern/exec_elf.c...
> > > 
> > > And perhaps more importantly, FreeBSD doesn't have bad ones like
> > > AT_SECURE.
> > > 
> > > > BTW, we currently always export 0 for AUX_flags.  The comment in
> > > > exec_elf.h says "processor flags".  Have you considered reusing this
> > > > for a quick compiler-rt hack?
> > > 
> > > AUX_flags would be AT_FLAGS, which is related to e_flags in the ELF
> > > header.  Solaris used this to mark binaries that (unconditionally) use
> > > certain instruction set extensions.  I suppose we could use it on
> > > arm64 but AT_HWCAP and AT_HWCAP2 on Linux and FreeBSD provide more
> > > flags than we could fit in AT_FLAGS.
> > 
> > Ack, forget my question.  I introduced new AUX_hwcap* requests, that
> > map to the AT_HWCAP* defines.
> > 
> > > If we go this route we do want the features to align with what Linux
> > > and FreeBSD use.  I don't think we want to burden porters with
> > > figuring out what OpenBSD feature bit maps onto what Linux uses.
> > 
> > For the diff below I just used the bits from FreeBSD.  Hopefully they
> > should be the same as Linux, but I haven't checked yet.
> > 
> > > > > I suspect that there is a much smaller number of ports that support
> > > > > elf_aux_info(3).
> > > > 
> > > > Well, maybe it's a good thing? ;)
> > > > 
> > > > More seriously, I've started an amd64 bulk build on a system with a
> > > > dumb elf_aux_info() that always returns ENOENT.  I should have numbers
> > > > in 2 days for ports that may automatically pick it up.
> > 
> > That bulk build completed with no fallout, but I doubt that
> > elf_aux_info() is used much on amd64.
> > 
> > > > There would also be a bunch of other ports where we'd have to add an
> > > > ugly "|| defined(__OpenBSD__)" chunk to the FreeBSD code path, but at
> > > > least that's something that could be upstreamed.
> > > >
> > > > Feedback from other porters would be welcome.
> > 
> > The diff below introduces elf_aux_info(3).  Manpage and
> > <machine/elf.h> bits taken from FreeBSD.  I have only tested this
> > (successfully) on amd64.  I have no arm64 machine at hand, and the
> > riscv64 ports machines are currently busy with a bulk build.
> > 
> > Mark, as discussed, I'm only setting the Atomics/LSE bit on arm64.
> > If I didn't mess something up, the regress test should show it.
> > 
> > The main TODO entries:
> > - arm
> > - remaining arm64 bits (cpu_sysctl/hwcap refactoring?)
> > - powerpc
> > 
> > Thoughts?  ok?
> 
> A few thoughts here.
> 
> * Reading the auxv stuff during libc init and storing it in local
>   variables is a good thing as it avoids issues from messing around
>   with envp and such.
> 
> * I have no objection to also supporting AT_PAGESZ.

Rationale was: it's harmless and it gives the regress test something
to test on architectures with no hwcap support.

> * We should probably properly prune the man page instead of commenting
>   out AT_xxx entries (unless we intend to support them at a later stage).

I looked and decided to just drop them for now.  There may be
candidates but I'd rather have them discussed later if at all.

> * I think we should prune the list of AT_xxx defines.  Maybe we should
>   only provide the ones that we actually implement?  Or at least we
>   should prune some of the non-standard ones that FreeBSD added.  Or
>   are you afraid this may break ports code?

That was my concern, indeed.  Looking at the FreeBSD code, they're
also not supporting all the defines they provide, they even document
this in BUGS (which I trimmed and renamed to CAVEATS).  Code using
that function should check for ENOENT to know whether a feature is not
supported.

However, doing a quick audit using https://codesearch.debian.net/ it
seems only very few of them are used; actually I could find only one,
used in FreeBSD-specific code.  So I trimmed the list, but keeping the
same AT_* values (they are supposed to match our AUX_* values).
I guess we could re-add some in case we find actual consumers.

> * There are some tab vs. spaces inconsistencies, especially in the
>   multiple-include protection stuff.

They were present in the original files, I just didn't bother to fix
them.  Done in the updated diff.

> A few more comments below...

Also adressed, thanks, see new diff.  Christian and Stuart confirmed
they liked the idea.

ok?


diff --git a/lib/libc/Symbols.list b/lib/libc/Symbols.list
index eb4d78cc947..48c4965a6d9 100644
--- a/lib/libc/Symbols.list
+++ b/lib/libc/Symbols.list
@@ -608,6 +608,7 @@ daemon
 devname
 dirfd
 dirname
+elf_aux_info
 endfsent
 endgrent
 endnetgrent
diff --git a/lib/libc/dlfcn/init.c b/lib/libc/dlfcn/init.c
index 9fc63c97f98..0cf4347631c 100644
--- a/lib/libc/dlfcn/init.c
+++ b/lib/libc/dlfcn/init.c
@@ -49,6 +49,8 @@ char	***_csu_finish(char **_argv, char **_envp, void (*_cleanup)(void));
 /* provide definitions for these */
 int	_pagesize = 0;
 struct timekeep	*_timekeep;
+unsigned long	_hwcap, _hwcap2;
+int	_hwcap_avail, _hwcap2_avail;
 
 /*
  * In dynamically linked binaries environ and __progname are overridden by
@@ -96,6 +98,14 @@ _libc_preinit(int argc, char **argv, char **envp, dl_cb_cb *cb)
 		;
 	for (aux = (void *)envp; aux->au_id != AUX_null; aux++) {
 		switch (aux->au_id) {
+		case AUX_hwcap:
+			_hwcap = aux->au_v;
+			_hwcap_avail = 1;
+			break;
+		case AUX_hwcap2:
+			_hwcap2 = aux->au_v;
+			_hwcap2_avail = 1;
+			break;
 		case AUX_pagesz:
 			_pagesize = aux->au_v;
 			break;
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc
index cf36ead40e9..1f1c25a9af5 100644
--- a/lib/libc/gen/Makefile.inc
+++ b/lib/libc/gen/Makefile.inc
@@ -6,8 +6,8 @@
 SRCS+=  alarm.c assert.c auth_subr.c authenticate.c \
         basename.c clock.c clock_getcpuclockid.c \
         closedir.c confstr.c ctermid.c ctype_.c \
-        daemon.c devname.c dirfd.c dirname.c disklabel.c err.c \
-        errc.c errx.c errlist.c errno.c exec.c \
+        daemon.c devname.c dirfd.c dirname.c disklabel.c elf_aux_info.c \
+        err.c errc.c errx.c errlist.c errno.c exec.c \
         fdatasync.c fnmatch.c fpclassify.c frexp.c \
         fstab.c ftok.c fts.c ftw.c getbsize.c getcap.c getcwd.c \
         getdomainname.c getgrent.c getgrouplist.c gethostname.c \
@@ -36,7 +36,7 @@ SRCS+=  alarm.c assert.c auth_subr.c authenticate.c \
 
 MAN+=	__tfork_thread.3 alarm.3 auth_subr.3 authenticate.3 basename.3 clock.3 \
 	clock_getcpuclockid.3 confstr.3 \
-	ctermid.3 daemon.3 devname.3 opendir.3 dirname.3 err.3 \
+	ctermid.3 daemon.3 devname.3 opendir.3 dirname.3 elf_aux_info.3 err.3 \
 	execv.3 fabs.3 fnmatch.3 fpclassify.3 fpgetmask.3 frexp.3 ftok.3 fts_open.3 \
 	ftw.3 getbsize.3 cgetent.3 getcwd.3 getdomainname.3 getdiskbyname.3 \
 	getfsent.3 getgrent.3 getgrouplist.3 gethostname.3 getloadavg.3 \
diff --git a/lib/libc/gen/elf_aux_info.3 b/lib/libc/gen/elf_aux_info.3
new file mode 100644
index 00000000000..c2a63c87e74
--- /dev/null
+++ b/lib/libc/gen/elf_aux_info.3
@@ -0,0 +1,74 @@
+.\"	$OpenBSD$
+.\"
+.\" Origin: FreeBSD auxv.3
+.\"
+.\" Copyright (c) 2019 Ian Lepore <ian@freebsd.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd $Mdocdate$
+.Dt ELF_AUX_INFO 3
+.Os
+.Sh NAME
+.Nm elf_aux_info
+.Nd extract data from the elf auxiliary vector of the current process
+.Sh SYNOPSIS
+.In sys/auxv.h
+.Ft int
+.Fn elf_aux_info "int aux" "void *buf" "int buflen"
+.Sh DESCRIPTION
+The
+.Fn elf_aux_info
+function retrieves the auxiliary info vector requested in
+.Va aux .
+The information is stored into the provided buffer if it will fit.
+The following values can be requested (corresponding buffer sizes are
+specified in parenthesis):
+.Bl -tag -width AT_HWCAP2
+.It AT_HWCAP
+CPU / hardware feature flags
+.Dv (sizeof(unsigned long)) .
+.It AT_HWCAP2
+CPU / hardware feature flags
+.Dv (sizeof(unsigned long)) .
+.It AT_PAGESZ
+Page size in bytes
+.Dv (sizeof(int)) .
+.El
+.Sh RETURN VALUES
+Returns zero on success, or an error number on failure.
+.Sh ERRORS
+.Bl -tag -width Er
+.It Bq Er EINVAL
+An unknown item was requested.
+.It Bq Er EINVAL
+The provided buffer was not the right size for the requested item.
+.It Bq Er ENOENT
+The requested item is not available.
+.El
+.Sh HISTORY
+The
+.Fn elf_aux_info
+function appeared in
+.Fx 12.0
+and was first available in
+.Ox 7.6 .
diff --git a/lib/libc/gen/elf_aux_info.c b/lib/libc/gen/elf_aux_info.c
new file mode 100644
index 00000000000..eef979a89e7
--- /dev/null
+++ b/lib/libc/gen/elf_aux_info.c
@@ -0,0 +1,70 @@
+/*	$OpenBSD$	*/
+
+/*
+ * Copyright (c) 2024 Jeremie Courreges-Anglas <jca@wxcvbn.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/auxv.h>
+
+#include <errno.h>
+
+extern int _pagesize;
+extern unsigned long _hwcap, _hwcap2;
+extern int _hwcap_avail, _hwcap2_avail;
+
+int
+elf_aux_info(int request, void *buf, int buflen)
+{
+	int ret = 0;
+
+	if (buflen < 0)
+		return EINVAL;
+
+	switch (request) {
+	case AT_HWCAP:
+		if (buflen != sizeof(unsigned long))
+			ret = EINVAL;
+		else if (!_hwcap_avail)
+			ret = ENOENT;
+		else
+			*(unsigned long *)buf = _hwcap;
+		break;
+	case AT_HWCAP2:
+		if (buflen != sizeof(unsigned long))
+			ret = EINVAL;
+		else if (!_hwcap2_avail)
+			ret = ENOENT;
+		else
+			*(unsigned long *)buf = _hwcap2;
+		break;
+	case AT_PAGESZ:
+		if (buflen != sizeof(int))
+			ret = EINVAL;
+		else if (!_pagesize)
+			ret = ENOENT;
+		else
+			*(int *)buf = _pagesize;
+		break;
+	default:
+		if (request < 0 || request >= AT_COUNT)
+			ret = EINVAL;
+		else
+			ret = ENOENT;
+		break;
+	}
+
+	return ret;
+}
diff --git a/lib/libc/hidden/sys/auxv.h b/lib/libc/hidden/sys/auxv.h
new file mode 100644
index 00000000000..8d25aaaa826
--- /dev/null
+++ b/lib/libc/hidden/sys/auxv.h
@@ -0,0 +1,26 @@
+/*	$OpenBSD$	*/
+
+/*
+ * Copyright (c) 2024 Jeremie Courreges-Anglas <jca@wxcvbn.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _LIBC_SYS_AUXV_H_
+#define _LIBC_SYS_AUXV_H_
+
+#include_next <sys/auxv.h>
+
+PROTO_DEPRECATED(elf_aux_info);
+
+#endif /* !_LIBC_SYS_AUXV_H_ */
diff --git a/regress/lib/libc/Makefile b/regress/lib/libc/Makefile
index 8b5e4d45034..f27137d3f64 100644
--- a/regress/lib/libc/Makefile
+++ b/regress/lib/libc/Makefile
@@ -5,6 +5,7 @@ SUBDIR+= alloca arc4random-fork atexit
 SUBDIR+= basename
 SUBDIR+= cephes cxa-atexit
 SUBDIR+= db dirname
+SUBDIR+= elf_aux_info
 SUBDIR+= env explicit_bzero
 SUBDIR+= ffs fmemopen fnmatch fpclassify fread
 SUBDIR+= gcvt getaddrinfo getcap getopt getopt_long glob
diff --git a/regress/lib/libc/elf_aux_info/Makefile b/regress/lib/libc/elf_aux_info/Makefile
new file mode 100644
index 00000000000..2885fb18512
--- /dev/null
+++ b/regress/lib/libc/elf_aux_info/Makefile
@@ -0,0 +1,3 @@
+PROG=elf_aux_info
+
+.include <bsd.regress.mk>
diff --git a/regress/lib/libc/elf_aux_info/elf_aux_info.c b/regress/lib/libc/elf_aux_info/elf_aux_info.c
new file mode 100644
index 00000000000..481085d6d97
--- /dev/null
+++ b/regress/lib/libc/elf_aux_info/elf_aux_info.c
@@ -0,0 +1,54 @@
+#include <sys/auxv.h>
+
+#include <errno.h>
+#include <stdio.h>
+
+int
+main(void)
+{
+	int ret = 0;
+	int a;
+	unsigned long b;
+
+
+	/* Should always succeed */
+	if (elf_aux_info(AT_PAGESZ, &a, sizeof(a)))
+		ret |= 1;
+	else
+		fprintf(stderr, "AT_PAGESZ %d\n", a);
+
+	/* Wrong size */
+	if (elf_aux_info(AT_PAGESZ, &b, sizeof(b)) != EINVAL)
+		ret |= 2;
+
+	/* Invalid request */
+	if (elf_aux_info(-1, &a, sizeof(a)) != EINVAL)
+		ret |= 4;
+
+	/* Should either succeed or fail with ENOENT if not supported */
+	switch (elf_aux_info(AT_HWCAP, &b, sizeof(b))) {
+	case 0:
+		fprintf(stderr, "AT_HWCAP %lx\n", b);
+		break;
+	case ENOENT:
+		break;
+	default:
+		ret |= 8;
+	}
+
+	/* Should either succeed or fail with ENOENT if not supported */
+	switch (elf_aux_info(AT_HWCAP2, &b, sizeof(b))) {
+	case 0:
+		fprintf(stderr, "AT_HWCAP2 %lx\n", b);
+		break;
+	case ENOENT:
+		break;
+	default:
+		ret |= 16;
+	}
+
+	if (ret)
+		fprintf(stderr, "FAILED (status %x)\n", ret);
+
+	return ret;
+}
diff --git a/sys/arch/alpha/include/elf.h b/sys/arch/alpha/include/elf.h
new file mode 100644
index 00000000000..5864bc487f4
--- /dev/null
+++ b/sys/arch/alpha/include/elf.h
@@ -0,0 +1,7 @@
+/*	$OpenBSD$	*/
+
+/*
+ * This file is in the public domain.
+ */
+
+/* Nothing for now */
diff --git a/sys/arch/amd64/include/elf.h b/sys/arch/amd64/include/elf.h
new file mode 100644
index 00000000000..5864bc487f4
--- /dev/null
+++ b/sys/arch/amd64/include/elf.h
@@ -0,0 +1,7 @@
+/*	$OpenBSD$	*/
+
+/*
+ * This file is in the public domain.
+ */
+
+/* Nothing for now */
diff --git a/sys/arch/arm/include/elf.h b/sys/arch/arm/include/elf.h
new file mode 100644
index 00000000000..a17ba1ae396
--- /dev/null
+++ b/sys/arch/arm/include/elf.h
@@ -0,0 +1,77 @@
+/*	$OpenBSD$	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2001 David E. O'Brien
+ * Copyright (c) 1996-1997 John D. Polstra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef	_MACHINE_ELF_H_
+#define	_MACHINE_ELF_H_
+
+/*
+ * ELF definitions for the ARM architecture.
+ */
+
+#ifdef _KERNEL
+# define __HAVE_CPU_HWCAP
+# define __HAVE_CPU_HWCAP2
+extern unsigned long	hwcap, hwcap2;
+#endif /* _KERNEL */
+
+/* Flags passed in AT_HWCAP. */
+#define	HWCAP_SWP		0x00000001	/* Unsupported, never set.    */
+#define	HWCAP_HALF		0x00000002	/* Always set.                */
+#define	HWCAP_THUMB		0x00000004
+#define	HWCAP_26BIT		0x00000008	/* Unsupported, never set.    */
+#define	HWCAP_FAST_MULT		0x00000010	/* Always set.                */
+#define	HWCAP_FPA		0x00000020	/* Unsupported, never set.    */
+#define	HWCAP_VFP		0x00000040
+#define	HWCAP_EDSP		0x00000080	/* Always set for ARMv6+.     */
+#define	HWCAP_JAVA		0x00000100	/* Unsupported, never set.    */
+#define	HWCAP_IWMMXT		0x00000200	/* Unsupported, never set.    */
+#define	HWCAP_CRUNCH		0x00000400	/* Unsupported, never set.    */
+#define	HWCAP_THUMBEE		0x00000800
+#define	HWCAP_NEON		0x00001000
+#define	HWCAP_VFPv3		0x00002000
+#define	HWCAP_VFPv3D16		0x00004000
+#define	HWCAP_TLS		0x00008000	/* Always set for ARMv6+.     */
+#define	HWCAP_VFPv4		0x00010000
+#define	HWCAP_IDIVA		0x00020000
+#define	HWCAP_IDIVT		0x00040000
+#define	HWCAP_VFPD32		0x00080000
+#define	HWCAP_IDIV		(HWCAP_IDIVA | HWCAP_IDIVT)
+#define	HWCAP_LPAE		0x00100000
+#define	HWCAP_EVTSTRM		0x00200000	/* Not implemented yet.       */
+
+/* Flags passed in AT_HWCAP2. */
+#define	HWCAP2_AES		0x00000001
+#define	HWCAP2_PMULL		0x00000002
+#define	HWCAP2_SHA1		0x00000004
+#define	HWCAP2_SHA2		0x00000008
+#define	HWCAP2_CRC32		0x00000010
+
+#endif /* !_MACHINE_ELF_H_ */
diff --git a/sys/arch/arm64/arm64/cpu.c b/sys/arch/arm64/arm64/cpu.c
index ae17940fbc8..01db0046cb4 100644
--- a/sys/arch/arm64/arm64/cpu.c
+++ b/sys/arch/arm64/arm64/cpu.c
@@ -32,6 +32,7 @@
 #include <uvm/uvm.h>
 
 #include <machine/fdt.h>
+#include <machine/elf.h>
 
 #include <dev/ofw/openfirm.h>
 #include <dev/ofw/ofw_clock.h>
@@ -716,6 +717,10 @@ cpu_identify(struct cpu_info *ci)
 		printf("%sAtomic", sep);
 		sep = ",";
 		arm64_has_lse = 1;
+		/*
+		 * XXX should be populated and sanitized like cpu_sysctl() does
+		 */
+		hwcap |= HWCAP_ATOMICS;
 	}
 
 	if (ID_AA64ISAR0_CRC32(id) >= ID_AA64ISAR0_CRC32_BASE) {
diff --git a/sys/arch/arm64/include/elf.h b/sys/arch/arm64/include/elf.h
new file mode 100644
index 00000000000..53be0b910c2
--- /dev/null
+++ b/sys/arch/arm64/include/elf.h
@@ -0,0 +1,121 @@
+/*-
+ * Copyright (c) 1996-1997 John D. Polstra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef	_MACHINE_ELF_H_
+#define	_MACHINE_ELF_H_
+
+/*
+ * ELF definitions for the AArch64 architecture.
+ */
+
+#ifdef _KERNEL
+# define __HAVE_CPU_HWCAP
+# define __HAVE_CPU_HWCAP2
+extern unsigned long	hwcap, hwcap2;
+#endif /* _KERNEL */
+
+/* HWCAP */
+#define	HWCAP_FP		0x00000001
+#define	HWCAP_ASIMD		0x00000002
+#define	HWCAP_EVTSTRM		0x00000004
+#define	HWCAP_AES		0x00000008
+#define	HWCAP_PMULL		0x00000010
+#define	HWCAP_SHA1		0x00000020
+#define	HWCAP_SHA2		0x00000040
+#define	HWCAP_CRC32		0x00000080
+#define	HWCAP_ATOMICS		0x00000100
+#define	HWCAP_FPHP		0x00000200
+#define	HWCAP_ASIMDHP		0x00000400
+#define	HWCAP_CPUID		0x00000800
+#define	HWCAP_ASIMDRDM		0x00001000
+#define	HWCAP_JSCVT		0x00002000
+#define	HWCAP_FCMA		0x00004000
+#define	HWCAP_LRCPC		0x00008000
+#define	HWCAP_DCPOP		0x00010000
+#define	HWCAP_SHA3		0x00020000
+#define	HWCAP_SM3		0x00040000
+#define	HWCAP_SM4		0x00080000
+#define	HWCAP_ASIMDDP		0x00100000
+#define	HWCAP_SHA512		0x00200000
+#define	HWCAP_SVE		0x00400000
+#define	HWCAP_ASIMDFHM		0x00800000
+#define	HWCAP_DIT		0x01000000
+#define	HWCAP_USCAT		0x02000000
+#define	HWCAP_ILRCPC		0x04000000
+#define	HWCAP_FLAGM		0x08000000
+#define	HWCAP_SSBS		0x10000000
+#define	HWCAP_SB		0x20000000
+#define	HWCAP_PACA		0x40000000
+#define	HWCAP_PACG		0x80000000
+
+/* HWCAP2 */
+#define	HWCAP2_DCPODP		0x0000000000000001ul
+#define	HWCAP2_SVE2		0x0000000000000002ul
+#define	HWCAP2_SVEAES		0x0000000000000004ul
+#define	HWCAP2_SVEPMULL		0x0000000000000008ul
+#define	HWCAP2_SVEBITPERM	0x0000000000000010ul
+#define	HWCAP2_SVESHA3		0x0000000000000020ul
+#define	HWCAP2_SVESM4		0x0000000000000040ul
+#define	HWCAP2_FLAGM2		0x0000000000000080ul
+#define	HWCAP2_FRINT		0x0000000000000100ul
+#define	HWCAP2_SVEI8MM		0x0000000000000200ul
+#define	HWCAP2_SVEF32MM		0x0000000000000400ul
+#define	HWCAP2_SVEF64MM		0x0000000000000800ul
+#define	HWCAP2_SVEBF16		0x0000000000001000ul
+#define	HWCAP2_I8MM		0x0000000000002000ul
+#define	HWCAP2_BF16		0x0000000000004000ul
+#define	HWCAP2_DGH		0x0000000000008000ul
+#define	HWCAP2_RNG		0x0000000000010000ul
+#define	HWCAP2_BTI		0x0000000000020000ul
+#define	HWCAP2_MTE		0x0000000000040000ul
+#define	HWCAP2_ECV		0x0000000000080000ul
+#define	HWCAP2_AFP		0x0000000000100000ul
+#define	HWCAP2_RPRES		0x0000000000200000ul
+#define	HWCAP2_MTE3		0x0000000000400000ul
+#define	HWCAP2_SME		0x0000000000800000ul
+#define	HWCAP2_SME_I16I64	0x0000000001000000ul
+#define	HWCAP2_SME_F64F64	0x0000000002000000ul
+#define	HWCAP2_SME_I8I32	0x0000000004000000ul
+#define	HWCAP2_SME_F16F32	0x0000000008000000ul
+#define	HWCAP2_SME_B16F32	0x0000000010000000ul
+#define	HWCAP2_SME_F32F32	0x0000000020000000ul
+#define	HWCAP2_SME_FA64		0x0000000040000000ul
+#define	HWCAP2_WFXT		0x0000000080000000ul
+#define	HWCAP2_EBF16		0x0000000100000000ul
+#define	HWCAP2_SVE_EBF16	0x0000000200000000ul
+#define	HWCAP2_CSSC		0x0000000400000000ul
+#define	HWCAP2_RPRFM		0x0000000800000000ul
+#define	HWCAP2_SVE2P1		0x0000001000000000ul
+#define	HWCAP2_SME2		0x0000002000000000ul
+#define	HWCAP2_SME2P1		0x0000004000000000ul
+#define	HWCAP2_SME_I16I32	0x0000008000000000ul
+#define	HWCAP2_SME_BI32I32	0x0000010000000000ul
+#define	HWCAP2_SME_B16B16	0x0000020000000000ul
+#define	HWCAP2_SME_F16F16	0x0000040000000000ul
+#define	HWCAP2_MOPS		0x0000080000000000ul
+#define	HWCAP2_HBC		0x0000100000000000ul
+
+#endif /* !_MACHINE_ELF_H_ */
diff --git a/sys/arch/hppa/include/elf.h b/sys/arch/hppa/include/elf.h
new file mode 100644
index 00000000000..5864bc487f4
--- /dev/null
+++ b/sys/arch/hppa/include/elf.h
@@ -0,0 +1,7 @@
+/*	$OpenBSD$	*/
+
+/*
+ * This file is in the public domain.
+ */
+
+/* Nothing for now */
diff --git a/sys/arch/i386/include/elf.h b/sys/arch/i386/include/elf.h
new file mode 100644
index 00000000000..5864bc487f4
--- /dev/null
+++ b/sys/arch/i386/include/elf.h
@@ -0,0 +1,7 @@
+/*	$OpenBSD$	*/
+
+/*
+ * This file is in the public domain.
+ */
+
+/* Nothing for now */
diff --git a/sys/arch/m88k/include/elf.h b/sys/arch/m88k/include/elf.h
new file mode 100644
index 00000000000..5864bc487f4
--- /dev/null
+++ b/sys/arch/m88k/include/elf.h
@@ -0,0 +1,7 @@
+/*	$OpenBSD$	*/
+
+/*
+ * This file is in the public domain.
+ */
+
+/* Nothing for now */
diff --git a/sys/arch/mips64/include/elf.h b/sys/arch/mips64/include/elf.h
new file mode 100644
index 00000000000..5864bc487f4
--- /dev/null
+++ b/sys/arch/mips64/include/elf.h
@@ -0,0 +1,7 @@
+/*	$OpenBSD$	*/
+
+/*
+ * This file is in the public domain.
+ */
+
+/* Nothing for now */
diff --git a/sys/arch/powerpc/include/elf.h b/sys/arch/powerpc/include/elf.h
new file mode 100644
index 00000000000..821ba5ae3cb
--- /dev/null
+++ b/sys/arch/powerpc/include/elf.h
@@ -0,0 +1,14 @@
+/*	$OpenBSD$	*/
+
+/*
+ * This file is in the public domain.
+ */
+
+#ifndef	_MACHINE_ELF_H_
+#define	_MACHINE_ELF_H_
+
+/*
+ * TODO FreeBSD puts PPC_FEATURE* in cpu.h
+ */
+
+#endif /* !_MACHINE_ELF_H_ */
diff --git a/sys/arch/powerpc64/include/elf.h b/sys/arch/powerpc64/include/elf.h
new file mode 100644
index 00000000000..821ba5ae3cb
--- /dev/null
+++ b/sys/arch/powerpc64/include/elf.h
@@ -0,0 +1,14 @@
+/*	$OpenBSD$	*/
+
+/*
+ * This file is in the public domain.
+ */
+
+#ifndef	_MACHINE_ELF_H_
+#define	_MACHINE_ELF_H_
+
+/*
+ * TODO FreeBSD puts PPC_FEATURE* in cpu.h
+ */
+
+#endif /* !_MACHINE_ELF_H_ */
diff --git a/sys/arch/riscv64/include/elf.h b/sys/arch/riscv64/include/elf.h
new file mode 100644
index 00000000000..de902743da5
--- /dev/null
+++ b/sys/arch/riscv64/include/elf.h
@@ -0,0 +1,52 @@
+/*	$OpenBSD$	*/
+
+/*-
+ * Copyright (c) 1996-1997 John D. Polstra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef	_MACHINE_ELF_H_
+#define	_MACHINE_ELF_H_
+
+/*
+ * ELF definitions for the RISC-V architecture.
+ */
+
+#ifdef _KERNEL
+# define __HAVE_CPU_HWCAP
+extern unsigned long	hwcap;
+#endif /* _KERNEL */
+
+/* Flags passed in AT_HWCAP */
+#define	HWCAP_ISA_BIT(c)	(1 << ((c) - 'a'))
+#define	HWCAP_ISA_I		HWCAP_ISA_BIT('i')
+#define	HWCAP_ISA_M		HWCAP_ISA_BIT('m')
+#define	HWCAP_ISA_A		HWCAP_ISA_BIT('a')
+#define	HWCAP_ISA_F		HWCAP_ISA_BIT('f')
+#define	HWCAP_ISA_D		HWCAP_ISA_BIT('d')
+#define	HWCAP_ISA_C		HWCAP_ISA_BIT('c')
+#define	HWCAP_ISA_G		\
+    (HWCAP_ISA_I | HWCAP_ISA_M | HWCAP_ISA_A | HWCAP_ISA_F | HWCAP_ISA_D)
+
+#endif /* !_MACHINE_ELF_H_ */
diff --git a/sys/arch/riscv64/riscv64/cpu.c b/sys/arch/riscv64/riscv64/cpu.c
index 0d40b236569..4e6c08adacf 100644
--- a/sys/arch/riscv64/riscv64/cpu.c
+++ b/sys/arch/riscv64/riscv64/cpu.c
@@ -28,6 +28,7 @@
 #include <uvm/uvm.h>
 
 #include <machine/cpufunc.h>
+#include <machine/elf.h>
 #include <machine/fdt.h>
 #include <machine/sbi.h>
 
@@ -236,6 +237,8 @@ cpu_attach(struct device *parent, struct device *dev, void *aux)
 #endif
 		cpu_identify(ci);
 
+		hwcap |= HWCAP_ISA_G | HWCAP_ISA_C;
+
 		if (OF_getproplen(ci->ci_node, "clocks") > 0) {
 			cpu_node = ci->ci_node;
 			cpu_cpuspeed = cpu_clockspeed;
diff --git a/sys/arch/sh/include/elf.h b/sys/arch/sh/include/elf.h
new file mode 100644
index 00000000000..5864bc487f4
--- /dev/null
+++ b/sys/arch/sh/include/elf.h
@@ -0,0 +1,7 @@
+/*	$OpenBSD$	*/
+
+/*
+ * This file is in the public domain.
+ */
+
+/* Nothing for now */
diff --git a/sys/arch/sparc64/include/elf.h b/sys/arch/sparc64/include/elf.h
new file mode 100644
index 00000000000..5864bc487f4
--- /dev/null
+++ b/sys/arch/sparc64/include/elf.h
@@ -0,0 +1,7 @@
+/*	$OpenBSD$	*/
+
+/*
+ * This file is in the public domain.
+ */
+
+/* Nothing for now */
diff --git a/sys/sys/auxv.h b/sys/sys/auxv.h
new file mode 100644
index 00000000000..26de550fdc6
--- /dev/null
+++ b/sys/sys/auxv.h
@@ -0,0 +1,50 @@
+/*	$OpenBSD$	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2017 Michal Meloun
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef	_SYS_AUXV_H_
+#define	_SYS_AUXV_H_
+
+#include <sys/types.h>
+#include <machine/elf.h>
+
+/* Values for a_type. */
+#define	AT_NULL		0	/* Terminates the vector. */
+#define	AT_IGNORE	1	/* Ignored entry. */
+#define	AT_PAGESZ	6	/* Page size in bytes. */
+#define	AT_HWCAP	25	/* CPU feature flags. */
+#define	AT_HWCAP2	26	/* CPU feature flags 2. */
+
+#define	AT_COUNT	27	/* Count of defined aux entry types. */
+
+__BEGIN_DECLS
+int elf_aux_info(int aux, void *buf, int buflen);
+__END_DECLS
+
+#endif /* !_SYS_AUXV_H_ */
diff --git a/sys/sys/exec_elf.h b/sys/sys/exec_elf.h
index 7825dff418b..1b45c3ebb70 100644
--- a/sys/sys/exec_elf.h
+++ b/sys/sys/exec_elf.h
@@ -727,6 +727,8 @@ enum AuxID {
 	AUX_base = 7,			/* base addr for ld.so or static PIE */
 	AUX_flags = 8,			/* processor flags */
 	AUX_entry = 9,			/* a.out entry */
+	AUX_hwcap = 25,			/* processor flags */
+	AUX_hwcap2 = 26,		/* processor flags (continued) */
 	AUX_sun_uid = 2000,		/* euid */
 	AUX_sun_ruid = 2001,		/* ruid */
 	AUX_sun_gid = 2002,		/* egid */
@@ -820,7 +822,7 @@ extern Elf_Dyn		_DYNAMIC[];
 /*
  * How many entries are in the AuxInfo array we pass to the process?
  */
-#define	ELF_AUX_ENTRIES	9
+#define	ELF_AUX_ENTRIES	11
 #define	ELF_AUX_WORDS	(sizeof(AuxInfo) * ELF_AUX_ENTRIES / sizeof(char *))
 
 struct exec_package;


-- 
jca