summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bundled/Makefile.am1
-rw-r--r--bundled/linux/include/uapi/linux/userfaultfd.h269
-rw-r--r--configure.ac1
-rw-r--r--src/ioctl.c2
-rw-r--r--src/userfaultfd.c19
-rw-r--r--src/xlat/uffd_api_features.in19
-rw-r--r--src/xlat/uffd_api_flags.in1
-rw-r--r--src/xlat/uffd_copy_flags.in5
-rw-r--r--src/xlat/uffd_flags.in3
-rw-r--r--src/xlat/uffd_register_ioctl_flags.in1
-rw-r--r--src/xlat/uffd_register_mode_flags.in1
-rw-r--r--src/xlat/uffd_zeropage_flags.in1
-rw-r--r--tests/ioctl_uffdio.c31
13 files changed, 310 insertions, 44 deletions
diff --git a/bundled/Makefile.am b/bundled/Makefile.am
index 9debffb5b..e2d305fa7 100644
--- a/bundled/Makefile.am
+++ b/bundled/Makefile.am
@@ -63,6 +63,7 @@ EXTRA_DIST = \
linux/include/uapi/linux/tee.h \
linux/include/uapi/linux/types.h \
linux/include/uapi/linux/unix_diag.h \
+ linux/include/uapi/linux/userfaultfd.h \
linux/include/uapi/linux/v4l2-common.h \
linux/include/uapi/linux/v4l2-controls.h \
linux/include/uapi/linux/videodev2.h \
diff --git a/bundled/linux/include/uapi/linux/userfaultfd.h b/bundled/linux/include/uapi/linux/userfaultfd.h
new file mode 100644
index 000000000..1ba9a9fee
--- /dev/null
+++ b/bundled/linux/include/uapi/linux/userfaultfd.h
@@ -0,0 +1,269 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * include/linux/userfaultfd.h
+ *
+ * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org>
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ */
+
+#ifndef _LINUX_USERFAULTFD_H
+#define _LINUX_USERFAULTFD_H
+
+#include <linux/types.h>
+
+/*
+ * If the UFFDIO_API is upgraded someday, the UFFDIO_UNREGISTER and
+ * UFFDIO_WAKE ioctls should be defined as _IOW and not as _IOR. In
+ * userfaultfd.h we assumed the kernel was reading (instead _IOC_READ
+ * means the userland is reading).
+ */
+#define UFFD_API ((__u64)0xAA)
+#define UFFD_API_FEATURES (UFFD_FEATURE_PAGEFAULT_FLAG_WP | \
+ UFFD_FEATURE_EVENT_FORK | \
+ UFFD_FEATURE_EVENT_REMAP | \
+ UFFD_FEATURE_EVENT_REMOVE | \
+ UFFD_FEATURE_EVENT_UNMAP | \
+ UFFD_FEATURE_MISSING_HUGETLBFS | \
+ UFFD_FEATURE_MISSING_SHMEM | \
+ UFFD_FEATURE_SIGBUS | \
+ UFFD_FEATURE_THREAD_ID)
+#define UFFD_API_IOCTLS \
+ ((__u64)1 << _UFFDIO_REGISTER | \
+ (__u64)1 << _UFFDIO_UNREGISTER | \
+ (__u64)1 << _UFFDIO_API)
+#define UFFD_API_RANGE_IOCTLS \
+ ((__u64)1 << _UFFDIO_WAKE | \
+ (__u64)1 << _UFFDIO_COPY | \
+ (__u64)1 << _UFFDIO_ZEROPAGE | \
+ (__u64)1 << _UFFDIO_WRITEPROTECT)
+#define UFFD_API_RANGE_IOCTLS_BASIC \
+ ((__u64)1 << _UFFDIO_WAKE | \
+ (__u64)1 << _UFFDIO_COPY)
+
+/*
+ * Valid ioctl command number range with this API is from 0x00 to
+ * 0x3F. UFFDIO_API is the fixed number, everything else can be
+ * changed by implementing a different UFFD_API. If sticking to the
+ * same UFFD_API more ioctl can be added and userland will be aware of
+ * which ioctl the running kernel implements through the ioctl command
+ * bitmask written by the UFFDIO_API.
+ */
+#define _UFFDIO_REGISTER (0x00)
+#define _UFFDIO_UNREGISTER (0x01)
+#define _UFFDIO_WAKE (0x02)
+#define _UFFDIO_COPY (0x03)
+#define _UFFDIO_ZEROPAGE (0x04)
+#define _UFFDIO_WRITEPROTECT (0x06)
+#define _UFFDIO_API (0x3F)
+
+/* userfaultfd ioctl ids */
+#define UFFDIO 0xAA
+#define UFFDIO_API _IOWR(UFFDIO, _UFFDIO_API, \
+ struct uffdio_api)
+#define UFFDIO_REGISTER _IOWR(UFFDIO, _UFFDIO_REGISTER, \
+ struct uffdio_register)
+#define UFFDIO_UNREGISTER _IOR(UFFDIO, _UFFDIO_UNREGISTER, \
+ struct uffdio_range)
+#define UFFDIO_WAKE _IOR(UFFDIO, _UFFDIO_WAKE, \
+ struct uffdio_range)
+#define UFFDIO_COPY _IOWR(UFFDIO, _UFFDIO_COPY, \
+ struct uffdio_copy)
+#define UFFDIO_ZEROPAGE _IOWR(UFFDIO, _UFFDIO_ZEROPAGE, \
+ struct uffdio_zeropage)
+#define UFFDIO_WRITEPROTECT _IOWR(UFFDIO, _UFFDIO_WRITEPROTECT, \
+ struct uffdio_writeprotect)
+
+/* read() structure */
+struct uffd_msg {
+ __u8 event;
+
+ __u8 reserved1;
+ __u16 reserved2;
+ __u32 reserved3;
+
+ union {
+ struct {
+ __u64 flags;
+ __u64 address;
+ union {
+ __u32 ptid;
+ } feat;
+ } pagefault;
+
+ struct {
+ __u32 ufd;
+ } fork;
+
+ struct {
+ __u64 from;
+ __u64 to;
+ __u64 len;
+ } remap;
+
+ struct {
+ __u64 start;
+ __u64 end;
+ } remove;
+
+ struct {
+ /* unused reserved fields */
+ __u64 reserved1;
+ __u64 reserved2;
+ __u64 reserved3;
+ } reserved;
+ } arg;
+} __attribute__((packed));
+
+/*
+ * Start at 0x12 and not at 0 to be more strict against bugs.
+ */
+#define UFFD_EVENT_PAGEFAULT 0x12
+#define UFFD_EVENT_FORK 0x13
+#define UFFD_EVENT_REMAP 0x14
+#define UFFD_EVENT_REMOVE 0x15
+#define UFFD_EVENT_UNMAP 0x16
+
+/* flags for UFFD_EVENT_PAGEFAULT */
+#define UFFD_PAGEFAULT_FLAG_WRITE (1<<0) /* If this was a write fault */
+#define UFFD_PAGEFAULT_FLAG_WP (1<<1) /* If reason is VM_UFFD_WP */
+
+struct uffdio_api {
+ /* userland asks for an API number and the features to enable */
+ __u64 api;
+ /*
+ * Kernel answers below with the all available features for
+ * the API, this notifies userland of which events and/or
+ * which flags for each event are enabled in the current
+ * kernel.
+ *
+ * Note: UFFD_EVENT_PAGEFAULT and UFFD_PAGEFAULT_FLAG_WRITE
+ * are to be considered implicitly always enabled in all kernels as
+ * long as the uffdio_api.api requested matches UFFD_API.
+ *
+ * UFFD_FEATURE_MISSING_HUGETLBFS means an UFFDIO_REGISTER
+ * with UFFDIO_REGISTER_MODE_MISSING mode will succeed on
+ * hugetlbfs virtual memory ranges. Adding or not adding
+ * UFFD_FEATURE_MISSING_HUGETLBFS to uffdio_api.features has
+ * no real functional effect after UFFDIO_API returns, but
+ * it's only useful for an initial feature set probe at
+ * UFFDIO_API time. There are two ways to use it:
+ *
+ * 1) by adding UFFD_FEATURE_MISSING_HUGETLBFS to the
+ * uffdio_api.features before calling UFFDIO_API, an error
+ * will be returned by UFFDIO_API on a kernel without
+ * hugetlbfs missing support
+ *
+ * 2) the UFFD_FEATURE_MISSING_HUGETLBFS can not be added in
+ * uffdio_api.features and instead it will be set by the
+ * kernel in the uffdio_api.features if the kernel supports
+ * it, so userland can later check if the feature flag is
+ * present in uffdio_api.features after UFFDIO_API
+ * succeeded.
+ *
+ * UFFD_FEATURE_MISSING_SHMEM works the same as
+ * UFFD_FEATURE_MISSING_HUGETLBFS, but it applies to shmem
+ * (i.e. tmpfs and other shmem based APIs).
+ *
+ * UFFD_FEATURE_SIGBUS feature means no page-fault
+ * (UFFD_EVENT_PAGEFAULT) event will be delivered, instead
+ * a SIGBUS signal will be sent to the faulting process.
+ *
+ * UFFD_FEATURE_THREAD_ID pid of the page faulted task_struct will
+ * be returned, if feature is not requested 0 will be returned.
+ */
+#define UFFD_FEATURE_PAGEFAULT_FLAG_WP (1<<0)
+#define UFFD_FEATURE_EVENT_FORK (1<<1)
+#define UFFD_FEATURE_EVENT_REMAP (1<<2)
+#define UFFD_FEATURE_EVENT_REMOVE (1<<3)
+#define UFFD_FEATURE_MISSING_HUGETLBFS (1<<4)
+#define UFFD_FEATURE_MISSING_SHMEM (1<<5)
+#define UFFD_FEATURE_EVENT_UNMAP (1<<6)
+#define UFFD_FEATURE_SIGBUS (1<<7)
+#define UFFD_FEATURE_THREAD_ID (1<<8)
+ __u64 features;
+
+ __u64 ioctls;
+};
+
+struct uffdio_range {
+ __u64 start;
+ __u64 len;
+};
+
+struct uffdio_register {
+ struct uffdio_range range;
+#define UFFDIO_REGISTER_MODE_MISSING ((__u64)1<<0)
+#define UFFDIO_REGISTER_MODE_WP ((__u64)1<<1)
+ __u64 mode;
+
+ /*
+ * kernel answers which ioctl commands are available for the
+ * range, keep at the end as the last 8 bytes aren't read.
+ */
+ __u64 ioctls;
+};
+
+struct uffdio_copy {
+ __u64 dst;
+ __u64 src;
+ __u64 len;
+#define UFFDIO_COPY_MODE_DONTWAKE ((__u64)1<<0)
+ /*
+ * UFFDIO_COPY_MODE_WP will map the page write protected on
+ * the fly. UFFDIO_COPY_MODE_WP is available only if the
+ * write protected ioctl is implemented for the range
+ * according to the uffdio_register.ioctls.
+ */
+#define UFFDIO_COPY_MODE_WP ((__u64)1<<1)
+ __u64 mode;
+
+ /*
+ * "copy" is written by the ioctl and must be at the end: the
+ * copy_from_user will not read the last 8 bytes.
+ */
+ __s64 copy;
+};
+
+struct uffdio_zeropage {
+ struct uffdio_range range;
+#define UFFDIO_ZEROPAGE_MODE_DONTWAKE ((__u64)1<<0)
+ __u64 mode;
+
+ /*
+ * "zeropage" is written by the ioctl and must be at the end:
+ * the copy_from_user will not read the last 8 bytes.
+ */
+ __s64 zeropage;
+};
+
+struct uffdio_writeprotect {
+ struct uffdio_range range;
+/*
+ * UFFDIO_WRITEPROTECT_MODE_WP: set the flag to write protect a range,
+ * unset the flag to undo protection of a range which was previously
+ * write protected.
+ *
+ * UFFDIO_WRITEPROTECT_MODE_DONTWAKE: set the flag to avoid waking up
+ * any wait thread after the operation succeeds.
+ *
+ * NOTE: Write protecting a region (WP=1) is unrelated to page faults,
+ * therefore DONTWAKE flag is meaningless with WP=1. Removing write
+ * protection (WP=0) in response to a page fault wakes the faulting
+ * task unless DONTWAKE is set.
+ */
+#define UFFDIO_WRITEPROTECT_MODE_WP ((__u64)1<<0)
+#define UFFDIO_WRITEPROTECT_MODE_DONTWAKE ((__u64)1<<1)
+ __u64 mode;
+};
+
+/*
+ * Flags for the userfaultfd(2) system call itself.
+ */
+
+/*
+ * Create a userfaultfd that can handle page faults only in user mode.
+ */
+#define UFFD_USER_MODE_ONLY 1
+
+#endif /* _LINUX_USERFAULTFD_H */
diff --git a/configure.ac b/configure.ac
index 84a4abc6e..95d84502d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -460,7 +460,6 @@ AC_CHECK_HEADERS(m4_normalize([
linux/sched.h
linux/seccomp.h
linux/securebits.h
- linux/userfaultfd.h
linux/utsname.h
]),,, [AC_INCLUDES_DEFAULT
#include <linux/types.h>
diff --git a/src/ioctl.c b/src/ioctl.c
index aac7a4b27..01cb0e7cf 100644
--- a/src/ioctl.c
+++ b/src/ioctl.c
@@ -349,10 +349,8 @@ ioctl_decode(struct tcb *tcp)
return fs_0x94_ioctl(tcp, code, arg);
case 0xa4:
return tee_ioctl(tcp, code, arg);
-#ifdef HAVE_LINUX_USERFAULTFD_H
case 0xaa:
return uffdio_ioctl(tcp, code, arg);
-#endif
case 0xab:
return nbd_ioctl(tcp, code, arg);
#ifdef HAVE_LINUX_KVM_H
diff --git a/src/userfaultfd.c b/src/userfaultfd.c
index d87d6e781..7996c94f2 100644
--- a/src/userfaultfd.c
+++ b/src/userfaultfd.c
@@ -8,6 +8,9 @@
#include "defs.h"
#include "kernel_fcntl.h"
+#include <linux/ioctl.h>
+#include <linux/userfaultfd.h>
+
#include "xlat/uffd_flags.h"
SYS_FUNC(userfaultfd)
@@ -17,16 +20,13 @@ SYS_FUNC(userfaultfd)
return RVAL_DECODED | RVAL_FD;
}
-#ifdef HAVE_LINUX_USERFAULTFD_H
-# include <linux/ioctl.h>
-# include <linux/userfaultfd.h>
-# include "xlat/uffd_api_features.h"
-# include "xlat/uffd_api_flags.h"
-# include "xlat/uffd_copy_flags.h"
-# include "xlat/uffd_register_ioctl_flags.h"
-# include "xlat/uffd_register_mode_flags.h"
-# include "xlat/uffd_zeropage_flags.h"
+#include "xlat/uffd_api_features.h"
+#include "xlat/uffd_api_flags.h"
+#include "xlat/uffd_copy_flags.h"
+#include "xlat/uffd_register_ioctl_flags.h"
+#include "xlat/uffd_register_mode_flags.h"
+#include "xlat/uffd_zeropage_flags.h"
static void
tprintf_uffdio_range(const struct uffdio_range *range)
@@ -191,4 +191,3 @@ uffdio_ioctl(struct tcb *const tcp, const unsigned int code,
return RVAL_IOCTL_DECODED;
}
-#endif /* HAVE_LINUX_USERFAULTFD_H */
diff --git a/src/xlat/uffd_api_features.in b/src/xlat/uffd_api_features.in
index 33d644778..603086f9c 100644
--- a/src/xlat/uffd_api_features.in
+++ b/src/xlat/uffd_api_features.in
@@ -1,10 +1,11 @@
+#unconditional
#val_type uint64_t
-UFFD_FEATURE_PAGEFAULT_FLAG_WP (1<<0)
-UFFD_FEATURE_EVENT_FORK (1<<1)
-UFFD_FEATURE_EVENT_REMAP (1<<2)
-UFFD_FEATURE_EVENT_REMOVE (1<<3)
-UFFD_FEATURE_MISSING_HUGETLBFS (1<<4)
-UFFD_FEATURE_MISSING_SHMEM (1<<5)
-UFFD_FEATURE_EVENT_UNMAP (1<<6)
-UFFD_FEATURE_SIGBUS (1<<7)
-UFFD_FEATURE_THREAD_ID (1<<8)
+UFFD_FEATURE_PAGEFAULT_FLAG_WP
+UFFD_FEATURE_EVENT_FORK
+UFFD_FEATURE_EVENT_REMAP
+UFFD_FEATURE_EVENT_REMOVE
+UFFD_FEATURE_MISSING_HUGETLBFS
+UFFD_FEATURE_MISSING_SHMEM
+UFFD_FEATURE_EVENT_UNMAP
+UFFD_FEATURE_SIGBUS
+UFFD_FEATURE_THREAD_ID
diff --git a/src/xlat/uffd_api_flags.in b/src/xlat/uffd_api_flags.in
index fd210872b..66b968959 100644
--- a/src/xlat/uffd_api_flags.in
+++ b/src/xlat/uffd_api_flags.in
@@ -1,3 +1,4 @@
+#unconditional
#val_type uint64_t
1<<_UFFDIO_REGISTER
1<<_UFFDIO_UNREGISTER
diff --git a/src/xlat/uffd_copy_flags.in b/src/xlat/uffd_copy_flags.in
index a9e3e9416..362b20761 100644
--- a/src/xlat/uffd_copy_flags.in
+++ b/src/xlat/uffd_copy_flags.in
@@ -1,3 +1,4 @@
+#unconditional
#val_type uint64_t
-UFFDIO_COPY_MODE_DONTWAKE (1ULL<<0)
-UFFDIO_COPY_MODE_WP (1ULL<<1)
+UFFDIO_COPY_MODE_DONTWAKE
+UFFDIO_COPY_MODE_WP
diff --git a/src/xlat/uffd_flags.in b/src/xlat/uffd_flags.in
index e925a8fe7..7a68a695d 100644
--- a/src/xlat/uffd_flags.in
+++ b/src/xlat/uffd_flags.in
@@ -1,3 +1,4 @@
-UFFD_USER_MODE_ONLY 1
+#unconditional
+UFFD_USER_MODE_ONLY
O_NONBLOCK
O_CLOEXEC
diff --git a/src/xlat/uffd_register_ioctl_flags.in b/src/xlat/uffd_register_ioctl_flags.in
index 077871f93..6d04ca3be 100644
--- a/src/xlat/uffd_register_ioctl_flags.in
+++ b/src/xlat/uffd_register_ioctl_flags.in
@@ -1,3 +1,4 @@
+#unconditional
#val_type uint64_t
1<<_UFFDIO_WAKE
1<<_UFFDIO_COPY
diff --git a/src/xlat/uffd_register_mode_flags.in b/src/xlat/uffd_register_mode_flags.in
index 996b1f32e..adae3c64a 100644
--- a/src/xlat/uffd_register_mode_flags.in
+++ b/src/xlat/uffd_register_mode_flags.in
@@ -1,3 +1,4 @@
+#unconditional
#val_type uint64_t
UFFDIO_REGISTER_MODE_MISSING
UFFDIO_REGISTER_MODE_WP
diff --git a/src/xlat/uffd_zeropage_flags.in b/src/xlat/uffd_zeropage_flags.in
index 6d48a040d..b2b3467ba 100644
--- a/src/xlat/uffd_zeropage_flags.in
+++ b/src/xlat/uffd_zeropage_flags.in
@@ -1,2 +1,3 @@
+#unconditional
#val_type uint64_t
UFFDIO_ZEROPAGE_MODE_DONTWAKE
diff --git a/tests/ioctl_uffdio.c b/tests/ioctl_uffdio.c
index 9b831bd3b..1aa60194a 100644
--- a/tests/ioctl_uffdio.c
+++ b/tests/ioctl_uffdio.c
@@ -10,22 +10,21 @@
#include "tests.h"
#include "scno.h"
-#if defined __NR_userfaultfd && defined HAVE_LINUX_USERFAULTFD_H
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
-# include <fcntl.h>
-# include <inttypes.h>
-# include <stdint.h>
-# include <stdio.h>
-# include <string.h>
-# include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
-# include <sys/ioctl.h>
-# include <sys/mman.h>
-# include <linux/ioctl.h>
-# include <linux/userfaultfd.h>
+#include "kernel_fcntl.h"
+#include <linux/ioctl.h>
+#include <linux/userfaultfd.h>
-# include "xlat.h"
-# include "xlat/uffd_api_features.h"
+#include "xlat.h"
+#include "xlat/uffd_api_features.h"
int
main(void)
@@ -200,9 +199,3 @@ main(void)
puts("+++ exited with 0 +++");
return 0;
}
-
-#else
-
-SKIP_MAIN_UNDEFINED("__NR_userfaultfd && HAVE_LINUX_USERFAULTFD_H")
-
-#endif