From 21b7898ff95c9f326d8ef5ed069f5a8026793648 Mon Sep 17 00:00:00 2001 From: Wizzard Date: Sun, 4 Feb 2024 00:08:35 -0500 Subject: [PATCH] Update NTSync patches --- ...or_device_number_and_ioctl\n_range..patch" | 68 ----- ...CREATE_SEM_and\n_NTSYNC_IOC_DELETE..patch" | 191 ------------- ...tsync:_Introduce_NTSYNC_IOC_PUT_SEM..patch | 147 ---------- ...ync:_Introduce_NTSYNC_IOC_PUT_MUTEX..patch | 107 ------- ...nc:_Introduce_NTSYNC_IOC_KILL_OWNER..patch | 170 ----------- ...ynchronization_primitive_driver_0000.patch | 24 +- ...ynchronization_primitive_driver_0001.patch | 224 +++++++++++++++ ...ynchronization_primitive_driver_0002.patch | 145 ++++++++++ ...nchronization_primitive_driver_0003.patch} | 189 ++++++------ ...nchronization_primitive_driver_0004.patch} | 170 ++++++----- ...nchronization_primitive_driver_0005.patch} | 93 +++--- ...ynchronization_primitive_driver_0006.patch | 117 ++++++++ ...ynchronization_primitive_driver_0007.patch | 176 ++++++++++++ ...ynchronization_primitive_driver_0008.patch | 175 ++++++++++++ ...ynchronization_primitive_driver_0009.patch | 88 ++++++ ...ynchronization_primitive_driver_0010.patch | 73 +++++ ...ynchronization_primitive_driver_0011.patch | 80 ++++++ ...ynchronization_primitive_driver_0012.patch | 72 +++++ ...ynchronization_primitive_driver_0013.patch | 74 +++++ ...ynchronization_primitive_driver_0014.patch | 72 +++++ ...ynchronization_primitive_driver_0015.patch | 194 +++++++++++++ ...ynchronization_primitive_driver_0016.patch | 213 ++++++++++++++ ...ynchronization_primitive_driver_0017.patch | 218 ++++++++++++++ ...ynchronization_primitive_driver_0018.patch | 136 +++++++++ ...ynchronization_primitive_driver_0019.patch | 147 ++++++++++ ...ynchronization_primitive_driver_0020.patch | 182 ++++++++++++ ...ynchronization_primitive_driver_0021.patch | 129 +++++++++ ...ynchronization_primitive_driver_0022.patch | 129 +++++++++ ...ynchronization_primitive_driver_0023.patch | 92 ++++++ ...ynchronization_primitive_driver_0024.patch | 270 ++++++++++++++++++ ...ynchronization_primitive_driver_0025.patch | 234 +++++++++++++++ ...ynchronization_primitive_driver_0026.patch | 121 ++++++++ ...ynchronization_primitive_driver_0027.patch | 39 +++ ...or_device_number_and_ioctl\n_range..patch" | 68 ----- ...CREATE_SEM_and\n_NTSYNC_IOC_DELETE..patch" | 191 ------------- ...tsync:_Introduce_NTSYNC_IOC_PUT_SEM..patch | 147 ---------- ...ync:_Introduce_NTSYNC_IOC_PUT_MUTEX..patch | 107 ------- ...nc:_Introduce_NTSYNC_IOC_KILL_OWNER..patch | 170 ----------- ...ynchronization_primitive_driver_0000.patch | 24 +- ...ynchronization_primitive_driver_0001.patch | 224 +++++++++++++++ ...ynchronization_primitive_driver_0002.patch | 145 ++++++++++ ...nchronization_primitive_driver_0003.patch} | 189 ++++++------ ...nchronization_primitive_driver_0004.patch} | 170 ++++++----- ...nchronization_primitive_driver_0005.patch} | 93 +++--- ...ynchronization_primitive_driver_0006.patch | 117 ++++++++ ...ynchronization_primitive_driver_0007.patch | 176 ++++++++++++ ...ynchronization_primitive_driver_0008.patch | 175 ++++++++++++ ...ynchronization_primitive_driver_0009.patch | 88 ++++++ ...ynchronization_primitive_driver_0010.patch | 73 +++++ ...ynchronization_primitive_driver_0011.patch | 80 ++++++ ...ynchronization_primitive_driver_0012.patch | 72 +++++ ...ynchronization_primitive_driver_0013.patch | 74 +++++ ...ynchronization_primitive_driver_0014.patch | 72 +++++ ...ynchronization_primitive_driver_0015.patch | 194 +++++++++++++ ...ynchronization_primitive_driver_0016.patch | 213 ++++++++++++++ ...ynchronization_primitive_driver_0017.patch | 218 ++++++++++++++ ...ynchronization_primitive_driver_0018.patch | 136 +++++++++ ...ynchronization_primitive_driver_0019.patch | 147 ++++++++++ ...ynchronization_primitive_driver_0020.patch | 182 ++++++++++++ ...ynchronization_primitive_driver_0021.patch | 129 +++++++++ ...ynchronization_primitive_driver_0022.patch | 129 +++++++++ ...ynchronization_primitive_driver_0023.patch | 92 ++++++ ...ynchronization_primitive_driver_0024.patch | 270 ++++++++++++++++++ ...ynchronization_primitive_driver_0025.patch | 234 +++++++++++++++ ...ynchronization_primitive_driver_0026.patch | 121 ++++++++ ...ynchronization_primitive_driver_0027.patch | 39 +++ 66 files changed, 7344 insertions(+), 1774 deletions(-) delete mode 100644 "linux-clang/linux6.7-zen/patches/0001-[PATCH_RFC_2_9]_ntsync:_Reserve_a_minor_device_number_and_ioctl\n_range..patch" delete mode 100644 "linux-clang/linux6.7-zen/patches/0002-[PATCH_RFC_3_9]_ntsync:_Introduce_NTSYNC_IOC_CREATE_SEM_and\n_NTSYNC_IOC_DELETE..patch" delete mode 100644 linux-clang/linux6.7-zen/patches/0003-[PATCH_RFC_4_9]_ntsync:_Introduce_NTSYNC_IOC_PUT_SEM..patch delete mode 100644 linux-clang/linux6.7-zen/patches/0007-[PATCH_RFC_8_9]_ntsync:_Introduce_NTSYNC_IOC_PUT_MUTEX..patch delete mode 100644 linux-clang/linux6.7-zen/patches/0008-[PATCH_RFC_9_9]_ntsync:_Introduce_NTSYNC_IOC_KILL_OWNER..patch rename "linux-clang/linux6.7-zen/patches/0000-[PATCH_RFC_1_9]_ntsync:_Introduce_the_ntsync_driver_and_character\n_device..patch" => linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0000.patch (82%) create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0001.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0002.patch rename linux-clang/linux6.7-zen/patches/{0004-[PATCH_RFC_5_9]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ANY..patch => v2_20240130_zfigura_nt_synchronization_primitive_driver_0003.patch} (60%) rename linux-clang/linux6.7-zen/patches/{0005-[PATCH_RFC_6_9]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ALL..patch => v2_20240130_zfigura_nt_synchronization_primitive_driver_0004.patch} (67%) rename linux-clang/linux6.7-zen/patches/{0006-[PATCH_RFC_7_9]_ntsync:_Introduce_NTSYNC_IOC_CREATE_MUTEX..patch => v2_20240130_zfigura_nt_synchronization_primitive_driver_0005.patch} (54%) create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0006.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0007.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0008.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0009.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0010.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0011.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0012.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0013.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0014.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0015.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0016.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0017.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0018.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0019.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0020.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0021.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0022.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0023.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0024.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0025.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0026.patch create mode 100644 linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0027.patch delete mode 100644 "linux-gcc/linux6.7-zen/patches/0001-[PATCH_RFC_2_9]_ntsync:_Reserve_a_minor_device_number_and_ioctl\n_range..patch" delete mode 100644 "linux-gcc/linux6.7-zen/patches/0002-[PATCH_RFC_3_9]_ntsync:_Introduce_NTSYNC_IOC_CREATE_SEM_and\n_NTSYNC_IOC_DELETE..patch" delete mode 100644 linux-gcc/linux6.7-zen/patches/0003-[PATCH_RFC_4_9]_ntsync:_Introduce_NTSYNC_IOC_PUT_SEM..patch delete mode 100644 linux-gcc/linux6.7-zen/patches/0007-[PATCH_RFC_8_9]_ntsync:_Introduce_NTSYNC_IOC_PUT_MUTEX..patch delete mode 100644 linux-gcc/linux6.7-zen/patches/0008-[PATCH_RFC_9_9]_ntsync:_Introduce_NTSYNC_IOC_KILL_OWNER..patch rename "linux-gcc/linux6.7-zen/patches/0000-[PATCH_RFC_1_9]_ntsync:_Introduce_the_ntsync_driver_and_character\n_device..patch" => linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0000.patch (82%) create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0001.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0002.patch rename linux-gcc/linux6.7-zen/patches/{0004-[PATCH_RFC_5_9]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ANY..patch => v2_20240130_zfigura_nt_synchronization_primitive_driver_0003.patch} (60%) rename linux-gcc/linux6.7-zen/patches/{0005-[PATCH_RFC_6_9]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ALL..patch => v2_20240130_zfigura_nt_synchronization_primitive_driver_0004.patch} (67%) rename linux-gcc/linux6.7-zen/patches/{0006-[PATCH_RFC_7_9]_ntsync:_Introduce_NTSYNC_IOC_CREATE_MUTEX..patch => v2_20240130_zfigura_nt_synchronization_primitive_driver_0005.patch} (54%) create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0006.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0007.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0008.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0009.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0010.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0011.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0012.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0013.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0014.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0015.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0016.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0017.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0018.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0019.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0020.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0021.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0022.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0023.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0024.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0025.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0026.patch create mode 100644 linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0027.patch diff --git "a/linux-clang/linux6.7-zen/patches/0001-[PATCH_RFC_2_9]_ntsync:_Reserve_a_minor_device_number_and_ioctl\n_range..patch" "b/linux-clang/linux6.7-zen/patches/0001-[PATCH_RFC_2_9]_ntsync:_Reserve_a_minor_device_number_and_ioctl\n_range..patch" deleted file mode 100644 index 0e03db0..0000000 --- "a/linux-clang/linux6.7-zen/patches/0001-[PATCH_RFC_2_9]_ntsync:_Reserve_a_minor_device_number_and_ioctl\n_range..patch" +++ /dev/null @@ -1,68 +0,0 @@ -Signed-off-by: Elizabeth Figura ---- - Documentation/admin-guide/devices.txt | 3 ++- - Documentation/userspace-api/ioctl/ioctl-number.rst | 2 ++ - drivers/misc/ntsync.c | 3 ++- - include/linux/miscdevice.h | 1 + - 4 files changed, 7 insertions(+), 2 deletions(-) - -diff --git a/Documentation/admin-guide/devices.txt b/Documentation/admin-guide/devices.txt -index 94c98be1329a..041404397ee5 100644 ---- a/Documentation/admin-guide/devices.txt -+++ b/Documentation/admin-guide/devices.txt -@@ -376,8 +376,9 @@ - 240 = /dev/userio Serio driver testing device - 241 = /dev/vhost-vsock Host kernel driver for virtio vsock - 242 = /dev/rfkill Turning off radio transmissions (rfkill) -+ 243 = /dev/ntsync NT synchronization primitive device - -- 243-254 Reserved for local use -+ 244-254 Reserved for local use - 255 Reserved for MISC_DYNAMIC_MINOR - - 11 char Raw keyboard device (Linux/SPARC only) -diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst -index 457e16f06e04..a1326a5bc2e0 100644 ---- a/Documentation/userspace-api/ioctl/ioctl-number.rst -+++ b/Documentation/userspace-api/ioctl/ioctl-number.rst -@@ -378,6 +378,8 @@ Code Seq# Include File Comments - - 0xF6 all LTTng Linux Trace Toolkit Next Generation - -+0xF7 00-1F uapi/linux/ntsync.h NT synchronization primitives -+ - 0xF8 all arch/x86/include/uapi/asm/amd_hsmp.h AMD HSMP EPYC system management interface driver - - 0xFD all linux/dm-ioctl.h -diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index 9424c6210e51..84b498e2b2d5 100644 ---- a/drivers/misc/ntsync.c -+++ b/drivers/misc/ntsync.c -@@ -40,7 +40,7 @@ static const struct file_operations ntsync_fops = { - }; - - static struct miscdevice ntsync_misc = { -- .minor = MISC_DYNAMIC_MINOR, -+ .minor = NTSYNC_MINOR, - .name = NTSYNC_NAME, - .fops = &ntsync_fops, - }; -@@ -51,3 +51,4 @@ MODULE_AUTHOR("Elizabeth Figura"); - MODULE_DESCRIPTION("Kernel driver for NT synchronization primitives"); - MODULE_LICENSE("GPL"); - MODULE_ALIAS("devname:" NTSYNC_NAME); -+MODULE_ALIAS_MISCDEV(NTSYNC_MINOR); -diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h -index c0fea6ca5076..fe5d9366fdf7 100644 ---- a/include/linux/miscdevice.h -+++ b/include/linux/miscdevice.h -@@ -71,6 +71,7 @@ - #define USERIO_MINOR 240 - #define VHOST_VSOCK_MINOR 241 - #define RFKILL_MINOR 242 -+#define NTSYNC_MINOR 243 - #define MISC_DYNAMIC_MINOR 255 - - struct device; --- -2.43.0 diff --git "a/linux-clang/linux6.7-zen/patches/0002-[PATCH_RFC_3_9]_ntsync:_Introduce_NTSYNC_IOC_CREATE_SEM_and\n_NTSYNC_IOC_DELETE..patch" "b/linux-clang/linux6.7-zen/patches/0002-[PATCH_RFC_3_9]_ntsync:_Introduce_NTSYNC_IOC_CREATE_SEM_and\n_NTSYNC_IOC_DELETE..patch" deleted file mode 100644 index c233e43..0000000 --- "a/linux-clang/linux6.7-zen/patches/0002-[PATCH_RFC_3_9]_ntsync:_Introduce_NTSYNC_IOC_CREATE_SEM_and\n_NTSYNC_IOC_DELETE..patch" +++ /dev/null @@ -1,191 +0,0 @@ -These correspond to the NT syscalls NtCreateSemaphore() and NtClose(). -Unlike those functions, however, these ioctls do not handle object names, or -lookup of existing objects, or handle reference counting, but simply create the -underlying primitive. The user space emulator is expected to implement those -functions if they are required. - -Signed-off-by: Elizabeth Figura ---- - drivers/misc/ntsync.c | 117 ++++++++++++++++++++++++++++++++++++ - include/uapi/linux/ntsync.h | 25 ++++++++ - 2 files changed, 142 insertions(+) - create mode 100644 include/uapi/linux/ntsync.h - -diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index 84b498e2b2d5..3287b94be351 100644 ---- a/drivers/misc/ntsync.c -+++ b/drivers/misc/ntsync.c -@@ -8,23 +8,140 @@ - #include - #include - #include -+#include -+#include -+#include - - #define NTSYNC_NAME "ntsync" - -+enum ntsync_type { -+ NTSYNC_TYPE_SEM, -+}; -+ -+struct ntsync_obj { -+ struct rcu_head rhead; -+ struct kref refcount; -+ -+ enum ntsync_type type; -+ -+ union { -+ struct { -+ __u32 count; -+ __u32 max; -+ } sem; -+ } u; -+}; -+ -+struct ntsync_device { -+ struct xarray objects; -+}; -+ -+static void destroy_obj(struct kref *ref) -+{ -+ struct ntsync_obj *obj = container_of(ref, struct ntsync_obj, refcount); -+ -+ kfree_rcu(obj, rhead); -+} -+ -+static void put_obj(struct ntsync_obj *obj) -+{ -+ kref_put(&obj->refcount, destroy_obj); -+} -+ - static int ntsync_char_open(struct inode *inode, struct file *file) - { -+ struct ntsync_device *dev; -+ -+ dev = kzalloc(sizeof(*dev), GFP_KERNEL); -+ if (!dev) -+ return -ENOMEM; -+ -+ xa_init_flags(&dev->objects, XA_FLAGS_ALLOC); -+ -+ file->private_data = dev; - return nonseekable_open(inode, file); - } - - static int ntsync_char_release(struct inode *inode, struct file *file) - { -+ struct ntsync_device *dev = file->private_data; -+ struct ntsync_obj *obj; -+ unsigned long id; -+ -+ xa_for_each(&dev->objects, id, obj) -+ put_obj(obj); -+ -+ xa_destroy(&dev->objects); -+ -+ kfree(dev); -+ -+ return 0; -+} -+ -+static void init_obj(struct ntsync_obj *obj) -+{ -+ kref_init(&obj->refcount); -+} -+ -+static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) -+{ -+ struct ntsync_sem_args __user *user_args = argp; -+ struct ntsync_sem_args args; -+ struct ntsync_obj *sem; -+ __u32 id; -+ int ret; -+ -+ if (copy_from_user(&args, argp, sizeof(args))) -+ return -EFAULT; -+ -+ if (args.count > args.max) -+ return -EINVAL; -+ -+ sem = kzalloc(sizeof(*sem), GFP_KERNEL); -+ if (!sem) -+ return -ENOMEM; -+ -+ init_obj(sem); -+ sem->type = NTSYNC_TYPE_SEM; -+ sem->u.sem.count = args.count; -+ sem->u.sem.max = args.max; -+ -+ ret = xa_alloc(&dev->objects, &id, sem, xa_limit_32b, GFP_KERNEL); -+ if (ret < 0) { -+ kfree(sem); -+ return ret; -+ } -+ -+ return put_user(id, &user_args->sem); -+} -+ -+static int ntsync_delete(struct ntsync_device *dev, void __user *argp) -+{ -+ struct ntsync_obj *obj; -+ __u32 id; -+ -+ if (get_user(id, (__u32 __user *)argp)) -+ return -EFAULT; -+ -+ obj = xa_erase(&dev->objects, id); -+ if (!obj) -+ return -EINVAL; -+ -+ put_obj(obj); - return 0; - } - - static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) - { -+ struct ntsync_device *dev = file->private_data; -+ void __user *argp = (void __user *)parm; -+ - switch (cmd) { -+ case NTSYNC_IOC_CREATE_SEM: -+ return ntsync_create_sem(dev, argp); -+ case NTSYNC_IOC_DELETE: -+ return ntsync_delete(dev, argp); - default: - return -ENOIOCTLCMD; - } -diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -new file mode 100644 -index 000000000000..d97afc138dcc ---- /dev/null -+++ b/include/uapi/linux/ntsync.h -@@ -0,0 +1,25 @@ -+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -+/* -+ * Kernel support for NT synchronization primitive emulation -+ * -+ * Copyright (C) 2021-2022 Elizabeth Figura -+ */ -+ -+#ifndef __LINUX_NTSYNC_H -+#define __LINUX_NTSYNC_H -+ -+#include -+ -+struct ntsync_sem_args { -+ __u32 sem; -+ __u32 count; -+ __u32 max; -+}; -+ -+#define NTSYNC_IOC_BASE 0xf7 -+ -+#define NTSYNC_IOC_CREATE_SEM _IOWR(NTSYNC_IOC_BASE, 0, \ -+ struct ntsync_sem_args) -+#define NTSYNC_IOC_DELETE _IOW (NTSYNC_IOC_BASE, 1, __u32) -+ -+#endif --- -2.43.0 diff --git a/linux-clang/linux6.7-zen/patches/0003-[PATCH_RFC_4_9]_ntsync:_Introduce_NTSYNC_IOC_PUT_SEM..patch b/linux-clang/linux6.7-zen/patches/0003-[PATCH_RFC_4_9]_ntsync:_Introduce_NTSYNC_IOC_PUT_SEM..patch deleted file mode 100644 index f5f30ce..0000000 --- a/linux-clang/linux6.7-zen/patches/0003-[PATCH_RFC_4_9]_ntsync:_Introduce_NTSYNC_IOC_PUT_SEM..patch +++ /dev/null @@ -1,147 +0,0 @@ -This corresponds to the NT syscall NtReleaseSemaphore(). - -Signed-off-by: Elizabeth Figura ---- - drivers/misc/ntsync.c | 76 +++++++++++++++++++++++++++++++++++++ - include/uapi/linux/ntsync.h | 2 + - 2 files changed, 78 insertions(+) - -diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index 3287b94be351..d1c91c2a4f1a 100644 ---- a/drivers/misc/ntsync.c -+++ b/drivers/misc/ntsync.c -@@ -21,9 +21,11 @@ enum ntsync_type { - struct ntsync_obj { - struct rcu_head rhead; - struct kref refcount; -+ spinlock_t lock; - - enum ntsync_type type; - -+ /* The following fields are protected by the object lock. */ - union { - struct { - __u32 count; -@@ -36,6 +38,19 @@ struct ntsync_device { - struct xarray objects; - }; - -+static struct ntsync_obj *get_obj(struct ntsync_device *dev, __u32 id) -+{ -+ struct ntsync_obj *obj; -+ -+ rcu_read_lock(); -+ obj = xa_load(&dev->objects, id); -+ if (obj && !kref_get_unless_zero(&obj->refcount)) -+ obj = NULL; -+ rcu_read_unlock(); -+ -+ return obj; -+} -+ - static void destroy_obj(struct kref *ref) - { - struct ntsync_obj *obj = container_of(ref, struct ntsync_obj, refcount); -@@ -48,6 +63,18 @@ static void put_obj(struct ntsync_obj *obj) - kref_put(&obj->refcount, destroy_obj); - } - -+static struct ntsync_obj *get_obj_typed(struct ntsync_device *dev, __u32 id, -+ enum ntsync_type type) -+{ -+ struct ntsync_obj *obj = get_obj(dev, id); -+ -+ if (obj && obj->type != type) { -+ put_obj(obj); -+ return NULL; -+ } -+ return obj; -+} -+ - static int ntsync_char_open(struct inode *inode, struct file *file) - { - struct ntsync_device *dev; -@@ -81,6 +108,7 @@ static int ntsync_char_release(struct inode *inode, struct file *file) - static void init_obj(struct ntsync_obj *obj) - { - kref_init(&obj->refcount); -+ spin_lock_init(&obj->lock); - } - - static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) -@@ -131,6 +159,52 @@ static int ntsync_delete(struct ntsync_device *dev, void __user *argp) - return 0; - } - -+/* -+ * Actually change the semaphore state, returning -EOVERFLOW if it is made -+ * invalid. -+ */ -+static int put_sem_state(struct ntsync_obj *sem, __u32 count) -+{ -+ lockdep_assert_held(&sem->lock); -+ -+ if (sem->u.sem.count + count < sem->u.sem.count || -+ sem->u.sem.count + count > sem->u.sem.max) -+ return -EOVERFLOW; -+ -+ sem->u.sem.count += count; -+ return 0; -+} -+ -+static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp) -+{ -+ struct ntsync_sem_args __user *user_args = argp; -+ struct ntsync_sem_args args; -+ struct ntsync_obj *sem; -+ __u32 prev_count; -+ int ret; -+ -+ if (copy_from_user(&args, argp, sizeof(args))) -+ return -EFAULT; -+ -+ sem = get_obj_typed(dev, args.sem, NTSYNC_TYPE_SEM); -+ if (!sem) -+ return -EINVAL; -+ -+ spin_lock(&sem->lock); -+ -+ prev_count = sem->u.sem.count; -+ ret = put_sem_state(sem, args.count); -+ -+ spin_unlock(&sem->lock); -+ -+ put_obj(sem); -+ -+ if (!ret && put_user(prev_count, &user_args->count)) -+ ret = -EFAULT; -+ -+ return ret; -+} -+ - static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) - { -@@ -142,6 +216,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - return ntsync_create_sem(dev, argp); - case NTSYNC_IOC_DELETE: - return ntsync_delete(dev, argp); -+ case NTSYNC_IOC_PUT_SEM: -+ return ntsync_put_sem(dev, argp); - default: - return -ENOIOCTLCMD; - } -diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -index d97afc138dcc..8c610d65f8ef 100644 ---- a/include/uapi/linux/ntsync.h -+++ b/include/uapi/linux/ntsync.h -@@ -21,5 +21,7 @@ struct ntsync_sem_args { - #define NTSYNC_IOC_CREATE_SEM _IOWR(NTSYNC_IOC_BASE, 0, \ - struct ntsync_sem_args) - #define NTSYNC_IOC_DELETE _IOW (NTSYNC_IOC_BASE, 1, __u32) -+#define NTSYNC_IOC_PUT_SEM _IOWR(NTSYNC_IOC_BASE, 2, \ -+ struct ntsync_sem_args) - - #endif --- -2.43.0 diff --git a/linux-clang/linux6.7-zen/patches/0007-[PATCH_RFC_8_9]_ntsync:_Introduce_NTSYNC_IOC_PUT_MUTEX..patch b/linux-clang/linux6.7-zen/patches/0007-[PATCH_RFC_8_9]_ntsync:_Introduce_NTSYNC_IOC_PUT_MUTEX..patch deleted file mode 100644 index 5ad77ae..0000000 --- a/linux-clang/linux6.7-zen/patches/0007-[PATCH_RFC_8_9]_ntsync:_Introduce_NTSYNC_IOC_PUT_MUTEX..patch +++ /dev/null @@ -1,107 +0,0 @@ -This corresponds to the NT syscall NtReleaseMutant(). - -Signed-off-by: Elizabeth Figura ---- - drivers/misc/ntsync.c | 67 +++++++++++++++++++++++++++++++++++++ - include/uapi/linux/ntsync.h | 2 ++ - 2 files changed, 69 insertions(+) - -diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index d48f2ef41341..28f43768d1c3 100644 ---- a/drivers/misc/ntsync.c -+++ b/drivers/misc/ntsync.c -@@ -449,6 +449,71 @@ static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp) - return ret; - } - -+/* -+ * Actually change the mutex state, returning -EPERM if not the owner. -+ */ -+static int put_mutex_state(struct ntsync_obj *mutex, -+ const struct ntsync_mutex_args *args) -+{ -+ lockdep_assert_held(&mutex->lock); -+ -+ if (mutex->u.mutex.owner != args->owner) -+ return -EPERM; -+ -+ if (!--mutex->u.mutex.count) -+ mutex->u.mutex.owner = 0; -+ return 0; -+} -+ -+static int ntsync_put_mutex(struct ntsync_device *dev, void __user *argp) -+{ -+ struct ntsync_mutex_args __user *user_args = argp; -+ struct ntsync_mutex_args args; -+ struct ntsync_obj *mutex; -+ __u32 prev_count; -+ int ret; -+ -+ if (copy_from_user(&args, argp, sizeof(args))) -+ return -EFAULT; -+ if (!args.owner) -+ return -EINVAL; -+ -+ mutex = get_obj_typed(dev, args.mutex, NTSYNC_TYPE_MUTEX); -+ if (!mutex) -+ return -EINVAL; -+ -+ if (atomic_read(&mutex->all_hint) > 0) { -+ spin_lock(&dev->wait_all_lock); -+ spin_lock_nest_lock(&mutex->lock, &dev->wait_all_lock); -+ -+ prev_count = mutex->u.mutex.count; -+ ret = put_mutex_state(mutex, &args); -+ if (!ret) { -+ try_wake_all_obj(dev, mutex); -+ try_wake_any_mutex(mutex); -+ } -+ -+ spin_unlock(&mutex->lock); -+ spin_unlock(&dev->wait_all_lock); -+ } else { -+ spin_lock(&mutex->lock); -+ -+ prev_count = mutex->u.mutex.count; -+ ret = put_mutex_state(mutex, &args); -+ if (!ret) -+ try_wake_any_mutex(mutex); -+ -+ spin_unlock(&mutex->lock); -+ } -+ -+ put_obj(mutex); -+ -+ if (!ret && put_user(prev_count, &user_args->count)) -+ ret = -EFAULT; -+ -+ return ret; -+} -+ - static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) - { - int ret = 0; -@@ -738,6 +803,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - return ntsync_create_sem(dev, argp); - case NTSYNC_IOC_DELETE: - return ntsync_delete(dev, argp); -+ case NTSYNC_IOC_PUT_MUTEX: -+ return ntsync_put_mutex(dev, argp); - case NTSYNC_IOC_PUT_SEM: - return ntsync_put_sem(dev, argp); - case NTSYNC_IOC_WAIT_ALL: -diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -index 26d1b3d4847f..2e44e7e77776 100644 ---- a/include/uapi/linux/ntsync.h -+++ b/include/uapi/linux/ntsync.h -@@ -46,5 +46,7 @@ struct ntsync_wait_args { - struct ntsync_wait_args) - #define NTSYNC_IOC_CREATE_MUTEX _IOWR(NTSYNC_IOC_BASE, 5, \ - struct ntsync_mutex_args) -+#define NTSYNC_IOC_PUT_MUTEX _IOWR(NTSYNC_IOC_BASE, 6, \ -+ struct ntsync_mutex_args) - - #endif --- -2.43.0 diff --git a/linux-clang/linux6.7-zen/patches/0008-[PATCH_RFC_9_9]_ntsync:_Introduce_NTSYNC_IOC_KILL_OWNER..patch b/linux-clang/linux6.7-zen/patches/0008-[PATCH_RFC_9_9]_ntsync:_Introduce_NTSYNC_IOC_KILL_OWNER..patch deleted file mode 100644 index eedfed0..0000000 --- a/linux-clang/linux6.7-zen/patches/0008-[PATCH_RFC_9_9]_ntsync:_Introduce_NTSYNC_IOC_KILL_OWNER..patch +++ /dev/null @@ -1,170 +0,0 @@ -This does not correspond to any NT syscall, but rather should be called by the -user-space NT emulator when a thread dies. It is responsible for marking any -mutexes owned by that thread as abandoned. - -Signed-off-by: Elizabeth Figura ---- - drivers/misc/ntsync.c | 80 ++++++++++++++++++++++++++++++++++++- - include/uapi/linux/ntsync.h | 1 + - 2 files changed, 79 insertions(+), 2 deletions(-) - -diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index 28f43768d1c3..1173c750c106 100644 ---- a/drivers/misc/ntsync.c -+++ b/drivers/misc/ntsync.c -@@ -64,6 +64,7 @@ struct ntsync_obj { - struct { - __u32 count; - __u32 owner; -+ bool ownerdead; - } mutex; - } u; - }; -@@ -87,6 +88,7 @@ struct ntsync_q { - atomic_t signaled; - - bool all; -+ bool ownerdead; - __u32 count; - struct ntsync_q_entry entries[]; - }; -@@ -240,6 +242,9 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, - obj->u.sem.count--; - break; - case NTSYNC_TYPE_MUTEX: -+ if (obj->u.mutex.ownerdead) -+ q->ownerdead = true; -+ obj->u.mutex.ownerdead = false; - obj->u.mutex.count++; - obj->u.mutex.owner = q->owner; - break; -@@ -299,6 +304,9 @@ static void try_wake_any_mutex(struct ntsync_obj *mutex) - continue; - - if (atomic_cmpxchg(&q->signaled, -1, entry->index) == -1) { -+ if (mutex->u.mutex.ownerdead) -+ q->ownerdead = true; -+ mutex->u.mutex.ownerdead = false; - mutex->u.mutex.count++; - mutex->u.mutex.owner = q->owner; - wake_up_process(q->task); -@@ -514,6 +522,71 @@ static int ntsync_put_mutex(struct ntsync_device *dev, void __user *argp) - return ret; - } - -+/* -+ * Actually change the mutex state to mark its owner as dead. -+ */ -+static void put_mutex_ownerdead_state(struct ntsync_obj *mutex) -+{ -+ lockdep_assert_held(&mutex->lock); -+ -+ mutex->u.mutex.ownerdead = true; -+ mutex->u.mutex.owner = 0; -+ mutex->u.mutex.count = 0; -+} -+ -+static int ntsync_kill_owner(struct ntsync_device *dev, void __user *argp) -+{ -+ struct ntsync_obj *obj; -+ unsigned long id; -+ __u32 owner; -+ -+ if (get_user(owner, (__u32 __user *)argp)) -+ return -EFAULT; -+ if (!owner) -+ return -EINVAL; -+ -+ rcu_read_lock(); -+ -+ xa_for_each(&dev->objects, id, obj) { -+ if (!kref_get_unless_zero(&obj->refcount)) -+ continue; -+ -+ if (obj->type != NTSYNC_TYPE_MUTEX) { -+ put_obj(obj); -+ continue; -+ } -+ -+ if (atomic_read(&obj->all_hint) > 0) { -+ spin_lock(&dev->wait_all_lock); -+ spin_lock_nest_lock(&obj->lock, &dev->wait_all_lock); -+ -+ if (obj->u.mutex.owner == owner) { -+ put_mutex_ownerdead_state(obj); -+ try_wake_all_obj(dev, obj); -+ try_wake_any_mutex(obj); -+ } -+ -+ spin_unlock(&obj->lock); -+ spin_unlock(&dev->wait_all_lock); -+ } else { -+ spin_lock(&obj->lock); -+ -+ if (obj->u.mutex.owner == owner) { -+ put_mutex_ownerdead_state(obj); -+ try_wake_any_mutex(obj); -+ } -+ -+ spin_unlock(&obj->lock); -+ } -+ -+ put_obj(obj); -+ } -+ -+ rcu_read_unlock(); -+ -+ return 0; -+} -+ - static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) - { - int ret = 0; -@@ -585,6 +658,7 @@ static int setup_wait(struct ntsync_device *dev, - q->owner = args->owner; - atomic_set(&q->signaled, -1); - q->all = all; -+ q->ownerdead = false; - q->count = count; - - for (i = 0; i < count; i++) { -@@ -697,7 +771,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) - struct ntsync_wait_args __user *user_args = argp; - - /* even if we caught a signal, we need to communicate success */ -- ret = 0; -+ ret = q->ownerdead ? -EOWNERDEAD : 0; - - if (put_user(signaled, &user_args->index)) - ret = -EFAULT; -@@ -778,7 +852,7 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp) - struct ntsync_wait_args __user *user_args = argp; - - /* even if we caught a signal, we need to communicate success */ -- ret = 0; -+ ret = q->ownerdead ? -EOWNERDEAD : 0; - - if (put_user(signaled, &user_args->index)) - ret = -EFAULT; -@@ -803,6 +877,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - return ntsync_create_sem(dev, argp); - case NTSYNC_IOC_DELETE: - return ntsync_delete(dev, argp); -+ case NTSYNC_IOC_KILL_OWNER: -+ return ntsync_kill_owner(dev, argp); - case NTSYNC_IOC_PUT_MUTEX: - return ntsync_put_mutex(dev, argp); - case NTSYNC_IOC_PUT_SEM: -diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -index 2e44e7e77776..fec9a3993322 100644 ---- a/include/uapi/linux/ntsync.h -+++ b/include/uapi/linux/ntsync.h -@@ -48,5 +48,6 @@ struct ntsync_wait_args { - struct ntsync_mutex_args) - #define NTSYNC_IOC_PUT_MUTEX _IOWR(NTSYNC_IOC_BASE, 6, \ - struct ntsync_mutex_args) -+#define NTSYNC_IOC_KILL_OWNER _IOW (NTSYNC_IOC_BASE, 7, __u32) - - #endif --- -2.43.0 diff --git "a/linux-clang/linux6.7-zen/patches/0000-[PATCH_RFC_1_9]_ntsync:_Introduce_the_ntsync_driver_and_character\n_device..patch" b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0000.patch similarity index 82% rename from "linux-clang/linux6.7-zen/patches/0000-[PATCH_RFC_1_9]_ntsync:_Introduce_the_ntsync_driver_and_character\n_device..patch" rename to linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0000.patch index 580a595..3459d34 100644 --- "a/linux-clang/linux6.7-zen/patches/0000-[PATCH_RFC_1_9]_ntsync:_Introduce_the_ntsync_driver_and_character\n_device..patch" +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0000.patch @@ -1,3 +1,13 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 1/29] ntsync: Introduce the ntsync driver and + character device. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:28 -0600 +Message-Id: <20240131021356.10322-2-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + ntsync uses a misc device as the simplest and least intrusive uAPI interface. Each file description on the device represents an isolated NT instance, intended @@ -7,8 +17,8 @@ Signed-off-by: Elizabeth Figura --- drivers/misc/Kconfig | 9 ++++++++ drivers/misc/Makefile | 1 + - drivers/misc/ntsync.c | 53 +++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 63 insertions(+) + drivers/misc/ntsync.c | 52 +++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 62 insertions(+) create mode 100644 drivers/misc/ntsync.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig @@ -45,15 +55,15 @@ index ea6ea5bbbc9c..153a3f4837e8 100644 obj-$(CONFIG_GP_PCI1XXXX) += mchp_pci1xxxx/ diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c new file mode 100644 -index 000000000000..9424c6210e51 +index 000000000000..e4969ef90722 --- /dev/null +++ b/drivers/misc/ntsync.c -@@ -0,0 +1,53 @@ +@@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ntsync.c - Kernel driver for NT synchronization primitives + * -+ * Copyright (C) 2021-2022 Elizabeth Figura ++ * Copyright (C) 2024 Elizabeth Figura + */ + +#include @@ -86,7 +96,7 @@ index 000000000000..9424c6210e51 + .open = ntsync_char_open, + .release = ntsync_char_release, + .unlocked_ioctl = ntsync_char_ioctl, -+ .compat_ioctl = ntsync_char_ioctl, ++ .compat_ioctl = compat_ptr_ioctl, + .llseek = no_llseek, +}; + @@ -101,6 +111,6 @@ index 000000000000..9424c6210e51 +MODULE_AUTHOR("Elizabeth Figura"); +MODULE_DESCRIPTION("Kernel driver for NT synchronization primitives"); +MODULE_LICENSE("GPL"); -+MODULE_ALIAS("devname:" NTSYNC_NAME); -- 2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0001.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0001.patch new file mode 100644 index 0000000..b8fe81c --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0001.patch @@ -0,0 +1,224 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 2/29] ntsync: Introduce NTSYNC_IOC_CREATE_SEM. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:29 -0600 +Message-Id: <20240131021356.10322-3-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This corresponds to the NT syscall NtCreateSemaphore(). + +Semaphores are one of three types of object to be implemented in this driver, +the others being mutexes and events. + +An NT semaphore contains a 32-bit counter, and is signaled and can be acquired +when the counter is nonzero. The counter has a maximum value which is specified +at creation time. The initial value of the semaphore is also specified at +creation time. There are no restrictions on the maximum and initial value. + +Each object is exposed as an file, to which any number of fds may be opened. +When all fds are closed, the object is deleted. + +Signed-off-by: Elizabeth Figura +--- + .../userspace-api/ioctl/ioctl-number.rst | 2 + + drivers/misc/ntsync.c | 120 ++++++++++++++++++ + include/uapi/linux/ntsync.h | 21 +++ + 3 files changed, 143 insertions(+) + create mode 100644 include/uapi/linux/ntsync.h + +diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst +index 457e16f06e04..2f5c6994f042 100644 +--- a/Documentation/userspace-api/ioctl/ioctl-number.rst ++++ b/Documentation/userspace-api/ioctl/ioctl-number.rst +@@ -173,6 +173,8 @@ Code Seq# Include File Comments + 'M' 00-0F drivers/video/fsl-diu-fb.h conflict! + 'N' 00-1F drivers/usb/scanner.h + 'N' 40-7F drivers/block/nvme.c ++'N' 80-8F uapi/linux/ntsync.h NT synchronization primitives ++ + 'O' 00-06 mtd/ubi-user.h UBI + 'P' all linux/soundcard.h conflict! + 'P' 60-6F sound/sscape_ioctl.h conflict! +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index e4969ef90722..3ad86d98b82d 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -5,26 +5,146 @@ + * Copyright (C) 2024 Elizabeth Figura + */ + ++#include ++#include + #include + #include + #include ++#include ++#include + + #define NTSYNC_NAME "ntsync" + ++enum ntsync_type { ++ NTSYNC_TYPE_SEM, ++}; ++ ++struct ntsync_obj { ++ enum ntsync_type type; ++ ++ union { ++ struct { ++ __u32 count; ++ __u32 max; ++ } sem; ++ } u; ++ ++ struct file *file; ++ struct ntsync_device *dev; ++}; ++ ++struct ntsync_device { ++ struct file *file; ++}; ++ ++static int ntsync_obj_release(struct inode *inode, struct file *file) ++{ ++ struct ntsync_obj *obj = file->private_data; ++ ++ fput(obj->dev->file); ++ kfree(obj); ++ ++ return 0; ++} ++ ++static const struct file_operations ntsync_obj_fops = { ++ .owner = THIS_MODULE, ++ .release = ntsync_obj_release, ++ .llseek = no_llseek, ++}; ++ ++static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev, ++ enum ntsync_type type) ++{ ++ struct ntsync_obj *obj; ++ ++ obj = kzalloc(sizeof(*obj), GFP_KERNEL); ++ if (!obj) ++ return NULL; ++ obj->type = type; ++ obj->dev = dev; ++ get_file(dev->file); ++ ++ return obj; ++} ++ ++static int ntsync_obj_get_fd(struct ntsync_obj *obj) ++{ ++ struct file *file; ++ int fd; ++ ++ fd = get_unused_fd_flags(O_CLOEXEC); ++ if (fd < 0) ++ return fd; ++ file = anon_inode_getfile("ntsync", &ntsync_obj_fops, obj, O_RDWR); ++ if (IS_ERR(file)) { ++ put_unused_fd(fd); ++ return PTR_ERR(file); ++ } ++ obj->file = file; ++ fd_install(fd, file); ++ ++ return fd; ++} ++ ++static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) ++{ ++ struct ntsync_sem_args __user *user_args = argp; ++ struct ntsync_sem_args args; ++ struct ntsync_obj *sem; ++ int fd; ++ ++ if (copy_from_user(&args, argp, sizeof(args))) ++ return -EFAULT; ++ ++ if (args.count > args.max) ++ return -EINVAL; ++ ++ sem = ntsync_alloc_obj(dev, NTSYNC_TYPE_SEM); ++ if (!sem) ++ return -ENOMEM; ++ sem->u.sem.count = args.count; ++ sem->u.sem.max = args.max; ++ fd = ntsync_obj_get_fd(sem); ++ if (fd < 0) { ++ kfree(sem); ++ return fd; ++ } ++ ++ return put_user(fd, &user_args->sem); ++} ++ + static int ntsync_char_open(struct inode *inode, struct file *file) + { ++ struct ntsync_device *dev; ++ ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ if (!dev) ++ return -ENOMEM; ++ ++ file->private_data = dev; ++ dev->file = file; + return nonseekable_open(inode, file); + } + + static int ntsync_char_release(struct inode *inode, struct file *file) + { ++ struct ntsync_device *dev = file->private_data; ++ ++ kfree(dev); ++ + return 0; + } + + static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + unsigned long parm) + { ++ struct ntsync_device *dev = file->private_data; ++ void __user *argp = (void __user *)parm; ++ + switch (cmd) { ++ case NTSYNC_IOC_CREATE_SEM: ++ return ntsync_create_sem(dev, argp); + default: + return -ENOIOCTLCMD; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +new file mode 100644 +index 000000000000..f38818e7759d +--- /dev/null ++++ b/include/uapi/linux/ntsync.h +@@ -0,0 +1,21 @@ ++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++/* ++ * Kernel support for NT synchronization primitive emulation ++ * ++ * Copyright (C) 2021-2022 Elizabeth Figura ++ */ ++ ++#ifndef __LINUX_NTSYNC_H ++#define __LINUX_NTSYNC_H ++ ++#include ++ ++struct ntsync_sem_args { ++ __u32 sem; ++ __u32 count; ++ __u32 max; ++}; ++ ++#define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args) ++ ++#endif +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0002.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0002.patch new file mode 100644 index 0000000..66b3ca2 --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0002.patch @@ -0,0 +1,145 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 3/29] ntsync: Introduce NTSYNC_IOC_SEM_POST. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:30 -0600 +Message-Id: <20240131021356.10322-4-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This corresponds to the NT syscall NtReleaseSemaphore(). + +This increases the semaphore's internal counter by the given value, and returns +the previous value. If the counter would overflow the defined maximum, the +function instead fails and returns -EOVERFLOW. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 68 +++++++++++++++++++++++++++++++++++-- + include/uapi/linux/ntsync.h | 2 ++ + 2 files changed, 67 insertions(+), 3 deletions(-) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 3ad86d98b82d..1af38969f9a2 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -20,23 +20,68 @@ enum ntsync_type { + }; + + struct ntsync_obj { ++ spinlock_t lock; ++ + enum ntsync_type type; + ++ struct file *file; ++ struct ntsync_device *dev; ++ ++ /* The following fields are protected by the object lock. */ + union { + struct { + __u32 count; + __u32 max; + } sem; + } u; +- +- struct file *file; +- struct ntsync_device *dev; + }; + + struct ntsync_device { + struct file *file; + }; + ++/* ++ * Actually change the semaphore state, returning -EOVERFLOW if it is made ++ * invalid. ++ */ ++static int post_sem_state(struct ntsync_obj *sem, __u32 count) ++{ ++ lockdep_assert_held(&sem->lock); ++ ++ if (sem->u.sem.count + count < sem->u.sem.count || ++ sem->u.sem.count + count > sem->u.sem.max) ++ return -EOVERFLOW; ++ ++ sem->u.sem.count += count; ++ return 0; ++} ++ ++static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp) ++{ ++ __u32 __user *user_args = argp; ++ __u32 prev_count; ++ __u32 args; ++ int ret; ++ ++ if (copy_from_user(&args, argp, sizeof(args))) ++ return -EFAULT; ++ ++ if (sem->type != NTSYNC_TYPE_SEM) ++ return -EINVAL; ++ ++ spin_lock(&sem->lock); ++ ++ prev_count = sem->u.sem.count; ++ ret = post_sem_state(sem, args); ++ ++ spin_unlock(&sem->lock); ++ ++ if (!ret && put_user(prev_count, user_args)) ++ ret = -EFAULT; ++ ++ return ret; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -47,9 +92,25 @@ static int ntsync_obj_release(struct inode *inode, struct file *file) + return 0; + } + ++static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, ++ unsigned long parm) ++{ ++ struct ntsync_obj *obj = file->private_data; ++ void __user *argp = (void __user *)parm; ++ ++ switch (cmd) { ++ case NTSYNC_IOC_SEM_POST: ++ return ntsync_sem_post(obj, argp); ++ default: ++ return -ENOIOCTLCMD; ++ } ++} ++ + static const struct file_operations ntsync_obj_fops = { + .owner = THIS_MODULE, + .release = ntsync_obj_release, ++ .unlocked_ioctl = ntsync_obj_ioctl, ++ .compat_ioctl = compat_ptr_ioctl, + .llseek = no_llseek, + }; + +@@ -64,6 +125,7 @@ static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev, + obj->type = type; + obj->dev = dev; + get_file(dev->file); ++ spin_lock_init(&obj->lock); + + return obj; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index f38818e7759d..878ec4f0f2e8 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -18,4 +18,6 @@ struct ntsync_sem_args { + + #define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args) + ++#define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) ++ + #endif +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/0004-[PATCH_RFC_5_9]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ANY..patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0003.patch similarity index 60% rename from linux-clang/linux6.7-zen/patches/0004-[PATCH_RFC_5_9]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ANY..patch rename to linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0003.patch index 8aa8f46..e610f90 100644 --- a/linux-clang/linux6.7-zen/patches/0004-[PATCH_RFC_5_9]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ANY..patch +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0003.patch @@ -1,31 +1,52 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 4/29] ntsync: Introduce NTSYNC_IOC_WAIT_ANY. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:31 -0600 +Message-Id: <20240131021356.10322-5-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + This corresponds to part of the functionality of the NT syscall NtWaitForMultipleObjects(). Specifically, it implements the behaviour where the third argument (wait_any) is TRUE, and it does not handle alertable waits. Those features have been split out into separate patches to ease review. +NTSYNC_IOC_WAIT_ANY is a vectored wait function similar to poll(). Unlike +poll(), it "consumes" objects when they are signaled. For semaphores, this means +decreasing one from the internal counter. At most one object can be consumed by +this function. + +Up to 64 objects can be waited on at once. As soon as one is signaled, the +object with the lowest index is consumed, and that index is returned via the +"index" field. + +A timeout is supported. The timeout is passed as a u64 nanosecond value, which +represents absolute time measured against the MONOTONIC clock. If U64_MAX is +passed, the ioctl waits indefinitely. + +This ioctl validates that all objects belong to the relevant device. This is not +necessary for any technical reason related to NTSYNC_IOC_WAIT_ANY, but will be +necessary for NTSYNC_IOC_WAIT_ALL introduced in the following patch. + Signed-off-by: Elizabeth Figura --- - drivers/misc/ntsync.c | 229 ++++++++++++++++++++++++++++++++++++ - include/uapi/linux/ntsync.h | 13 ++ - 2 files changed, 242 insertions(+) + drivers/misc/ntsync.c | 232 ++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 12 ++ + 2 files changed, 244 insertions(+) diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index d1c91c2a4f1a..2e8d3c2d51a4 100644 +index 1af38969f9a2..0a0ab755d57f 100644 --- a/drivers/misc/ntsync.c +++ b/drivers/misc/ntsync.c -@@ -23,6 +23,8 @@ struct ntsync_obj { - struct kref refcount; - spinlock_t lock; - -+ struct list_head any_waiters; -+ - enum ntsync_type type; - - /* The following fields are protected by the object lock. */ -@@ -34,6 +36,28 @@ struct ntsync_obj { +@@ -34,12 +34,55 @@ struct ntsync_obj { + __u32 max; + } sem; } u; - }; - ++ ++ struct list_head any_waiters; ++}; ++ +struct ntsync_q_entry { + struct list_head node; + struct ntsync_q *q; @@ -46,18 +67,12 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + + __u32 count; + struct ntsync_q_entry entries[]; -+}; -+ - struct ntsync_device { - struct xarray objects; }; -@@ -109,6 +133,26 @@ static void init_obj(struct ntsync_obj *obj) - { - kref_init(&obj->refcount); - spin_lock_init(&obj->lock); -+ INIT_LIST_HEAD(&obj->any_waiters); -+} -+ + + struct ntsync_device { + struct file *file; + }; + +static void try_wake_any_sem(struct ntsync_obj *sem) +{ + struct ntsync_q_entry *entry; @@ -75,22 +90,58 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + wake_up_process(q->task); + } + } - } - - static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) -@@ -194,6 +238,8 @@ static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp) ++} ++ + /* + * Actually change the semaphore state, returning -EOVERFLOW if it is made + * invalid. +@@ -73,6 +116,8 @@ static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp) prev_count = sem->u.sem.count; - ret = put_sem_state(sem, args.count); + ret = post_sem_state(sem, args); + if (!ret) + try_wake_any_sem(sem); spin_unlock(&sem->lock); -@@ -205,6 +251,187 @@ static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp) - return ret; +@@ -126,6 +171,7 @@ static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev, + obj->dev = dev; + get_file(dev->file); + spin_lock_init(&obj->lock); ++ INIT_LIST_HEAD(&obj->any_waiters); + + return obj; + } +@@ -176,6 +222,190 @@ static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) + return put_user(fd, &user_args->sem); } ++static struct ntsync_obj *get_obj(struct ntsync_device *dev, int fd) ++{ ++ struct file *file = fget(fd); ++ struct ntsync_obj *obj; ++ ++ if (file->f_op != &ntsync_obj_fops) ++ { ++ fput(file); ++ return NULL; ++ } ++ ++ obj = file->private_data; ++ if (obj->dev != dev) ++ { ++ fput(file); ++ return NULL; ++ } ++ ++ return obj; ++} ++ ++static void put_obj(struct ntsync_obj *obj) ++{ ++ fput(obj->file); ++} ++ +static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) +{ + int ret = 0; @@ -115,16 +166,14 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + +/* + * Allocate and initialize the ntsync_q structure, but do not queue us yet. -+ * Also, calculate the relative timeout. + */ +static int setup_wait(struct ntsync_device *dev, + const struct ntsync_wait_args *args, -+ ktime_t *ret_timeout, struct ntsync_q **ret_q) ++ struct ntsync_q **ret_q) +{ + const __u32 count = args->count; ++ int fds[NTSYNC_MAX_WAIT_COUNT]; + struct ntsync_q *q; -+ ktime_t timeout = 0; -+ __u32 *ids; + __u32 i, j; + + if (!args->owner || args->pad) @@ -133,31 +182,13 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + if (args->count > NTSYNC_MAX_WAIT_COUNT) + return -EINVAL; + -+ if (args->timeout) { -+ struct timespec64 to; -+ -+ if (get_timespec64(&to, u64_to_user_ptr(args->timeout))) -+ return -EFAULT; -+ if (!timespec64_valid(&to)) -+ return -EINVAL; -+ -+ timeout = timespec64_to_ns(&to); -+ } -+ -+ ids = kmalloc_array(count, sizeof(*ids), GFP_KERNEL); -+ if (!ids) -+ return -ENOMEM; -+ if (copy_from_user(ids, u64_to_user_ptr(args->objs), -+ array_size(count, sizeof(*ids)))) { -+ kfree(ids); ++ if (copy_from_user(fds, u64_to_user_ptr(args->objs), ++ array_size(count, sizeof(*fds)))) + return -EFAULT; -+ } + + q = kmalloc(struct_size(q, entries, count), GFP_KERNEL); -+ if (!q) { -+ kfree(ids); ++ if (!q) + return -ENOMEM; -+ } + q->task = current; + q->owner = args->owner; + atomic_set(&q->signaled, -1); @@ -165,7 +196,7 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + + for (i = 0; i < count; i++) { + struct ntsync_q_entry *entry = &q->entries[i]; -+ struct ntsync_obj *obj = get_obj(dev, ids[i]); ++ struct ntsync_obj *obj = get_obj(dev, fds[i]); + + if (!obj) + goto err; @@ -175,16 +206,12 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + entry->index = i; + } + -+ kfree(ids); -+ + *ret_q = q; -+ *ret_timeout = timeout; + return 0; + +err: + for (j = 0; j < i; j++) + put_obj(q->entries[j].obj); -+ kfree(ids); + kfree(q); + return -EINVAL; +} @@ -210,7 +237,7 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + if (copy_from_user(&args, argp, sizeof(args))) + return -EFAULT; + -+ ret = setup_wait(dev, &args, &timeout, &q); ++ ret = setup_wait(dev, &args, &q); + if (ret < 0) + return ret; + @@ -240,7 +267,8 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + + /* sleep */ + -+ ret = ntsync_schedule(q, args.timeout ? &timeout : NULL); ++ timeout = ns_to_ktime(args.timeout); ++ ret = ntsync_schedule(q, args.timeout == U64_MAX ? NULL : &timeout); + + /* and finally, unqueue */ + @@ -272,23 +300,23 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + return ret; +} + - static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) + static int ntsync_char_open(struct inode *inode, struct file *file) { -@@ -218,6 +445,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - return ntsync_delete(dev, argp); - case NTSYNC_IOC_PUT_SEM: - return ntsync_put_sem(dev, argp); + struct ntsync_device *dev; +@@ -207,6 +437,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + switch (cmd) { + case NTSYNC_IOC_CREATE_SEM: + return ntsync_create_sem(dev, argp); + case NTSYNC_IOC_WAIT_ANY: + return ntsync_wait_any(dev, argp); default: return -ENOIOCTLCMD; } diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -index 8c610d65f8ef..10f07da7864e 100644 +index 878ec4f0f2e8..9cd1dd05d971 100644 --- a/include/uapi/linux/ntsync.h +++ b/include/uapi/linux/ntsync.h -@@ -16,6 +16,17 @@ struct ntsync_sem_args { +@@ -16,7 +16,19 @@ struct ntsync_sem_args { __u32 max; }; @@ -303,16 +331,11 @@ index 8c610d65f8ef..10f07da7864e 100644 + +#define NTSYNC_MAX_WAIT_COUNT 64 + - #define NTSYNC_IOC_BASE 0xf7 + #define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args) ++#define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args) - #define NTSYNC_IOC_CREATE_SEM _IOWR(NTSYNC_IOC_BASE, 0, \ -@@ -23,5 +34,7 @@ struct ntsync_sem_args { - #define NTSYNC_IOC_DELETE _IOW (NTSYNC_IOC_BASE, 1, __u32) - #define NTSYNC_IOC_PUT_SEM _IOWR(NTSYNC_IOC_BASE, 2, \ - struct ntsync_sem_args) -+#define NTSYNC_IOC_WAIT_ANY _IOWR(NTSYNC_IOC_BASE, 3, \ -+ struct ntsync_wait_args) + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) - #endif -- 2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/0005-[PATCH_RFC_6_9]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ALL..patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0004.patch similarity index 67% rename from linux-clang/linux6.7-zen/patches/0005-[PATCH_RFC_6_9]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ALL..patch rename to linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0004.patch index c63ef03..34eac82 100644 --- a/linux-clang/linux6.7-zen/patches/0005-[PATCH_RFC_6_9]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ALL..patch +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0004.patch @@ -1,21 +1,29 @@ -This corresponds to part of the functionality of the NT syscall -NtWaitForMultipleObjects(). Specifically, it implements the behaviour where -the third argument (wait_any) is FALSE, and it does not yet handle alertable -waits. +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 5/29] ntsync: Introduce NTSYNC_IOC_WAIT_ALL. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:32 -0600 +Message-Id: <20240131021356.10322-6-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This is similar to NTSYNC_IOC_WAIT_ANY, but waits until all of the objects are +simultaneously signaled, and then acquires all of them as a single atomic +operation. Signed-off-by: Elizabeth Figura --- - drivers/misc/ntsync.c | 241 ++++++++++++++++++++++++++++++++++-- - include/uapi/linux/ntsync.h | 2 + - 2 files changed, 235 insertions(+), 8 deletions(-) + drivers/misc/ntsync.c | 244 ++++++++++++++++++++++++++++++++++-- + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 237 insertions(+), 8 deletions(-) diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index 2e8d3c2d51a4..2685363fae9e 100644 +index 0a0ab755d57f..b86d62094344 100644 --- a/drivers/misc/ntsync.c +++ b/drivers/misc/ntsync.c -@@ -23,7 +23,34 @@ struct ntsync_obj { - struct kref refcount; - spinlock_t lock; +@@ -35,7 +35,34 @@ struct ntsync_obj { + } sem; + } u; + /* + * any_waiters is protected by the object lock, but all_waiters is @@ -33,22 +41,22 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + * lock all of the objects, and that means grabbing the wait_all_lock + * below (and, due to lock ordering rules, before locking this object). + * However, wait-all is a rare operation, and grabbing the wait-all -+ * lock for every wake would create unnecessary contention. Therefore we -+ * first check whether all_hint is zero, and, if it is, we skip trying -+ * to wake "all" waiters. ++ * lock for every wake would create unnecessary contention. ++ * Therefore we first check whether all_hint is zero, and, if it is, ++ * we skip trying to wake "all" waiters. + * + * This hint isn't protected by any lock. It might change during the + * course of a wake, but there's no meaningful race there; it's only a + * hint. + * + * Since wait requests must originate from user-space threads, we're -+ * limited here by PID_MAX_LIMIT, so there's no risk of saturation. ++ * limited here by PID_MAX_LIMIT, so there's no risk of overflow. + */ + atomic_t all_hint; + }; - enum ntsync_type type; - -@@ -54,11 +81,25 @@ struct ntsync_q { + struct ntsync_q_entry { +@@ -56,14 +83,99 @@ struct ntsync_q { */ atomic_t signaled; @@ -60,9 +68,9 @@ index 2e8d3c2d51a4..2685363fae9e 100644 struct ntsync_device { + /* + * Wait-all operations must atomically grab all objects, and be totally -+ * ordered with respect to each other and wait-any operations. If one -+ * thread is trying to acquire several objects, another thread cannot -+ * touch the object at the same time. ++ * ordered with respect to each other and wait-any operations. ++ * If one thread is trying to acquire several objects, another thread ++ * cannot touch the object at the same time. + * + * We achieve this by grabbing multiple object locks at the same time. + * However, this creates a lock ordering problem. To solve that problem, @@ -71,28 +79,9 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + */ + spinlock_t wait_all_lock; + - struct xarray objects; + struct file *file; }; -@@ -107,6 +148,8 @@ static int ntsync_char_open(struct inode *inode, struct file *file) - if (!dev) - return -ENOMEM; - -+ spin_lock_init(&dev->wait_all_lock); -+ - xa_init_flags(&dev->objects, XA_FLAGS_ALLOC); - - file->private_data = dev; -@@ -132,8 +175,81 @@ static int ntsync_char_release(struct inode *inode, struct file *file) - static void init_obj(struct ntsync_obj *obj) - { - kref_init(&obj->refcount); -+ atomic_set(&obj->all_hint, 0); - spin_lock_init(&obj->lock); - INIT_LIST_HEAD(&obj->any_waiters); -+ INIT_LIST_HEAD(&obj->all_waiters); -+} -+ +static bool is_signaled(struct ntsync_obj *obj, __u32 owner) +{ + lockdep_assert_held(&obj->lock); @@ -162,11 +151,21 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + + list_for_each_entry(entry, &obj->all_waiters, node) + try_wake_all(dev, entry->q, obj); - } - ++} ++ static void try_wake_any_sem(struct ntsync_obj *sem) -@@ -234,14 +350,29 @@ static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp) - if (!sem) + { + struct ntsync_q_entry *entry; +@@ -101,6 +213,7 @@ static int post_sem_state(struct ntsync_obj *sem, __u32 count) + + static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp) + { ++ struct ntsync_device *dev = sem->dev; + __u32 __user *user_args = argp; + __u32 prev_count; + __u32 args; +@@ -112,14 +225,29 @@ static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp) + if (sem->type != NTSYNC_TYPE_SEM) return -EINVAL; - spin_lock(&sem->lock); @@ -175,11 +174,11 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + spin_lock_nest_lock(&sem->lock, &dev->wait_all_lock); - prev_count = sem->u.sem.count; -- ret = put_sem_state(sem, args.count); +- ret = post_sem_state(sem, args); - if (!ret) - try_wake_any_sem(sem); + prev_count = sem->u.sem.count; -+ ret = put_sem_state(sem, args.count); ++ ret = post_sem_state(sem, args); + if (!ret) { + try_wake_all_obj(dev, sem); + try_wake_any_sem(sem); @@ -192,25 +191,34 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + spin_lock(&sem->lock); + + prev_count = sem->u.sem.count; -+ ret = put_sem_state(sem, args.count); ++ ret = post_sem_state(sem, args); + if (!ret) + try_wake_any_sem(sem); + + spin_unlock(&sem->lock); + } - put_obj(sem); + if (!ret && put_user(prev_count, user_args)) + ret = -EFAULT; +@@ -172,6 +300,8 @@ static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev, + get_file(dev->file); + spin_lock_init(&obj->lock); + INIT_LIST_HEAD(&obj->any_waiters); ++ INIT_LIST_HEAD(&obj->all_waiters); ++ atomic_set(&obj->all_hint, 0); -@@ -278,7 +409,7 @@ static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) - * Also, calculate the relative timeout. + return obj; + } +@@ -274,7 +404,7 @@ static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) + * Allocate and initialize the ntsync_q structure, but do not queue us yet. */ static int setup_wait(struct ntsync_device *dev, - const struct ntsync_wait_args *args, + const struct ntsync_wait_args *args, bool all, - ktime_t *ret_timeout, struct ntsync_q **ret_q) + struct ntsync_q **ret_q) { const __u32 count = args->count; -@@ -321,6 +452,7 @@ static int setup_wait(struct ntsync_device *dev, +@@ -298,6 +428,7 @@ static int setup_wait(struct ntsync_device *dev, q->task = current; q->owner = args->owner; atomic_set(&q->signaled, -1); @@ -218,7 +226,7 @@ index 2e8d3c2d51a4..2685363fae9e 100644 q->count = count; for (i = 0; i < count; i++) { -@@ -330,6 +462,16 @@ static int setup_wait(struct ntsync_device *dev, +@@ -307,6 +438,16 @@ static int setup_wait(struct ntsync_device *dev, if (!obj) goto err; @@ -235,16 +243,16 @@ index 2e8d3c2d51a4..2685363fae9e 100644 entry->obj = obj; entry->q = q; entry->index = i; -@@ -370,7 +512,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) +@@ -343,7 +484,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) if (copy_from_user(&args, argp, sizeof(args))) return -EFAULT; -- ret = setup_wait(dev, &args, &timeout, &q); -+ ret = setup_wait(dev, &args, false, &timeout, &q); +- ret = setup_wait(dev, &args, &q); ++ ret = setup_wait(dev, &args, false, &q); if (ret < 0) return ret; -@@ -432,6 +574,87 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) +@@ -406,6 +547,89 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) return ret; } @@ -260,7 +268,7 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + if (copy_from_user(&args, argp, sizeof(args))) + return -EFAULT; + -+ ret = setup_wait(dev, &args, true, &timeout, &q); ++ ret = setup_wait(dev, &args, true, &q); + if (ret < 0) + return ret; + @@ -276,7 +284,8 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + + /* + * obj->all_waiters is protected by dev->wait_all_lock rather -+ * than obj->lock, so there is no need to acquire it here. ++ * than obj->lock, so there is no need to acquire obj->lock ++ * here. + */ + list_add_tail(&entry->node, &obj->all_waiters); + } @@ -289,7 +298,8 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + + /* sleep */ + -+ ret = ntsync_schedule(q, args.timeout ? &timeout : NULL); ++ timeout = ns_to_ktime(args.timeout); ++ ret = ntsync_schedule(q, args.timeout == U64_MAX ? NULL : &timeout); + + /* and finally, unqueue */ + @@ -329,29 +339,39 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + return ret; +} + - static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) + static int ntsync_char_open(struct inode *inode, struct file *file) { -@@ -445,6 +668,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - return ntsync_delete(dev, argp); - case NTSYNC_IOC_PUT_SEM: - return ntsync_put_sem(dev, argp); + struct ntsync_device *dev; +@@ -414,6 +638,8 @@ static int ntsync_char_open(struct inode *inode, struct file *file) + if (!dev) + return -ENOMEM; + ++ spin_lock_init(&dev->wait_all_lock); ++ + file->private_data = dev; + dev->file = file; + return nonseekable_open(inode, file); +@@ -437,6 +663,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + switch (cmd) { + case NTSYNC_IOC_CREATE_SEM: + return ntsync_create_sem(dev, argp); + case NTSYNC_IOC_WAIT_ALL: + return ntsync_wait_all(dev, argp); case NTSYNC_IOC_WAIT_ANY: return ntsync_wait_any(dev, argp); default: diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -index 10f07da7864e..a5bed5a39b21 100644 +index 9cd1dd05d971..524404f6aceb 100644 --- a/include/uapi/linux/ntsync.h +++ b/include/uapi/linux/ntsync.h -@@ -36,5 +36,7 @@ struct ntsync_wait_args { - struct ntsync_sem_args) - #define NTSYNC_IOC_WAIT_ANY _IOWR(NTSYNC_IOC_BASE, 3, \ - struct ntsync_wait_args) -+#define NTSYNC_IOC_WAIT_ALL _IOWR(NTSYNC_IOC_BASE, 4, \ -+ struct ntsync_wait_args) +@@ -29,6 +29,7 @@ struct ntsync_wait_args { + + #define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args) + #define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args) ++#define NTSYNC_IOC_WAIT_ALL _IOWR('N', 0x83, struct ntsync_wait_args) + + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) - #endif -- 2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/0006-[PATCH_RFC_7_9]_ntsync:_Introduce_NTSYNC_IOC_CREATE_MUTEX..patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0005.patch similarity index 54% rename from linux-clang/linux6.7-zen/patches/0006-[PATCH_RFC_7_9]_ntsync:_Introduce_NTSYNC_IOC_CREATE_MUTEX..patch rename to linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0005.patch index 5ed169a..54baae5 100644 --- a/linux-clang/linux6.7-zen/patches/0006-[PATCH_RFC_7_9]_ntsync:_Introduce_NTSYNC_IOC_CREATE_MUTEX..patch +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0005.patch @@ -1,16 +1,35 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 6/29] ntsync: Introduce NTSYNC_IOC_CREATE_MUTEX. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:33 -0600 +Message-Id: <20240131021356.10322-7-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + This corresponds to the NT syscall NtCreateMutant(). +An NT mutex is recursive, with a 32-bit recursion counter. When acquired via +NtWaitForMultipleObjects(), the recursion counter is incremented by one. + +The OS records the thread which acquired it. However, in order to keep this +driver self-contained, the owning thread ID is managed by user-space, and passed +as a parameter to all relevant ioctls. + +The initial owner and recursion count, if any, are specified when the mutex is +created. + Signed-off-by: Elizabeth Figura --- - drivers/misc/ntsync.c | 72 +++++++++++++++++++++++++++++++++++++ - include/uapi/linux/ntsync.h | 8 +++++ - 2 files changed, 80 insertions(+) + drivers/misc/ntsync.c | 67 +++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 7 ++++ + 2 files changed, 74 insertions(+) diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index 2685363fae9e..d48f2ef41341 100644 +index b86d62094344..484219a266ae 100644 --- a/drivers/misc/ntsync.c +++ b/drivers/misc/ntsync.c -@@ -16,6 +16,7 @@ +@@ -17,6 +17,7 @@ enum ntsync_type { NTSYNC_TYPE_SEM, @@ -18,7 +37,7 @@ index 2685363fae9e..d48f2ef41341 100644 }; struct ntsync_obj { -@@ -60,6 +61,10 @@ struct ntsync_obj { +@@ -33,6 +34,10 @@ struct ntsync_obj { __u32 count; __u32 max; } sem; @@ -27,9 +46,9 @@ index 2685363fae9e..d48f2ef41341 100644 + __u32 owner; + } mutex; } u; - }; -@@ -188,6 +193,10 @@ static bool is_signaled(struct ntsync_obj *obj, __u32 owner) + /* +@@ -112,6 +117,10 @@ static bool is_signaled(struct ntsync_obj *obj, __u32 owner) switch (obj->type) { case NTSYNC_TYPE_SEM: return !!obj->u.sem.count; @@ -40,7 +59,7 @@ index 2685363fae9e..d48f2ef41341 100644 } WARN(1, "bad object type %#x\n", obj->type); -@@ -230,6 +239,10 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, +@@ -154,6 +163,10 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, case NTSYNC_TYPE_SEM: obj->u.sem.count--; break; @@ -51,7 +70,7 @@ index 2685363fae9e..d48f2ef41341 100644 } } wake_up_process(q->task); -@@ -271,6 +284,28 @@ static void try_wake_any_sem(struct ntsync_obj *sem) +@@ -195,6 +208,28 @@ static void try_wake_any_sem(struct ntsync_obj *sem) } } @@ -77,11 +96,11 @@ index 2685363fae9e..d48f2ef41341 100644 + } +} + - static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) - { - struct ntsync_sem_args __user *user_args = argp; -@@ -303,6 +338,38 @@ static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) - return put_user(id, &user_args->sem); + /* + * Actually change the semaphore state, returning -EOVERFLOW if it is made + * invalid. +@@ -352,6 +387,33 @@ static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) + return put_user(fd, &user_args->sem); } +static int ntsync_create_mutex(struct ntsync_device *dev, void __user *argp) @@ -89,8 +108,7 @@ index 2685363fae9e..d48f2ef41341 100644 + struct ntsync_mutex_args __user *user_args = argp; + struct ntsync_mutex_args args; + struct ntsync_obj *mutex; -+ __u32 id; -+ int ret; ++ int fd; + + if (copy_from_user(&args, argp, sizeof(args))) + return -EFAULT; @@ -98,28 +116,24 @@ index 2685363fae9e..d48f2ef41341 100644 + if (!args.owner != !args.count) + return -EINVAL; + -+ mutex = kzalloc(sizeof(*mutex), GFP_KERNEL); ++ mutex = ntsync_alloc_obj(dev, NTSYNC_TYPE_MUTEX); + if (!mutex) + return -ENOMEM; -+ -+ init_obj(mutex); -+ mutex->type = NTSYNC_TYPE_MUTEX; + mutex->u.mutex.count = args.count; + mutex->u.mutex.owner = args.owner; -+ -+ ret = xa_alloc(&dev->objects, &id, mutex, xa_limit_32b, GFP_KERNEL); -+ if (ret < 0) { ++ fd = ntsync_obj_get_fd(mutex); ++ if (fd < 0) { + kfree(mutex); -+ return ret; ++ return fd; + } + -+ return put_user(id, &user_args->mutex); ++ return put_user(fd, &user_args->mutex); +} + - static int ntsync_delete(struct ntsync_device *dev, void __user *argp) + static struct ntsync_obj *get_obj(struct ntsync_device *dev, int fd) { - struct ntsync_obj *obj; -@@ -497,6 +564,9 @@ static void try_wake_any_obj(struct ntsync_obj *obj) + struct file *file = fget(fd); +@@ -469,6 +531,9 @@ static void try_wake_any_obj(struct ntsync_obj *obj) case NTSYNC_TYPE_SEM: try_wake_any_sem(obj); break; @@ -129,7 +143,7 @@ index 2685363fae9e..d48f2ef41341 100644 } } -@@ -662,6 +732,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, +@@ -661,6 +726,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, void __user *argp = (void __user *)parm; switch (cmd) { @@ -137,9 +151,9 @@ index 2685363fae9e..d48f2ef41341 100644 + return ntsync_create_mutex(dev, argp); case NTSYNC_IOC_CREATE_SEM: return ntsync_create_sem(dev, argp); - case NTSYNC_IOC_DELETE: + case NTSYNC_IOC_WAIT_ALL: diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -index a5bed5a39b21..26d1b3d4847f 100644 +index 524404f6aceb..d68f24fd75a2 100644 --- a/include/uapi/linux/ntsync.h +++ b/include/uapi/linux/ntsync.h @@ -16,6 +16,12 @@ struct ntsync_sem_args { @@ -155,13 +169,14 @@ index a5bed5a39b21..26d1b3d4847f 100644 struct ntsync_wait_args { __u64 timeout; __u64 objs; -@@ -38,5 +44,7 @@ struct ntsync_wait_args { - struct ntsync_wait_args) - #define NTSYNC_IOC_WAIT_ALL _IOWR(NTSYNC_IOC_BASE, 4, \ - struct ntsync_wait_args) -+#define NTSYNC_IOC_CREATE_MUTEX _IOWR(NTSYNC_IOC_BASE, 5, \ -+ struct ntsync_mutex_args) +@@ -30,6 +36,7 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args) + #define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args) + #define NTSYNC_IOC_WAIT_ALL _IOWR('N', 0x83, struct ntsync_wait_args) ++#define NTSYNC_IOC_CREATE_MUTEX _IOWR('N', 0x84, struct ntsync_sem_args) + + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) - #endif -- 2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0006.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0006.patch new file mode 100644 index 0000000..f88e505 --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0006.patch @@ -0,0 +1,117 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 7/29] ntsync: Introduce NTSYNC_IOC_MUTEX_UNLOCK. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:34 -0600 +Message-Id: <20240131021356.10322-8-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This corresponds to the NT syscall NtReleaseMutant(). + +This syscall decrements the mutex's recursion count by one, and returns the +previous value. If the mutex is not owned by the given owner ID, the function +instead fails and returns -EPERM. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 64 +++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 65 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 484219a266ae..1770ec4008af 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -290,6 +290,68 @@ static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp) + return ret; + } + ++/* ++ * Actually change the mutex state, returning -EPERM if not the owner. ++ */ ++static int unlock_mutex_state(struct ntsync_obj *mutex, ++ const struct ntsync_mutex_args *args) ++{ ++ lockdep_assert_held(&mutex->lock); ++ ++ if (mutex->u.mutex.owner != args->owner) ++ return -EPERM; ++ ++ if (!--mutex->u.mutex.count) ++ mutex->u.mutex.owner = 0; ++ return 0; ++} ++ ++static int ntsync_mutex_unlock(struct ntsync_obj *mutex, void __user *argp) ++{ ++ struct ntsync_mutex_args __user *user_args = argp; ++ struct ntsync_device *dev = mutex->dev; ++ struct ntsync_mutex_args args; ++ __u32 prev_count; ++ int ret; ++ ++ if (copy_from_user(&args, argp, sizeof(args))) ++ return -EFAULT; ++ if (!args.owner) ++ return -EINVAL; ++ ++ if (mutex->type != NTSYNC_TYPE_MUTEX) ++ return -EINVAL; ++ ++ if (atomic_read(&mutex->all_hint) > 0) { ++ spin_lock(&dev->wait_all_lock); ++ spin_lock_nest_lock(&mutex->lock, &dev->wait_all_lock); ++ ++ prev_count = mutex->u.mutex.count; ++ ret = unlock_mutex_state(mutex, &args); ++ if (!ret) { ++ try_wake_all_obj(dev, mutex); ++ try_wake_any_mutex(mutex); ++ } ++ ++ spin_unlock(&mutex->lock); ++ spin_unlock(&dev->wait_all_lock); ++ } else { ++ spin_lock(&mutex->lock); ++ ++ prev_count = mutex->u.mutex.count; ++ ret = unlock_mutex_state(mutex, &args); ++ if (!ret) ++ try_wake_any_mutex(mutex); ++ ++ spin_unlock(&mutex->lock); ++ } ++ ++ if (!ret && put_user(prev_count, &user_args->count)) ++ ret = -EFAULT; ++ ++ return ret; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -309,6 +371,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + switch (cmd) { + case NTSYNC_IOC_SEM_POST: + return ntsync_sem_post(obj, argp); ++ case NTSYNC_IOC_MUTEX_UNLOCK: ++ return ntsync_mutex_unlock(obj, argp); + default: + return -ENOIOCTLCMD; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index d68f24fd75a2..a3f5f4f13798 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -39,5 +39,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_CREATE_MUTEX _IOWR('N', 0x84, struct ntsync_sem_args) + + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) ++#define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args) + + #endif +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0007.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0007.patch new file mode 100644 index 0000000..c49854a --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0007.patch @@ -0,0 +1,176 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 8/29] ntsync: Introduce NTSYNC_IOC_MUTEX_KILL. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:35 -0600 +Message-Id: <20240131021356.10322-9-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This does not correspond to any NT syscall. Rather, when a thread dies, it +should be called by the NT emulator for each mutex. + +NT mutexes are robust (in the pthread sense). When an NT thread dies, any +mutexes it owned are immediately released. Acquisition of those mutexes by other +threads will return a special value indicating that the mutex was abandoned, +like EOWNERDEAD returned from pthread_mutex_lock(), and EOWNERDEAD is indeed +used here for that purpose. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 71 +++++++++++++++++++++++++++++++++++-- + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 70 insertions(+), 2 deletions(-) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 1770ec4008af..aadf01c65ca0 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -37,6 +37,7 @@ struct ntsync_obj { + struct { + __u32 count; + __u32 owner; ++ bool ownerdead; + } mutex; + } u; + +@@ -89,6 +90,7 @@ struct ntsync_q { + atomic_t signaled; + + bool all; ++ bool ownerdead; + __u32 count; + struct ntsync_q_entry entries[]; + }; +@@ -164,6 +166,9 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, + obj->u.sem.count--; + break; + case NTSYNC_TYPE_MUTEX: ++ if (obj->u.mutex.ownerdead) ++ q->ownerdead = true; ++ obj->u.mutex.ownerdead = false; + obj->u.mutex.count++; + obj->u.mutex.owner = q->owner; + break; +@@ -223,6 +228,9 @@ static void try_wake_any_mutex(struct ntsync_obj *mutex) + continue; + + if (atomic_cmpxchg(&q->signaled, -1, entry->index) == -1) { ++ if (mutex->u.mutex.ownerdead) ++ q->ownerdead = true; ++ mutex->u.mutex.ownerdead = false; + mutex->u.mutex.count++; + mutex->u.mutex.owner = q->owner; + wake_up_process(q->task); +@@ -352,6 +360,62 @@ static int ntsync_mutex_unlock(struct ntsync_obj *mutex, void __user *argp) + return ret; + } + ++/* ++ * Actually change the mutex state to mark its owner as dead, ++ * returning -EPERM if not the owner. ++ */ ++static int kill_mutex_state(struct ntsync_obj *mutex, __u32 owner) ++{ ++ lockdep_assert_held(&mutex->lock); ++ ++ if (mutex->u.mutex.owner != owner) ++ return -EPERM; ++ ++ mutex->u.mutex.ownerdead = true; ++ mutex->u.mutex.owner = 0; ++ mutex->u.mutex.count = 0; ++ return 0; ++} ++ ++static int ntsync_mutex_kill(struct ntsync_obj *mutex, void __user *argp) ++{ ++ struct ntsync_device *dev = mutex->dev; ++ __u32 owner; ++ int ret; ++ ++ if (get_user(owner, (__u32 __user *)argp)) ++ return -EFAULT; ++ if (!owner) ++ return -EINVAL; ++ ++ if (mutex->type != NTSYNC_TYPE_MUTEX) ++ return -EINVAL; ++ ++ if (atomic_read(&mutex->all_hint) > 0) { ++ spin_lock(&dev->wait_all_lock); ++ spin_lock_nest_lock(&mutex->lock, &dev->wait_all_lock); ++ ++ ret = kill_mutex_state(mutex, owner); ++ if (!ret) { ++ try_wake_all_obj(dev, mutex); ++ try_wake_any_mutex(mutex); ++ } ++ ++ spin_unlock(&mutex->lock); ++ spin_unlock(&dev->wait_all_lock); ++ } else { ++ spin_lock(&mutex->lock); ++ ++ ret = kill_mutex_state(mutex, owner); ++ if (!ret) ++ try_wake_any_mutex(mutex); ++ ++ spin_unlock(&mutex->lock); ++ } ++ ++ return ret; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -373,6 +437,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + return ntsync_sem_post(obj, argp); + case NTSYNC_IOC_MUTEX_UNLOCK: + return ntsync_mutex_unlock(obj, argp); ++ case NTSYNC_IOC_MUTEX_KILL: ++ return ntsync_mutex_kill(obj, argp); + default: + return -ENOIOCTLCMD; + } +@@ -555,6 +621,7 @@ static int setup_wait(struct ntsync_device *dev, + q->owner = args->owner; + atomic_set(&q->signaled, -1); + q->all = all; ++ q->ownerdead = false; + q->count = count; + + for (i = 0; i < count; i++) { +@@ -664,7 +731,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) + struct ntsync_wait_args __user *user_args = argp; + + /* even if we caught a signal, we need to communicate success */ +- ret = 0; ++ ret = q->ownerdead ? -EOWNERDEAD : 0; + + if (put_user(signaled, &user_args->index)) + ret = -EFAULT; +@@ -747,7 +814,7 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp) + struct ntsync_wait_args __user *user_args = argp; + + /* even if we caught a signal, we need to communicate success */ +- ret = 0; ++ ret = q->ownerdead ? -EOWNERDEAD : 0; + + if (put_user(signaled, &user_args->index)) + ret = -EFAULT; +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index a3f5f4f13798..3861397c6c2f 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -40,5 +40,6 @@ struct ntsync_wait_args { + + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) + #define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args) ++#define NTSYNC_IOC_MUTEX_KILL _IOW ('N', 0x86, __u32) + + #endif +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0008.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0008.patch new file mode 100644 index 0000000..623bf23 --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0008.patch @@ -0,0 +1,175 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 9/29] ntsync: Introduce NTSYNC_IOC_CREATE_EVENT. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:36 -0600 +Message-Id: <20240131021356.10322-10-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This correspond to the NT syscall NtCreateEvent(). + +An NT event holds a single bit of state denoting whether it is signaled or +unsignaled. + +There are two types of events: manual-reset and automatic-reset. When an +automatic-reset event is acquired via a wait function, its state is reset to +unsignaled. Manual-reset events are not affected by wait functions. + +Whether the event is manual-reset, and its initial state, are specified at +creation time. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 60 +++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 7 +++++ + 2 files changed, 67 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index aadf01c65ca0..c719ddd9f6d7 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -18,6 +18,7 @@ + enum ntsync_type { + NTSYNC_TYPE_SEM, + NTSYNC_TYPE_MUTEX, ++ NTSYNC_TYPE_EVENT, + }; + + struct ntsync_obj { +@@ -39,6 +40,10 @@ struct ntsync_obj { + __u32 owner; + bool ownerdead; + } mutex; ++ struct { ++ bool manual; ++ bool signaled; ++ } event; + } u; + + /* +@@ -123,6 +128,8 @@ static bool is_signaled(struct ntsync_obj *obj, __u32 owner) + if (obj->u.mutex.owner && obj->u.mutex.owner != owner) + return false; + return obj->u.mutex.count < UINT_MAX; ++ case NTSYNC_TYPE_EVENT: ++ return obj->u.event.signaled; + } + + WARN(1, "bad object type %#x\n", obj->type); +@@ -172,6 +179,10 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, + obj->u.mutex.count++; + obj->u.mutex.owner = q->owner; + break; ++ case NTSYNC_TYPE_EVENT: ++ if (!obj->u.event.manual) ++ obj->u.event.signaled = false; ++ break; + } + } + wake_up_process(q->task); +@@ -238,6 +249,26 @@ static void try_wake_any_mutex(struct ntsync_obj *mutex) + } + } + ++static void try_wake_any_event(struct ntsync_obj *event) ++{ ++ struct ntsync_q_entry *entry; ++ ++ lockdep_assert_held(&event->lock); ++ ++ list_for_each_entry(entry, &event->any_waiters, node) { ++ struct ntsync_q *q = entry->q; ++ ++ if (!event->u.event.signaled) ++ break; ++ ++ if (atomic_cmpxchg(&q->signaled, -1, entry->index) == -1) { ++ if (!event->u.event.manual) ++ event->u.event.signaled = false; ++ wake_up_process(q->task); ++ } ++ } ++} ++ + /* + * Actually change the semaphore state, returning -EOVERFLOW if it is made + * invalid. +@@ -544,6 +575,30 @@ static int ntsync_create_mutex(struct ntsync_device *dev, void __user *argp) + return put_user(fd, &user_args->mutex); + } + ++static int ntsync_create_event(struct ntsync_device *dev, void __user *argp) ++{ ++ struct ntsync_event_args __user *user_args = argp; ++ struct ntsync_event_args args; ++ struct ntsync_obj *event; ++ int fd; ++ ++ if (copy_from_user(&args, argp, sizeof(args))) ++ return -EFAULT; ++ ++ event = ntsync_alloc_obj(dev, NTSYNC_TYPE_EVENT); ++ if (!event) ++ return -ENOMEM; ++ event->u.event.manual = args.manual; ++ event->u.event.signaled = args.signaled; ++ fd = ntsync_obj_get_fd(event); ++ if (fd < 0) { ++ kfree(event); ++ return fd; ++ } ++ ++ return put_user(fd, &user_args->event); ++} ++ + static struct ntsync_obj *get_obj(struct ntsync_device *dev, int fd) + { + struct file *file = fget(fd); +@@ -665,6 +720,9 @@ static void try_wake_any_obj(struct ntsync_obj *obj) + case NTSYNC_TYPE_MUTEX: + try_wake_any_mutex(obj); + break; ++ case NTSYNC_TYPE_EVENT: ++ try_wake_any_event(obj); ++ break; + } + } + +@@ -857,6 +915,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + void __user *argp = (void __user *)parm; + + switch (cmd) { ++ case NTSYNC_IOC_CREATE_EVENT: ++ return ntsync_create_event(dev, argp); + case NTSYNC_IOC_CREATE_MUTEX: + return ntsync_create_mutex(dev, argp); + case NTSYNC_IOC_CREATE_SEM: +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 3861397c6c2f..b8cf503365ef 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -22,6 +22,12 @@ struct ntsync_mutex_args { + __u32 count; + }; + ++struct ntsync_event_args { ++ __u32 event; ++ __u32 manual; ++ __u32 signaled; ++}; ++ + struct ntsync_wait_args { + __u64 timeout; + __u64 objs; +@@ -37,6 +43,7 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args) + #define NTSYNC_IOC_WAIT_ALL _IOWR('N', 0x83, struct ntsync_wait_args) + #define NTSYNC_IOC_CREATE_MUTEX _IOWR('N', 0x84, struct ntsync_sem_args) ++#define NTSYNC_IOC_CREATE_EVENT _IOWR('N', 0x87, struct ntsync_event_args) + + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) + #define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args) +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0009.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0009.patch new file mode 100644 index 0000000..6411060 --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0009.patch @@ -0,0 +1,88 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 10/29] ntsync: Introduce NTSYNC_IOC_EVENT_SET. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:37 -0600 +Message-Id: <20240131021356.10322-11-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This corresponds to the NT syscall NtSetEvent(). + +This sets the event to the signaled state, and returns its previous state. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 37 +++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 38 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index c719ddd9f6d7..b2da50989953 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -447,6 +447,41 @@ static int ntsync_mutex_kill(struct ntsync_obj *mutex, void __user *argp) + return ret; + } + ++static int ntsync_event_set(struct ntsync_obj *event, void __user *argp) ++{ ++ struct ntsync_device *dev = event->dev; ++ __u32 prev_state; ++ ++ if (event->type != NTSYNC_TYPE_EVENT) ++ return -EINVAL; ++ ++ if (atomic_read(&event->all_hint) > 0) { ++ spin_lock(&dev->wait_all_lock); ++ spin_lock_nest_lock(&event->lock, &dev->wait_all_lock); ++ ++ prev_state = event->u.event.signaled; ++ event->u.event.signaled = true; ++ try_wake_all_obj(dev, event); ++ try_wake_any_event(event); ++ ++ spin_unlock(&event->lock); ++ spin_unlock(&dev->wait_all_lock); ++ } else { ++ spin_lock(&event->lock); ++ ++ prev_state = event->u.event.signaled; ++ event->u.event.signaled = true; ++ try_wake_any_event(event); ++ ++ spin_unlock(&event->lock); ++ } ++ ++ if (put_user(prev_state, (__u32 __user *)argp)) ++ return -EFAULT; ++ ++ return 0; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -470,6 +505,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + return ntsync_mutex_unlock(obj, argp); + case NTSYNC_IOC_MUTEX_KILL: + return ntsync_mutex_kill(obj, argp); ++ case NTSYNC_IOC_EVENT_SET: ++ return ntsync_event_set(obj, argp); + default: + return -ENOIOCTLCMD; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index b8cf503365ef..782057552483 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -48,5 +48,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) + #define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args) + #define NTSYNC_IOC_MUTEX_KILL _IOW ('N', 0x86, __u32) ++#define NTSYNC_IOC_EVENT_SET _IOR ('N', 0x88, __u32) + + #endif +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0010.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0010.patch new file mode 100644 index 0000000..36501b9 --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0010.patch @@ -0,0 +1,73 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 11/29] ntsync: Introduce NTSYNC_IOC_EVENT_RESET. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:38 -0600 +Message-Id: <20240131021356.10322-12-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This corresponds to the NT syscall NtResetEvent(). + +This sets the event to the unsignaled state, and returns its previous state. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 22 ++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 23 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index b2da50989953..009d927739b8 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -482,6 +482,26 @@ static int ntsync_event_set(struct ntsync_obj *event, void __user *argp) + return 0; + } + ++static int ntsync_event_reset(struct ntsync_obj *event, void __user *argp) ++{ ++ __u32 prev_state; ++ ++ if (event->type != NTSYNC_TYPE_EVENT) ++ return -EINVAL; ++ ++ spin_lock(&event->lock); ++ ++ prev_state = event->u.event.signaled; ++ event->u.event.signaled = false; ++ ++ spin_unlock(&event->lock); ++ ++ if (put_user(prev_state, (__u32 __user *)argp)) ++ return -EFAULT; ++ ++ return 0; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -507,6 +527,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + return ntsync_mutex_kill(obj, argp); + case NTSYNC_IOC_EVENT_SET: + return ntsync_event_set(obj, argp); ++ case NTSYNC_IOC_EVENT_RESET: ++ return ntsync_event_reset(obj, argp); + default: + return -ENOIOCTLCMD; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 782057552483..f2d7507d8438 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -49,5 +49,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args) + #define NTSYNC_IOC_MUTEX_KILL _IOW ('N', 0x86, __u32) + #define NTSYNC_IOC_EVENT_SET _IOR ('N', 0x88, __u32) ++#define NTSYNC_IOC_EVENT_RESET _IOR ('N', 0x89, __u32) + + #endif +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0011.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0011.patch new file mode 100644 index 0000000..b02d7da --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0011.patch @@ -0,0 +1,80 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 12/29] ntsync: Introduce NTSYNC_IOC_EVENT_PULSE. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:39 -0600 +Message-Id: <20240131021356.10322-13-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This corresponds to the NT syscall NtPulseEvent(). + +This wakes up any waiters as if the event had been set, but does not set the +event, instead resetting it if it had been signalled. Thus, for a manual-reset +event, all waiters are woken, whereas for an auto-reset event, at most one +waiter is woken. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 10 ++++++++-- + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 009d927739b8..240ae858fa96 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -447,7 +447,7 @@ static int ntsync_mutex_kill(struct ntsync_obj *mutex, void __user *argp) + return ret; + } + +-static int ntsync_event_set(struct ntsync_obj *event, void __user *argp) ++static int ntsync_event_set(struct ntsync_obj *event, void __user *argp, bool pulse) + { + struct ntsync_device *dev = event->dev; + __u32 prev_state; +@@ -463,6 +463,8 @@ static int ntsync_event_set(struct ntsync_obj *event, void __user *argp) + event->u.event.signaled = true; + try_wake_all_obj(dev, event); + try_wake_any_event(event); ++ if (pulse) ++ event->u.event.signaled = false; + + spin_unlock(&event->lock); + spin_unlock(&dev->wait_all_lock); +@@ -472,6 +474,8 @@ static int ntsync_event_set(struct ntsync_obj *event, void __user *argp) + prev_state = event->u.event.signaled; + event->u.event.signaled = true; + try_wake_any_event(event); ++ if (pulse) ++ event->u.event.signaled = false; + + spin_unlock(&event->lock); + } +@@ -526,9 +530,11 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + case NTSYNC_IOC_MUTEX_KILL: + return ntsync_mutex_kill(obj, argp); + case NTSYNC_IOC_EVENT_SET: +- return ntsync_event_set(obj, argp); ++ return ntsync_event_set(obj, argp, false); + case NTSYNC_IOC_EVENT_RESET: + return ntsync_event_reset(obj, argp); ++ case NTSYNC_IOC_EVENT_PULSE: ++ return ntsync_event_set(obj, argp, true); + default: + return -ENOIOCTLCMD; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index f2d7507d8438..598f894f868d 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -50,5 +50,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_MUTEX_KILL _IOW ('N', 0x86, __u32) + #define NTSYNC_IOC_EVENT_SET _IOR ('N', 0x88, __u32) + #define NTSYNC_IOC_EVENT_RESET _IOR ('N', 0x89, __u32) ++#define NTSYNC_IOC_EVENT_PULSE _IOR ('N', 0x8a, __u32) + + #endif +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0012.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0012.patch new file mode 100644 index 0000000..e05d69c --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0012.patch @@ -0,0 +1,72 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 13/29] ntsync: Introduce NTSYNC_IOC_SEM_READ. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:40 -0600 +Message-Id: <20240131021356.10322-14-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This corresponds to the NT syscall NtQuerySemaphore(). + +This returns the current count and maximum count of the semaphore. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 21 +++++++++++++++++++++ + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 22 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 240ae858fa96..6dccfbfb2512 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -506,6 +506,25 @@ static int ntsync_event_reset(struct ntsync_obj *event, void __user *argp) + return 0; + } + ++static int ntsync_sem_read(struct ntsync_obj *sem, void __user *argp) ++{ ++ struct ntsync_sem_args __user *user_args = argp; ++ struct ntsync_sem_args args; ++ ++ if (sem->type != NTSYNC_TYPE_SEM) ++ return -EINVAL; ++ ++ args.sem = 0; ++ spin_lock(&sem->lock); ++ args.count = sem->u.sem.count; ++ args.max = sem->u.sem.max; ++ spin_unlock(&sem->lock); ++ ++ if (copy_to_user(user_args, &args, sizeof(args))) ++ return -EFAULT; ++ return 0; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -525,6 +544,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + switch (cmd) { + case NTSYNC_IOC_SEM_POST: + return ntsync_sem_post(obj, argp); ++ case NTSYNC_IOC_SEM_READ: ++ return ntsync_sem_read(obj, argp); + case NTSYNC_IOC_MUTEX_UNLOCK: + return ntsync_mutex_unlock(obj, argp); + case NTSYNC_IOC_MUTEX_KILL: +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 598f894f868d..6017f621687e 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -51,5 +51,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_EVENT_SET _IOR ('N', 0x88, __u32) + #define NTSYNC_IOC_EVENT_RESET _IOR ('N', 0x89, __u32) + #define NTSYNC_IOC_EVENT_PULSE _IOR ('N', 0x8a, __u32) ++#define NTSYNC_IOC_SEM_READ _IOR ('N', 0x8b, struct ntsync_sem_args) + + #endif +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0013.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0013.patch new file mode 100644 index 0000000..4a4b6a6 --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0013.patch @@ -0,0 +1,74 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 14/29] ntsync: Introduce NTSYNC_IOC_MUTEX_READ. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:41 -0600 +Message-Id: <20240131021356.10322-15-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This corresponds to the NT syscall NtQueryMutant(). + +This returns the recursion count, owner, and abandoned state of the mutex. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 23 +++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 24 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 6dccfbfb2512..7f5f96ec7c69 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -525,6 +525,27 @@ static int ntsync_sem_read(struct ntsync_obj *sem, void __user *argp) + return 0; + } + ++static int ntsync_mutex_read(struct ntsync_obj *mutex, void __user *argp) ++{ ++ struct ntsync_mutex_args __user *user_args = argp; ++ struct ntsync_mutex_args args; ++ int ret; ++ ++ if (mutex->type != NTSYNC_TYPE_MUTEX) ++ return -EINVAL; ++ ++ args.mutex = 0; ++ spin_lock(&mutex->lock); ++ args.count = mutex->u.mutex.count; ++ args.owner = mutex->u.mutex.owner; ++ ret = mutex->u.mutex.ownerdead ? -EOWNERDEAD : 0; ++ spin_unlock(&mutex->lock); ++ ++ if (copy_to_user(user_args, &args, sizeof(args))) ++ return -EFAULT; ++ return ret; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -550,6 +571,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + return ntsync_mutex_unlock(obj, argp); + case NTSYNC_IOC_MUTEX_KILL: + return ntsync_mutex_kill(obj, argp); ++ case NTSYNC_IOC_MUTEX_READ: ++ return ntsync_mutex_read(obj, argp); + case NTSYNC_IOC_EVENT_SET: + return ntsync_event_set(obj, argp, false); + case NTSYNC_IOC_EVENT_RESET: +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 6017f621687e..a1d0ef581212 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -52,5 +52,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_EVENT_RESET _IOR ('N', 0x89, __u32) + #define NTSYNC_IOC_EVENT_PULSE _IOR ('N', 0x8a, __u32) + #define NTSYNC_IOC_SEM_READ _IOR ('N', 0x8b, struct ntsync_sem_args) ++#define NTSYNC_IOC_MUTEX_READ _IOR ('N', 0x8c, struct ntsync_mutex_args) + + #endif +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0014.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0014.patch new file mode 100644 index 0000000..ff7ac42 --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0014.patch @@ -0,0 +1,72 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 15/29] ntsync: Introduce NTSYNC_IOC_EVENT_READ. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:42 -0600 +Message-Id: <20240131021356.10322-16-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This corresponds to the NT syscall NtQueryEvent(). + +This returns the signaled state of the event and whether it is manual-reset. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 21 +++++++++++++++++++++ + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 22 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 7f5f96ec7c69..5439c1c9e90f 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -546,6 +546,25 @@ static int ntsync_mutex_read(struct ntsync_obj *mutex, void __user *argp) + return ret; + } + ++static int ntsync_event_read(struct ntsync_obj *event, void __user *argp) ++{ ++ struct ntsync_event_args __user *user_args = argp; ++ struct ntsync_event_args args; ++ ++ if (event->type != NTSYNC_TYPE_EVENT) ++ return -EINVAL; ++ ++ args.event = 0; ++ spin_lock(&event->lock); ++ args.manual = event->u.event.manual; ++ args.signaled = event->u.event.signaled; ++ spin_unlock(&event->lock); ++ ++ if (copy_to_user(user_args, &args, sizeof(args))) ++ return -EFAULT; ++ return 0; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -579,6 +598,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + return ntsync_event_reset(obj, argp); + case NTSYNC_IOC_EVENT_PULSE: + return ntsync_event_set(obj, argp, true); ++ case NTSYNC_IOC_EVENT_READ: ++ return ntsync_event_read(obj, argp); + default: + return -ENOIOCTLCMD; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index a1d0ef581212..582d33b0dcac 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -53,5 +53,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_EVENT_PULSE _IOR ('N', 0x8a, __u32) + #define NTSYNC_IOC_SEM_READ _IOR ('N', 0x8b, struct ntsync_sem_args) + #define NTSYNC_IOC_MUTEX_READ _IOR ('N', 0x8c, struct ntsync_mutex_args) ++#define NTSYNC_IOC_EVENT_READ _IOR ('N', 0x8d, struct ntsync_event_args) + + #endif +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0015.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0015.patch new file mode 100644 index 0000000..9a3a0c9 --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0015.patch @@ -0,0 +1,194 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 16/29] ntsync: Introduce alertable waits. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:43 -0600 +Message-Id: <20240131021356.10322-17-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +NT waits can optionally be made "alertable". This is a special channel for +thread wakeup that is mildly similar to SIGIO. A thread has an internal single +bit of "alerted" state, and if a thread is made alerted while an alertable wait, +the wait will return a special value, consume the "alerted" state, and will not +consume any of its objects. + +Alerts are implemented using events; the user-space NT emulator is expected to +create an internal ntsync event for each thread and pass that event to wait +functions. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 68 ++++++++++++++++++++++++++++++++----- + include/uapi/linux/ntsync.h | 2 +- + 2 files changed, 60 insertions(+), 10 deletions(-) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 5439c1c9e90f..1e619e1ce6a6 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -784,22 +784,29 @@ static int setup_wait(struct ntsync_device *dev, + const struct ntsync_wait_args *args, bool all, + struct ntsync_q **ret_q) + { ++ int fds[NTSYNC_MAX_WAIT_COUNT + 1]; + const __u32 count = args->count; +- int fds[NTSYNC_MAX_WAIT_COUNT]; + struct ntsync_q *q; ++ __u32 total_count; + __u32 i, j; + +- if (!args->owner || args->pad) ++ if (!args->owner) + return -EINVAL; + + if (args->count > NTSYNC_MAX_WAIT_COUNT) + return -EINVAL; + ++ total_count = count; ++ if (args->alert) ++ total_count++; ++ + if (copy_from_user(fds, u64_to_user_ptr(args->objs), + array_size(count, sizeof(*fds)))) + return -EFAULT; ++ if (args->alert) ++ fds[count] = args->alert; + +- q = kmalloc(struct_size(q, entries, count), GFP_KERNEL); ++ q = kmalloc(struct_size(q, entries, total_count), GFP_KERNEL); + if (!q) + return -ENOMEM; + q->task = current; +@@ -809,7 +816,7 @@ static int setup_wait(struct ntsync_device *dev, + q->ownerdead = false; + q->count = count; + +- for (i = 0; i < count; i++) { ++ for (i = 0; i < total_count; i++) { + struct ntsync_q_entry *entry = &q->entries[i]; + struct ntsync_obj *obj = get_obj(dev, fds[i]); + +@@ -860,9 +867,9 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) + { + struct ntsync_wait_args args; + struct ntsync_q *q; ++ __u32 i, total_count; + ktime_t timeout; + int signaled; +- __u32 i; + int ret; + + if (copy_from_user(&args, argp, sizeof(args))) +@@ -872,9 +879,13 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) + if (ret < 0) + return ret; + ++ total_count = args.count; ++ if (args.alert) ++ total_count++; ++ + /* queue ourselves */ + +- for (i = 0; i < args.count; i++) { ++ for (i = 0; i < total_count; i++) { + struct ntsync_q_entry *entry = &q->entries[i]; + struct ntsync_obj *obj = entry->obj; + +@@ -883,9 +894,15 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) + spin_unlock(&obj->lock); + } + +- /* check if we are already signaled */ ++ /* ++ * Check if we are already signaled. ++ * ++ * Note that the API requires that normal objects are checked before ++ * the alert event. Hence we queue the alert event last, and check ++ * objects in order. ++ */ + +- for (i = 0; i < args.count; i++) { ++ for (i = 0; i < total_count; i++) { + struct ntsync_obj *obj = q->entries[i].obj; + + if (atomic_read(&q->signaled) != -1) +@@ -903,7 +920,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) + + /* and finally, unqueue */ + +- for (i = 0; i < args.count; i++) { ++ for (i = 0; i < total_count; i++) { + struct ntsync_q_entry *entry = &q->entries[i]; + struct ntsync_obj *obj = entry->obj; + +@@ -964,6 +981,14 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp) + */ + list_add_tail(&entry->node, &obj->all_waiters); + } ++ if (args.alert) { ++ struct ntsync_q_entry *entry = &q->entries[args.count]; ++ struct ntsync_obj *obj = entry->obj; ++ ++ spin_lock_nest_lock(&obj->lock, &dev->wait_all_lock); ++ list_add_tail(&entry->node, &obj->any_waiters); ++ spin_unlock(&obj->lock); ++ } + + /* check if we are already signaled */ + +@@ -971,6 +996,21 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp) + + spin_unlock(&dev->wait_all_lock); + ++ /* ++ * Check if the alert event is signaled, making sure to do so only ++ * after checking if the other objects are signaled. ++ */ ++ ++ if (args.alert) { ++ struct ntsync_obj *obj = q->entries[args.count].obj; ++ ++ if (atomic_read(&q->signaled) == -1) { ++ spin_lock(&obj->lock); ++ try_wake_any_obj(obj); ++ spin_unlock(&obj->lock); ++ } ++ } ++ + /* sleep */ + + timeout = ns_to_ktime(args.timeout); +@@ -994,6 +1034,16 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp) + + put_obj(obj); + } ++ if (args.alert) { ++ struct ntsync_q_entry *entry = &q->entries[args.count]; ++ struct ntsync_obj *obj = entry->obj; ++ ++ spin_lock_nest_lock(&obj->lock, &dev->wait_all_lock); ++ list_del(&entry->node); ++ spin_unlock(&obj->lock); ++ ++ put_obj(obj); ++ } + + spin_unlock(&dev->wait_all_lock); + +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 582d33b0dcac..7c91af7011e4 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -34,7 +34,7 @@ struct ntsync_wait_args { + __u32 count; + __u32 owner; + __u32 index; +- __u32 pad; ++ __u32 alert; + }; + + #define NTSYNC_MAX_WAIT_COUNT 64 +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0016.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0016.patch new file mode 100644 index 0000000..cc3864a --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0016.patch @@ -0,0 +1,213 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 17/29] selftests: ntsync: Add some tests for + semaphore state. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:44 -0600 +Message-Id: <20240131021356.10322-18-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Wine has tests for its synchronization primitives, but these are more accessible +to kernel developers, and also allow us to test some edge cases that Wine does +not care about. + +This patch adds tests for semaphore-specific ioctls NTSYNC_IOC_SEM_POST and +NTSYNC_IOC_SEM_READ, and waiting on semaphores. + +Signed-off-by: Elizabeth Figura +--- + tools/testing/selftests/Makefile | 1 + + .../testing/selftests/drivers/ntsync/Makefile | 8 + + tools/testing/selftests/drivers/ntsync/config | 1 + + .../testing/selftests/drivers/ntsync/ntsync.c | 143 ++++++++++++++++++ + 4 files changed, 153 insertions(+) + create mode 100644 tools/testing/selftests/drivers/ntsync/Makefile + create mode 100644 tools/testing/selftests/drivers/ntsync/config + create mode 100644 tools/testing/selftests/drivers/ntsync/ntsync.c + +diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile +index 15b6a111c3be..6c714a4e6478 100644 +--- a/tools/testing/selftests/Makefile ++++ b/tools/testing/selftests/Makefile +@@ -15,6 +15,7 @@ TARGETS += cpu-hotplug + TARGETS += damon + TARGETS += dmabuf-heaps + TARGETS += drivers/dma-buf ++TARGETS += drivers/ntsync + TARGETS += drivers/s390x/uvdevice + TARGETS += drivers/net/bonding + TARGETS += drivers/net/team +diff --git a/tools/testing/selftests/drivers/ntsync/Makefile b/tools/testing/selftests/drivers/ntsync/Makefile +new file mode 100644 +index 000000000000..a34da5ccacf0 +--- /dev/null ++++ b/tools/testing/selftests/drivers/ntsync/Makefile +@@ -0,0 +1,8 @@ ++# SPDX-LICENSE-IDENTIFIER: GPL-2.0-only ++TEST_GEN_PROGS := ntsync ++ ++top_srcdir =../../../../.. ++CFLAGS += -I$(top_srcdir)/usr/include ++LDLIBS += -lpthread ++ ++include ../../lib.mk +diff --git a/tools/testing/selftests/drivers/ntsync/config b/tools/testing/selftests/drivers/ntsync/config +new file mode 100644 +index 000000000000..60539c826d06 +--- /dev/null ++++ b/tools/testing/selftests/drivers/ntsync/config +@@ -0,0 +1 @@ ++CONFIG_WINESYNC=y +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +new file mode 100644 +index 000000000000..6ceb48fb42e3 +--- /dev/null ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -0,0 +1,143 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Various unit tests for the "ntsync" synchronization primitive driver. ++ * ++ * Copyright (C) 2021-2022 Elizabeth Figura ++ */ ++ ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../../kselftest_harness.h" ++ ++static int read_sem_state(int sem, __u32 *count, __u32 *max) ++{ ++ struct ntsync_sem_args args; ++ int ret; ++ ++ memset(&args, 0xcc, sizeof(args)); ++ ret = ioctl(sem, NTSYNC_IOC_SEM_READ, &args); ++ *count = args.count; ++ *max = args.max; ++ return ret; ++} ++ ++#define check_sem_state(sem, count, max) \ ++ ({ \ ++ __u32 __count, __max; \ ++ int ret = read_sem_state((sem), &__count, &__max); \ ++ EXPECT_EQ(0, ret); \ ++ EXPECT_EQ((count), __count); \ ++ EXPECT_EQ((max), __max); \ ++ }) ++ ++static int post_sem(int sem, __u32 *count) ++{ ++ return ioctl(sem, NTSYNC_IOC_SEM_POST, count); ++} ++ ++static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) ++{ ++ struct ntsync_wait_args args = {0}; ++ struct timespec timeout; ++ int ret; ++ ++ clock_gettime(CLOCK_MONOTONIC, &timeout); ++ ++ args.timeout = timeout.tv_sec * 1000000000 + timeout.tv_nsec; ++ args.count = count; ++ args.objs = (uintptr_t)objs; ++ args.owner = owner; ++ args.index = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_WAIT_ANY, &args); ++ *index = args.index; ++ return ret; ++} ++ ++TEST(semaphore_state) ++{ ++ struct ntsync_sem_args sem_args; ++ struct timespec timeout; ++ __u32 count, index; ++ int fd, ret, sem; ++ ++ clock_gettime(CLOCK_MONOTONIC, &timeout); ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 3; ++ sem_args.max = 2; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ sem_args.count = 2; ++ sem_args.max = 2; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ sem = sem_args.sem; ++ check_sem_state(sem, 2, 2); ++ ++ count = 0; ++ ret = post_sem(sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, count); ++ check_sem_state(sem, 2, 2); ++ ++ count = 1; ++ ret = post_sem(sem, &count); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOVERFLOW, errno); ++ check_sem_state(sem, 2, 2); ++ ++ ret = wait_any(fd, 1, &sem, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem, 1, 2); ++ ++ ret = wait_any(fd, 1, &sem, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem, 0, 2); ++ ++ ret = wait_any(fd, 1, &sem, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ count = 3; ++ ret = post_sem(sem, &count); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOVERFLOW, errno); ++ check_sem_state(sem, 0, 2); ++ ++ count = 2; ++ ret = post_sem(sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ check_sem_state(sem, 2, 2); ++ ++ ret = wait_any(fd, 1, &sem, 123, &index); ++ EXPECT_EQ(0, ret); ++ ret = wait_any(fd, 1, &sem, 123, &index); ++ EXPECT_EQ(0, ret); ++ ++ count = 1; ++ ret = post_sem(sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ check_sem_state(sem, 1, 2); ++ ++ close(sem); ++ ++ close(fd); ++} ++ ++TEST_HARNESS_MAIN +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0017.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0017.patch new file mode 100644 index 0000000..35a182e --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0017.patch @@ -0,0 +1,218 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 18/29] selftests: ntsync: Add some tests for mutex + state. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:45 -0600 +Message-Id: <20240131021356.10322-19-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Test mutex-specific ioctls NTSYNC_IOC_MUTEX_UNLOCK and NTSYNC_IOC_MUTEX_READ, +and waiting on mutexes. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 181 ++++++++++++++++++ + 1 file changed, 181 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 6ceb48fb42e3..80c8bd409d68 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -40,6 +40,39 @@ static int post_sem(int sem, __u32 *count) + return ioctl(sem, NTSYNC_IOC_SEM_POST, count); + } + ++static int read_mutex_state(int mutex, __u32 *count, __u32 *owner) ++{ ++ struct ntsync_mutex_args args; ++ int ret; ++ ++ memset(&args, 0xcc, sizeof(args)); ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &args); ++ *count = args.count; ++ *owner = args.owner; ++ return ret; ++} ++ ++#define check_mutex_state(mutex, count, owner) \ ++ ({ \ ++ __u32 __count, __owner; \ ++ int ret = read_mutex_state((mutex), &__count, &__owner); \ ++ EXPECT_EQ(0, ret); \ ++ EXPECT_EQ((count), __count); \ ++ EXPECT_EQ((owner), __owner); \ ++ }) ++ ++static int unlock_mutex(int mutex, __u32 owner, __u32 *count) ++{ ++ struct ntsync_mutex_args args; ++ int ret; ++ ++ args.owner = owner; ++ args.count = 0xdeadbeef; ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_UNLOCK, &args); ++ *count = args.count; ++ return ret; ++} ++ + static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) + { + struct ntsync_wait_args args = {0}; +@@ -140,4 +173,152 @@ TEST(semaphore_state) + close(fd); + } + ++TEST(mutex_state) ++{ ++ struct ntsync_mutex_args mutex_args; ++ __u32 owner, count, index; ++ struct timespec timeout; ++ int fd, ret, mutex; ++ ++ clock_gettime(CLOCK_MONOTONIC, &timeout); ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ mutex_args.owner = 123; ++ mutex_args.count = 0; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ mutex_args.owner = 0; ++ mutex_args.count = 2; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ mutex_args.owner = 123; ++ mutex_args.count = 2; ++ mutex_args.mutex = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, mutex_args.mutex); ++ mutex = mutex_args.mutex; ++ check_mutex_state(mutex, 2, 123); ++ ++ ret = unlock_mutex(mutex, 0, &count); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ ret = unlock_mutex(mutex, 456, &count); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EPERM, errno); ++ check_mutex_state(mutex, 2, 123); ++ ++ ret = unlock_mutex(mutex, 123, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, count); ++ check_mutex_state(mutex, 1, 123); ++ ++ ret = unlock_mutex(mutex, 123, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, count); ++ check_mutex_state(mutex, 0, 0); ++ ++ ret = unlock_mutex(mutex, 123, &count); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EPERM, errno); ++ ++ ret = wait_any(fd, 1, &mutex, 456, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_mutex_state(mutex, 1, 456); ++ ++ ret = wait_any(fd, 1, &mutex, 456, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_mutex_state(mutex, 2, 456); ++ ++ ret = unlock_mutex(mutex, 456, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, count); ++ check_mutex_state(mutex, 1, 456); ++ ++ ret = wait_any(fd, 1, &mutex, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ owner = 0; ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ owner = 123; ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EPERM, errno); ++ check_mutex_state(mutex, 1, 456); ++ ++ owner = 456; ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); ++ EXPECT_EQ(0, ret); ++ ++ memset(&mutex_args, 0xcc, sizeof(mutex_args)); ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ EXPECT_EQ(0, mutex_args.count); ++ EXPECT_EQ(0, mutex_args.owner); ++ ++ memset(&mutex_args, 0xcc, sizeof(mutex_args)); ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ EXPECT_EQ(0, mutex_args.count); ++ EXPECT_EQ(0, mutex_args.owner); ++ ++ ret = wait_any(fd, 1, &mutex, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ EXPECT_EQ(0, index); ++ check_mutex_state(mutex, 1, 123); ++ ++ owner = 123; ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); ++ EXPECT_EQ(0, ret); ++ ++ memset(&mutex_args, 0xcc, sizeof(mutex_args)); ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ EXPECT_EQ(0, mutex_args.count); ++ EXPECT_EQ(0, mutex_args.owner); ++ ++ ret = wait_any(fd, 1, &mutex, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ EXPECT_EQ(0, index); ++ check_mutex_state(mutex, 1, 123); ++ ++ close(mutex); ++ ++ mutex_args.owner = 0; ++ mutex_args.count = 0; ++ mutex_args.mutex = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, mutex_args.mutex); ++ mutex = mutex_args.mutex; ++ check_mutex_state(mutex, 0, 0); ++ ++ ret = wait_any(fd, 1, &mutex, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_mutex_state(mutex, 1, 123); ++ ++ close(mutex); ++ ++ close(fd); ++} ++ + TEST_HARNESS_MAIN +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0018.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0018.patch new file mode 100644 index 0000000..d82f310 --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0018.patch @@ -0,0 +1,136 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 19/29] selftests: ntsync: Add some tests for + NTSYNC_IOC_WAIT_ANY. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:46 -0600 +Message-Id: <20240131021356.10322-20-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Test basic synchronous functionality of NTSYNC_IOC_WAIT_ANY, when objects are +considered signaled or not signaled, and how they are affected by a successful +wait. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 105 ++++++++++++++++++ + 1 file changed, 105 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 80c8bd409d68..13e7c9d7441e 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -321,4 +321,109 @@ TEST(mutex_state) + close(fd); + } + ++TEST(test_wait_any) ++{ ++ struct ntsync_mutex_args mutex_args = {0}; ++ struct ntsync_wait_args wait_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; ++ __u32 owner, index, count; ++ struct timespec timeout; ++ int objs[2], fd, ret; ++ ++ clock_gettime(CLOCK_MONOTONIC, &timeout); ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 2; ++ sem_args.max = 3; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ ++ mutex_args.owner = 0; ++ mutex_args.count = 0; ++ mutex_args.mutex = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, mutex_args.mutex); ++ ++ objs[0] = sem_args.sem; ++ objs[1] = mutex_args.mutex; ++ ++ ret = wait_any(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 1, 3); ++ check_mutex_state(mutex_args.mutex, 0, 0); ++ ++ ret = wait_any(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_mutex_state(mutex_args.mutex, 0, 0); ++ ++ ret = wait_any(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, index); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_mutex_state(mutex_args.mutex, 1, 123); ++ ++ count = 1; ++ ret = post_sem(sem_args.sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ ++ ret = wait_any(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_mutex_state(mutex_args.mutex, 1, 123); ++ ++ ret = wait_any(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, index); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_mutex_state(mutex_args.mutex, 2, 123); ++ ++ ret = wait_any(fd, 2, objs, 456, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ owner = 123; ++ ret = ioctl(mutex_args.mutex, NTSYNC_IOC_MUTEX_KILL, &owner); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_any(fd, 2, objs, 456, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ EXPECT_EQ(1, index); ++ ++ ret = wait_any(fd, 2, objs, 456, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, index); ++ ++ /* test waiting on the same object twice */ ++ count = 2; ++ ret = post_sem(sem_args.sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ ++ objs[0] = objs[1] = sem_args.sem; ++ ret = wait_any(fd, 2, objs, 456, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, wait_args.index); ++ check_sem_state(sem_args.sem, 1, 3); ++ ++ ret = wait_any(fd, 0, NULL, 456, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ close(sem_args.sem); ++ close(mutex_args.mutex); ++ ++ close(fd); ++} ++ + TEST_HARNESS_MAIN +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0019.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0019.patch new file mode 100644 index 0000000..ec7fb58 --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0019.patch @@ -0,0 +1,147 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 20/29] selftests: ntsync: Add some tests for + NTSYNC_IOC_WAIT_ALL. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:47 -0600 +Message-Id: <20240131021356.10322-21-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Test basic synchronous functionality of NTSYNC_IOC_WAIT_ALL, and when objects +are considered simultaneously signaled. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 99 ++++++++++++++++++- + 1 file changed, 97 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 13e7c9d7441e..77f1b7e42d76 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -73,7 +73,8 @@ static int unlock_mutex(int mutex, __u32 owner, __u32 *count) + return ret; + } + +-static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) ++static int wait_objs(int fd, unsigned long request, __u32 count, ++ const int *objs, __u32 owner, __u32 *index) + { + struct ntsync_wait_args args = {0}; + struct timespec timeout; +@@ -86,11 +87,21 @@ static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *in + args.objs = (uintptr_t)objs; + args.owner = owner; + args.index = 0xdeadbeef; +- ret = ioctl(fd, NTSYNC_IOC_WAIT_ANY, &args); ++ ret = ioctl(fd, request, &args); + *index = args.index; + return ret; + } + ++static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) ++{ ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, count, objs, owner, index); ++} ++ ++static int wait_all(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) ++{ ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, count, objs, owner, index); ++} ++ + TEST(semaphore_state) + { + struct ntsync_sem_args sem_args; +@@ -426,4 +437,88 @@ TEST(test_wait_any) + close(fd); + } + ++TEST(test_wait_all) ++{ ++ struct ntsync_mutex_args mutex_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; ++ __u32 owner, index, count; ++ int objs[2], fd, ret; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 2; ++ sem_args.max = 3; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ ++ mutex_args.owner = 0; ++ mutex_args.count = 0; ++ mutex_args.mutex = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, mutex_args.mutex); ++ ++ objs[0] = sem_args.sem; ++ objs[1] = mutex_args.mutex; ++ ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 1, 3); ++ check_mutex_state(mutex_args.mutex, 1, 123); ++ ++ ret = wait_all(fd, 2, objs, 456, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ check_sem_state(sem_args.sem, 1, 3); ++ check_mutex_state(mutex_args.mutex, 1, 123); ++ ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_mutex_state(mutex_args.mutex, 2, 123); ++ ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_mutex_state(mutex_args.mutex, 2, 123); ++ ++ count = 3; ++ ret = post_sem(sem_args.sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 2, 3); ++ check_mutex_state(mutex_args.mutex, 3, 123); ++ ++ owner = 123; ++ ret = ioctl(mutex_args.mutex, NTSYNC_IOC_MUTEX_KILL, &owner); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ check_sem_state(sem_args.sem, 1, 3); ++ check_mutex_state(mutex_args.mutex, 1, 123); ++ ++ /* test waiting on the same object twice */ ++ objs[0] = objs[1] = sem_args.sem; ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ close(sem_args.sem); ++ close(mutex_args.mutex); ++ ++ close(fd); ++} ++ + TEST_HARNESS_MAIN +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0020.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0020.patch new file mode 100644 index 0000000..3d9e0d2 --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0020.patch @@ -0,0 +1,182 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 21/29] selftests: ntsync: Add some tests for wakeup + signaling with WINESYNC_IOC_WAIT_ANY. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:48 -0600 +Message-Id: <20240131021356.10322-22-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Test contended "wait-for-any" waits, to make sure that scheduling and wakeup +logic works correctly. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 152 ++++++++++++++++++ + 1 file changed, 152 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 77f1b7e42d76..96a866ef235f 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -521,4 +521,156 @@ TEST(test_wait_all) + close(fd); + } + ++struct wake_args ++{ ++ int fd; ++ int obj; ++}; ++ ++struct wait_args ++{ ++ int fd; ++ unsigned long request; ++ struct ntsync_wait_args *args; ++ int ret; ++ int err; ++}; ++ ++static void *wait_thread(void *arg) ++{ ++ struct wait_args *args = arg; ++ ++ args->ret = ioctl(args->fd, args->request, args->args); ++ args->err = errno; ++ return NULL; ++} ++ ++static __u64 get_abs_timeout(unsigned int ms) ++{ ++ struct timespec timeout; ++ clock_gettime(CLOCK_MONOTONIC, &timeout); ++ return (timeout.tv_sec * 1000000000) + timeout.tv_nsec + (ms * 1000000); ++} ++ ++static int wait_for_thread(pthread_t thread, unsigned int ms) ++{ ++ struct timespec timeout; ++ ++ clock_gettime(CLOCK_REALTIME, &timeout); ++ timeout.tv_nsec += ms * 1000000; ++ timeout.tv_sec += (timeout.tv_nsec / 1000000000); ++ timeout.tv_nsec %= 1000000000; ++ return pthread_timedjoin_np(thread, NULL, &timeout); ++} ++ ++TEST(wake_any) ++{ ++ struct ntsync_mutex_args mutex_args = {0}; ++ struct ntsync_wait_args wait_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; ++ struct wait_args thread_args; ++ int objs[2], fd, ret; ++ __u32 count, index; ++ pthread_t thread; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 0; ++ sem_args.max = 3; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ ++ mutex_args.owner = 123; ++ mutex_args.count = 1; ++ mutex_args.mutex = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, mutex_args.mutex); ++ ++ objs[0] = sem_args.sem; ++ objs[1] = mutex_args.mutex; ++ ++ /* test waking the semaphore */ ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ wait_args.objs = (uintptr_t)objs; ++ wait_args.count = 2; ++ wait_args.owner = 456; ++ wait_args.index = 0xdeadbeef; ++ thread_args.fd = fd; ++ thread_args.args = &wait_args; ++ thread_args.request = NTSYNC_IOC_WAIT_ANY; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ count = 1; ++ ret = post_sem(sem_args.sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ check_sem_state(sem_args.sem, 0, 3); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(0, wait_args.index); ++ ++ /* test waking the mutex */ ++ ++ /* first grab it again for owner 123 */ ++ ret = wait_any(fd, 1, &mutex_args.mutex, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ wait_args.owner = 456; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = unlock_mutex(mutex_args.mutex, 123, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, count); ++ ++ ret = pthread_tryjoin_np(thread, NULL); ++ EXPECT_EQ(EBUSY, ret); ++ ++ ret = unlock_mutex(mutex_args.mutex, 123, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, mutex_args.count); ++ check_mutex_state(mutex_args.mutex, 1, 456); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(1, wait_args.index); ++ ++ /* delete an object while it's being waited on */ ++ ++ wait_args.timeout = get_abs_timeout(200); ++ wait_args.owner = 123; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ close(sem_args.sem); ++ close(mutex_args.mutex); ++ ++ ret = wait_for_thread(thread, 200); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(-1, thread_args.ret); ++ EXPECT_EQ(ETIMEDOUT, thread_args.err); ++ ++ close(fd); ++} ++ + TEST_HARNESS_MAIN +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0021.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0021.patch new file mode 100644 index 0000000..522d6a6 --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0021.patch @@ -0,0 +1,129 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 22/29] selftests: ntsync: Add some tests for wakeup + signaling with WINESYNC_IOC_WAIT_ALL. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:49 -0600 +Message-Id: <20240131021356.10322-23-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Test contended "wait-for-all" waits, to make sure that scheduling and wakeup +logic works correctly, and that the wait only exits once objects are all +simultaneously signaled. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 98 +++++++++++++++++++ + 1 file changed, 98 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 96a866ef235f..7776fe71b8ef 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -673,4 +673,102 @@ TEST(wake_any) + close(fd); + } + ++TEST(wake_all) ++{ ++ struct ntsync_mutex_args mutex_args = {0}; ++ struct ntsync_wait_args wait_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; ++ struct wait_args thread_args; ++ int objs[2], fd, ret; ++ __u32 count, index; ++ pthread_t thread; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 0; ++ sem_args.max = 3; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ ++ mutex_args.owner = 123; ++ mutex_args.count = 1; ++ mutex_args.mutex = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, mutex_args.mutex); ++ ++ objs[0] = sem_args.sem; ++ objs[1] = mutex_args.mutex; ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ wait_args.objs = (uintptr_t)objs; ++ wait_args.count = 2; ++ wait_args.owner = 456; ++ thread_args.fd = fd; ++ thread_args.args = &wait_args; ++ thread_args.request = NTSYNC_IOC_WAIT_ALL; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ count = 1; ++ ret = post_sem(sem_args.sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ ++ ret = pthread_tryjoin_np(thread, NULL); ++ EXPECT_EQ(EBUSY, ret); ++ ++ check_sem_state(sem_args.sem, 1, 3); ++ ++ ret = wait_any(fd, 1, &sem_args.sem, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ ++ ret = unlock_mutex(mutex_args.mutex, 123, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, count); ++ ++ ret = pthread_tryjoin_np(thread, NULL); ++ EXPECT_EQ(EBUSY, ret); ++ ++ check_mutex_state(mutex_args.mutex, 0, 0); ++ ++ count = 2; ++ ret = post_sem(sem_args.sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ check_sem_state(sem_args.sem, 1, 3); ++ check_mutex_state(mutex_args.mutex, 1, 456); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ ++ /* delete an object while it's being waited on */ ++ ++ wait_args.timeout = get_abs_timeout(200); ++ wait_args.owner = 123; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ close(sem_args.sem); ++ close(mutex_args.mutex); ++ ++ ret = wait_for_thread(thread, 200); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(-1, thread_args.ret); ++ EXPECT_EQ(ETIMEDOUT, thread_args.err); ++ ++ close(fd); ++} ++ + TEST_HARNESS_MAIN +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0022.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0022.patch new file mode 100644 index 0000000..1d3a60d --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0022.patch @@ -0,0 +1,129 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 23/29] selftests: ntsync: Add some tests for + manual-reset event state. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:50 -0600 +Message-Id: <20240131021356.10322-24-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Test event-specific ioctls NTSYNC_IOC_EVENT_SET, NTSYNC_IOC_EVENT_RESET, +NTSYNC_IOC_EVENT_PULSE, NTSYNC_IOC_EVENT_READ for manual-reset events, and +waiting on manual-reset events. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 89 +++++++++++++++++++ + 1 file changed, 89 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 7776fe71b8ef..98fc70a9a58b 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -73,6 +73,27 @@ static int unlock_mutex(int mutex, __u32 owner, __u32 *count) + return ret; + } + ++static int read_event_state(int event, __u32 *signaled, __u32 *manual) ++{ ++ struct ntsync_event_args args; ++ int ret; ++ ++ memset(&args, 0xcc, sizeof(args)); ++ ret = ioctl(event, NTSYNC_IOC_EVENT_READ, &args); ++ *signaled = args.signaled; ++ *manual = args.manual; ++ return ret; ++} ++ ++#define check_event_state(event, signaled, manual) \ ++ ({ \ ++ __u32 __signaled, __manual; \ ++ int ret = read_event_state((event), &__signaled, &__manual); \ ++ EXPECT_EQ(0, ret); \ ++ EXPECT_EQ((signaled), __signaled); \ ++ EXPECT_EQ((manual), __manual); \ ++ }) ++ + static int wait_objs(int fd, unsigned long request, __u32 count, + const int *objs, __u32 owner, __u32 *index) + { +@@ -332,6 +353,74 @@ TEST(mutex_state) + close(fd); + } + ++TEST(manual_event_state) ++{ ++ struct ntsync_event_args event_args; ++ __u32 index, signaled; ++ int fd, event, ret; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ event_args.manual = 1; ++ event_args.signaled = 0; ++ event_args.event = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, event_args.event); ++ event = event_args.event; ++ check_event_state(event, 0, 1); ++ ++ signaled = 0xdeadbeef; ++ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event, 1, 1); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ check_event_state(event, 1, 1); ++ ++ ret = wait_any(fd, 1, &event, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_event_state(event, 1, 1); ++ ++ signaled = 0xdeadbeef; ++ ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ check_event_state(event, 0, 1); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event, 0, 1); ++ ++ ret = wait_any(fd, 1, &event, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ check_event_state(event, 0, 1); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event, 0, 1); ++ ++ close(event); ++ ++ close(fd); ++} ++ + TEST(test_wait_any) + { + struct ntsync_mutex_args mutex_args = {0}; +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0023.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0023.patch new file mode 100644 index 0000000..f34c5e4 --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0023.patch @@ -0,0 +1,92 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 24/29] selftests: ntsync: Add some tests for + auto-reset event state. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:51 -0600 +Message-Id: <20240131021356.10322-25-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Test event-specific ioctls NTSYNC_IOC_EVENT_SET, NTSYNC_IOC_EVENT_RESET, +NTSYNC_IOC_EVENT_PULSE, NTSYNC_IOC_EVENT_READ for auto-reset events, and +waiting on auto-reset events. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 59 +++++++++++++++++++ + 1 file changed, 59 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 98fc70a9a58b..f1fb28949367 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -421,6 +421,65 @@ TEST(manual_event_state) + close(fd); + } + ++TEST(auto_event_state) ++{ ++ struct ntsync_event_args event_args; ++ __u32 index, signaled; ++ int fd, event, ret; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ event_args.manual = 0; ++ event_args.signaled = 1; ++ event_args.event = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, event_args.event); ++ event = event_args.event; ++ ++ check_event_state(event, 1, 0); ++ ++ signaled = 0xdeadbeef; ++ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ check_event_state(event, 1, 0); ++ ++ ret = wait_any(fd, 1, &event, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_event_state(event, 0, 0); ++ ++ signaled = 0xdeadbeef; ++ ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event, 0, 0); ++ ++ ret = wait_any(fd, 1, &event, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ check_event_state(event, 0, 0); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event, 0, 0); ++ ++ close(event); ++ ++ close(fd); ++} ++ + TEST(test_wait_any) + { + struct ntsync_mutex_args mutex_args = {0}; +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0024.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0024.patch new file mode 100644 index 0000000..39fadaa --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0024.patch @@ -0,0 +1,270 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 25/29] selftests: ntsync: Add some tests for wakeup + signaling with events. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:52 -0600 +Message-Id: <20240131021356.10322-26-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Expand the contended wait tests, which previously only covered events and +semaphores, to cover events as well. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 151 +++++++++++++++++- + 1 file changed, 147 insertions(+), 4 deletions(-) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index f1fb28949367..598333df3e6d 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -587,6 +587,7 @@ TEST(test_wait_any) + + TEST(test_wait_all) + { ++ struct ntsync_event_args event_args = {0}; + struct ntsync_mutex_args mutex_args = {0}; + struct ntsync_sem_args sem_args = {0}; + __u32 owner, index, count; +@@ -609,6 +610,11 @@ TEST(test_wait_all) + EXPECT_EQ(0, ret); + EXPECT_NE(0xdeadbeef, mutex_args.mutex); + ++ event_args.manual = true; ++ event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ + objs[0] = sem_args.sem; + objs[1] = mutex_args.mutex; + +@@ -657,6 +663,14 @@ TEST(test_wait_all) + check_sem_state(sem_args.sem, 1, 3); + check_mutex_state(mutex_args.mutex, 1, 123); + ++ objs[0] = sem_args.sem; ++ objs[1] = event_args.event; ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_event_state(event_args.event, 1, 1); ++ + /* test waiting on the same object twice */ + objs[0] = objs[1] = sem_args.sem; + ret = wait_all(fd, 2, objs, 123, &index); +@@ -665,6 +679,7 @@ TEST(test_wait_all) + + close(sem_args.sem); + close(mutex_args.mutex); ++ close(event_args.event); + + close(fd); + } +@@ -713,12 +728,13 @@ static int wait_for_thread(pthread_t thread, unsigned int ms) + + TEST(wake_any) + { ++ struct ntsync_event_args event_args = {0}; + struct ntsync_mutex_args mutex_args = {0}; + struct ntsync_wait_args wait_args = {0}; + struct ntsync_sem_args sem_args = {0}; + struct wait_args thread_args; ++ __u32 count, index, signaled; + int objs[2], fd, ret; +- __u32 count, index; + pthread_t thread; + + fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); +@@ -800,10 +816,101 @@ TEST(wake_any) + EXPECT_EQ(0, thread_args.ret); + EXPECT_EQ(1, wait_args.index); + ++ /* test waking events */ ++ ++ event_args.manual = false; ++ event_args.signaled = false; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ ++ objs[1] = event_args.event; ++ wait_args.timeout = get_abs_timeout(1000); ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event_args.event, 0, 0); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(1, wait_args.index); ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_PULSE, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event_args.event, 0, 0); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(1, wait_args.index); ++ ++ close(event_args.event); ++ ++ event_args.manual = true; ++ event_args.signaled = false; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ ++ objs[1] = event_args.event; ++ wait_args.timeout = get_abs_timeout(1000); ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event_args.event, 1, 1); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(1, wait_args.index); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_PULSE, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event_args.event, 0, 1); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(1, wait_args.index); ++ ++ close(event_args.event); ++ + /* delete an object while it's being waited on */ + + wait_args.timeout = get_abs_timeout(200); + wait_args.owner = 123; ++ objs[1] = mutex_args.mutex; + ret = pthread_create(&thread, NULL, wait_thread, &thread_args); + EXPECT_EQ(0, ret); + +@@ -823,12 +930,14 @@ TEST(wake_any) + + TEST(wake_all) + { ++ struct ntsync_event_args manual_event_args = {0}; ++ struct ntsync_event_args auto_event_args = {0}; + struct ntsync_mutex_args mutex_args = {0}; + struct ntsync_wait_args wait_args = {0}; + struct ntsync_sem_args sem_args = {0}; + struct wait_args thread_args; +- int objs[2], fd, ret; +- __u32 count, index; ++ __u32 count, index, signaled; ++ int objs[4], fd, ret; + pthread_t thread; + + fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); +@@ -848,12 +957,24 @@ TEST(wake_all) + EXPECT_EQ(0, ret); + EXPECT_NE(0xdeadbeef, mutex_args.mutex); + ++ manual_event_args.manual = true; ++ manual_event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &manual_event_args); ++ EXPECT_EQ(0, ret); ++ ++ auto_event_args.manual = false; ++ auto_event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &auto_event_args); ++ EXPECT_EQ(0, ret); ++ + objs[0] = sem_args.sem; + objs[1] = mutex_args.mutex; ++ objs[2] = manual_event_args.event; ++ objs[3] = auto_event_args.event; + + wait_args.timeout = get_abs_timeout(1000); + wait_args.objs = (uintptr_t)objs; +- wait_args.count = 2; ++ wait_args.count = 4; + wait_args.owner = 456; + thread_args.fd = fd; + thread_args.args = &wait_args; +@@ -887,12 +1008,32 @@ TEST(wake_all) + + check_mutex_state(mutex_args.mutex, 0, 0); + ++ ret = ioctl(manual_event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ + count = 2; + ret = post_sem(sem_args.sem, &count); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, count); ++ check_sem_state(sem_args.sem, 2, 3); ++ ++ ret = ioctl(auto_event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ ++ ret = ioctl(manual_event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ ++ ret = ioctl(auto_event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ + check_sem_state(sem_args.sem, 1, 3); + check_mutex_state(mutex_args.mutex, 1, 456); ++ check_event_state(manual_event_args.event, 1, 1); ++ check_event_state(auto_event_args.event, 0, 0); + + ret = wait_for_thread(thread, 100); + EXPECT_EQ(0, ret); +@@ -910,6 +1051,8 @@ TEST(wake_all) + + close(sem_args.sem); + close(mutex_args.mutex); ++ close(manual_event_args.event); ++ close(auto_event_args.event); + + ret = wait_for_thread(thread, 200); + EXPECT_EQ(0, ret); +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0025.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0025.patch new file mode 100644 index 0000000..5ed6d50 --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0025.patch @@ -0,0 +1,234 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 26/29] selftests: ntsync: Add tests for alertable + waits. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:53 -0600 +Message-Id: <20240131021356.10322-27-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Test the "alert" functionality of NTSYNC_IOC_WAIT_ALL and NTSYNC_IOC_WAIT_ANY, +when a wait is woken with an alert and when it is woken by an object. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 179 +++++++++++++++++- + 1 file changed, 176 insertions(+), 3 deletions(-) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 598333df3e6d..6c00a55909aa 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -95,7 +95,7 @@ static int read_event_state(int event, __u32 *signaled, __u32 *manual) + }) + + static int wait_objs(int fd, unsigned long request, __u32 count, +- const int *objs, __u32 owner, __u32 *index) ++ const int *objs, __u32 owner, int alert, __u32 *index) + { + struct ntsync_wait_args args = {0}; + struct timespec timeout; +@@ -108,6 +108,7 @@ static int wait_objs(int fd, unsigned long request, __u32 count, + args.objs = (uintptr_t)objs; + args.owner = owner; + args.index = 0xdeadbeef; ++ args.alert = alert; + ret = ioctl(fd, request, &args); + *index = args.index; + return ret; +@@ -115,12 +116,26 @@ static int wait_objs(int fd, unsigned long request, __u32 count, + + static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) + { +- return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, count, objs, owner, index); ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, count, objs, owner, 0, index); + } + + static int wait_all(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) + { +- return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, count, objs, owner, index); ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, count, objs, owner, 0, index); ++} ++ ++static int wait_any_alert(int fd, __u32 count, const int *objs, ++ __u32 owner, int alert, __u32 *index) ++{ ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, ++ count, objs, owner, alert, index); ++} ++ ++static int wait_all_alert(int fd, __u32 count, const int *objs, ++ __u32 owner, int alert, __u32 *index) ++{ ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, ++ count, objs, owner, alert, index); + } + + TEST(semaphore_state) +@@ -1062,4 +1077,162 @@ TEST(wake_all) + close(fd); + } + ++TEST(alert_any) ++{ ++ struct ntsync_event_args event_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; ++ __u32 index, count, signaled; ++ int objs[2], fd, ret; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 0; ++ sem_args.max = 2; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ objs[0] = sem_args.sem; ++ ++ sem_args.count = 1; ++ sem_args.max = 2; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ objs[1] = sem_args.sem; ++ ++ event_args.manual = true; ++ event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_any_alert(fd, 0, NULL, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_any_alert(fd, 0, NULL, 123, event_args.event, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, index); ++ ++ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, index); ++ ++ close(event_args.event); ++ ++ /* test with an auto-reset event */ ++ ++ event_args.manual = false; ++ event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ ++ count = 1; ++ ret = post_sem(objs[0], &count); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ ++ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, index); ++ ++ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ close(event_args.event); ++ ++ close(objs[0]); ++ close(objs[1]); ++ ++ close(fd); ++} ++ ++TEST(alert_all) ++{ ++ struct ntsync_event_args event_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; ++ __u32 index, count, signaled; ++ int objs[2], fd, ret; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 2; ++ sem_args.max = 2; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ objs[0] = sem_args.sem; ++ ++ sem_args.count = 1; ++ sem_args.max = 2; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ objs[1] = sem_args.sem; ++ ++ event_args.manual = true; ++ event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ ++ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, index); ++ ++ close(event_args.event); ++ ++ /* test with an auto-reset event */ ++ ++ event_args.manual = false; ++ event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ ++ count = 2; ++ ret = post_sem(objs[1], &count); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ ++ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, index); ++ ++ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ close(event_args.event); ++ ++ close(objs[0]); ++ close(objs[1]); ++ ++ close(fd); ++} ++ + TEST_HARNESS_MAIN +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0026.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0026.patch new file mode 100644 index 0000000..12e8859 --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0026.patch @@ -0,0 +1,121 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 27/29] selftests: ntsync: Add some tests for wakeup + signaling via alerts. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:54 -0600 +Message-Id: <20240131021356.10322-28-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Expand the alert tests to cover alerting a thread mid-wait, to test that the +relevant scheduling logic works correctly. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 62 +++++++++++++++++++ + 1 file changed, 62 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 6c00a55909aa..09153d0686ac 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -1080,9 +1080,12 @@ TEST(wake_all) + TEST(alert_any) + { + struct ntsync_event_args event_args = {0}; ++ struct ntsync_wait_args wait_args = {0}; + struct ntsync_sem_args sem_args = {0}; + __u32 index, count, signaled; ++ struct wait_args thread_args; + int objs[2], fd, ret; ++ pthread_t thread; + + fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); + ASSERT_LE(0, fd); +@@ -1130,6 +1133,34 @@ TEST(alert_any) + EXPECT_EQ(0, ret); + EXPECT_EQ(2, index); + ++ /* test wakeup via alert */ ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ wait_args.objs = (uintptr_t)objs; ++ wait_args.count = 2; ++ wait_args.owner = 123; ++ wait_args.index = 0xdeadbeef; ++ wait_args.alert = event_args.event; ++ thread_args.fd = fd; ++ thread_args.args = &wait_args; ++ thread_args.request = NTSYNC_IOC_WAIT_ANY; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(2, wait_args.index); ++ + close(event_args.event); + + /* test with an auto-reset event */ +@@ -1166,9 +1197,12 @@ TEST(alert_any) + TEST(alert_all) + { + struct ntsync_event_args event_args = {0}; ++ struct ntsync_wait_args wait_args = {0}; + struct ntsync_sem_args sem_args = {0}; ++ struct wait_args thread_args; + __u32 index, count, signaled; + int objs[2], fd, ret; ++ pthread_t thread; + + fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); + ASSERT_LE(0, fd); +@@ -1202,6 +1236,34 @@ TEST(alert_all) + EXPECT_EQ(0, ret); + EXPECT_EQ(2, index); + ++ /* test wakeup via alert */ ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ wait_args.objs = (uintptr_t)objs; ++ wait_args.count = 2; ++ wait_args.owner = 123; ++ wait_args.index = 0xdeadbeef; ++ wait_args.alert = event_args.event; ++ thread_args.fd = fd; ++ thread_args.args = &wait_args; ++ thread_args.request = NTSYNC_IOC_WAIT_ALL; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(2, wait_args.index); ++ + close(event_args.event); + + /* test with an auto-reset event */ +-- +2.43.0 + diff --git a/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0027.patch b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0027.patch new file mode 100644 index 0000000..fee7a66 --- /dev/null +++ b/linux-clang/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0027.patch @@ -0,0 +1,39 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 28/29] maintainers: Add an entry for ntsync. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:55 -0600 +Message-Id: <20240131021356.10322-29-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Add myself as maintainer, supported by CodeWeavers. + +Signed-off-by: Elizabeth Figura +--- + MAINTAINERS | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index 8d1052fa6a69..7924127d351b 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -15585,6 +15585,15 @@ T: git https://github.com/Paragon-Software-Group/linux-ntfs3.git + F: Documentation/filesystems/ntfs3.rst + F: fs/ntfs3/ + ++NTSYNC SYNCHRONIZATION PRIMITIVE DRIVER ++M: Elizabeth Figura ++L: wine-devel@winehq.org ++S: Supported ++F: Documentation/userspace-api/ntsync.rst ++F: drivers/misc/ntsync.c ++F: include/uapi/linux/ntsync.h ++F: tools/testing/selftests/drivers/ntsync/ ++ + NUBUS SUBSYSTEM + M: Finn Thain + L: linux-m68k@lists.linux-m68k.org +-- +2.43.0 + diff --git "a/linux-gcc/linux6.7-zen/patches/0001-[PATCH_RFC_2_9]_ntsync:_Reserve_a_minor_device_number_and_ioctl\n_range..patch" "b/linux-gcc/linux6.7-zen/patches/0001-[PATCH_RFC_2_9]_ntsync:_Reserve_a_minor_device_number_and_ioctl\n_range..patch" deleted file mode 100644 index 0e03db0..0000000 --- "a/linux-gcc/linux6.7-zen/patches/0001-[PATCH_RFC_2_9]_ntsync:_Reserve_a_minor_device_number_and_ioctl\n_range..patch" +++ /dev/null @@ -1,68 +0,0 @@ -Signed-off-by: Elizabeth Figura ---- - Documentation/admin-guide/devices.txt | 3 ++- - Documentation/userspace-api/ioctl/ioctl-number.rst | 2 ++ - drivers/misc/ntsync.c | 3 ++- - include/linux/miscdevice.h | 1 + - 4 files changed, 7 insertions(+), 2 deletions(-) - -diff --git a/Documentation/admin-guide/devices.txt b/Documentation/admin-guide/devices.txt -index 94c98be1329a..041404397ee5 100644 ---- a/Documentation/admin-guide/devices.txt -+++ b/Documentation/admin-guide/devices.txt -@@ -376,8 +376,9 @@ - 240 = /dev/userio Serio driver testing device - 241 = /dev/vhost-vsock Host kernel driver for virtio vsock - 242 = /dev/rfkill Turning off radio transmissions (rfkill) -+ 243 = /dev/ntsync NT synchronization primitive device - -- 243-254 Reserved for local use -+ 244-254 Reserved for local use - 255 Reserved for MISC_DYNAMIC_MINOR - - 11 char Raw keyboard device (Linux/SPARC only) -diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst -index 457e16f06e04..a1326a5bc2e0 100644 ---- a/Documentation/userspace-api/ioctl/ioctl-number.rst -+++ b/Documentation/userspace-api/ioctl/ioctl-number.rst -@@ -378,6 +378,8 @@ Code Seq# Include File Comments - - 0xF6 all LTTng Linux Trace Toolkit Next Generation - -+0xF7 00-1F uapi/linux/ntsync.h NT synchronization primitives -+ - 0xF8 all arch/x86/include/uapi/asm/amd_hsmp.h AMD HSMP EPYC system management interface driver - - 0xFD all linux/dm-ioctl.h -diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index 9424c6210e51..84b498e2b2d5 100644 ---- a/drivers/misc/ntsync.c -+++ b/drivers/misc/ntsync.c -@@ -40,7 +40,7 @@ static const struct file_operations ntsync_fops = { - }; - - static struct miscdevice ntsync_misc = { -- .minor = MISC_DYNAMIC_MINOR, -+ .minor = NTSYNC_MINOR, - .name = NTSYNC_NAME, - .fops = &ntsync_fops, - }; -@@ -51,3 +51,4 @@ MODULE_AUTHOR("Elizabeth Figura"); - MODULE_DESCRIPTION("Kernel driver for NT synchronization primitives"); - MODULE_LICENSE("GPL"); - MODULE_ALIAS("devname:" NTSYNC_NAME); -+MODULE_ALIAS_MISCDEV(NTSYNC_MINOR); -diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h -index c0fea6ca5076..fe5d9366fdf7 100644 ---- a/include/linux/miscdevice.h -+++ b/include/linux/miscdevice.h -@@ -71,6 +71,7 @@ - #define USERIO_MINOR 240 - #define VHOST_VSOCK_MINOR 241 - #define RFKILL_MINOR 242 -+#define NTSYNC_MINOR 243 - #define MISC_DYNAMIC_MINOR 255 - - struct device; --- -2.43.0 diff --git "a/linux-gcc/linux6.7-zen/patches/0002-[PATCH_RFC_3_9]_ntsync:_Introduce_NTSYNC_IOC_CREATE_SEM_and\n_NTSYNC_IOC_DELETE..patch" "b/linux-gcc/linux6.7-zen/patches/0002-[PATCH_RFC_3_9]_ntsync:_Introduce_NTSYNC_IOC_CREATE_SEM_and\n_NTSYNC_IOC_DELETE..patch" deleted file mode 100644 index c233e43..0000000 --- "a/linux-gcc/linux6.7-zen/patches/0002-[PATCH_RFC_3_9]_ntsync:_Introduce_NTSYNC_IOC_CREATE_SEM_and\n_NTSYNC_IOC_DELETE..patch" +++ /dev/null @@ -1,191 +0,0 @@ -These correspond to the NT syscalls NtCreateSemaphore() and NtClose(). -Unlike those functions, however, these ioctls do not handle object names, or -lookup of existing objects, or handle reference counting, but simply create the -underlying primitive. The user space emulator is expected to implement those -functions if they are required. - -Signed-off-by: Elizabeth Figura ---- - drivers/misc/ntsync.c | 117 ++++++++++++++++++++++++++++++++++++ - include/uapi/linux/ntsync.h | 25 ++++++++ - 2 files changed, 142 insertions(+) - create mode 100644 include/uapi/linux/ntsync.h - -diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index 84b498e2b2d5..3287b94be351 100644 ---- a/drivers/misc/ntsync.c -+++ b/drivers/misc/ntsync.c -@@ -8,23 +8,140 @@ - #include - #include - #include -+#include -+#include -+#include - - #define NTSYNC_NAME "ntsync" - -+enum ntsync_type { -+ NTSYNC_TYPE_SEM, -+}; -+ -+struct ntsync_obj { -+ struct rcu_head rhead; -+ struct kref refcount; -+ -+ enum ntsync_type type; -+ -+ union { -+ struct { -+ __u32 count; -+ __u32 max; -+ } sem; -+ } u; -+}; -+ -+struct ntsync_device { -+ struct xarray objects; -+}; -+ -+static void destroy_obj(struct kref *ref) -+{ -+ struct ntsync_obj *obj = container_of(ref, struct ntsync_obj, refcount); -+ -+ kfree_rcu(obj, rhead); -+} -+ -+static void put_obj(struct ntsync_obj *obj) -+{ -+ kref_put(&obj->refcount, destroy_obj); -+} -+ - static int ntsync_char_open(struct inode *inode, struct file *file) - { -+ struct ntsync_device *dev; -+ -+ dev = kzalloc(sizeof(*dev), GFP_KERNEL); -+ if (!dev) -+ return -ENOMEM; -+ -+ xa_init_flags(&dev->objects, XA_FLAGS_ALLOC); -+ -+ file->private_data = dev; - return nonseekable_open(inode, file); - } - - static int ntsync_char_release(struct inode *inode, struct file *file) - { -+ struct ntsync_device *dev = file->private_data; -+ struct ntsync_obj *obj; -+ unsigned long id; -+ -+ xa_for_each(&dev->objects, id, obj) -+ put_obj(obj); -+ -+ xa_destroy(&dev->objects); -+ -+ kfree(dev); -+ -+ return 0; -+} -+ -+static void init_obj(struct ntsync_obj *obj) -+{ -+ kref_init(&obj->refcount); -+} -+ -+static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) -+{ -+ struct ntsync_sem_args __user *user_args = argp; -+ struct ntsync_sem_args args; -+ struct ntsync_obj *sem; -+ __u32 id; -+ int ret; -+ -+ if (copy_from_user(&args, argp, sizeof(args))) -+ return -EFAULT; -+ -+ if (args.count > args.max) -+ return -EINVAL; -+ -+ sem = kzalloc(sizeof(*sem), GFP_KERNEL); -+ if (!sem) -+ return -ENOMEM; -+ -+ init_obj(sem); -+ sem->type = NTSYNC_TYPE_SEM; -+ sem->u.sem.count = args.count; -+ sem->u.sem.max = args.max; -+ -+ ret = xa_alloc(&dev->objects, &id, sem, xa_limit_32b, GFP_KERNEL); -+ if (ret < 0) { -+ kfree(sem); -+ return ret; -+ } -+ -+ return put_user(id, &user_args->sem); -+} -+ -+static int ntsync_delete(struct ntsync_device *dev, void __user *argp) -+{ -+ struct ntsync_obj *obj; -+ __u32 id; -+ -+ if (get_user(id, (__u32 __user *)argp)) -+ return -EFAULT; -+ -+ obj = xa_erase(&dev->objects, id); -+ if (!obj) -+ return -EINVAL; -+ -+ put_obj(obj); - return 0; - } - - static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) - { -+ struct ntsync_device *dev = file->private_data; -+ void __user *argp = (void __user *)parm; -+ - switch (cmd) { -+ case NTSYNC_IOC_CREATE_SEM: -+ return ntsync_create_sem(dev, argp); -+ case NTSYNC_IOC_DELETE: -+ return ntsync_delete(dev, argp); - default: - return -ENOIOCTLCMD; - } -diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -new file mode 100644 -index 000000000000..d97afc138dcc ---- /dev/null -+++ b/include/uapi/linux/ntsync.h -@@ -0,0 +1,25 @@ -+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -+/* -+ * Kernel support for NT synchronization primitive emulation -+ * -+ * Copyright (C) 2021-2022 Elizabeth Figura -+ */ -+ -+#ifndef __LINUX_NTSYNC_H -+#define __LINUX_NTSYNC_H -+ -+#include -+ -+struct ntsync_sem_args { -+ __u32 sem; -+ __u32 count; -+ __u32 max; -+}; -+ -+#define NTSYNC_IOC_BASE 0xf7 -+ -+#define NTSYNC_IOC_CREATE_SEM _IOWR(NTSYNC_IOC_BASE, 0, \ -+ struct ntsync_sem_args) -+#define NTSYNC_IOC_DELETE _IOW (NTSYNC_IOC_BASE, 1, __u32) -+ -+#endif --- -2.43.0 diff --git a/linux-gcc/linux6.7-zen/patches/0003-[PATCH_RFC_4_9]_ntsync:_Introduce_NTSYNC_IOC_PUT_SEM..patch b/linux-gcc/linux6.7-zen/patches/0003-[PATCH_RFC_4_9]_ntsync:_Introduce_NTSYNC_IOC_PUT_SEM..patch deleted file mode 100644 index f5f30ce..0000000 --- a/linux-gcc/linux6.7-zen/patches/0003-[PATCH_RFC_4_9]_ntsync:_Introduce_NTSYNC_IOC_PUT_SEM..patch +++ /dev/null @@ -1,147 +0,0 @@ -This corresponds to the NT syscall NtReleaseSemaphore(). - -Signed-off-by: Elizabeth Figura ---- - drivers/misc/ntsync.c | 76 +++++++++++++++++++++++++++++++++++++ - include/uapi/linux/ntsync.h | 2 + - 2 files changed, 78 insertions(+) - -diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index 3287b94be351..d1c91c2a4f1a 100644 ---- a/drivers/misc/ntsync.c -+++ b/drivers/misc/ntsync.c -@@ -21,9 +21,11 @@ enum ntsync_type { - struct ntsync_obj { - struct rcu_head rhead; - struct kref refcount; -+ spinlock_t lock; - - enum ntsync_type type; - -+ /* The following fields are protected by the object lock. */ - union { - struct { - __u32 count; -@@ -36,6 +38,19 @@ struct ntsync_device { - struct xarray objects; - }; - -+static struct ntsync_obj *get_obj(struct ntsync_device *dev, __u32 id) -+{ -+ struct ntsync_obj *obj; -+ -+ rcu_read_lock(); -+ obj = xa_load(&dev->objects, id); -+ if (obj && !kref_get_unless_zero(&obj->refcount)) -+ obj = NULL; -+ rcu_read_unlock(); -+ -+ return obj; -+} -+ - static void destroy_obj(struct kref *ref) - { - struct ntsync_obj *obj = container_of(ref, struct ntsync_obj, refcount); -@@ -48,6 +63,18 @@ static void put_obj(struct ntsync_obj *obj) - kref_put(&obj->refcount, destroy_obj); - } - -+static struct ntsync_obj *get_obj_typed(struct ntsync_device *dev, __u32 id, -+ enum ntsync_type type) -+{ -+ struct ntsync_obj *obj = get_obj(dev, id); -+ -+ if (obj && obj->type != type) { -+ put_obj(obj); -+ return NULL; -+ } -+ return obj; -+} -+ - static int ntsync_char_open(struct inode *inode, struct file *file) - { - struct ntsync_device *dev; -@@ -81,6 +108,7 @@ static int ntsync_char_release(struct inode *inode, struct file *file) - static void init_obj(struct ntsync_obj *obj) - { - kref_init(&obj->refcount); -+ spin_lock_init(&obj->lock); - } - - static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) -@@ -131,6 +159,52 @@ static int ntsync_delete(struct ntsync_device *dev, void __user *argp) - return 0; - } - -+/* -+ * Actually change the semaphore state, returning -EOVERFLOW if it is made -+ * invalid. -+ */ -+static int put_sem_state(struct ntsync_obj *sem, __u32 count) -+{ -+ lockdep_assert_held(&sem->lock); -+ -+ if (sem->u.sem.count + count < sem->u.sem.count || -+ sem->u.sem.count + count > sem->u.sem.max) -+ return -EOVERFLOW; -+ -+ sem->u.sem.count += count; -+ return 0; -+} -+ -+static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp) -+{ -+ struct ntsync_sem_args __user *user_args = argp; -+ struct ntsync_sem_args args; -+ struct ntsync_obj *sem; -+ __u32 prev_count; -+ int ret; -+ -+ if (copy_from_user(&args, argp, sizeof(args))) -+ return -EFAULT; -+ -+ sem = get_obj_typed(dev, args.sem, NTSYNC_TYPE_SEM); -+ if (!sem) -+ return -EINVAL; -+ -+ spin_lock(&sem->lock); -+ -+ prev_count = sem->u.sem.count; -+ ret = put_sem_state(sem, args.count); -+ -+ spin_unlock(&sem->lock); -+ -+ put_obj(sem); -+ -+ if (!ret && put_user(prev_count, &user_args->count)) -+ ret = -EFAULT; -+ -+ return ret; -+} -+ - static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) - { -@@ -142,6 +216,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - return ntsync_create_sem(dev, argp); - case NTSYNC_IOC_DELETE: - return ntsync_delete(dev, argp); -+ case NTSYNC_IOC_PUT_SEM: -+ return ntsync_put_sem(dev, argp); - default: - return -ENOIOCTLCMD; - } -diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -index d97afc138dcc..8c610d65f8ef 100644 ---- a/include/uapi/linux/ntsync.h -+++ b/include/uapi/linux/ntsync.h -@@ -21,5 +21,7 @@ struct ntsync_sem_args { - #define NTSYNC_IOC_CREATE_SEM _IOWR(NTSYNC_IOC_BASE, 0, \ - struct ntsync_sem_args) - #define NTSYNC_IOC_DELETE _IOW (NTSYNC_IOC_BASE, 1, __u32) -+#define NTSYNC_IOC_PUT_SEM _IOWR(NTSYNC_IOC_BASE, 2, \ -+ struct ntsync_sem_args) - - #endif --- -2.43.0 diff --git a/linux-gcc/linux6.7-zen/patches/0007-[PATCH_RFC_8_9]_ntsync:_Introduce_NTSYNC_IOC_PUT_MUTEX..patch b/linux-gcc/linux6.7-zen/patches/0007-[PATCH_RFC_8_9]_ntsync:_Introduce_NTSYNC_IOC_PUT_MUTEX..patch deleted file mode 100644 index 5ad77ae..0000000 --- a/linux-gcc/linux6.7-zen/patches/0007-[PATCH_RFC_8_9]_ntsync:_Introduce_NTSYNC_IOC_PUT_MUTEX..patch +++ /dev/null @@ -1,107 +0,0 @@ -This corresponds to the NT syscall NtReleaseMutant(). - -Signed-off-by: Elizabeth Figura ---- - drivers/misc/ntsync.c | 67 +++++++++++++++++++++++++++++++++++++ - include/uapi/linux/ntsync.h | 2 ++ - 2 files changed, 69 insertions(+) - -diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index d48f2ef41341..28f43768d1c3 100644 ---- a/drivers/misc/ntsync.c -+++ b/drivers/misc/ntsync.c -@@ -449,6 +449,71 @@ static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp) - return ret; - } - -+/* -+ * Actually change the mutex state, returning -EPERM if not the owner. -+ */ -+static int put_mutex_state(struct ntsync_obj *mutex, -+ const struct ntsync_mutex_args *args) -+{ -+ lockdep_assert_held(&mutex->lock); -+ -+ if (mutex->u.mutex.owner != args->owner) -+ return -EPERM; -+ -+ if (!--mutex->u.mutex.count) -+ mutex->u.mutex.owner = 0; -+ return 0; -+} -+ -+static int ntsync_put_mutex(struct ntsync_device *dev, void __user *argp) -+{ -+ struct ntsync_mutex_args __user *user_args = argp; -+ struct ntsync_mutex_args args; -+ struct ntsync_obj *mutex; -+ __u32 prev_count; -+ int ret; -+ -+ if (copy_from_user(&args, argp, sizeof(args))) -+ return -EFAULT; -+ if (!args.owner) -+ return -EINVAL; -+ -+ mutex = get_obj_typed(dev, args.mutex, NTSYNC_TYPE_MUTEX); -+ if (!mutex) -+ return -EINVAL; -+ -+ if (atomic_read(&mutex->all_hint) > 0) { -+ spin_lock(&dev->wait_all_lock); -+ spin_lock_nest_lock(&mutex->lock, &dev->wait_all_lock); -+ -+ prev_count = mutex->u.mutex.count; -+ ret = put_mutex_state(mutex, &args); -+ if (!ret) { -+ try_wake_all_obj(dev, mutex); -+ try_wake_any_mutex(mutex); -+ } -+ -+ spin_unlock(&mutex->lock); -+ spin_unlock(&dev->wait_all_lock); -+ } else { -+ spin_lock(&mutex->lock); -+ -+ prev_count = mutex->u.mutex.count; -+ ret = put_mutex_state(mutex, &args); -+ if (!ret) -+ try_wake_any_mutex(mutex); -+ -+ spin_unlock(&mutex->lock); -+ } -+ -+ put_obj(mutex); -+ -+ if (!ret && put_user(prev_count, &user_args->count)) -+ ret = -EFAULT; -+ -+ return ret; -+} -+ - static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) - { - int ret = 0; -@@ -738,6 +803,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - return ntsync_create_sem(dev, argp); - case NTSYNC_IOC_DELETE: - return ntsync_delete(dev, argp); -+ case NTSYNC_IOC_PUT_MUTEX: -+ return ntsync_put_mutex(dev, argp); - case NTSYNC_IOC_PUT_SEM: - return ntsync_put_sem(dev, argp); - case NTSYNC_IOC_WAIT_ALL: -diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -index 26d1b3d4847f..2e44e7e77776 100644 ---- a/include/uapi/linux/ntsync.h -+++ b/include/uapi/linux/ntsync.h -@@ -46,5 +46,7 @@ struct ntsync_wait_args { - struct ntsync_wait_args) - #define NTSYNC_IOC_CREATE_MUTEX _IOWR(NTSYNC_IOC_BASE, 5, \ - struct ntsync_mutex_args) -+#define NTSYNC_IOC_PUT_MUTEX _IOWR(NTSYNC_IOC_BASE, 6, \ -+ struct ntsync_mutex_args) - - #endif --- -2.43.0 diff --git a/linux-gcc/linux6.7-zen/patches/0008-[PATCH_RFC_9_9]_ntsync:_Introduce_NTSYNC_IOC_KILL_OWNER..patch b/linux-gcc/linux6.7-zen/patches/0008-[PATCH_RFC_9_9]_ntsync:_Introduce_NTSYNC_IOC_KILL_OWNER..patch deleted file mode 100644 index eedfed0..0000000 --- a/linux-gcc/linux6.7-zen/patches/0008-[PATCH_RFC_9_9]_ntsync:_Introduce_NTSYNC_IOC_KILL_OWNER..patch +++ /dev/null @@ -1,170 +0,0 @@ -This does not correspond to any NT syscall, but rather should be called by the -user-space NT emulator when a thread dies. It is responsible for marking any -mutexes owned by that thread as abandoned. - -Signed-off-by: Elizabeth Figura ---- - drivers/misc/ntsync.c | 80 ++++++++++++++++++++++++++++++++++++- - include/uapi/linux/ntsync.h | 1 + - 2 files changed, 79 insertions(+), 2 deletions(-) - -diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index 28f43768d1c3..1173c750c106 100644 ---- a/drivers/misc/ntsync.c -+++ b/drivers/misc/ntsync.c -@@ -64,6 +64,7 @@ struct ntsync_obj { - struct { - __u32 count; - __u32 owner; -+ bool ownerdead; - } mutex; - } u; - }; -@@ -87,6 +88,7 @@ struct ntsync_q { - atomic_t signaled; - - bool all; -+ bool ownerdead; - __u32 count; - struct ntsync_q_entry entries[]; - }; -@@ -240,6 +242,9 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, - obj->u.sem.count--; - break; - case NTSYNC_TYPE_MUTEX: -+ if (obj->u.mutex.ownerdead) -+ q->ownerdead = true; -+ obj->u.mutex.ownerdead = false; - obj->u.mutex.count++; - obj->u.mutex.owner = q->owner; - break; -@@ -299,6 +304,9 @@ static void try_wake_any_mutex(struct ntsync_obj *mutex) - continue; - - if (atomic_cmpxchg(&q->signaled, -1, entry->index) == -1) { -+ if (mutex->u.mutex.ownerdead) -+ q->ownerdead = true; -+ mutex->u.mutex.ownerdead = false; - mutex->u.mutex.count++; - mutex->u.mutex.owner = q->owner; - wake_up_process(q->task); -@@ -514,6 +522,71 @@ static int ntsync_put_mutex(struct ntsync_device *dev, void __user *argp) - return ret; - } - -+/* -+ * Actually change the mutex state to mark its owner as dead. -+ */ -+static void put_mutex_ownerdead_state(struct ntsync_obj *mutex) -+{ -+ lockdep_assert_held(&mutex->lock); -+ -+ mutex->u.mutex.ownerdead = true; -+ mutex->u.mutex.owner = 0; -+ mutex->u.mutex.count = 0; -+} -+ -+static int ntsync_kill_owner(struct ntsync_device *dev, void __user *argp) -+{ -+ struct ntsync_obj *obj; -+ unsigned long id; -+ __u32 owner; -+ -+ if (get_user(owner, (__u32 __user *)argp)) -+ return -EFAULT; -+ if (!owner) -+ return -EINVAL; -+ -+ rcu_read_lock(); -+ -+ xa_for_each(&dev->objects, id, obj) { -+ if (!kref_get_unless_zero(&obj->refcount)) -+ continue; -+ -+ if (obj->type != NTSYNC_TYPE_MUTEX) { -+ put_obj(obj); -+ continue; -+ } -+ -+ if (atomic_read(&obj->all_hint) > 0) { -+ spin_lock(&dev->wait_all_lock); -+ spin_lock_nest_lock(&obj->lock, &dev->wait_all_lock); -+ -+ if (obj->u.mutex.owner == owner) { -+ put_mutex_ownerdead_state(obj); -+ try_wake_all_obj(dev, obj); -+ try_wake_any_mutex(obj); -+ } -+ -+ spin_unlock(&obj->lock); -+ spin_unlock(&dev->wait_all_lock); -+ } else { -+ spin_lock(&obj->lock); -+ -+ if (obj->u.mutex.owner == owner) { -+ put_mutex_ownerdead_state(obj); -+ try_wake_any_mutex(obj); -+ } -+ -+ spin_unlock(&obj->lock); -+ } -+ -+ put_obj(obj); -+ } -+ -+ rcu_read_unlock(); -+ -+ return 0; -+} -+ - static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) - { - int ret = 0; -@@ -585,6 +658,7 @@ static int setup_wait(struct ntsync_device *dev, - q->owner = args->owner; - atomic_set(&q->signaled, -1); - q->all = all; -+ q->ownerdead = false; - q->count = count; - - for (i = 0; i < count; i++) { -@@ -697,7 +771,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) - struct ntsync_wait_args __user *user_args = argp; - - /* even if we caught a signal, we need to communicate success */ -- ret = 0; -+ ret = q->ownerdead ? -EOWNERDEAD : 0; - - if (put_user(signaled, &user_args->index)) - ret = -EFAULT; -@@ -778,7 +852,7 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp) - struct ntsync_wait_args __user *user_args = argp; - - /* even if we caught a signal, we need to communicate success */ -- ret = 0; -+ ret = q->ownerdead ? -EOWNERDEAD : 0; - - if (put_user(signaled, &user_args->index)) - ret = -EFAULT; -@@ -803,6 +877,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - return ntsync_create_sem(dev, argp); - case NTSYNC_IOC_DELETE: - return ntsync_delete(dev, argp); -+ case NTSYNC_IOC_KILL_OWNER: -+ return ntsync_kill_owner(dev, argp); - case NTSYNC_IOC_PUT_MUTEX: - return ntsync_put_mutex(dev, argp); - case NTSYNC_IOC_PUT_SEM: -diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -index 2e44e7e77776..fec9a3993322 100644 ---- a/include/uapi/linux/ntsync.h -+++ b/include/uapi/linux/ntsync.h -@@ -48,5 +48,6 @@ struct ntsync_wait_args { - struct ntsync_mutex_args) - #define NTSYNC_IOC_PUT_MUTEX _IOWR(NTSYNC_IOC_BASE, 6, \ - struct ntsync_mutex_args) -+#define NTSYNC_IOC_KILL_OWNER _IOW (NTSYNC_IOC_BASE, 7, __u32) - - #endif --- -2.43.0 diff --git "a/linux-gcc/linux6.7-zen/patches/0000-[PATCH_RFC_1_9]_ntsync:_Introduce_the_ntsync_driver_and_character\n_device..patch" b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0000.patch similarity index 82% rename from "linux-gcc/linux6.7-zen/patches/0000-[PATCH_RFC_1_9]_ntsync:_Introduce_the_ntsync_driver_and_character\n_device..patch" rename to linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0000.patch index 580a595..3459d34 100644 --- "a/linux-gcc/linux6.7-zen/patches/0000-[PATCH_RFC_1_9]_ntsync:_Introduce_the_ntsync_driver_and_character\n_device..patch" +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0000.patch @@ -1,3 +1,13 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 1/29] ntsync: Introduce the ntsync driver and + character device. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:28 -0600 +Message-Id: <20240131021356.10322-2-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + ntsync uses a misc device as the simplest and least intrusive uAPI interface. Each file description on the device represents an isolated NT instance, intended @@ -7,8 +17,8 @@ Signed-off-by: Elizabeth Figura --- drivers/misc/Kconfig | 9 ++++++++ drivers/misc/Makefile | 1 + - drivers/misc/ntsync.c | 53 +++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 63 insertions(+) + drivers/misc/ntsync.c | 52 +++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 62 insertions(+) create mode 100644 drivers/misc/ntsync.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig @@ -45,15 +55,15 @@ index ea6ea5bbbc9c..153a3f4837e8 100644 obj-$(CONFIG_GP_PCI1XXXX) += mchp_pci1xxxx/ diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c new file mode 100644 -index 000000000000..9424c6210e51 +index 000000000000..e4969ef90722 --- /dev/null +++ b/drivers/misc/ntsync.c -@@ -0,0 +1,53 @@ +@@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * ntsync.c - Kernel driver for NT synchronization primitives + * -+ * Copyright (C) 2021-2022 Elizabeth Figura ++ * Copyright (C) 2024 Elizabeth Figura + */ + +#include @@ -86,7 +96,7 @@ index 000000000000..9424c6210e51 + .open = ntsync_char_open, + .release = ntsync_char_release, + .unlocked_ioctl = ntsync_char_ioctl, -+ .compat_ioctl = ntsync_char_ioctl, ++ .compat_ioctl = compat_ptr_ioctl, + .llseek = no_llseek, +}; + @@ -101,6 +111,6 @@ index 000000000000..9424c6210e51 +MODULE_AUTHOR("Elizabeth Figura"); +MODULE_DESCRIPTION("Kernel driver for NT synchronization primitives"); +MODULE_LICENSE("GPL"); -+MODULE_ALIAS("devname:" NTSYNC_NAME); -- 2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0001.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0001.patch new file mode 100644 index 0000000..b8fe81c --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0001.patch @@ -0,0 +1,224 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 2/29] ntsync: Introduce NTSYNC_IOC_CREATE_SEM. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:29 -0600 +Message-Id: <20240131021356.10322-3-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This corresponds to the NT syscall NtCreateSemaphore(). + +Semaphores are one of three types of object to be implemented in this driver, +the others being mutexes and events. + +An NT semaphore contains a 32-bit counter, and is signaled and can be acquired +when the counter is nonzero. The counter has a maximum value which is specified +at creation time. The initial value of the semaphore is also specified at +creation time. There are no restrictions on the maximum and initial value. + +Each object is exposed as an file, to which any number of fds may be opened. +When all fds are closed, the object is deleted. + +Signed-off-by: Elizabeth Figura +--- + .../userspace-api/ioctl/ioctl-number.rst | 2 + + drivers/misc/ntsync.c | 120 ++++++++++++++++++ + include/uapi/linux/ntsync.h | 21 +++ + 3 files changed, 143 insertions(+) + create mode 100644 include/uapi/linux/ntsync.h + +diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst +index 457e16f06e04..2f5c6994f042 100644 +--- a/Documentation/userspace-api/ioctl/ioctl-number.rst ++++ b/Documentation/userspace-api/ioctl/ioctl-number.rst +@@ -173,6 +173,8 @@ Code Seq# Include File Comments + 'M' 00-0F drivers/video/fsl-diu-fb.h conflict! + 'N' 00-1F drivers/usb/scanner.h + 'N' 40-7F drivers/block/nvme.c ++'N' 80-8F uapi/linux/ntsync.h NT synchronization primitives ++ + 'O' 00-06 mtd/ubi-user.h UBI + 'P' all linux/soundcard.h conflict! + 'P' 60-6F sound/sscape_ioctl.h conflict! +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index e4969ef90722..3ad86d98b82d 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -5,26 +5,146 @@ + * Copyright (C) 2024 Elizabeth Figura + */ + ++#include ++#include + #include + #include + #include ++#include ++#include + + #define NTSYNC_NAME "ntsync" + ++enum ntsync_type { ++ NTSYNC_TYPE_SEM, ++}; ++ ++struct ntsync_obj { ++ enum ntsync_type type; ++ ++ union { ++ struct { ++ __u32 count; ++ __u32 max; ++ } sem; ++ } u; ++ ++ struct file *file; ++ struct ntsync_device *dev; ++}; ++ ++struct ntsync_device { ++ struct file *file; ++}; ++ ++static int ntsync_obj_release(struct inode *inode, struct file *file) ++{ ++ struct ntsync_obj *obj = file->private_data; ++ ++ fput(obj->dev->file); ++ kfree(obj); ++ ++ return 0; ++} ++ ++static const struct file_operations ntsync_obj_fops = { ++ .owner = THIS_MODULE, ++ .release = ntsync_obj_release, ++ .llseek = no_llseek, ++}; ++ ++static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev, ++ enum ntsync_type type) ++{ ++ struct ntsync_obj *obj; ++ ++ obj = kzalloc(sizeof(*obj), GFP_KERNEL); ++ if (!obj) ++ return NULL; ++ obj->type = type; ++ obj->dev = dev; ++ get_file(dev->file); ++ ++ return obj; ++} ++ ++static int ntsync_obj_get_fd(struct ntsync_obj *obj) ++{ ++ struct file *file; ++ int fd; ++ ++ fd = get_unused_fd_flags(O_CLOEXEC); ++ if (fd < 0) ++ return fd; ++ file = anon_inode_getfile("ntsync", &ntsync_obj_fops, obj, O_RDWR); ++ if (IS_ERR(file)) { ++ put_unused_fd(fd); ++ return PTR_ERR(file); ++ } ++ obj->file = file; ++ fd_install(fd, file); ++ ++ return fd; ++} ++ ++static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) ++{ ++ struct ntsync_sem_args __user *user_args = argp; ++ struct ntsync_sem_args args; ++ struct ntsync_obj *sem; ++ int fd; ++ ++ if (copy_from_user(&args, argp, sizeof(args))) ++ return -EFAULT; ++ ++ if (args.count > args.max) ++ return -EINVAL; ++ ++ sem = ntsync_alloc_obj(dev, NTSYNC_TYPE_SEM); ++ if (!sem) ++ return -ENOMEM; ++ sem->u.sem.count = args.count; ++ sem->u.sem.max = args.max; ++ fd = ntsync_obj_get_fd(sem); ++ if (fd < 0) { ++ kfree(sem); ++ return fd; ++ } ++ ++ return put_user(fd, &user_args->sem); ++} ++ + static int ntsync_char_open(struct inode *inode, struct file *file) + { ++ struct ntsync_device *dev; ++ ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ if (!dev) ++ return -ENOMEM; ++ ++ file->private_data = dev; ++ dev->file = file; + return nonseekable_open(inode, file); + } + + static int ntsync_char_release(struct inode *inode, struct file *file) + { ++ struct ntsync_device *dev = file->private_data; ++ ++ kfree(dev); ++ + return 0; + } + + static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + unsigned long parm) + { ++ struct ntsync_device *dev = file->private_data; ++ void __user *argp = (void __user *)parm; ++ + switch (cmd) { ++ case NTSYNC_IOC_CREATE_SEM: ++ return ntsync_create_sem(dev, argp); + default: + return -ENOIOCTLCMD; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +new file mode 100644 +index 000000000000..f38818e7759d +--- /dev/null ++++ b/include/uapi/linux/ntsync.h +@@ -0,0 +1,21 @@ ++/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ ++/* ++ * Kernel support for NT synchronization primitive emulation ++ * ++ * Copyright (C) 2021-2022 Elizabeth Figura ++ */ ++ ++#ifndef __LINUX_NTSYNC_H ++#define __LINUX_NTSYNC_H ++ ++#include ++ ++struct ntsync_sem_args { ++ __u32 sem; ++ __u32 count; ++ __u32 max; ++}; ++ ++#define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args) ++ ++#endif +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0002.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0002.patch new file mode 100644 index 0000000..66b3ca2 --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0002.patch @@ -0,0 +1,145 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 3/29] ntsync: Introduce NTSYNC_IOC_SEM_POST. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:30 -0600 +Message-Id: <20240131021356.10322-4-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This corresponds to the NT syscall NtReleaseSemaphore(). + +This increases the semaphore's internal counter by the given value, and returns +the previous value. If the counter would overflow the defined maximum, the +function instead fails and returns -EOVERFLOW. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 68 +++++++++++++++++++++++++++++++++++-- + include/uapi/linux/ntsync.h | 2 ++ + 2 files changed, 67 insertions(+), 3 deletions(-) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 3ad86d98b82d..1af38969f9a2 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -20,23 +20,68 @@ enum ntsync_type { + }; + + struct ntsync_obj { ++ spinlock_t lock; ++ + enum ntsync_type type; + ++ struct file *file; ++ struct ntsync_device *dev; ++ ++ /* The following fields are protected by the object lock. */ + union { + struct { + __u32 count; + __u32 max; + } sem; + } u; +- +- struct file *file; +- struct ntsync_device *dev; + }; + + struct ntsync_device { + struct file *file; + }; + ++/* ++ * Actually change the semaphore state, returning -EOVERFLOW if it is made ++ * invalid. ++ */ ++static int post_sem_state(struct ntsync_obj *sem, __u32 count) ++{ ++ lockdep_assert_held(&sem->lock); ++ ++ if (sem->u.sem.count + count < sem->u.sem.count || ++ sem->u.sem.count + count > sem->u.sem.max) ++ return -EOVERFLOW; ++ ++ sem->u.sem.count += count; ++ return 0; ++} ++ ++static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp) ++{ ++ __u32 __user *user_args = argp; ++ __u32 prev_count; ++ __u32 args; ++ int ret; ++ ++ if (copy_from_user(&args, argp, sizeof(args))) ++ return -EFAULT; ++ ++ if (sem->type != NTSYNC_TYPE_SEM) ++ return -EINVAL; ++ ++ spin_lock(&sem->lock); ++ ++ prev_count = sem->u.sem.count; ++ ret = post_sem_state(sem, args); ++ ++ spin_unlock(&sem->lock); ++ ++ if (!ret && put_user(prev_count, user_args)) ++ ret = -EFAULT; ++ ++ return ret; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -47,9 +92,25 @@ static int ntsync_obj_release(struct inode *inode, struct file *file) + return 0; + } + ++static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, ++ unsigned long parm) ++{ ++ struct ntsync_obj *obj = file->private_data; ++ void __user *argp = (void __user *)parm; ++ ++ switch (cmd) { ++ case NTSYNC_IOC_SEM_POST: ++ return ntsync_sem_post(obj, argp); ++ default: ++ return -ENOIOCTLCMD; ++ } ++} ++ + static const struct file_operations ntsync_obj_fops = { + .owner = THIS_MODULE, + .release = ntsync_obj_release, ++ .unlocked_ioctl = ntsync_obj_ioctl, ++ .compat_ioctl = compat_ptr_ioctl, + .llseek = no_llseek, + }; + +@@ -64,6 +125,7 @@ static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev, + obj->type = type; + obj->dev = dev; + get_file(dev->file); ++ spin_lock_init(&obj->lock); + + return obj; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index f38818e7759d..878ec4f0f2e8 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -18,4 +18,6 @@ struct ntsync_sem_args { + + #define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args) + ++#define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) ++ + #endif +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/0004-[PATCH_RFC_5_9]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ANY..patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0003.patch similarity index 60% rename from linux-gcc/linux6.7-zen/patches/0004-[PATCH_RFC_5_9]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ANY..patch rename to linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0003.patch index 8aa8f46..e610f90 100644 --- a/linux-gcc/linux6.7-zen/patches/0004-[PATCH_RFC_5_9]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ANY..patch +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0003.patch @@ -1,31 +1,52 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 4/29] ntsync: Introduce NTSYNC_IOC_WAIT_ANY. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:31 -0600 +Message-Id: <20240131021356.10322-5-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + This corresponds to part of the functionality of the NT syscall NtWaitForMultipleObjects(). Specifically, it implements the behaviour where the third argument (wait_any) is TRUE, and it does not handle alertable waits. Those features have been split out into separate patches to ease review. +NTSYNC_IOC_WAIT_ANY is a vectored wait function similar to poll(). Unlike +poll(), it "consumes" objects when they are signaled. For semaphores, this means +decreasing one from the internal counter. At most one object can be consumed by +this function. + +Up to 64 objects can be waited on at once. As soon as one is signaled, the +object with the lowest index is consumed, and that index is returned via the +"index" field. + +A timeout is supported. The timeout is passed as a u64 nanosecond value, which +represents absolute time measured against the MONOTONIC clock. If U64_MAX is +passed, the ioctl waits indefinitely. + +This ioctl validates that all objects belong to the relevant device. This is not +necessary for any technical reason related to NTSYNC_IOC_WAIT_ANY, but will be +necessary for NTSYNC_IOC_WAIT_ALL introduced in the following patch. + Signed-off-by: Elizabeth Figura --- - drivers/misc/ntsync.c | 229 ++++++++++++++++++++++++++++++++++++ - include/uapi/linux/ntsync.h | 13 ++ - 2 files changed, 242 insertions(+) + drivers/misc/ntsync.c | 232 ++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 12 ++ + 2 files changed, 244 insertions(+) diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index d1c91c2a4f1a..2e8d3c2d51a4 100644 +index 1af38969f9a2..0a0ab755d57f 100644 --- a/drivers/misc/ntsync.c +++ b/drivers/misc/ntsync.c -@@ -23,6 +23,8 @@ struct ntsync_obj { - struct kref refcount; - spinlock_t lock; - -+ struct list_head any_waiters; -+ - enum ntsync_type type; - - /* The following fields are protected by the object lock. */ -@@ -34,6 +36,28 @@ struct ntsync_obj { +@@ -34,12 +34,55 @@ struct ntsync_obj { + __u32 max; + } sem; } u; - }; - ++ ++ struct list_head any_waiters; ++}; ++ +struct ntsync_q_entry { + struct list_head node; + struct ntsync_q *q; @@ -46,18 +67,12 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + + __u32 count; + struct ntsync_q_entry entries[]; -+}; -+ - struct ntsync_device { - struct xarray objects; }; -@@ -109,6 +133,26 @@ static void init_obj(struct ntsync_obj *obj) - { - kref_init(&obj->refcount); - spin_lock_init(&obj->lock); -+ INIT_LIST_HEAD(&obj->any_waiters); -+} -+ + + struct ntsync_device { + struct file *file; + }; + +static void try_wake_any_sem(struct ntsync_obj *sem) +{ + struct ntsync_q_entry *entry; @@ -75,22 +90,58 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + wake_up_process(q->task); + } + } - } - - static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) -@@ -194,6 +238,8 @@ static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp) ++} ++ + /* + * Actually change the semaphore state, returning -EOVERFLOW if it is made + * invalid. +@@ -73,6 +116,8 @@ static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp) prev_count = sem->u.sem.count; - ret = put_sem_state(sem, args.count); + ret = post_sem_state(sem, args); + if (!ret) + try_wake_any_sem(sem); spin_unlock(&sem->lock); -@@ -205,6 +251,187 @@ static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp) - return ret; +@@ -126,6 +171,7 @@ static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev, + obj->dev = dev; + get_file(dev->file); + spin_lock_init(&obj->lock); ++ INIT_LIST_HEAD(&obj->any_waiters); + + return obj; + } +@@ -176,6 +222,190 @@ static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) + return put_user(fd, &user_args->sem); } ++static struct ntsync_obj *get_obj(struct ntsync_device *dev, int fd) ++{ ++ struct file *file = fget(fd); ++ struct ntsync_obj *obj; ++ ++ if (file->f_op != &ntsync_obj_fops) ++ { ++ fput(file); ++ return NULL; ++ } ++ ++ obj = file->private_data; ++ if (obj->dev != dev) ++ { ++ fput(file); ++ return NULL; ++ } ++ ++ return obj; ++} ++ ++static void put_obj(struct ntsync_obj *obj) ++{ ++ fput(obj->file); ++} ++ +static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) +{ + int ret = 0; @@ -115,16 +166,14 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + +/* + * Allocate and initialize the ntsync_q structure, but do not queue us yet. -+ * Also, calculate the relative timeout. + */ +static int setup_wait(struct ntsync_device *dev, + const struct ntsync_wait_args *args, -+ ktime_t *ret_timeout, struct ntsync_q **ret_q) ++ struct ntsync_q **ret_q) +{ + const __u32 count = args->count; ++ int fds[NTSYNC_MAX_WAIT_COUNT]; + struct ntsync_q *q; -+ ktime_t timeout = 0; -+ __u32 *ids; + __u32 i, j; + + if (!args->owner || args->pad) @@ -133,31 +182,13 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + if (args->count > NTSYNC_MAX_WAIT_COUNT) + return -EINVAL; + -+ if (args->timeout) { -+ struct timespec64 to; -+ -+ if (get_timespec64(&to, u64_to_user_ptr(args->timeout))) -+ return -EFAULT; -+ if (!timespec64_valid(&to)) -+ return -EINVAL; -+ -+ timeout = timespec64_to_ns(&to); -+ } -+ -+ ids = kmalloc_array(count, sizeof(*ids), GFP_KERNEL); -+ if (!ids) -+ return -ENOMEM; -+ if (copy_from_user(ids, u64_to_user_ptr(args->objs), -+ array_size(count, sizeof(*ids)))) { -+ kfree(ids); ++ if (copy_from_user(fds, u64_to_user_ptr(args->objs), ++ array_size(count, sizeof(*fds)))) + return -EFAULT; -+ } + + q = kmalloc(struct_size(q, entries, count), GFP_KERNEL); -+ if (!q) { -+ kfree(ids); ++ if (!q) + return -ENOMEM; -+ } + q->task = current; + q->owner = args->owner; + atomic_set(&q->signaled, -1); @@ -165,7 +196,7 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + + for (i = 0; i < count; i++) { + struct ntsync_q_entry *entry = &q->entries[i]; -+ struct ntsync_obj *obj = get_obj(dev, ids[i]); ++ struct ntsync_obj *obj = get_obj(dev, fds[i]); + + if (!obj) + goto err; @@ -175,16 +206,12 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + entry->index = i; + } + -+ kfree(ids); -+ + *ret_q = q; -+ *ret_timeout = timeout; + return 0; + +err: + for (j = 0; j < i; j++) + put_obj(q->entries[j].obj); -+ kfree(ids); + kfree(q); + return -EINVAL; +} @@ -210,7 +237,7 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + if (copy_from_user(&args, argp, sizeof(args))) + return -EFAULT; + -+ ret = setup_wait(dev, &args, &timeout, &q); ++ ret = setup_wait(dev, &args, &q); + if (ret < 0) + return ret; + @@ -240,7 +267,8 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + + /* sleep */ + -+ ret = ntsync_schedule(q, args.timeout ? &timeout : NULL); ++ timeout = ns_to_ktime(args.timeout); ++ ret = ntsync_schedule(q, args.timeout == U64_MAX ? NULL : &timeout); + + /* and finally, unqueue */ + @@ -272,23 +300,23 @@ index d1c91c2a4f1a..2e8d3c2d51a4 100644 + return ret; +} + - static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) + static int ntsync_char_open(struct inode *inode, struct file *file) { -@@ -218,6 +445,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - return ntsync_delete(dev, argp); - case NTSYNC_IOC_PUT_SEM: - return ntsync_put_sem(dev, argp); + struct ntsync_device *dev; +@@ -207,6 +437,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + switch (cmd) { + case NTSYNC_IOC_CREATE_SEM: + return ntsync_create_sem(dev, argp); + case NTSYNC_IOC_WAIT_ANY: + return ntsync_wait_any(dev, argp); default: return -ENOIOCTLCMD; } diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -index 8c610d65f8ef..10f07da7864e 100644 +index 878ec4f0f2e8..9cd1dd05d971 100644 --- a/include/uapi/linux/ntsync.h +++ b/include/uapi/linux/ntsync.h -@@ -16,6 +16,17 @@ struct ntsync_sem_args { +@@ -16,7 +16,19 @@ struct ntsync_sem_args { __u32 max; }; @@ -303,16 +331,11 @@ index 8c610d65f8ef..10f07da7864e 100644 + +#define NTSYNC_MAX_WAIT_COUNT 64 + - #define NTSYNC_IOC_BASE 0xf7 + #define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args) ++#define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args) - #define NTSYNC_IOC_CREATE_SEM _IOWR(NTSYNC_IOC_BASE, 0, \ -@@ -23,5 +34,7 @@ struct ntsync_sem_args { - #define NTSYNC_IOC_DELETE _IOW (NTSYNC_IOC_BASE, 1, __u32) - #define NTSYNC_IOC_PUT_SEM _IOWR(NTSYNC_IOC_BASE, 2, \ - struct ntsync_sem_args) -+#define NTSYNC_IOC_WAIT_ANY _IOWR(NTSYNC_IOC_BASE, 3, \ -+ struct ntsync_wait_args) + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) - #endif -- 2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/0005-[PATCH_RFC_6_9]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ALL..patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0004.patch similarity index 67% rename from linux-gcc/linux6.7-zen/patches/0005-[PATCH_RFC_6_9]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ALL..patch rename to linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0004.patch index c63ef03..34eac82 100644 --- a/linux-gcc/linux6.7-zen/patches/0005-[PATCH_RFC_6_9]_ntsync:_Introduce_NTSYNC_IOC_WAIT_ALL..patch +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0004.patch @@ -1,21 +1,29 @@ -This corresponds to part of the functionality of the NT syscall -NtWaitForMultipleObjects(). Specifically, it implements the behaviour where -the third argument (wait_any) is FALSE, and it does not yet handle alertable -waits. +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 5/29] ntsync: Introduce NTSYNC_IOC_WAIT_ALL. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:32 -0600 +Message-Id: <20240131021356.10322-6-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This is similar to NTSYNC_IOC_WAIT_ANY, but waits until all of the objects are +simultaneously signaled, and then acquires all of them as a single atomic +operation. Signed-off-by: Elizabeth Figura --- - drivers/misc/ntsync.c | 241 ++++++++++++++++++++++++++++++++++-- - include/uapi/linux/ntsync.h | 2 + - 2 files changed, 235 insertions(+), 8 deletions(-) + drivers/misc/ntsync.c | 244 ++++++++++++++++++++++++++++++++++-- + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 237 insertions(+), 8 deletions(-) diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index 2e8d3c2d51a4..2685363fae9e 100644 +index 0a0ab755d57f..b86d62094344 100644 --- a/drivers/misc/ntsync.c +++ b/drivers/misc/ntsync.c -@@ -23,7 +23,34 @@ struct ntsync_obj { - struct kref refcount; - spinlock_t lock; +@@ -35,7 +35,34 @@ struct ntsync_obj { + } sem; + } u; + /* + * any_waiters is protected by the object lock, but all_waiters is @@ -33,22 +41,22 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + * lock all of the objects, and that means grabbing the wait_all_lock + * below (and, due to lock ordering rules, before locking this object). + * However, wait-all is a rare operation, and grabbing the wait-all -+ * lock for every wake would create unnecessary contention. Therefore we -+ * first check whether all_hint is zero, and, if it is, we skip trying -+ * to wake "all" waiters. ++ * lock for every wake would create unnecessary contention. ++ * Therefore we first check whether all_hint is zero, and, if it is, ++ * we skip trying to wake "all" waiters. + * + * This hint isn't protected by any lock. It might change during the + * course of a wake, but there's no meaningful race there; it's only a + * hint. + * + * Since wait requests must originate from user-space threads, we're -+ * limited here by PID_MAX_LIMIT, so there's no risk of saturation. ++ * limited here by PID_MAX_LIMIT, so there's no risk of overflow. + */ + atomic_t all_hint; + }; - enum ntsync_type type; - -@@ -54,11 +81,25 @@ struct ntsync_q { + struct ntsync_q_entry { +@@ -56,14 +83,99 @@ struct ntsync_q { */ atomic_t signaled; @@ -60,9 +68,9 @@ index 2e8d3c2d51a4..2685363fae9e 100644 struct ntsync_device { + /* + * Wait-all operations must atomically grab all objects, and be totally -+ * ordered with respect to each other and wait-any operations. If one -+ * thread is trying to acquire several objects, another thread cannot -+ * touch the object at the same time. ++ * ordered with respect to each other and wait-any operations. ++ * If one thread is trying to acquire several objects, another thread ++ * cannot touch the object at the same time. + * + * We achieve this by grabbing multiple object locks at the same time. + * However, this creates a lock ordering problem. To solve that problem, @@ -71,28 +79,9 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + */ + spinlock_t wait_all_lock; + - struct xarray objects; + struct file *file; }; -@@ -107,6 +148,8 @@ static int ntsync_char_open(struct inode *inode, struct file *file) - if (!dev) - return -ENOMEM; - -+ spin_lock_init(&dev->wait_all_lock); -+ - xa_init_flags(&dev->objects, XA_FLAGS_ALLOC); - - file->private_data = dev; -@@ -132,8 +175,81 @@ static int ntsync_char_release(struct inode *inode, struct file *file) - static void init_obj(struct ntsync_obj *obj) - { - kref_init(&obj->refcount); -+ atomic_set(&obj->all_hint, 0); - spin_lock_init(&obj->lock); - INIT_LIST_HEAD(&obj->any_waiters); -+ INIT_LIST_HEAD(&obj->all_waiters); -+} -+ +static bool is_signaled(struct ntsync_obj *obj, __u32 owner) +{ + lockdep_assert_held(&obj->lock); @@ -162,11 +151,21 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + + list_for_each_entry(entry, &obj->all_waiters, node) + try_wake_all(dev, entry->q, obj); - } - ++} ++ static void try_wake_any_sem(struct ntsync_obj *sem) -@@ -234,14 +350,29 @@ static int ntsync_put_sem(struct ntsync_device *dev, void __user *argp) - if (!sem) + { + struct ntsync_q_entry *entry; +@@ -101,6 +213,7 @@ static int post_sem_state(struct ntsync_obj *sem, __u32 count) + + static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp) + { ++ struct ntsync_device *dev = sem->dev; + __u32 __user *user_args = argp; + __u32 prev_count; + __u32 args; +@@ -112,14 +225,29 @@ static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp) + if (sem->type != NTSYNC_TYPE_SEM) return -EINVAL; - spin_lock(&sem->lock); @@ -175,11 +174,11 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + spin_lock_nest_lock(&sem->lock, &dev->wait_all_lock); - prev_count = sem->u.sem.count; -- ret = put_sem_state(sem, args.count); +- ret = post_sem_state(sem, args); - if (!ret) - try_wake_any_sem(sem); + prev_count = sem->u.sem.count; -+ ret = put_sem_state(sem, args.count); ++ ret = post_sem_state(sem, args); + if (!ret) { + try_wake_all_obj(dev, sem); + try_wake_any_sem(sem); @@ -192,25 +191,34 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + spin_lock(&sem->lock); + + prev_count = sem->u.sem.count; -+ ret = put_sem_state(sem, args.count); ++ ret = post_sem_state(sem, args); + if (!ret) + try_wake_any_sem(sem); + + spin_unlock(&sem->lock); + } - put_obj(sem); + if (!ret && put_user(prev_count, user_args)) + ret = -EFAULT; +@@ -172,6 +300,8 @@ static struct ntsync_obj *ntsync_alloc_obj(struct ntsync_device *dev, + get_file(dev->file); + spin_lock_init(&obj->lock); + INIT_LIST_HEAD(&obj->any_waiters); ++ INIT_LIST_HEAD(&obj->all_waiters); ++ atomic_set(&obj->all_hint, 0); -@@ -278,7 +409,7 @@ static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) - * Also, calculate the relative timeout. + return obj; + } +@@ -274,7 +404,7 @@ static int ntsync_schedule(const struct ntsync_q *q, ktime_t *timeout) + * Allocate and initialize the ntsync_q structure, but do not queue us yet. */ static int setup_wait(struct ntsync_device *dev, - const struct ntsync_wait_args *args, + const struct ntsync_wait_args *args, bool all, - ktime_t *ret_timeout, struct ntsync_q **ret_q) + struct ntsync_q **ret_q) { const __u32 count = args->count; -@@ -321,6 +452,7 @@ static int setup_wait(struct ntsync_device *dev, +@@ -298,6 +428,7 @@ static int setup_wait(struct ntsync_device *dev, q->task = current; q->owner = args->owner; atomic_set(&q->signaled, -1); @@ -218,7 +226,7 @@ index 2e8d3c2d51a4..2685363fae9e 100644 q->count = count; for (i = 0; i < count; i++) { -@@ -330,6 +462,16 @@ static int setup_wait(struct ntsync_device *dev, +@@ -307,6 +438,16 @@ static int setup_wait(struct ntsync_device *dev, if (!obj) goto err; @@ -235,16 +243,16 @@ index 2e8d3c2d51a4..2685363fae9e 100644 entry->obj = obj; entry->q = q; entry->index = i; -@@ -370,7 +512,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) +@@ -343,7 +484,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) if (copy_from_user(&args, argp, sizeof(args))) return -EFAULT; -- ret = setup_wait(dev, &args, &timeout, &q); -+ ret = setup_wait(dev, &args, false, &timeout, &q); +- ret = setup_wait(dev, &args, &q); ++ ret = setup_wait(dev, &args, false, &q); if (ret < 0) return ret; -@@ -432,6 +574,87 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) +@@ -406,6 +547,89 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) return ret; } @@ -260,7 +268,7 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + if (copy_from_user(&args, argp, sizeof(args))) + return -EFAULT; + -+ ret = setup_wait(dev, &args, true, &timeout, &q); ++ ret = setup_wait(dev, &args, true, &q); + if (ret < 0) + return ret; + @@ -276,7 +284,8 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + + /* + * obj->all_waiters is protected by dev->wait_all_lock rather -+ * than obj->lock, so there is no need to acquire it here. ++ * than obj->lock, so there is no need to acquire obj->lock ++ * here. + */ + list_add_tail(&entry->node, &obj->all_waiters); + } @@ -289,7 +298,8 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + + /* sleep */ + -+ ret = ntsync_schedule(q, args.timeout ? &timeout : NULL); ++ timeout = ns_to_ktime(args.timeout); ++ ret = ntsync_schedule(q, args.timeout == U64_MAX ? NULL : &timeout); + + /* and finally, unqueue */ + @@ -329,29 +339,39 @@ index 2e8d3c2d51a4..2685363fae9e 100644 + return ret; +} + - static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - unsigned long parm) + static int ntsync_char_open(struct inode *inode, struct file *file) { -@@ -445,6 +668,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, - return ntsync_delete(dev, argp); - case NTSYNC_IOC_PUT_SEM: - return ntsync_put_sem(dev, argp); + struct ntsync_device *dev; +@@ -414,6 +638,8 @@ static int ntsync_char_open(struct inode *inode, struct file *file) + if (!dev) + return -ENOMEM; + ++ spin_lock_init(&dev->wait_all_lock); ++ + file->private_data = dev; + dev->file = file; + return nonseekable_open(inode, file); +@@ -437,6 +663,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + switch (cmd) { + case NTSYNC_IOC_CREATE_SEM: + return ntsync_create_sem(dev, argp); + case NTSYNC_IOC_WAIT_ALL: + return ntsync_wait_all(dev, argp); case NTSYNC_IOC_WAIT_ANY: return ntsync_wait_any(dev, argp); default: diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -index 10f07da7864e..a5bed5a39b21 100644 +index 9cd1dd05d971..524404f6aceb 100644 --- a/include/uapi/linux/ntsync.h +++ b/include/uapi/linux/ntsync.h -@@ -36,5 +36,7 @@ struct ntsync_wait_args { - struct ntsync_sem_args) - #define NTSYNC_IOC_WAIT_ANY _IOWR(NTSYNC_IOC_BASE, 3, \ - struct ntsync_wait_args) -+#define NTSYNC_IOC_WAIT_ALL _IOWR(NTSYNC_IOC_BASE, 4, \ -+ struct ntsync_wait_args) +@@ -29,6 +29,7 @@ struct ntsync_wait_args { + + #define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args) + #define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args) ++#define NTSYNC_IOC_WAIT_ALL _IOWR('N', 0x83, struct ntsync_wait_args) + + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) - #endif -- 2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/0006-[PATCH_RFC_7_9]_ntsync:_Introduce_NTSYNC_IOC_CREATE_MUTEX..patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0005.patch similarity index 54% rename from linux-gcc/linux6.7-zen/patches/0006-[PATCH_RFC_7_9]_ntsync:_Introduce_NTSYNC_IOC_CREATE_MUTEX..patch rename to linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0005.patch index 5ed169a..54baae5 100644 --- a/linux-gcc/linux6.7-zen/patches/0006-[PATCH_RFC_7_9]_ntsync:_Introduce_NTSYNC_IOC_CREATE_MUTEX..patch +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0005.patch @@ -1,16 +1,35 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 6/29] ntsync: Introduce NTSYNC_IOC_CREATE_MUTEX. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:33 -0600 +Message-Id: <20240131021356.10322-7-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + This corresponds to the NT syscall NtCreateMutant(). +An NT mutex is recursive, with a 32-bit recursion counter. When acquired via +NtWaitForMultipleObjects(), the recursion counter is incremented by one. + +The OS records the thread which acquired it. However, in order to keep this +driver self-contained, the owning thread ID is managed by user-space, and passed +as a parameter to all relevant ioctls. + +The initial owner and recursion count, if any, are specified when the mutex is +created. + Signed-off-by: Elizabeth Figura --- - drivers/misc/ntsync.c | 72 +++++++++++++++++++++++++++++++++++++ - include/uapi/linux/ntsync.h | 8 +++++ - 2 files changed, 80 insertions(+) + drivers/misc/ntsync.c | 67 +++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 7 ++++ + 2 files changed, 74 insertions(+) diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c -index 2685363fae9e..d48f2ef41341 100644 +index b86d62094344..484219a266ae 100644 --- a/drivers/misc/ntsync.c +++ b/drivers/misc/ntsync.c -@@ -16,6 +16,7 @@ +@@ -17,6 +17,7 @@ enum ntsync_type { NTSYNC_TYPE_SEM, @@ -18,7 +37,7 @@ index 2685363fae9e..d48f2ef41341 100644 }; struct ntsync_obj { -@@ -60,6 +61,10 @@ struct ntsync_obj { +@@ -33,6 +34,10 @@ struct ntsync_obj { __u32 count; __u32 max; } sem; @@ -27,9 +46,9 @@ index 2685363fae9e..d48f2ef41341 100644 + __u32 owner; + } mutex; } u; - }; -@@ -188,6 +193,10 @@ static bool is_signaled(struct ntsync_obj *obj, __u32 owner) + /* +@@ -112,6 +117,10 @@ static bool is_signaled(struct ntsync_obj *obj, __u32 owner) switch (obj->type) { case NTSYNC_TYPE_SEM: return !!obj->u.sem.count; @@ -40,7 +59,7 @@ index 2685363fae9e..d48f2ef41341 100644 } WARN(1, "bad object type %#x\n", obj->type); -@@ -230,6 +239,10 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, +@@ -154,6 +163,10 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, case NTSYNC_TYPE_SEM: obj->u.sem.count--; break; @@ -51,7 +70,7 @@ index 2685363fae9e..d48f2ef41341 100644 } } wake_up_process(q->task); -@@ -271,6 +284,28 @@ static void try_wake_any_sem(struct ntsync_obj *sem) +@@ -195,6 +208,28 @@ static void try_wake_any_sem(struct ntsync_obj *sem) } } @@ -77,11 +96,11 @@ index 2685363fae9e..d48f2ef41341 100644 + } +} + - static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) - { - struct ntsync_sem_args __user *user_args = argp; -@@ -303,6 +338,38 @@ static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) - return put_user(id, &user_args->sem); + /* + * Actually change the semaphore state, returning -EOVERFLOW if it is made + * invalid. +@@ -352,6 +387,33 @@ static int ntsync_create_sem(struct ntsync_device *dev, void __user *argp) + return put_user(fd, &user_args->sem); } +static int ntsync_create_mutex(struct ntsync_device *dev, void __user *argp) @@ -89,8 +108,7 @@ index 2685363fae9e..d48f2ef41341 100644 + struct ntsync_mutex_args __user *user_args = argp; + struct ntsync_mutex_args args; + struct ntsync_obj *mutex; -+ __u32 id; -+ int ret; ++ int fd; + + if (copy_from_user(&args, argp, sizeof(args))) + return -EFAULT; @@ -98,28 +116,24 @@ index 2685363fae9e..d48f2ef41341 100644 + if (!args.owner != !args.count) + return -EINVAL; + -+ mutex = kzalloc(sizeof(*mutex), GFP_KERNEL); ++ mutex = ntsync_alloc_obj(dev, NTSYNC_TYPE_MUTEX); + if (!mutex) + return -ENOMEM; -+ -+ init_obj(mutex); -+ mutex->type = NTSYNC_TYPE_MUTEX; + mutex->u.mutex.count = args.count; + mutex->u.mutex.owner = args.owner; -+ -+ ret = xa_alloc(&dev->objects, &id, mutex, xa_limit_32b, GFP_KERNEL); -+ if (ret < 0) { ++ fd = ntsync_obj_get_fd(mutex); ++ if (fd < 0) { + kfree(mutex); -+ return ret; ++ return fd; + } + -+ return put_user(id, &user_args->mutex); ++ return put_user(fd, &user_args->mutex); +} + - static int ntsync_delete(struct ntsync_device *dev, void __user *argp) + static struct ntsync_obj *get_obj(struct ntsync_device *dev, int fd) { - struct ntsync_obj *obj; -@@ -497,6 +564,9 @@ static void try_wake_any_obj(struct ntsync_obj *obj) + struct file *file = fget(fd); +@@ -469,6 +531,9 @@ static void try_wake_any_obj(struct ntsync_obj *obj) case NTSYNC_TYPE_SEM: try_wake_any_sem(obj); break; @@ -129,7 +143,7 @@ index 2685363fae9e..d48f2ef41341 100644 } } -@@ -662,6 +732,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, +@@ -661,6 +726,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, void __user *argp = (void __user *)parm; switch (cmd) { @@ -137,9 +151,9 @@ index 2685363fae9e..d48f2ef41341 100644 + return ntsync_create_mutex(dev, argp); case NTSYNC_IOC_CREATE_SEM: return ntsync_create_sem(dev, argp); - case NTSYNC_IOC_DELETE: + case NTSYNC_IOC_WAIT_ALL: diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h -index a5bed5a39b21..26d1b3d4847f 100644 +index 524404f6aceb..d68f24fd75a2 100644 --- a/include/uapi/linux/ntsync.h +++ b/include/uapi/linux/ntsync.h @@ -16,6 +16,12 @@ struct ntsync_sem_args { @@ -155,13 +169,14 @@ index a5bed5a39b21..26d1b3d4847f 100644 struct ntsync_wait_args { __u64 timeout; __u64 objs; -@@ -38,5 +44,7 @@ struct ntsync_wait_args { - struct ntsync_wait_args) - #define NTSYNC_IOC_WAIT_ALL _IOWR(NTSYNC_IOC_BASE, 4, \ - struct ntsync_wait_args) -+#define NTSYNC_IOC_CREATE_MUTEX _IOWR(NTSYNC_IOC_BASE, 5, \ -+ struct ntsync_mutex_args) +@@ -30,6 +36,7 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_CREATE_SEM _IOWR('N', 0x80, struct ntsync_sem_args) + #define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args) + #define NTSYNC_IOC_WAIT_ALL _IOWR('N', 0x83, struct ntsync_wait_args) ++#define NTSYNC_IOC_CREATE_MUTEX _IOWR('N', 0x84, struct ntsync_sem_args) + + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) - #endif -- 2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0006.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0006.patch new file mode 100644 index 0000000..f88e505 --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0006.patch @@ -0,0 +1,117 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 7/29] ntsync: Introduce NTSYNC_IOC_MUTEX_UNLOCK. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:34 -0600 +Message-Id: <20240131021356.10322-8-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This corresponds to the NT syscall NtReleaseMutant(). + +This syscall decrements the mutex's recursion count by one, and returns the +previous value. If the mutex is not owned by the given owner ID, the function +instead fails and returns -EPERM. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 64 +++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 65 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 484219a266ae..1770ec4008af 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -290,6 +290,68 @@ static int ntsync_sem_post(struct ntsync_obj *sem, void __user *argp) + return ret; + } + ++/* ++ * Actually change the mutex state, returning -EPERM if not the owner. ++ */ ++static int unlock_mutex_state(struct ntsync_obj *mutex, ++ const struct ntsync_mutex_args *args) ++{ ++ lockdep_assert_held(&mutex->lock); ++ ++ if (mutex->u.mutex.owner != args->owner) ++ return -EPERM; ++ ++ if (!--mutex->u.mutex.count) ++ mutex->u.mutex.owner = 0; ++ return 0; ++} ++ ++static int ntsync_mutex_unlock(struct ntsync_obj *mutex, void __user *argp) ++{ ++ struct ntsync_mutex_args __user *user_args = argp; ++ struct ntsync_device *dev = mutex->dev; ++ struct ntsync_mutex_args args; ++ __u32 prev_count; ++ int ret; ++ ++ if (copy_from_user(&args, argp, sizeof(args))) ++ return -EFAULT; ++ if (!args.owner) ++ return -EINVAL; ++ ++ if (mutex->type != NTSYNC_TYPE_MUTEX) ++ return -EINVAL; ++ ++ if (atomic_read(&mutex->all_hint) > 0) { ++ spin_lock(&dev->wait_all_lock); ++ spin_lock_nest_lock(&mutex->lock, &dev->wait_all_lock); ++ ++ prev_count = mutex->u.mutex.count; ++ ret = unlock_mutex_state(mutex, &args); ++ if (!ret) { ++ try_wake_all_obj(dev, mutex); ++ try_wake_any_mutex(mutex); ++ } ++ ++ spin_unlock(&mutex->lock); ++ spin_unlock(&dev->wait_all_lock); ++ } else { ++ spin_lock(&mutex->lock); ++ ++ prev_count = mutex->u.mutex.count; ++ ret = unlock_mutex_state(mutex, &args); ++ if (!ret) ++ try_wake_any_mutex(mutex); ++ ++ spin_unlock(&mutex->lock); ++ } ++ ++ if (!ret && put_user(prev_count, &user_args->count)) ++ ret = -EFAULT; ++ ++ return ret; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -309,6 +371,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + switch (cmd) { + case NTSYNC_IOC_SEM_POST: + return ntsync_sem_post(obj, argp); ++ case NTSYNC_IOC_MUTEX_UNLOCK: ++ return ntsync_mutex_unlock(obj, argp); + default: + return -ENOIOCTLCMD; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index d68f24fd75a2..a3f5f4f13798 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -39,5 +39,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_CREATE_MUTEX _IOWR('N', 0x84, struct ntsync_sem_args) + + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) ++#define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args) + + #endif +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0007.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0007.patch new file mode 100644 index 0000000..c49854a --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0007.patch @@ -0,0 +1,176 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 8/29] ntsync: Introduce NTSYNC_IOC_MUTEX_KILL. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:35 -0600 +Message-Id: <20240131021356.10322-9-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This does not correspond to any NT syscall. Rather, when a thread dies, it +should be called by the NT emulator for each mutex. + +NT mutexes are robust (in the pthread sense). When an NT thread dies, any +mutexes it owned are immediately released. Acquisition of those mutexes by other +threads will return a special value indicating that the mutex was abandoned, +like EOWNERDEAD returned from pthread_mutex_lock(), and EOWNERDEAD is indeed +used here for that purpose. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 71 +++++++++++++++++++++++++++++++++++-- + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 70 insertions(+), 2 deletions(-) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 1770ec4008af..aadf01c65ca0 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -37,6 +37,7 @@ struct ntsync_obj { + struct { + __u32 count; + __u32 owner; ++ bool ownerdead; + } mutex; + } u; + +@@ -89,6 +90,7 @@ struct ntsync_q { + atomic_t signaled; + + bool all; ++ bool ownerdead; + __u32 count; + struct ntsync_q_entry entries[]; + }; +@@ -164,6 +166,9 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, + obj->u.sem.count--; + break; + case NTSYNC_TYPE_MUTEX: ++ if (obj->u.mutex.ownerdead) ++ q->ownerdead = true; ++ obj->u.mutex.ownerdead = false; + obj->u.mutex.count++; + obj->u.mutex.owner = q->owner; + break; +@@ -223,6 +228,9 @@ static void try_wake_any_mutex(struct ntsync_obj *mutex) + continue; + + if (atomic_cmpxchg(&q->signaled, -1, entry->index) == -1) { ++ if (mutex->u.mutex.ownerdead) ++ q->ownerdead = true; ++ mutex->u.mutex.ownerdead = false; + mutex->u.mutex.count++; + mutex->u.mutex.owner = q->owner; + wake_up_process(q->task); +@@ -352,6 +360,62 @@ static int ntsync_mutex_unlock(struct ntsync_obj *mutex, void __user *argp) + return ret; + } + ++/* ++ * Actually change the mutex state to mark its owner as dead, ++ * returning -EPERM if not the owner. ++ */ ++static int kill_mutex_state(struct ntsync_obj *mutex, __u32 owner) ++{ ++ lockdep_assert_held(&mutex->lock); ++ ++ if (mutex->u.mutex.owner != owner) ++ return -EPERM; ++ ++ mutex->u.mutex.ownerdead = true; ++ mutex->u.mutex.owner = 0; ++ mutex->u.mutex.count = 0; ++ return 0; ++} ++ ++static int ntsync_mutex_kill(struct ntsync_obj *mutex, void __user *argp) ++{ ++ struct ntsync_device *dev = mutex->dev; ++ __u32 owner; ++ int ret; ++ ++ if (get_user(owner, (__u32 __user *)argp)) ++ return -EFAULT; ++ if (!owner) ++ return -EINVAL; ++ ++ if (mutex->type != NTSYNC_TYPE_MUTEX) ++ return -EINVAL; ++ ++ if (atomic_read(&mutex->all_hint) > 0) { ++ spin_lock(&dev->wait_all_lock); ++ spin_lock_nest_lock(&mutex->lock, &dev->wait_all_lock); ++ ++ ret = kill_mutex_state(mutex, owner); ++ if (!ret) { ++ try_wake_all_obj(dev, mutex); ++ try_wake_any_mutex(mutex); ++ } ++ ++ spin_unlock(&mutex->lock); ++ spin_unlock(&dev->wait_all_lock); ++ } else { ++ spin_lock(&mutex->lock); ++ ++ ret = kill_mutex_state(mutex, owner); ++ if (!ret) ++ try_wake_any_mutex(mutex); ++ ++ spin_unlock(&mutex->lock); ++ } ++ ++ return ret; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -373,6 +437,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + return ntsync_sem_post(obj, argp); + case NTSYNC_IOC_MUTEX_UNLOCK: + return ntsync_mutex_unlock(obj, argp); ++ case NTSYNC_IOC_MUTEX_KILL: ++ return ntsync_mutex_kill(obj, argp); + default: + return -ENOIOCTLCMD; + } +@@ -555,6 +621,7 @@ static int setup_wait(struct ntsync_device *dev, + q->owner = args->owner; + atomic_set(&q->signaled, -1); + q->all = all; ++ q->ownerdead = false; + q->count = count; + + for (i = 0; i < count; i++) { +@@ -664,7 +731,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) + struct ntsync_wait_args __user *user_args = argp; + + /* even if we caught a signal, we need to communicate success */ +- ret = 0; ++ ret = q->ownerdead ? -EOWNERDEAD : 0; + + if (put_user(signaled, &user_args->index)) + ret = -EFAULT; +@@ -747,7 +814,7 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp) + struct ntsync_wait_args __user *user_args = argp; + + /* even if we caught a signal, we need to communicate success */ +- ret = 0; ++ ret = q->ownerdead ? -EOWNERDEAD : 0; + + if (put_user(signaled, &user_args->index)) + ret = -EFAULT; +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index a3f5f4f13798..3861397c6c2f 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -40,5 +40,6 @@ struct ntsync_wait_args { + + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) + #define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args) ++#define NTSYNC_IOC_MUTEX_KILL _IOW ('N', 0x86, __u32) + + #endif +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0008.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0008.patch new file mode 100644 index 0000000..623bf23 --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0008.patch @@ -0,0 +1,175 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 9/29] ntsync: Introduce NTSYNC_IOC_CREATE_EVENT. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:36 -0600 +Message-Id: <20240131021356.10322-10-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This correspond to the NT syscall NtCreateEvent(). + +An NT event holds a single bit of state denoting whether it is signaled or +unsignaled. + +There are two types of events: manual-reset and automatic-reset. When an +automatic-reset event is acquired via a wait function, its state is reset to +unsignaled. Manual-reset events are not affected by wait functions. + +Whether the event is manual-reset, and its initial state, are specified at +creation time. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 60 +++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 7 +++++ + 2 files changed, 67 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index aadf01c65ca0..c719ddd9f6d7 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -18,6 +18,7 @@ + enum ntsync_type { + NTSYNC_TYPE_SEM, + NTSYNC_TYPE_MUTEX, ++ NTSYNC_TYPE_EVENT, + }; + + struct ntsync_obj { +@@ -39,6 +40,10 @@ struct ntsync_obj { + __u32 owner; + bool ownerdead; + } mutex; ++ struct { ++ bool manual; ++ bool signaled; ++ } event; + } u; + + /* +@@ -123,6 +128,8 @@ static bool is_signaled(struct ntsync_obj *obj, __u32 owner) + if (obj->u.mutex.owner && obj->u.mutex.owner != owner) + return false; + return obj->u.mutex.count < UINT_MAX; ++ case NTSYNC_TYPE_EVENT: ++ return obj->u.event.signaled; + } + + WARN(1, "bad object type %#x\n", obj->type); +@@ -172,6 +179,10 @@ static void try_wake_all(struct ntsync_device *dev, struct ntsync_q *q, + obj->u.mutex.count++; + obj->u.mutex.owner = q->owner; + break; ++ case NTSYNC_TYPE_EVENT: ++ if (!obj->u.event.manual) ++ obj->u.event.signaled = false; ++ break; + } + } + wake_up_process(q->task); +@@ -238,6 +249,26 @@ static void try_wake_any_mutex(struct ntsync_obj *mutex) + } + } + ++static void try_wake_any_event(struct ntsync_obj *event) ++{ ++ struct ntsync_q_entry *entry; ++ ++ lockdep_assert_held(&event->lock); ++ ++ list_for_each_entry(entry, &event->any_waiters, node) { ++ struct ntsync_q *q = entry->q; ++ ++ if (!event->u.event.signaled) ++ break; ++ ++ if (atomic_cmpxchg(&q->signaled, -1, entry->index) == -1) { ++ if (!event->u.event.manual) ++ event->u.event.signaled = false; ++ wake_up_process(q->task); ++ } ++ } ++} ++ + /* + * Actually change the semaphore state, returning -EOVERFLOW if it is made + * invalid. +@@ -544,6 +575,30 @@ static int ntsync_create_mutex(struct ntsync_device *dev, void __user *argp) + return put_user(fd, &user_args->mutex); + } + ++static int ntsync_create_event(struct ntsync_device *dev, void __user *argp) ++{ ++ struct ntsync_event_args __user *user_args = argp; ++ struct ntsync_event_args args; ++ struct ntsync_obj *event; ++ int fd; ++ ++ if (copy_from_user(&args, argp, sizeof(args))) ++ return -EFAULT; ++ ++ event = ntsync_alloc_obj(dev, NTSYNC_TYPE_EVENT); ++ if (!event) ++ return -ENOMEM; ++ event->u.event.manual = args.manual; ++ event->u.event.signaled = args.signaled; ++ fd = ntsync_obj_get_fd(event); ++ if (fd < 0) { ++ kfree(event); ++ return fd; ++ } ++ ++ return put_user(fd, &user_args->event); ++} ++ + static struct ntsync_obj *get_obj(struct ntsync_device *dev, int fd) + { + struct file *file = fget(fd); +@@ -665,6 +720,9 @@ static void try_wake_any_obj(struct ntsync_obj *obj) + case NTSYNC_TYPE_MUTEX: + try_wake_any_mutex(obj); + break; ++ case NTSYNC_TYPE_EVENT: ++ try_wake_any_event(obj); ++ break; + } + } + +@@ -857,6 +915,8 @@ static long ntsync_char_ioctl(struct file *file, unsigned int cmd, + void __user *argp = (void __user *)parm; + + switch (cmd) { ++ case NTSYNC_IOC_CREATE_EVENT: ++ return ntsync_create_event(dev, argp); + case NTSYNC_IOC_CREATE_MUTEX: + return ntsync_create_mutex(dev, argp); + case NTSYNC_IOC_CREATE_SEM: +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 3861397c6c2f..b8cf503365ef 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -22,6 +22,12 @@ struct ntsync_mutex_args { + __u32 count; + }; + ++struct ntsync_event_args { ++ __u32 event; ++ __u32 manual; ++ __u32 signaled; ++}; ++ + struct ntsync_wait_args { + __u64 timeout; + __u64 objs; +@@ -37,6 +43,7 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_WAIT_ANY _IOWR('N', 0x82, struct ntsync_wait_args) + #define NTSYNC_IOC_WAIT_ALL _IOWR('N', 0x83, struct ntsync_wait_args) + #define NTSYNC_IOC_CREATE_MUTEX _IOWR('N', 0x84, struct ntsync_sem_args) ++#define NTSYNC_IOC_CREATE_EVENT _IOWR('N', 0x87, struct ntsync_event_args) + + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) + #define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args) +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0009.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0009.patch new file mode 100644 index 0000000..6411060 --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0009.patch @@ -0,0 +1,88 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 10/29] ntsync: Introduce NTSYNC_IOC_EVENT_SET. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:37 -0600 +Message-Id: <20240131021356.10322-11-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This corresponds to the NT syscall NtSetEvent(). + +This sets the event to the signaled state, and returns its previous state. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 37 +++++++++++++++++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 38 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index c719ddd9f6d7..b2da50989953 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -447,6 +447,41 @@ static int ntsync_mutex_kill(struct ntsync_obj *mutex, void __user *argp) + return ret; + } + ++static int ntsync_event_set(struct ntsync_obj *event, void __user *argp) ++{ ++ struct ntsync_device *dev = event->dev; ++ __u32 prev_state; ++ ++ if (event->type != NTSYNC_TYPE_EVENT) ++ return -EINVAL; ++ ++ if (atomic_read(&event->all_hint) > 0) { ++ spin_lock(&dev->wait_all_lock); ++ spin_lock_nest_lock(&event->lock, &dev->wait_all_lock); ++ ++ prev_state = event->u.event.signaled; ++ event->u.event.signaled = true; ++ try_wake_all_obj(dev, event); ++ try_wake_any_event(event); ++ ++ spin_unlock(&event->lock); ++ spin_unlock(&dev->wait_all_lock); ++ } else { ++ spin_lock(&event->lock); ++ ++ prev_state = event->u.event.signaled; ++ event->u.event.signaled = true; ++ try_wake_any_event(event); ++ ++ spin_unlock(&event->lock); ++ } ++ ++ if (put_user(prev_state, (__u32 __user *)argp)) ++ return -EFAULT; ++ ++ return 0; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -470,6 +505,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + return ntsync_mutex_unlock(obj, argp); + case NTSYNC_IOC_MUTEX_KILL: + return ntsync_mutex_kill(obj, argp); ++ case NTSYNC_IOC_EVENT_SET: ++ return ntsync_event_set(obj, argp); + default: + return -ENOIOCTLCMD; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index b8cf503365ef..782057552483 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -48,5 +48,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_SEM_POST _IOWR('N', 0x81, __u32) + #define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args) + #define NTSYNC_IOC_MUTEX_KILL _IOW ('N', 0x86, __u32) ++#define NTSYNC_IOC_EVENT_SET _IOR ('N', 0x88, __u32) + + #endif +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0010.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0010.patch new file mode 100644 index 0000000..36501b9 --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0010.patch @@ -0,0 +1,73 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 11/29] ntsync: Introduce NTSYNC_IOC_EVENT_RESET. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:38 -0600 +Message-Id: <20240131021356.10322-12-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This corresponds to the NT syscall NtResetEvent(). + +This sets the event to the unsignaled state, and returns its previous state. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 22 ++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 23 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index b2da50989953..009d927739b8 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -482,6 +482,26 @@ static int ntsync_event_set(struct ntsync_obj *event, void __user *argp) + return 0; + } + ++static int ntsync_event_reset(struct ntsync_obj *event, void __user *argp) ++{ ++ __u32 prev_state; ++ ++ if (event->type != NTSYNC_TYPE_EVENT) ++ return -EINVAL; ++ ++ spin_lock(&event->lock); ++ ++ prev_state = event->u.event.signaled; ++ event->u.event.signaled = false; ++ ++ spin_unlock(&event->lock); ++ ++ if (put_user(prev_state, (__u32 __user *)argp)) ++ return -EFAULT; ++ ++ return 0; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -507,6 +527,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + return ntsync_mutex_kill(obj, argp); + case NTSYNC_IOC_EVENT_SET: + return ntsync_event_set(obj, argp); ++ case NTSYNC_IOC_EVENT_RESET: ++ return ntsync_event_reset(obj, argp); + default: + return -ENOIOCTLCMD; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 782057552483..f2d7507d8438 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -49,5 +49,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_MUTEX_UNLOCK _IOWR('N', 0x85, struct ntsync_mutex_args) + #define NTSYNC_IOC_MUTEX_KILL _IOW ('N', 0x86, __u32) + #define NTSYNC_IOC_EVENT_SET _IOR ('N', 0x88, __u32) ++#define NTSYNC_IOC_EVENT_RESET _IOR ('N', 0x89, __u32) + + #endif +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0011.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0011.patch new file mode 100644 index 0000000..b02d7da --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0011.patch @@ -0,0 +1,80 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 12/29] ntsync: Introduce NTSYNC_IOC_EVENT_PULSE. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:39 -0600 +Message-Id: <20240131021356.10322-13-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This corresponds to the NT syscall NtPulseEvent(). + +This wakes up any waiters as if the event had been set, but does not set the +event, instead resetting it if it had been signalled. Thus, for a manual-reset +event, all waiters are woken, whereas for an auto-reset event, at most one +waiter is woken. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 10 ++++++++-- + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 009d927739b8..240ae858fa96 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -447,7 +447,7 @@ static int ntsync_mutex_kill(struct ntsync_obj *mutex, void __user *argp) + return ret; + } + +-static int ntsync_event_set(struct ntsync_obj *event, void __user *argp) ++static int ntsync_event_set(struct ntsync_obj *event, void __user *argp, bool pulse) + { + struct ntsync_device *dev = event->dev; + __u32 prev_state; +@@ -463,6 +463,8 @@ static int ntsync_event_set(struct ntsync_obj *event, void __user *argp) + event->u.event.signaled = true; + try_wake_all_obj(dev, event); + try_wake_any_event(event); ++ if (pulse) ++ event->u.event.signaled = false; + + spin_unlock(&event->lock); + spin_unlock(&dev->wait_all_lock); +@@ -472,6 +474,8 @@ static int ntsync_event_set(struct ntsync_obj *event, void __user *argp) + prev_state = event->u.event.signaled; + event->u.event.signaled = true; + try_wake_any_event(event); ++ if (pulse) ++ event->u.event.signaled = false; + + spin_unlock(&event->lock); + } +@@ -526,9 +530,11 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + case NTSYNC_IOC_MUTEX_KILL: + return ntsync_mutex_kill(obj, argp); + case NTSYNC_IOC_EVENT_SET: +- return ntsync_event_set(obj, argp); ++ return ntsync_event_set(obj, argp, false); + case NTSYNC_IOC_EVENT_RESET: + return ntsync_event_reset(obj, argp); ++ case NTSYNC_IOC_EVENT_PULSE: ++ return ntsync_event_set(obj, argp, true); + default: + return -ENOIOCTLCMD; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index f2d7507d8438..598f894f868d 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -50,5 +50,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_MUTEX_KILL _IOW ('N', 0x86, __u32) + #define NTSYNC_IOC_EVENT_SET _IOR ('N', 0x88, __u32) + #define NTSYNC_IOC_EVENT_RESET _IOR ('N', 0x89, __u32) ++#define NTSYNC_IOC_EVENT_PULSE _IOR ('N', 0x8a, __u32) + + #endif +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0012.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0012.patch new file mode 100644 index 0000000..e05d69c --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0012.patch @@ -0,0 +1,72 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 13/29] ntsync: Introduce NTSYNC_IOC_SEM_READ. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:40 -0600 +Message-Id: <20240131021356.10322-14-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This corresponds to the NT syscall NtQuerySemaphore(). + +This returns the current count and maximum count of the semaphore. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 21 +++++++++++++++++++++ + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 22 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 240ae858fa96..6dccfbfb2512 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -506,6 +506,25 @@ static int ntsync_event_reset(struct ntsync_obj *event, void __user *argp) + return 0; + } + ++static int ntsync_sem_read(struct ntsync_obj *sem, void __user *argp) ++{ ++ struct ntsync_sem_args __user *user_args = argp; ++ struct ntsync_sem_args args; ++ ++ if (sem->type != NTSYNC_TYPE_SEM) ++ return -EINVAL; ++ ++ args.sem = 0; ++ spin_lock(&sem->lock); ++ args.count = sem->u.sem.count; ++ args.max = sem->u.sem.max; ++ spin_unlock(&sem->lock); ++ ++ if (copy_to_user(user_args, &args, sizeof(args))) ++ return -EFAULT; ++ return 0; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -525,6 +544,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + switch (cmd) { + case NTSYNC_IOC_SEM_POST: + return ntsync_sem_post(obj, argp); ++ case NTSYNC_IOC_SEM_READ: ++ return ntsync_sem_read(obj, argp); + case NTSYNC_IOC_MUTEX_UNLOCK: + return ntsync_mutex_unlock(obj, argp); + case NTSYNC_IOC_MUTEX_KILL: +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 598f894f868d..6017f621687e 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -51,5 +51,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_EVENT_SET _IOR ('N', 0x88, __u32) + #define NTSYNC_IOC_EVENT_RESET _IOR ('N', 0x89, __u32) + #define NTSYNC_IOC_EVENT_PULSE _IOR ('N', 0x8a, __u32) ++#define NTSYNC_IOC_SEM_READ _IOR ('N', 0x8b, struct ntsync_sem_args) + + #endif +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0013.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0013.patch new file mode 100644 index 0000000..4a4b6a6 --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0013.patch @@ -0,0 +1,74 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 14/29] ntsync: Introduce NTSYNC_IOC_MUTEX_READ. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:41 -0600 +Message-Id: <20240131021356.10322-15-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This corresponds to the NT syscall NtQueryMutant(). + +This returns the recursion count, owner, and abandoned state of the mutex. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 23 +++++++++++++++++++++++ + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 24 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 6dccfbfb2512..7f5f96ec7c69 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -525,6 +525,27 @@ static int ntsync_sem_read(struct ntsync_obj *sem, void __user *argp) + return 0; + } + ++static int ntsync_mutex_read(struct ntsync_obj *mutex, void __user *argp) ++{ ++ struct ntsync_mutex_args __user *user_args = argp; ++ struct ntsync_mutex_args args; ++ int ret; ++ ++ if (mutex->type != NTSYNC_TYPE_MUTEX) ++ return -EINVAL; ++ ++ args.mutex = 0; ++ spin_lock(&mutex->lock); ++ args.count = mutex->u.mutex.count; ++ args.owner = mutex->u.mutex.owner; ++ ret = mutex->u.mutex.ownerdead ? -EOWNERDEAD : 0; ++ spin_unlock(&mutex->lock); ++ ++ if (copy_to_user(user_args, &args, sizeof(args))) ++ return -EFAULT; ++ return ret; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -550,6 +571,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + return ntsync_mutex_unlock(obj, argp); + case NTSYNC_IOC_MUTEX_KILL: + return ntsync_mutex_kill(obj, argp); ++ case NTSYNC_IOC_MUTEX_READ: ++ return ntsync_mutex_read(obj, argp); + case NTSYNC_IOC_EVENT_SET: + return ntsync_event_set(obj, argp, false); + case NTSYNC_IOC_EVENT_RESET: +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 6017f621687e..a1d0ef581212 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -52,5 +52,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_EVENT_RESET _IOR ('N', 0x89, __u32) + #define NTSYNC_IOC_EVENT_PULSE _IOR ('N', 0x8a, __u32) + #define NTSYNC_IOC_SEM_READ _IOR ('N', 0x8b, struct ntsync_sem_args) ++#define NTSYNC_IOC_MUTEX_READ _IOR ('N', 0x8c, struct ntsync_mutex_args) + + #endif +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0014.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0014.patch new file mode 100644 index 0000000..ff7ac42 --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0014.patch @@ -0,0 +1,72 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 15/29] ntsync: Introduce NTSYNC_IOC_EVENT_READ. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:42 -0600 +Message-Id: <20240131021356.10322-16-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +This corresponds to the NT syscall NtQueryEvent(). + +This returns the signaled state of the event and whether it is manual-reset. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 21 +++++++++++++++++++++ + include/uapi/linux/ntsync.h | 1 + + 2 files changed, 22 insertions(+) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 7f5f96ec7c69..5439c1c9e90f 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -546,6 +546,25 @@ static int ntsync_mutex_read(struct ntsync_obj *mutex, void __user *argp) + return ret; + } + ++static int ntsync_event_read(struct ntsync_obj *event, void __user *argp) ++{ ++ struct ntsync_event_args __user *user_args = argp; ++ struct ntsync_event_args args; ++ ++ if (event->type != NTSYNC_TYPE_EVENT) ++ return -EINVAL; ++ ++ args.event = 0; ++ spin_lock(&event->lock); ++ args.manual = event->u.event.manual; ++ args.signaled = event->u.event.signaled; ++ spin_unlock(&event->lock); ++ ++ if (copy_to_user(user_args, &args, sizeof(args))) ++ return -EFAULT; ++ return 0; ++} ++ + static int ntsync_obj_release(struct inode *inode, struct file *file) + { + struct ntsync_obj *obj = file->private_data; +@@ -579,6 +598,8 @@ static long ntsync_obj_ioctl(struct file *file, unsigned int cmd, + return ntsync_event_reset(obj, argp); + case NTSYNC_IOC_EVENT_PULSE: + return ntsync_event_set(obj, argp, true); ++ case NTSYNC_IOC_EVENT_READ: ++ return ntsync_event_read(obj, argp); + default: + return -ENOIOCTLCMD; + } +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index a1d0ef581212..582d33b0dcac 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -53,5 +53,6 @@ struct ntsync_wait_args { + #define NTSYNC_IOC_EVENT_PULSE _IOR ('N', 0x8a, __u32) + #define NTSYNC_IOC_SEM_READ _IOR ('N', 0x8b, struct ntsync_sem_args) + #define NTSYNC_IOC_MUTEX_READ _IOR ('N', 0x8c, struct ntsync_mutex_args) ++#define NTSYNC_IOC_EVENT_READ _IOR ('N', 0x8d, struct ntsync_event_args) + + #endif +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0015.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0015.patch new file mode 100644 index 0000000..9a3a0c9 --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0015.patch @@ -0,0 +1,194 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 16/29] ntsync: Introduce alertable waits. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:43 -0600 +Message-Id: <20240131021356.10322-17-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +NT waits can optionally be made "alertable". This is a special channel for +thread wakeup that is mildly similar to SIGIO. A thread has an internal single +bit of "alerted" state, and if a thread is made alerted while an alertable wait, +the wait will return a special value, consume the "alerted" state, and will not +consume any of its objects. + +Alerts are implemented using events; the user-space NT emulator is expected to +create an internal ntsync event for each thread and pass that event to wait +functions. + +Signed-off-by: Elizabeth Figura +--- + drivers/misc/ntsync.c | 68 ++++++++++++++++++++++++++++++++----- + include/uapi/linux/ntsync.h | 2 +- + 2 files changed, 60 insertions(+), 10 deletions(-) + +diff --git a/drivers/misc/ntsync.c b/drivers/misc/ntsync.c +index 5439c1c9e90f..1e619e1ce6a6 100644 +--- a/drivers/misc/ntsync.c ++++ b/drivers/misc/ntsync.c +@@ -784,22 +784,29 @@ static int setup_wait(struct ntsync_device *dev, + const struct ntsync_wait_args *args, bool all, + struct ntsync_q **ret_q) + { ++ int fds[NTSYNC_MAX_WAIT_COUNT + 1]; + const __u32 count = args->count; +- int fds[NTSYNC_MAX_WAIT_COUNT]; + struct ntsync_q *q; ++ __u32 total_count; + __u32 i, j; + +- if (!args->owner || args->pad) ++ if (!args->owner) + return -EINVAL; + + if (args->count > NTSYNC_MAX_WAIT_COUNT) + return -EINVAL; + ++ total_count = count; ++ if (args->alert) ++ total_count++; ++ + if (copy_from_user(fds, u64_to_user_ptr(args->objs), + array_size(count, sizeof(*fds)))) + return -EFAULT; ++ if (args->alert) ++ fds[count] = args->alert; + +- q = kmalloc(struct_size(q, entries, count), GFP_KERNEL); ++ q = kmalloc(struct_size(q, entries, total_count), GFP_KERNEL); + if (!q) + return -ENOMEM; + q->task = current; +@@ -809,7 +816,7 @@ static int setup_wait(struct ntsync_device *dev, + q->ownerdead = false; + q->count = count; + +- for (i = 0; i < count; i++) { ++ for (i = 0; i < total_count; i++) { + struct ntsync_q_entry *entry = &q->entries[i]; + struct ntsync_obj *obj = get_obj(dev, fds[i]); + +@@ -860,9 +867,9 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) + { + struct ntsync_wait_args args; + struct ntsync_q *q; ++ __u32 i, total_count; + ktime_t timeout; + int signaled; +- __u32 i; + int ret; + + if (copy_from_user(&args, argp, sizeof(args))) +@@ -872,9 +879,13 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) + if (ret < 0) + return ret; + ++ total_count = args.count; ++ if (args.alert) ++ total_count++; ++ + /* queue ourselves */ + +- for (i = 0; i < args.count; i++) { ++ for (i = 0; i < total_count; i++) { + struct ntsync_q_entry *entry = &q->entries[i]; + struct ntsync_obj *obj = entry->obj; + +@@ -883,9 +894,15 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) + spin_unlock(&obj->lock); + } + +- /* check if we are already signaled */ ++ /* ++ * Check if we are already signaled. ++ * ++ * Note that the API requires that normal objects are checked before ++ * the alert event. Hence we queue the alert event last, and check ++ * objects in order. ++ */ + +- for (i = 0; i < args.count; i++) { ++ for (i = 0; i < total_count; i++) { + struct ntsync_obj *obj = q->entries[i].obj; + + if (atomic_read(&q->signaled) != -1) +@@ -903,7 +920,7 @@ static int ntsync_wait_any(struct ntsync_device *dev, void __user *argp) + + /* and finally, unqueue */ + +- for (i = 0; i < args.count; i++) { ++ for (i = 0; i < total_count; i++) { + struct ntsync_q_entry *entry = &q->entries[i]; + struct ntsync_obj *obj = entry->obj; + +@@ -964,6 +981,14 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp) + */ + list_add_tail(&entry->node, &obj->all_waiters); + } ++ if (args.alert) { ++ struct ntsync_q_entry *entry = &q->entries[args.count]; ++ struct ntsync_obj *obj = entry->obj; ++ ++ spin_lock_nest_lock(&obj->lock, &dev->wait_all_lock); ++ list_add_tail(&entry->node, &obj->any_waiters); ++ spin_unlock(&obj->lock); ++ } + + /* check if we are already signaled */ + +@@ -971,6 +996,21 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp) + + spin_unlock(&dev->wait_all_lock); + ++ /* ++ * Check if the alert event is signaled, making sure to do so only ++ * after checking if the other objects are signaled. ++ */ ++ ++ if (args.alert) { ++ struct ntsync_obj *obj = q->entries[args.count].obj; ++ ++ if (atomic_read(&q->signaled) == -1) { ++ spin_lock(&obj->lock); ++ try_wake_any_obj(obj); ++ spin_unlock(&obj->lock); ++ } ++ } ++ + /* sleep */ + + timeout = ns_to_ktime(args.timeout); +@@ -994,6 +1034,16 @@ static int ntsync_wait_all(struct ntsync_device *dev, void __user *argp) + + put_obj(obj); + } ++ if (args.alert) { ++ struct ntsync_q_entry *entry = &q->entries[args.count]; ++ struct ntsync_obj *obj = entry->obj; ++ ++ spin_lock_nest_lock(&obj->lock, &dev->wait_all_lock); ++ list_del(&entry->node); ++ spin_unlock(&obj->lock); ++ ++ put_obj(obj); ++ } + + spin_unlock(&dev->wait_all_lock); + +diff --git a/include/uapi/linux/ntsync.h b/include/uapi/linux/ntsync.h +index 582d33b0dcac..7c91af7011e4 100644 +--- a/include/uapi/linux/ntsync.h ++++ b/include/uapi/linux/ntsync.h +@@ -34,7 +34,7 @@ struct ntsync_wait_args { + __u32 count; + __u32 owner; + __u32 index; +- __u32 pad; ++ __u32 alert; + }; + + #define NTSYNC_MAX_WAIT_COUNT 64 +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0016.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0016.patch new file mode 100644 index 0000000..cc3864a --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0016.patch @@ -0,0 +1,213 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 17/29] selftests: ntsync: Add some tests for + semaphore state. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:44 -0600 +Message-Id: <20240131021356.10322-18-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Wine has tests for its synchronization primitives, but these are more accessible +to kernel developers, and also allow us to test some edge cases that Wine does +not care about. + +This patch adds tests for semaphore-specific ioctls NTSYNC_IOC_SEM_POST and +NTSYNC_IOC_SEM_READ, and waiting on semaphores. + +Signed-off-by: Elizabeth Figura +--- + tools/testing/selftests/Makefile | 1 + + .../testing/selftests/drivers/ntsync/Makefile | 8 + + tools/testing/selftests/drivers/ntsync/config | 1 + + .../testing/selftests/drivers/ntsync/ntsync.c | 143 ++++++++++++++++++ + 4 files changed, 153 insertions(+) + create mode 100644 tools/testing/selftests/drivers/ntsync/Makefile + create mode 100644 tools/testing/selftests/drivers/ntsync/config + create mode 100644 tools/testing/selftests/drivers/ntsync/ntsync.c + +diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile +index 15b6a111c3be..6c714a4e6478 100644 +--- a/tools/testing/selftests/Makefile ++++ b/tools/testing/selftests/Makefile +@@ -15,6 +15,7 @@ TARGETS += cpu-hotplug + TARGETS += damon + TARGETS += dmabuf-heaps + TARGETS += drivers/dma-buf ++TARGETS += drivers/ntsync + TARGETS += drivers/s390x/uvdevice + TARGETS += drivers/net/bonding + TARGETS += drivers/net/team +diff --git a/tools/testing/selftests/drivers/ntsync/Makefile b/tools/testing/selftests/drivers/ntsync/Makefile +new file mode 100644 +index 000000000000..a34da5ccacf0 +--- /dev/null ++++ b/tools/testing/selftests/drivers/ntsync/Makefile +@@ -0,0 +1,8 @@ ++# SPDX-LICENSE-IDENTIFIER: GPL-2.0-only ++TEST_GEN_PROGS := ntsync ++ ++top_srcdir =../../../../.. ++CFLAGS += -I$(top_srcdir)/usr/include ++LDLIBS += -lpthread ++ ++include ../../lib.mk +diff --git a/tools/testing/selftests/drivers/ntsync/config b/tools/testing/selftests/drivers/ntsync/config +new file mode 100644 +index 000000000000..60539c826d06 +--- /dev/null ++++ b/tools/testing/selftests/drivers/ntsync/config +@@ -0,0 +1 @@ ++CONFIG_WINESYNC=y +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +new file mode 100644 +index 000000000000..6ceb48fb42e3 +--- /dev/null ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -0,0 +1,143 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * Various unit tests for the "ntsync" synchronization primitive driver. ++ * ++ * Copyright (C) 2021-2022 Elizabeth Figura ++ */ ++ ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++#include ++#include ++#include "../../kselftest_harness.h" ++ ++static int read_sem_state(int sem, __u32 *count, __u32 *max) ++{ ++ struct ntsync_sem_args args; ++ int ret; ++ ++ memset(&args, 0xcc, sizeof(args)); ++ ret = ioctl(sem, NTSYNC_IOC_SEM_READ, &args); ++ *count = args.count; ++ *max = args.max; ++ return ret; ++} ++ ++#define check_sem_state(sem, count, max) \ ++ ({ \ ++ __u32 __count, __max; \ ++ int ret = read_sem_state((sem), &__count, &__max); \ ++ EXPECT_EQ(0, ret); \ ++ EXPECT_EQ((count), __count); \ ++ EXPECT_EQ((max), __max); \ ++ }) ++ ++static int post_sem(int sem, __u32 *count) ++{ ++ return ioctl(sem, NTSYNC_IOC_SEM_POST, count); ++} ++ ++static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) ++{ ++ struct ntsync_wait_args args = {0}; ++ struct timespec timeout; ++ int ret; ++ ++ clock_gettime(CLOCK_MONOTONIC, &timeout); ++ ++ args.timeout = timeout.tv_sec * 1000000000 + timeout.tv_nsec; ++ args.count = count; ++ args.objs = (uintptr_t)objs; ++ args.owner = owner; ++ args.index = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_WAIT_ANY, &args); ++ *index = args.index; ++ return ret; ++} ++ ++TEST(semaphore_state) ++{ ++ struct ntsync_sem_args sem_args; ++ struct timespec timeout; ++ __u32 count, index; ++ int fd, ret, sem; ++ ++ clock_gettime(CLOCK_MONOTONIC, &timeout); ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 3; ++ sem_args.max = 2; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ sem_args.count = 2; ++ sem_args.max = 2; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ sem = sem_args.sem; ++ check_sem_state(sem, 2, 2); ++ ++ count = 0; ++ ret = post_sem(sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, count); ++ check_sem_state(sem, 2, 2); ++ ++ count = 1; ++ ret = post_sem(sem, &count); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOVERFLOW, errno); ++ check_sem_state(sem, 2, 2); ++ ++ ret = wait_any(fd, 1, &sem, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem, 1, 2); ++ ++ ret = wait_any(fd, 1, &sem, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem, 0, 2); ++ ++ ret = wait_any(fd, 1, &sem, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ count = 3; ++ ret = post_sem(sem, &count); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOVERFLOW, errno); ++ check_sem_state(sem, 0, 2); ++ ++ count = 2; ++ ret = post_sem(sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ check_sem_state(sem, 2, 2); ++ ++ ret = wait_any(fd, 1, &sem, 123, &index); ++ EXPECT_EQ(0, ret); ++ ret = wait_any(fd, 1, &sem, 123, &index); ++ EXPECT_EQ(0, ret); ++ ++ count = 1; ++ ret = post_sem(sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ check_sem_state(sem, 1, 2); ++ ++ close(sem); ++ ++ close(fd); ++} ++ ++TEST_HARNESS_MAIN +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0017.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0017.patch new file mode 100644 index 0000000..35a182e --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0017.patch @@ -0,0 +1,218 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 18/29] selftests: ntsync: Add some tests for mutex + state. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:45 -0600 +Message-Id: <20240131021356.10322-19-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Test mutex-specific ioctls NTSYNC_IOC_MUTEX_UNLOCK and NTSYNC_IOC_MUTEX_READ, +and waiting on mutexes. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 181 ++++++++++++++++++ + 1 file changed, 181 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 6ceb48fb42e3..80c8bd409d68 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -40,6 +40,39 @@ static int post_sem(int sem, __u32 *count) + return ioctl(sem, NTSYNC_IOC_SEM_POST, count); + } + ++static int read_mutex_state(int mutex, __u32 *count, __u32 *owner) ++{ ++ struct ntsync_mutex_args args; ++ int ret; ++ ++ memset(&args, 0xcc, sizeof(args)); ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &args); ++ *count = args.count; ++ *owner = args.owner; ++ return ret; ++} ++ ++#define check_mutex_state(mutex, count, owner) \ ++ ({ \ ++ __u32 __count, __owner; \ ++ int ret = read_mutex_state((mutex), &__count, &__owner); \ ++ EXPECT_EQ(0, ret); \ ++ EXPECT_EQ((count), __count); \ ++ EXPECT_EQ((owner), __owner); \ ++ }) ++ ++static int unlock_mutex(int mutex, __u32 owner, __u32 *count) ++{ ++ struct ntsync_mutex_args args; ++ int ret; ++ ++ args.owner = owner; ++ args.count = 0xdeadbeef; ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_UNLOCK, &args); ++ *count = args.count; ++ return ret; ++} ++ + static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) + { + struct ntsync_wait_args args = {0}; +@@ -140,4 +173,152 @@ TEST(semaphore_state) + close(fd); + } + ++TEST(mutex_state) ++{ ++ struct ntsync_mutex_args mutex_args; ++ __u32 owner, count, index; ++ struct timespec timeout; ++ int fd, ret, mutex; ++ ++ clock_gettime(CLOCK_MONOTONIC, &timeout); ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ mutex_args.owner = 123; ++ mutex_args.count = 0; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ mutex_args.owner = 0; ++ mutex_args.count = 2; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ mutex_args.owner = 123; ++ mutex_args.count = 2; ++ mutex_args.mutex = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, mutex_args.mutex); ++ mutex = mutex_args.mutex; ++ check_mutex_state(mutex, 2, 123); ++ ++ ret = unlock_mutex(mutex, 0, &count); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ ret = unlock_mutex(mutex, 456, &count); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EPERM, errno); ++ check_mutex_state(mutex, 2, 123); ++ ++ ret = unlock_mutex(mutex, 123, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, count); ++ check_mutex_state(mutex, 1, 123); ++ ++ ret = unlock_mutex(mutex, 123, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, count); ++ check_mutex_state(mutex, 0, 0); ++ ++ ret = unlock_mutex(mutex, 123, &count); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EPERM, errno); ++ ++ ret = wait_any(fd, 1, &mutex, 456, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_mutex_state(mutex, 1, 456); ++ ++ ret = wait_any(fd, 1, &mutex, 456, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_mutex_state(mutex, 2, 456); ++ ++ ret = unlock_mutex(mutex, 456, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, count); ++ check_mutex_state(mutex, 1, 456); ++ ++ ret = wait_any(fd, 1, &mutex, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ owner = 0; ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ owner = 123; ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EPERM, errno); ++ check_mutex_state(mutex, 1, 456); ++ ++ owner = 456; ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); ++ EXPECT_EQ(0, ret); ++ ++ memset(&mutex_args, 0xcc, sizeof(mutex_args)); ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ EXPECT_EQ(0, mutex_args.count); ++ EXPECT_EQ(0, mutex_args.owner); ++ ++ memset(&mutex_args, 0xcc, sizeof(mutex_args)); ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ EXPECT_EQ(0, mutex_args.count); ++ EXPECT_EQ(0, mutex_args.owner); ++ ++ ret = wait_any(fd, 1, &mutex, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ EXPECT_EQ(0, index); ++ check_mutex_state(mutex, 1, 123); ++ ++ owner = 123; ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); ++ EXPECT_EQ(0, ret); ++ ++ memset(&mutex_args, 0xcc, sizeof(mutex_args)); ++ ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ EXPECT_EQ(0, mutex_args.count); ++ EXPECT_EQ(0, mutex_args.owner); ++ ++ ret = wait_any(fd, 1, &mutex, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ EXPECT_EQ(0, index); ++ check_mutex_state(mutex, 1, 123); ++ ++ close(mutex); ++ ++ mutex_args.owner = 0; ++ mutex_args.count = 0; ++ mutex_args.mutex = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, mutex_args.mutex); ++ mutex = mutex_args.mutex; ++ check_mutex_state(mutex, 0, 0); ++ ++ ret = wait_any(fd, 1, &mutex, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_mutex_state(mutex, 1, 123); ++ ++ close(mutex); ++ ++ close(fd); ++} ++ + TEST_HARNESS_MAIN +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0018.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0018.patch new file mode 100644 index 0000000..d82f310 --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0018.patch @@ -0,0 +1,136 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 19/29] selftests: ntsync: Add some tests for + NTSYNC_IOC_WAIT_ANY. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:46 -0600 +Message-Id: <20240131021356.10322-20-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Test basic synchronous functionality of NTSYNC_IOC_WAIT_ANY, when objects are +considered signaled or not signaled, and how they are affected by a successful +wait. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 105 ++++++++++++++++++ + 1 file changed, 105 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 80c8bd409d68..13e7c9d7441e 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -321,4 +321,109 @@ TEST(mutex_state) + close(fd); + } + ++TEST(test_wait_any) ++{ ++ struct ntsync_mutex_args mutex_args = {0}; ++ struct ntsync_wait_args wait_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; ++ __u32 owner, index, count; ++ struct timespec timeout; ++ int objs[2], fd, ret; ++ ++ clock_gettime(CLOCK_MONOTONIC, &timeout); ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 2; ++ sem_args.max = 3; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ ++ mutex_args.owner = 0; ++ mutex_args.count = 0; ++ mutex_args.mutex = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, mutex_args.mutex); ++ ++ objs[0] = sem_args.sem; ++ objs[1] = mutex_args.mutex; ++ ++ ret = wait_any(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 1, 3); ++ check_mutex_state(mutex_args.mutex, 0, 0); ++ ++ ret = wait_any(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_mutex_state(mutex_args.mutex, 0, 0); ++ ++ ret = wait_any(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, index); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_mutex_state(mutex_args.mutex, 1, 123); ++ ++ count = 1; ++ ret = post_sem(sem_args.sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ ++ ret = wait_any(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_mutex_state(mutex_args.mutex, 1, 123); ++ ++ ret = wait_any(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, index); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_mutex_state(mutex_args.mutex, 2, 123); ++ ++ ret = wait_any(fd, 2, objs, 456, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ owner = 123; ++ ret = ioctl(mutex_args.mutex, NTSYNC_IOC_MUTEX_KILL, &owner); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_any(fd, 2, objs, 456, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ EXPECT_EQ(1, index); ++ ++ ret = wait_any(fd, 2, objs, 456, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, index); ++ ++ /* test waiting on the same object twice */ ++ count = 2; ++ ret = post_sem(sem_args.sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ ++ objs[0] = objs[1] = sem_args.sem; ++ ret = wait_any(fd, 2, objs, 456, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, wait_args.index); ++ check_sem_state(sem_args.sem, 1, 3); ++ ++ ret = wait_any(fd, 0, NULL, 456, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ close(sem_args.sem); ++ close(mutex_args.mutex); ++ ++ close(fd); ++} ++ + TEST_HARNESS_MAIN +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0019.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0019.patch new file mode 100644 index 0000000..ec7fb58 --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0019.patch @@ -0,0 +1,147 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 20/29] selftests: ntsync: Add some tests for + NTSYNC_IOC_WAIT_ALL. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:47 -0600 +Message-Id: <20240131021356.10322-21-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Test basic synchronous functionality of NTSYNC_IOC_WAIT_ALL, and when objects +are considered simultaneously signaled. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 99 ++++++++++++++++++- + 1 file changed, 97 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 13e7c9d7441e..77f1b7e42d76 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -73,7 +73,8 @@ static int unlock_mutex(int mutex, __u32 owner, __u32 *count) + return ret; + } + +-static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) ++static int wait_objs(int fd, unsigned long request, __u32 count, ++ const int *objs, __u32 owner, __u32 *index) + { + struct ntsync_wait_args args = {0}; + struct timespec timeout; +@@ -86,11 +87,21 @@ static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *in + args.objs = (uintptr_t)objs; + args.owner = owner; + args.index = 0xdeadbeef; +- ret = ioctl(fd, NTSYNC_IOC_WAIT_ANY, &args); ++ ret = ioctl(fd, request, &args); + *index = args.index; + return ret; + } + ++static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) ++{ ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, count, objs, owner, index); ++} ++ ++static int wait_all(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) ++{ ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, count, objs, owner, index); ++} ++ + TEST(semaphore_state) + { + struct ntsync_sem_args sem_args; +@@ -426,4 +437,88 @@ TEST(test_wait_any) + close(fd); + } + ++TEST(test_wait_all) ++{ ++ struct ntsync_mutex_args mutex_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; ++ __u32 owner, index, count; ++ int objs[2], fd, ret; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 2; ++ sem_args.max = 3; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ ++ mutex_args.owner = 0; ++ mutex_args.count = 0; ++ mutex_args.mutex = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, mutex_args.mutex); ++ ++ objs[0] = sem_args.sem; ++ objs[1] = mutex_args.mutex; ++ ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 1, 3); ++ check_mutex_state(mutex_args.mutex, 1, 123); ++ ++ ret = wait_all(fd, 2, objs, 456, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ check_sem_state(sem_args.sem, 1, 3); ++ check_mutex_state(mutex_args.mutex, 1, 123); ++ ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_mutex_state(mutex_args.mutex, 2, 123); ++ ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_mutex_state(mutex_args.mutex, 2, 123); ++ ++ count = 3; ++ ret = post_sem(sem_args.sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 2, 3); ++ check_mutex_state(mutex_args.mutex, 3, 123); ++ ++ owner = 123; ++ ret = ioctl(mutex_args.mutex, NTSYNC_IOC_MUTEX_KILL, &owner); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EOWNERDEAD, errno); ++ check_sem_state(sem_args.sem, 1, 3); ++ check_mutex_state(mutex_args.mutex, 1, 123); ++ ++ /* test waiting on the same object twice */ ++ objs[0] = objs[1] = sem_args.sem; ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(EINVAL, errno); ++ ++ close(sem_args.sem); ++ close(mutex_args.mutex); ++ ++ close(fd); ++} ++ + TEST_HARNESS_MAIN +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0020.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0020.patch new file mode 100644 index 0000000..3d9e0d2 --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0020.patch @@ -0,0 +1,182 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 21/29] selftests: ntsync: Add some tests for wakeup + signaling with WINESYNC_IOC_WAIT_ANY. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:48 -0600 +Message-Id: <20240131021356.10322-22-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Test contended "wait-for-any" waits, to make sure that scheduling and wakeup +logic works correctly. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 152 ++++++++++++++++++ + 1 file changed, 152 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 77f1b7e42d76..96a866ef235f 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -521,4 +521,156 @@ TEST(test_wait_all) + close(fd); + } + ++struct wake_args ++{ ++ int fd; ++ int obj; ++}; ++ ++struct wait_args ++{ ++ int fd; ++ unsigned long request; ++ struct ntsync_wait_args *args; ++ int ret; ++ int err; ++}; ++ ++static void *wait_thread(void *arg) ++{ ++ struct wait_args *args = arg; ++ ++ args->ret = ioctl(args->fd, args->request, args->args); ++ args->err = errno; ++ return NULL; ++} ++ ++static __u64 get_abs_timeout(unsigned int ms) ++{ ++ struct timespec timeout; ++ clock_gettime(CLOCK_MONOTONIC, &timeout); ++ return (timeout.tv_sec * 1000000000) + timeout.tv_nsec + (ms * 1000000); ++} ++ ++static int wait_for_thread(pthread_t thread, unsigned int ms) ++{ ++ struct timespec timeout; ++ ++ clock_gettime(CLOCK_REALTIME, &timeout); ++ timeout.tv_nsec += ms * 1000000; ++ timeout.tv_sec += (timeout.tv_nsec / 1000000000); ++ timeout.tv_nsec %= 1000000000; ++ return pthread_timedjoin_np(thread, NULL, &timeout); ++} ++ ++TEST(wake_any) ++{ ++ struct ntsync_mutex_args mutex_args = {0}; ++ struct ntsync_wait_args wait_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; ++ struct wait_args thread_args; ++ int objs[2], fd, ret; ++ __u32 count, index; ++ pthread_t thread; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 0; ++ sem_args.max = 3; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ ++ mutex_args.owner = 123; ++ mutex_args.count = 1; ++ mutex_args.mutex = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, mutex_args.mutex); ++ ++ objs[0] = sem_args.sem; ++ objs[1] = mutex_args.mutex; ++ ++ /* test waking the semaphore */ ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ wait_args.objs = (uintptr_t)objs; ++ wait_args.count = 2; ++ wait_args.owner = 456; ++ wait_args.index = 0xdeadbeef; ++ thread_args.fd = fd; ++ thread_args.args = &wait_args; ++ thread_args.request = NTSYNC_IOC_WAIT_ANY; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ count = 1; ++ ret = post_sem(sem_args.sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ check_sem_state(sem_args.sem, 0, 3); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(0, wait_args.index); ++ ++ /* test waking the mutex */ ++ ++ /* first grab it again for owner 123 */ ++ ret = wait_any(fd, 1, &mutex_args.mutex, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ wait_args.owner = 456; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = unlock_mutex(mutex_args.mutex, 123, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, count); ++ ++ ret = pthread_tryjoin_np(thread, NULL); ++ EXPECT_EQ(EBUSY, ret); ++ ++ ret = unlock_mutex(mutex_args.mutex, 123, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, mutex_args.count); ++ check_mutex_state(mutex_args.mutex, 1, 456); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(1, wait_args.index); ++ ++ /* delete an object while it's being waited on */ ++ ++ wait_args.timeout = get_abs_timeout(200); ++ wait_args.owner = 123; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ close(sem_args.sem); ++ close(mutex_args.mutex); ++ ++ ret = wait_for_thread(thread, 200); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(-1, thread_args.ret); ++ EXPECT_EQ(ETIMEDOUT, thread_args.err); ++ ++ close(fd); ++} ++ + TEST_HARNESS_MAIN +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0021.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0021.patch new file mode 100644 index 0000000..522d6a6 --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0021.patch @@ -0,0 +1,129 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 22/29] selftests: ntsync: Add some tests for wakeup + signaling with WINESYNC_IOC_WAIT_ALL. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:49 -0600 +Message-Id: <20240131021356.10322-23-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Test contended "wait-for-all" waits, to make sure that scheduling and wakeup +logic works correctly, and that the wait only exits once objects are all +simultaneously signaled. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 98 +++++++++++++++++++ + 1 file changed, 98 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 96a866ef235f..7776fe71b8ef 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -673,4 +673,102 @@ TEST(wake_any) + close(fd); + } + ++TEST(wake_all) ++{ ++ struct ntsync_mutex_args mutex_args = {0}; ++ struct ntsync_wait_args wait_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; ++ struct wait_args thread_args; ++ int objs[2], fd, ret; ++ __u32 count, index; ++ pthread_t thread; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 0; ++ sem_args.max = 3; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ ++ mutex_args.owner = 123; ++ mutex_args.count = 1; ++ mutex_args.mutex = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, mutex_args.mutex); ++ ++ objs[0] = sem_args.sem; ++ objs[1] = mutex_args.mutex; ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ wait_args.objs = (uintptr_t)objs; ++ wait_args.count = 2; ++ wait_args.owner = 456; ++ thread_args.fd = fd; ++ thread_args.args = &wait_args; ++ thread_args.request = NTSYNC_IOC_WAIT_ALL; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ count = 1; ++ ret = post_sem(sem_args.sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ ++ ret = pthread_tryjoin_np(thread, NULL); ++ EXPECT_EQ(EBUSY, ret); ++ ++ check_sem_state(sem_args.sem, 1, 3); ++ ++ ret = wait_any(fd, 1, &sem_args.sem, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ ++ ret = unlock_mutex(mutex_args.mutex, 123, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, count); ++ ++ ret = pthread_tryjoin_np(thread, NULL); ++ EXPECT_EQ(EBUSY, ret); ++ ++ check_mutex_state(mutex_args.mutex, 0, 0); ++ ++ count = 2; ++ ret = post_sem(sem_args.sem, &count); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, count); ++ check_sem_state(sem_args.sem, 1, 3); ++ check_mutex_state(mutex_args.mutex, 1, 456); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ ++ /* delete an object while it's being waited on */ ++ ++ wait_args.timeout = get_abs_timeout(200); ++ wait_args.owner = 123; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ close(sem_args.sem); ++ close(mutex_args.mutex); ++ ++ ret = wait_for_thread(thread, 200); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(-1, thread_args.ret); ++ EXPECT_EQ(ETIMEDOUT, thread_args.err); ++ ++ close(fd); ++} ++ + TEST_HARNESS_MAIN +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0022.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0022.patch new file mode 100644 index 0000000..1d3a60d --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0022.patch @@ -0,0 +1,129 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 23/29] selftests: ntsync: Add some tests for + manual-reset event state. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:50 -0600 +Message-Id: <20240131021356.10322-24-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Test event-specific ioctls NTSYNC_IOC_EVENT_SET, NTSYNC_IOC_EVENT_RESET, +NTSYNC_IOC_EVENT_PULSE, NTSYNC_IOC_EVENT_READ for manual-reset events, and +waiting on manual-reset events. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 89 +++++++++++++++++++ + 1 file changed, 89 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 7776fe71b8ef..98fc70a9a58b 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -73,6 +73,27 @@ static int unlock_mutex(int mutex, __u32 owner, __u32 *count) + return ret; + } + ++static int read_event_state(int event, __u32 *signaled, __u32 *manual) ++{ ++ struct ntsync_event_args args; ++ int ret; ++ ++ memset(&args, 0xcc, sizeof(args)); ++ ret = ioctl(event, NTSYNC_IOC_EVENT_READ, &args); ++ *signaled = args.signaled; ++ *manual = args.manual; ++ return ret; ++} ++ ++#define check_event_state(event, signaled, manual) \ ++ ({ \ ++ __u32 __signaled, __manual; \ ++ int ret = read_event_state((event), &__signaled, &__manual); \ ++ EXPECT_EQ(0, ret); \ ++ EXPECT_EQ((signaled), __signaled); \ ++ EXPECT_EQ((manual), __manual); \ ++ }) ++ + static int wait_objs(int fd, unsigned long request, __u32 count, + const int *objs, __u32 owner, __u32 *index) + { +@@ -332,6 +353,74 @@ TEST(mutex_state) + close(fd); + } + ++TEST(manual_event_state) ++{ ++ struct ntsync_event_args event_args; ++ __u32 index, signaled; ++ int fd, event, ret; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ event_args.manual = 1; ++ event_args.signaled = 0; ++ event_args.event = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, event_args.event); ++ event = event_args.event; ++ check_event_state(event, 0, 1); ++ ++ signaled = 0xdeadbeef; ++ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event, 1, 1); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ check_event_state(event, 1, 1); ++ ++ ret = wait_any(fd, 1, &event, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_event_state(event, 1, 1); ++ ++ signaled = 0xdeadbeef; ++ ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ check_event_state(event, 0, 1); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event, 0, 1); ++ ++ ret = wait_any(fd, 1, &event, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ check_event_state(event, 0, 1); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event, 0, 1); ++ ++ close(event); ++ ++ close(fd); ++} ++ + TEST(test_wait_any) + { + struct ntsync_mutex_args mutex_args = {0}; +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0023.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0023.patch new file mode 100644 index 0000000..f34c5e4 --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0023.patch @@ -0,0 +1,92 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 24/29] selftests: ntsync: Add some tests for + auto-reset event state. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:51 -0600 +Message-Id: <20240131021356.10322-25-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Test event-specific ioctls NTSYNC_IOC_EVENT_SET, NTSYNC_IOC_EVENT_RESET, +NTSYNC_IOC_EVENT_PULSE, NTSYNC_IOC_EVENT_READ for auto-reset events, and +waiting on auto-reset events. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 59 +++++++++++++++++++ + 1 file changed, 59 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 98fc70a9a58b..f1fb28949367 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -421,6 +421,65 @@ TEST(manual_event_state) + close(fd); + } + ++TEST(auto_event_state) ++{ ++ struct ntsync_event_args event_args; ++ __u32 index, signaled; ++ int fd, event, ret; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ event_args.manual = 0; ++ event_args.signaled = 1; ++ event_args.event = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, event_args.event); ++ event = event_args.event; ++ ++ check_event_state(event, 1, 0); ++ ++ signaled = 0xdeadbeef; ++ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ check_event_state(event, 1, 0); ++ ++ ret = wait_any(fd, 1, &event, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_event_state(event, 0, 0); ++ ++ signaled = 0xdeadbeef; ++ ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event, 0, 0); ++ ++ ret = wait_any(fd, 1, &event, 123, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ check_event_state(event, 0, 0); ++ ++ ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event, 0, 0); ++ ++ close(event); ++ ++ close(fd); ++} ++ + TEST(test_wait_any) + { + struct ntsync_mutex_args mutex_args = {0}; +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0024.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0024.patch new file mode 100644 index 0000000..39fadaa --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0024.patch @@ -0,0 +1,270 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 25/29] selftests: ntsync: Add some tests for wakeup + signaling with events. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:52 -0600 +Message-Id: <20240131021356.10322-26-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Expand the contended wait tests, which previously only covered events and +semaphores, to cover events as well. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 151 +++++++++++++++++- + 1 file changed, 147 insertions(+), 4 deletions(-) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index f1fb28949367..598333df3e6d 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -587,6 +587,7 @@ TEST(test_wait_any) + + TEST(test_wait_all) + { ++ struct ntsync_event_args event_args = {0}; + struct ntsync_mutex_args mutex_args = {0}; + struct ntsync_sem_args sem_args = {0}; + __u32 owner, index, count; +@@ -609,6 +610,11 @@ TEST(test_wait_all) + EXPECT_EQ(0, ret); + EXPECT_NE(0xdeadbeef, mutex_args.mutex); + ++ event_args.manual = true; ++ event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ + objs[0] = sem_args.sem; + objs[1] = mutex_args.mutex; + +@@ -657,6 +663,14 @@ TEST(test_wait_all) + check_sem_state(sem_args.sem, 1, 3); + check_mutex_state(mutex_args.mutex, 1, 123); + ++ objs[0] = sem_args.sem; ++ objs[1] = event_args.event; ++ ret = wait_all(fd, 2, objs, 123, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ check_sem_state(sem_args.sem, 0, 3); ++ check_event_state(event_args.event, 1, 1); ++ + /* test waiting on the same object twice */ + objs[0] = objs[1] = sem_args.sem; + ret = wait_all(fd, 2, objs, 123, &index); +@@ -665,6 +679,7 @@ TEST(test_wait_all) + + close(sem_args.sem); + close(mutex_args.mutex); ++ close(event_args.event); + + close(fd); + } +@@ -713,12 +728,13 @@ static int wait_for_thread(pthread_t thread, unsigned int ms) + + TEST(wake_any) + { ++ struct ntsync_event_args event_args = {0}; + struct ntsync_mutex_args mutex_args = {0}; + struct ntsync_wait_args wait_args = {0}; + struct ntsync_sem_args sem_args = {0}; + struct wait_args thread_args; ++ __u32 count, index, signaled; + int objs[2], fd, ret; +- __u32 count, index; + pthread_t thread; + + fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); +@@ -800,10 +816,101 @@ TEST(wake_any) + EXPECT_EQ(0, thread_args.ret); + EXPECT_EQ(1, wait_args.index); + ++ /* test waking events */ ++ ++ event_args.manual = false; ++ event_args.signaled = false; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ ++ objs[1] = event_args.event; ++ wait_args.timeout = get_abs_timeout(1000); ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event_args.event, 0, 0); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(1, wait_args.index); ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_PULSE, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event_args.event, 0, 0); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(1, wait_args.index); ++ ++ close(event_args.event); ++ ++ event_args.manual = true; ++ event_args.signaled = false; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ ++ objs[1] = event_args.event; ++ wait_args.timeout = get_abs_timeout(1000); ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event_args.event, 1, 1); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(1, wait_args.index); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_PULSE, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ check_event_state(event_args.event, 0, 1); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(1, wait_args.index); ++ ++ close(event_args.event); ++ + /* delete an object while it's being waited on */ + + wait_args.timeout = get_abs_timeout(200); + wait_args.owner = 123; ++ objs[1] = mutex_args.mutex; + ret = pthread_create(&thread, NULL, wait_thread, &thread_args); + EXPECT_EQ(0, ret); + +@@ -823,12 +930,14 @@ TEST(wake_any) + + TEST(wake_all) + { ++ struct ntsync_event_args manual_event_args = {0}; ++ struct ntsync_event_args auto_event_args = {0}; + struct ntsync_mutex_args mutex_args = {0}; + struct ntsync_wait_args wait_args = {0}; + struct ntsync_sem_args sem_args = {0}; + struct wait_args thread_args; +- int objs[2], fd, ret; +- __u32 count, index; ++ __u32 count, index, signaled; ++ int objs[4], fd, ret; + pthread_t thread; + + fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); +@@ -848,12 +957,24 @@ TEST(wake_all) + EXPECT_EQ(0, ret); + EXPECT_NE(0xdeadbeef, mutex_args.mutex); + ++ manual_event_args.manual = true; ++ manual_event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &manual_event_args); ++ EXPECT_EQ(0, ret); ++ ++ auto_event_args.manual = false; ++ auto_event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &auto_event_args); ++ EXPECT_EQ(0, ret); ++ + objs[0] = sem_args.sem; + objs[1] = mutex_args.mutex; ++ objs[2] = manual_event_args.event; ++ objs[3] = auto_event_args.event; + + wait_args.timeout = get_abs_timeout(1000); + wait_args.objs = (uintptr_t)objs; +- wait_args.count = 2; ++ wait_args.count = 4; + wait_args.owner = 456; + thread_args.fd = fd; + thread_args.args = &wait_args; +@@ -887,12 +1008,32 @@ TEST(wake_all) + + check_mutex_state(mutex_args.mutex, 0, 0); + ++ ret = ioctl(manual_event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ + count = 2; + ret = post_sem(sem_args.sem, &count); + EXPECT_EQ(0, ret); + EXPECT_EQ(0, count); ++ check_sem_state(sem_args.sem, 2, 3); ++ ++ ret = ioctl(auto_event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, signaled); ++ ++ ret = ioctl(manual_event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ ++ ret = ioctl(auto_event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, signaled); ++ + check_sem_state(sem_args.sem, 1, 3); + check_mutex_state(mutex_args.mutex, 1, 456); ++ check_event_state(manual_event_args.event, 1, 1); ++ check_event_state(auto_event_args.event, 0, 0); + + ret = wait_for_thread(thread, 100); + EXPECT_EQ(0, ret); +@@ -910,6 +1051,8 @@ TEST(wake_all) + + close(sem_args.sem); + close(mutex_args.mutex); ++ close(manual_event_args.event); ++ close(auto_event_args.event); + + ret = wait_for_thread(thread, 200); + EXPECT_EQ(0, ret); +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0025.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0025.patch new file mode 100644 index 0000000..5ed6d50 --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0025.patch @@ -0,0 +1,234 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 26/29] selftests: ntsync: Add tests for alertable + waits. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:53 -0600 +Message-Id: <20240131021356.10322-27-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Test the "alert" functionality of NTSYNC_IOC_WAIT_ALL and NTSYNC_IOC_WAIT_ANY, +when a wait is woken with an alert and when it is woken by an object. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 179 +++++++++++++++++- + 1 file changed, 176 insertions(+), 3 deletions(-) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 598333df3e6d..6c00a55909aa 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -95,7 +95,7 @@ static int read_event_state(int event, __u32 *signaled, __u32 *manual) + }) + + static int wait_objs(int fd, unsigned long request, __u32 count, +- const int *objs, __u32 owner, __u32 *index) ++ const int *objs, __u32 owner, int alert, __u32 *index) + { + struct ntsync_wait_args args = {0}; + struct timespec timeout; +@@ -108,6 +108,7 @@ static int wait_objs(int fd, unsigned long request, __u32 count, + args.objs = (uintptr_t)objs; + args.owner = owner; + args.index = 0xdeadbeef; ++ args.alert = alert; + ret = ioctl(fd, request, &args); + *index = args.index; + return ret; +@@ -115,12 +116,26 @@ static int wait_objs(int fd, unsigned long request, __u32 count, + + static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) + { +- return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, count, objs, owner, index); ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, count, objs, owner, 0, index); + } + + static int wait_all(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) + { +- return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, count, objs, owner, index); ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, count, objs, owner, 0, index); ++} ++ ++static int wait_any_alert(int fd, __u32 count, const int *objs, ++ __u32 owner, int alert, __u32 *index) ++{ ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, ++ count, objs, owner, alert, index); ++} ++ ++static int wait_all_alert(int fd, __u32 count, const int *objs, ++ __u32 owner, int alert, __u32 *index) ++{ ++ return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, ++ count, objs, owner, alert, index); + } + + TEST(semaphore_state) +@@ -1062,4 +1077,162 @@ TEST(wake_all) + close(fd); + } + ++TEST(alert_any) ++{ ++ struct ntsync_event_args event_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; ++ __u32 index, count, signaled; ++ int objs[2], fd, ret; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 0; ++ sem_args.max = 2; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ objs[0] = sem_args.sem; ++ ++ sem_args.count = 1; ++ sem_args.max = 2; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ objs[1] = sem_args.sem; ++ ++ event_args.manual = true; ++ event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_any_alert(fd, 0, NULL, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_any_alert(fd, 0, NULL, 123, event_args.event, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(1, index); ++ ++ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, index); ++ ++ close(event_args.event); ++ ++ /* test with an auto-reset event */ ++ ++ event_args.manual = false; ++ event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ ++ count = 1; ++ ret = post_sem(objs[0], &count); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ ++ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, index); ++ ++ ret = wait_any_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ close(event_args.event); ++ ++ close(objs[0]); ++ close(objs[1]); ++ ++ close(fd); ++} ++ ++TEST(alert_all) ++{ ++ struct ntsync_event_args event_args = {0}; ++ struct ntsync_sem_args sem_args = {0}; ++ __u32 index, count, signaled; ++ int objs[2], fd, ret; ++ ++ fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ++ ASSERT_LE(0, fd); ++ ++ sem_args.count = 2; ++ sem_args.max = 2; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ objs[0] = sem_args.sem; ++ ++ sem_args.count = 1; ++ sem_args.max = 2; ++ sem_args.sem = 0xdeadbeef; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); ++ EXPECT_EQ(0, ret); ++ EXPECT_NE(0xdeadbeef, sem_args.sem); ++ objs[1] = sem_args.sem; ++ ++ event_args.manual = true; ++ event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ ++ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, index); ++ ++ close(event_args.event); ++ ++ /* test with an auto-reset event */ ++ ++ event_args.manual = false; ++ event_args.signaled = true; ++ ret = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); ++ EXPECT_EQ(0, ret); ++ ++ count = 2; ++ ret = post_sem(objs[1], &count); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, index); ++ ++ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(2, index); ++ ++ ret = wait_all_alert(fd, 2, objs, 123, event_args.event, &index); ++ EXPECT_EQ(-1, ret); ++ EXPECT_EQ(ETIMEDOUT, errno); ++ ++ close(event_args.event); ++ ++ close(objs[0]); ++ close(objs[1]); ++ ++ close(fd); ++} ++ + TEST_HARNESS_MAIN +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0026.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0026.patch new file mode 100644 index 0000000..12e8859 --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0026.patch @@ -0,0 +1,121 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 27/29] selftests: ntsync: Add some tests for wakeup + signaling via alerts. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:54 -0600 +Message-Id: <20240131021356.10322-28-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Expand the alert tests to cover alerting a thread mid-wait, to test that the +relevant scheduling logic works correctly. + +Signed-off-by: Elizabeth Figura +--- + .../testing/selftests/drivers/ntsync/ntsync.c | 62 +++++++++++++++++++ + 1 file changed, 62 insertions(+) + +diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c +index 6c00a55909aa..09153d0686ac 100644 +--- a/tools/testing/selftests/drivers/ntsync/ntsync.c ++++ b/tools/testing/selftests/drivers/ntsync/ntsync.c +@@ -1080,9 +1080,12 @@ TEST(wake_all) + TEST(alert_any) + { + struct ntsync_event_args event_args = {0}; ++ struct ntsync_wait_args wait_args = {0}; + struct ntsync_sem_args sem_args = {0}; + __u32 index, count, signaled; ++ struct wait_args thread_args; + int objs[2], fd, ret; ++ pthread_t thread; + + fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); + ASSERT_LE(0, fd); +@@ -1130,6 +1133,34 @@ TEST(alert_any) + EXPECT_EQ(0, ret); + EXPECT_EQ(2, index); + ++ /* test wakeup via alert */ ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ wait_args.objs = (uintptr_t)objs; ++ wait_args.count = 2; ++ wait_args.owner = 123; ++ wait_args.index = 0xdeadbeef; ++ wait_args.alert = event_args.event; ++ thread_args.fd = fd; ++ thread_args.args = &wait_args; ++ thread_args.request = NTSYNC_IOC_WAIT_ANY; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(2, wait_args.index); ++ + close(event_args.event); + + /* test with an auto-reset event */ +@@ -1166,9 +1197,12 @@ TEST(alert_any) + TEST(alert_all) + { + struct ntsync_event_args event_args = {0}; ++ struct ntsync_wait_args wait_args = {0}; + struct ntsync_sem_args sem_args = {0}; ++ struct wait_args thread_args; + __u32 index, count, signaled; + int objs[2], fd, ret; ++ pthread_t thread; + + fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); + ASSERT_LE(0, fd); +@@ -1202,6 +1236,34 @@ TEST(alert_all) + EXPECT_EQ(0, ret); + EXPECT_EQ(2, index); + ++ /* test wakeup via alert */ ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_RESET, &signaled); ++ EXPECT_EQ(0, ret); ++ ++ wait_args.timeout = get_abs_timeout(1000); ++ wait_args.objs = (uintptr_t)objs; ++ wait_args.count = 2; ++ wait_args.owner = 123; ++ wait_args.index = 0xdeadbeef; ++ wait_args.alert = event_args.event; ++ thread_args.fd = fd; ++ thread_args.args = &wait_args; ++ thread_args.request = NTSYNC_IOC_WAIT_ALL; ++ ret = pthread_create(&thread, NULL, wait_thread, &thread_args); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(ETIMEDOUT, ret); ++ ++ ret = ioctl(event_args.event, NTSYNC_IOC_EVENT_SET, &signaled); ++ EXPECT_EQ(0, ret); ++ ++ ret = wait_for_thread(thread, 100); ++ EXPECT_EQ(0, ret); ++ EXPECT_EQ(0, thread_args.ret); ++ EXPECT_EQ(2, wait_args.index); ++ + close(event_args.event); + + /* test with an auto-reset event */ +-- +2.43.0 + diff --git a/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0027.patch b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0027.patch new file mode 100644 index 0000000..fee7a66 --- /dev/null +++ b/linux-gcc/linux6.7-zen/patches/v2_20240130_zfigura_nt_synchronization_primitive_driver_0027.patch @@ -0,0 +1,39 @@ +From git@z Thu Jan 1 00:00:00 1970 +Subject: [PATCH RFC v2 28/29] maintainers: Add an entry for ntsync. +From: Elizabeth Figura +Date: Tue, 30 Jan 2024 20:13:55 -0600 +Message-Id: <20240131021356.10322-29-zfigura@codeweavers.com> +MIME-Version: 1.0 +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 7bit + +Add myself as maintainer, supported by CodeWeavers. + +Signed-off-by: Elizabeth Figura +--- + MAINTAINERS | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index 8d1052fa6a69..7924127d351b 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -15585,6 +15585,15 @@ T: git https://github.com/Paragon-Software-Group/linux-ntfs3.git + F: Documentation/filesystems/ntfs3.rst + F: fs/ntfs3/ + ++NTSYNC SYNCHRONIZATION PRIMITIVE DRIVER ++M: Elizabeth Figura ++L: wine-devel@winehq.org ++S: Supported ++F: Documentation/userspace-api/ntsync.rst ++F: drivers/misc/ntsync.c ++F: include/uapi/linux/ntsync.h ++F: tools/testing/selftests/drivers/ntsync/ ++ + NUBUS SUBSYSTEM + M: Finn Thain + L: linux-m68k@lists.linux-m68k.org +-- +2.43.0 +